From 754716874389ccbea5ee03174df8ad9e72e41880 Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Fri, 22 Mar 2013 16:34:01 +0200 Subject: gpu: host1x: Add host1x driver Add host1x, the driver for host1x and its client unit 2D. The Tegra host1x module is the DMA engine for register access to Tegra's graphics- and multimedia-related modules. The modules served by host1x are referred to as clients. host1x includes some other functionality, such as synchronization. Signed-off-by: Arto Merilainen Signed-off-by: Terje Bergstrom Reviewed-by: Thierry Reding Tested-by: Thierry Reding Tested-by: Erik Faye-Lund Signed-off-by: Thierry Reding --- drivers/gpu/host1x/dev.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 drivers/gpu/host1x/dev.c (limited to 'drivers/gpu/host1x/dev.c') diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c new file mode 100644 index 000000000000..0d6002cb67c1 --- /dev/null +++ b/drivers/gpu/host1x/dev.c @@ -0,0 +1,153 @@ +/* + * Tegra host1x driver + * + * Copyright (c) 2010-2013, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#define CREATE_TRACE_POINTS +#include + +#include "dev.h" +#include "hw/host1x01.h" + +void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) +{ + void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset; + + writel(v, sync_regs + r); +} + +u32 host1x_sync_readl(struct host1x *host1x, u32 r) +{ + void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset; + + return readl(sync_regs + r); +} + +static const struct host1x_info host1x01_info = { + .nb_channels = 8, + .nb_pts = 32, + .nb_mlocks = 16, + .nb_bases = 8, + .init = host1x01_init, + .sync_offset = 0x3000, +}; + +static struct of_device_id host1x_of_match[] = { + { .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, }, + { .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, }, + { }, +}; +MODULE_DEVICE_TABLE(of, host1x_of_match); + +static int host1x_probe(struct platform_device *pdev) +{ + const struct of_device_id *id; + struct host1x *host; + struct resource *regs; + int syncpt_irq; + int err; + + id = of_match_device(host1x_of_match, &pdev->dev); + if (!id) + return -EINVAL; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(&pdev->dev, "failed to get registers\n"); + return -ENXIO; + } + + syncpt_irq = platform_get_irq(pdev, 0); + if (syncpt_irq < 0) { + dev_err(&pdev->dev, "failed to get IRQ\n"); + return -ENXIO; + } + + host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); + if (!host) + return -ENOMEM; + + host->dev = &pdev->dev; + host->info = id->data; + + /* set common host1x device data */ + platform_set_drvdata(pdev, host); + + host->regs = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(host->regs)) + return PTR_ERR(host->regs); + + if (host->info->init) { + err = host->info->init(host); + if (err) + return err; + } + + host->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(host->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + err = PTR_ERR(host->clk); + return err; + } + + err = clk_prepare_enable(host->clk); + if (err < 0) { + dev_err(&pdev->dev, "failed to enable clock\n"); + return err; + } + + err = host1x_syncpt_init(host); + if (err) { + dev_err(&pdev->dev, "failed to initialize syncpts\n"); + return err; + } + + return 0; +} + +static int __exit host1x_remove(struct platform_device *pdev) +{ + struct host1x *host = platform_get_drvdata(pdev); + + host1x_syncpt_deinit(host); + clk_disable_unprepare(host->clk); + + return 0; +} + +static struct platform_driver platform_driver = { + .probe = host1x_probe, + .remove = __exit_p(host1x_remove), + .driver = { + .owner = THIS_MODULE, + .name = "tegra-host1x", + .of_match_table = host1x_of_match, + }, +}; + +module_platform_driver(platform_driver); + +MODULE_AUTHOR("Terje Bergstrom "); +MODULE_DESCRIPTION("Host1x driver for Tegra products"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 7ede0b0bf3e2595d40d6195b6fe4c4dcef438830 Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Fri, 22 Mar 2013 16:34:02 +0200 Subject: gpu: host1x: Add syncpoint wait and interrupts Add support for sync point interrupts, and sync point wait. Sync point wait used interrupts for unblocking wait. Signed-off-by: Arto Merilainen Signed-off-by: Terje Bergstrom Reviewed-by: Thierry Reding Tested-by: Thierry Reding Tested-by: Erik Faye-Lund Signed-off-by: Thierry Reding --- drivers/gpu/host1x/dev.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/gpu/host1x/dev.c') diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 0d6002cb67c1..b967f6e8df55 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -28,6 +28,7 @@ #include #include "dev.h" +#include "intr.h" #include "hw/host1x01.h" void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) @@ -123,13 +124,24 @@ static int host1x_probe(struct platform_device *pdev) return err; } + err = host1x_intr_init(host, syncpt_irq); + if (err) { + dev_err(&pdev->dev, "failed to initialize interrupts\n"); + goto fail_deinit_syncpt; + } + return 0; + +fail_deinit_syncpt: + host1x_syncpt_deinit(host); + return err; } static int __exit host1x_remove(struct platform_device *pdev) { struct host1x *host = platform_get_drvdata(pdev); + host1x_intr_deinit(host); host1x_syncpt_deinit(host); clk_disable_unprepare(host->clk); -- cgit v1.2.2 From 6579324a41cc414009a601738b70a53d6376325c Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Fri, 22 Mar 2013 16:34:03 +0200 Subject: gpu: host1x: Add channel support Add support for host1x client modules, and host1x channels to submit work to the clients. Signed-off-by: Arto Merilainen Signed-off-by: Terje Bergstrom Reviewed-by: Thierry Reding Tested-by: Thierry Reding Tested-by: Erik Faye-Lund Signed-off-by: Thierry Reding --- drivers/gpu/host1x/dev.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/gpu/host1x/dev.c') diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index b967f6e8df55..4e522c532bc8 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -29,6 +29,7 @@ #include "dev.h" #include "intr.h" +#include "channel.h" #include "hw/host1x01.h" void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) @@ -45,6 +46,16 @@ u32 host1x_sync_readl(struct host1x *host1x, u32 r) return readl(sync_regs + r); } +void host1x_ch_writel(struct host1x_channel *ch, u32 v, u32 r) +{ + writel(v, ch->regs + r); +} + +u32 host1x_ch_readl(struct host1x_channel *ch, u32 r) +{ + return readl(ch->regs + r); +} + static const struct host1x_info host1x01_info = { .nb_channels = 8, .nb_pts = 32, @@ -112,6 +123,12 @@ static int host1x_probe(struct platform_device *pdev) return err; } + err = host1x_channel_list_init(host); + if (err) { + dev_err(&pdev->dev, "failed to initialize channel list\n"); + return err; + } + err = clk_prepare_enable(host->clk); if (err < 0) { dev_err(&pdev->dev, "failed to enable clock\n"); -- cgit v1.2.2 From 6236451d83a720072053855fa63d51934024a707 Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Fri, 22 Mar 2013 16:34:04 +0200 Subject: gpu: host1x: Add debug support Add support for host1x debugging. Adds debugfs entries, and dumps channel state to UART in case of stuck job. Signed-off-by: Arto Merilainen Signed-off-by: Terje Bergstrom Reviewed-by: Thierry Reding Tested-by: Thierry Reding Tested-by: Erik Faye-Lund Signed-off-by: Thierry Reding --- drivers/gpu/host1x/dev.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/host1x/dev.c') diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 4e522c532bc8..96897242fcc2 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -30,6 +30,7 @@ #include "dev.h" #include "intr.h" #include "channel.h" +#include "debug.h" #include "hw/host1x01.h" void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) @@ -147,6 +148,8 @@ static int host1x_probe(struct platform_device *pdev) goto fail_deinit_syncpt; } + host1x_debug_init(host); + return 0; fail_deinit_syncpt: -- cgit v1.2.2 From 692e6d7be8099225f04b2d97299bc03479a5fcdb Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Fri, 22 Mar 2013 16:34:07 +0200 Subject: gpu: host1x: Remove second host1x driver Remove second host1x driver, and bind tegra-drm to the new host1x driver. The logic to parse device tree and track clients is moved to drm.c. Signed-off-by: Arto Merilainen Signed-off-by: Terje Bergstrom Reviewed-by: Thierry Reding Tested-by: Thierry Reding Tested-by: Erik Faye-Lund Signed-off-by: Thierry Reding --- drivers/gpu/host1x/dev.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/host1x/dev.c') diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 96897242fcc2..8ce9889cefd5 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -32,6 +32,19 @@ #include "channel.h" #include "debug.h" #include "hw/host1x01.h" +#include "host1x_client.h" + +void host1x_set_drm_data(struct device *dev, void *data) +{ + struct host1x *host1x = dev_get_drvdata(dev); + host1x->drm_data = data; +} + +void *host1x_get_drm_data(struct device *dev) +{ + struct host1x *host1x = dev_get_drvdata(dev); + return host1x->drm_data; +} void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) { @@ -150,6 +163,8 @@ static int host1x_probe(struct platform_device *pdev) host1x_debug_init(host); + host1x_drm_alloc(pdev); + return 0; fail_deinit_syncpt: @@ -168,7 +183,7 @@ static int __exit host1x_remove(struct platform_device *pdev) return 0; } -static struct platform_driver platform_driver = { +static struct platform_driver tegra_host1x_driver = { .probe = host1x_probe, .remove = __exit_p(host1x_remove), .driver = { @@ -178,8 +193,47 @@ static struct platform_driver platform_driver = { }, }; -module_platform_driver(platform_driver); +static int __init tegra_host1x_init(void) +{ + int err; + + err = platform_driver_register(&tegra_host1x_driver); + if (err < 0) + return err; + +#ifdef CONFIG_DRM_TEGRA + err = platform_driver_register(&tegra_dc_driver); + if (err < 0) + goto unregister_host1x; + + err = platform_driver_register(&tegra_hdmi_driver); + if (err < 0) + goto unregister_dc; +#endif + + return 0; + +#ifdef CONFIG_DRM_TEGRA +unregister_dc: + platform_driver_unregister(&tegra_dc_driver); +unregister_host1x: + platform_driver_unregister(&tegra_host1x_driver); + return err; +#endif +} +module_init(tegra_host1x_init); + +static void __exit tegra_host1x_exit(void) +{ +#ifdef CONFIG_DRM_TEGRA + platform_driver_unregister(&tegra_hdmi_driver); + platform_driver_unregister(&tegra_dc_driver); +#endif + platform_driver_unregister(&tegra_host1x_driver); +} +module_exit(tegra_host1x_exit); +MODULE_AUTHOR("Thierry Reding "); MODULE_AUTHOR("Terje Bergstrom "); MODULE_DESCRIPTION("Host1x driver for Tegra products"); MODULE_LICENSE("GPL"); -- cgit v1.2.2 From d43f81cbaf43531a977e8b4c4427f19acf8a5061 Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Fri, 22 Mar 2013 16:34:09 +0200 Subject: drm/tegra: Add gr2d device Add client driver for 2D device, and IOCTLs to pass work to host1x channel for 2D. Also adds functions that can be called to access sync points from DRM. Signed-off-by: Arto Merilainen Signed-off-by: Terje Bergstrom Reviewed-by: Thierry Reding Tested-by: Thierry Reding Tested-by: Erik Faye-Lund Signed-off-by: Thierry Reding --- drivers/gpu/host1x/dev.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/gpu/host1x/dev.c') diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 8ce9889cefd5..28e28a23d444 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -209,11 +209,17 @@ static int __init tegra_host1x_init(void) err = platform_driver_register(&tegra_hdmi_driver); if (err < 0) goto unregister_dc; + + err = platform_driver_register(&tegra_gr2d_driver); + if (err < 0) + goto unregister_hdmi; #endif return 0; #ifdef CONFIG_DRM_TEGRA +unregister_hdmi: + platform_driver_unregister(&tegra_hdmi_driver); unregister_dc: platform_driver_unregister(&tegra_dc_driver); unregister_host1x: @@ -226,6 +232,7 @@ module_init(tegra_host1x_init); static void __exit tegra_host1x_exit(void) { #ifdef CONFIG_DRM_TEGRA + platform_driver_unregister(&tegra_gr2d_driver); platform_driver_unregister(&tegra_hdmi_driver); platform_driver_unregister(&tegra_dc_driver); #endif -- cgit v1.2.2