From 22b9442a6ad8f43994ff96d2a38bee9cea4d6641 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 4 Apr 2023 13:55:20 +0200 Subject: [PATCH 01/33] MAINTAINERS: Add Mikko as backup maintainer for Tegra DRM Mikko has been involved as the primary author of the host1x driver and has volunteered to help out with maintenance. Signed-off-by: Thierry Reding --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index d8ebab595b2a..32406625cefb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6916,6 +6916,7 @@ F: drivers/phy/mediatek/phy-mtk-mipi* DRM DRIVERS FOR NVIDIA TEGRA M: Thierry Reding +M: Mikko Perttunen L: dri-devel@lists.freedesktop.org L: linux-tegra@vger.kernel.org S: Supported From 1d83d1a2df0bfb6bd79400746c289e2c4edc5909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 22 Mar 2023 18:02:12 +0100 Subject: [PATCH 02/33] gpu: host1x: Make host1x_client_unregister() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function returned zero unconditionally. Make it return no value and simplify all callers accordingly. Signed-off-by: Uwe Kleine-König Acked-by: Hans Verkuil Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 7 +------ drivers/gpu/drm/tegra/dsi.c | 8 +------- drivers/gpu/drm/tegra/gr2d.c | 8 +------- drivers/gpu/drm/tegra/gr3d.c | 8 +------- drivers/gpu/drm/tegra/hdmi.c | 8 +------- drivers/gpu/drm/tegra/hub.c | 9 ++------- drivers/gpu/drm/tegra/nvdec.c | 8 +------- drivers/gpu/drm/tegra/sor.c | 8 +------- drivers/gpu/drm/tegra/vic.c | 8 +------- drivers/gpu/host1x/bus.c | 6 ++---- drivers/staging/media/tegra-video/csi.c | 8 +------- drivers/staging/media/tegra-video/vi.c | 8 +------- include/linux/host1x.h | 2 +- 13 files changed, 15 insertions(+), 81 deletions(-) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index a67453cee883..bd108159fc2c 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -3268,12 +3268,7 @@ static int tegra_dc_remove(struct platform_device *pdev) struct tegra_dc *dc = platform_get_drvdata(pdev); int err; - err = host1x_client_unregister(&dc->client); - if (err < 0) { - dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", - err); - return err; - } + host1x_client_unregister(&dc->client); err = tegra_dc_rgb_remove(dc); if (err < 0) { diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index de1333dc0d86..c8a02a1024bc 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1662,16 +1662,10 @@ mipi_free: static int tegra_dsi_remove(struct platform_device *pdev) { struct tegra_dsi *dsi = platform_get_drvdata(pdev); - int err; pm_runtime_disable(&pdev->dev); - err = host1x_client_unregister(&dsi->client); - if (err < 0) { - dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", - err); - return err; - } + host1x_client_unregister(&dsi->client); tegra_output_remove(&dsi->output); diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index e3bb4c99ed39..49b8d4953e7f 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -298,14 +298,8 @@ static int gr2d_probe(struct platform_device *pdev) static int gr2d_remove(struct platform_device *pdev) { struct gr2d *gr2d = platform_get_drvdata(pdev); - int err; - err = host1x_client_unregister(&gr2d->client.base); - if (err < 0) { - dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", - err); - return err; - } + host1x_client_unregister(&gr2d->client.base); return 0; } diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index a1fd3113ea96..cd3679d8eef9 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -553,14 +553,8 @@ static int gr3d_probe(struct platform_device *pdev) static int gr3d_remove(struct platform_device *pdev) { struct gr3d *gr3d = platform_get_drvdata(pdev); - int err; - err = host1x_client_unregister(&gr3d->client.base); - if (err < 0) { - dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", - err); - return err; - } + host1x_client_unregister(&gr3d->client.base); return 0; } diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 40ec3e6cf204..6798eea317df 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1877,14 +1877,8 @@ static int tegra_hdmi_probe(struct platform_device *pdev) static int tegra_hdmi_remove(struct platform_device *pdev) { struct tegra_hdmi *hdmi = platform_get_drvdata(pdev); - int err; - err = host1x_client_unregister(&hdmi->client); - if (err < 0) { - dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", - err); - return err; - } + host1x_client_unregister(&hdmi->client); tegra_output_remove(&hdmi->output); diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index b872527a123c..2c91dc444085 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -1178,13 +1178,8 @@ static int tegra_display_hub_remove(struct platform_device *pdev) { struct tegra_display_hub *hub = platform_get_drvdata(pdev); unsigned int i; - int err; - err = host1x_client_unregister(&hub->client); - if (err < 0) { - dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", - err); - } + host1x_client_unregister(&hub->client); for (i = 0; i < hub->soc->num_wgrps; i++) { struct tegra_windowgroup *wgrp = &hub->wgrps[i]; @@ -1194,7 +1189,7 @@ static int tegra_display_hub_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); - return err; + return 0; } static const struct tegra_display_hub_soc tegra186_display_hub = { diff --git a/drivers/gpu/drm/tegra/nvdec.c b/drivers/gpu/drm/tegra/nvdec.c index 86c5818ac27b..077f3af0d0b6 100644 --- a/drivers/gpu/drm/tegra/nvdec.c +++ b/drivers/gpu/drm/tegra/nvdec.c @@ -550,14 +550,8 @@ exit_falcon: static int nvdec_remove(struct platform_device *pdev) { struct nvdec *nvdec = platform_get_drvdata(pdev); - int err; - err = host1x_client_unregister(&nvdec->client.base); - if (err < 0) { - dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", - err); - return err; - } + host1x_client_unregister(&nvdec->client.base); falcon_exit(&nvdec->falcon); diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 8af632740673..d067b2d01b2e 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -3981,14 +3981,8 @@ put_aux: static int tegra_sor_remove(struct platform_device *pdev) { struct tegra_sor *sor = platform_get_drvdata(pdev); - int err; - err = host1x_client_unregister(&sor->client); - if (err < 0) { - dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", - err); - return err; - } + host1x_client_unregister(&sor->client); pm_runtime_disable(&pdev->dev); diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index 531a71c72061..fd614756ecf8 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -540,14 +540,8 @@ exit_falcon: static int vic_remove(struct platform_device *pdev) { struct vic *vic = platform_get_drvdata(pdev); - int err; - err = host1x_client_unregister(&vic->client.base); - if (err < 0) { - dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", - err); - return err; - } + host1x_client_unregister(&vic->client.base); falcon_exit(&vic->falcon); diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c index bc7271a00a94..4d16a3396c4a 100644 --- a/drivers/gpu/host1x/bus.c +++ b/drivers/gpu/host1x/bus.c @@ -803,7 +803,7 @@ EXPORT_SYMBOL(__host1x_client_register); * Removes a host1x client from its host1x controller instance. If a logical * device has already been initialized, it will be torn down. */ -int host1x_client_unregister(struct host1x_client *client) +void host1x_client_unregister(struct host1x_client *client) { struct host1x_client *c; struct host1x *host1x; @@ -815,7 +815,7 @@ int host1x_client_unregister(struct host1x_client *client) err = host1x_del_client(host1x, client); if (!err) { mutex_unlock(&devices_lock); - return 0; + return; } } @@ -832,8 +832,6 @@ int host1x_client_unregister(struct host1x_client *client) mutex_unlock(&clients_lock); host1x_bo_cache_destroy(&client->cache); - - return 0; } EXPORT_SYMBOL(host1x_client_unregister); diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c index 426e653bd55d..36ca639622c9 100644 --- a/drivers/staging/media/tegra-video/csi.c +++ b/drivers/staging/media/tegra-video/csi.c @@ -778,14 +778,8 @@ rpm_disable: static int tegra_csi_remove(struct platform_device *pdev) { struct tegra_csi *csi = platform_get_drvdata(pdev); - int err; - err = host1x_client_unregister(&csi->client); - if (err < 0) { - dev_err(&pdev->dev, - "failed to unregister host1x client: %d\n", err); - return err; - } + host1x_client_unregister(&csi->client); pm_runtime_disable(&pdev->dev); diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c index 11dd142c98c5..26f7aedce718 100644 --- a/drivers/staging/media/tegra-video/vi.c +++ b/drivers/staging/media/tegra-video/vi.c @@ -2041,14 +2041,8 @@ rpm_disable: static int tegra_vi_remove(struct platform_device *pdev) { struct tegra_vi *vi = platform_get_drvdata(pdev); - int err; - err = host1x_client_unregister(&vi->client); - if (err < 0) { - dev_err(&pdev->dev, - "failed to unregister host1x client: %d\n", err); - return err; - } + host1x_client_unregister(&vi->client); pm_runtime_disable(&pdev->dev); diff --git a/include/linux/host1x.h b/include/linux/host1x.h index 9a9de4b97a25..9c8119ed13a4 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -443,7 +443,7 @@ int __host1x_client_register(struct host1x_client *client); __host1x_client_register(client); \ }) -int host1x_client_unregister(struct host1x_client *client); +void host1x_client_unregister(struct host1x_client *client); int host1x_client_suspend(struct host1x_client *client); int host1x_client_resume(struct host1x_client *client); From c1aaee94380874fd40f7bb8417c597aba3f72c75 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 1 Mar 2023 15:51:06 +0200 Subject: [PATCH 03/33] gpu: host1x: Don't rely on dma_fence_wait_timeout return value dma_fence_wait_timeout (along with a host of other jiffies-based timeouting functions) returns zero both in case of timeout and when the wait completes during the last jiffy before timeout. As such, we can't rely on it to distinguish between success and timeout. To prevent confusing callers by returning -EAGAIN before the timeout period has elapsed, check if the fence got signaled again after the wait. Signed-off-by: Mikko Perttunen Signed-off-by: Thierry Reding --- drivers/gpu/host1x/syncpt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index 2d2007760eac..f63d14a57a1d 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c @@ -248,7 +248,13 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, if (value) *value = host1x_syncpt_load(sp); - if (wait_err == 0) + /* + * Don't rely on dma_fence_wait_timeout return value, + * since it returns zero both on timeout and if the + * wait completed with 0 jiffies left. + */ + host1x_hw_syncpt_load(sp->host, sp); + if (wait_err == 0 && !host1x_syncpt_is_expired(sp, thresh)) return -EAGAIN; else if (wait_err < 0) return wait_err; From 791b5ecece5e6c22aa9aa55b7a9ee827a971a799 Mon Sep 17 00:00:00 2001 From: Ye Xingchen Date: Wed, 8 Feb 2023 15:41:56 +0800 Subject: [PATCH 04/33] gpu: host1x: mipi: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Ye Xingchen Signed-off-by: Thierry Reding --- drivers/gpu/host1x/mipi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c index 2efe12dde8bc..4dcec535ec21 100644 --- a/drivers/gpu/host1x/mipi.c +++ b/drivers/gpu/host1x/mipi.c @@ -501,7 +501,6 @@ static int tegra_mipi_probe(struct platform_device *pdev) { const struct of_device_id *match; struct tegra_mipi *mipi; - struct resource *res; int err; match = of_match_node(tegra_mipi_of_match, pdev->dev.of_node); @@ -515,8 +514,7 @@ static int tegra_mipi_probe(struct platform_device *pdev) mipi->soc = match->data; mipi->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mipi->regs = devm_ioremap_resource(&pdev->dev, res); + mipi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(mipi->regs)) return PTR_ERR(mipi->regs); From 8466ff24a37a9a18fb935e90dda64f049131ae28 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Sat, 26 Nov 2022 15:33:14 +0800 Subject: [PATCH 05/33] gpu: host1x: Fix potential double free if IOMMU is disabled If context device has no IOMMU, the 'cdl->devs' is freed in error path, but host1x_memory_context_list_init() doesn't return an error code, so the module can be loaded successfully, when it's unloading, the host1x_memory_context_list_free() is called in host1x_remove(), it will cause double free. Set the 'cdl->devs' to NULL after freeing it to avoid double free. Fixes: 8aa5bcb61612 ("gpu: host1x: Add context device management code") Signed-off-by: Yang Yingliang Reviewed-by: Mikko Perttunen Signed-off-by: Thierry Reding --- drivers/gpu/host1x/context.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/host1x/context.c b/drivers/gpu/host1x/context.c index 8beedcf080ab..5ec18315ff9f 100644 --- a/drivers/gpu/host1x/context.c +++ b/drivers/gpu/host1x/context.c @@ -83,6 +83,7 @@ del_devices: device_del(&cdl->devs[i].dev); kfree(cdl->devs); + cdl->devs = NULL; cdl->len = 0; return err; From 55879dad0f3ae8468444b42f785ad79eac05fe5b Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Sat, 26 Nov 2022 15:33:15 +0800 Subject: [PATCH 06/33] gpu: host1x: Fix memory leak of device names The device names allocated by dev_set_name() need be freed before module unloading, but they can not be freed because the kobject's refcount which was set in device_initialize() has not be decreased to 0. As comment of device_add() says, if it fails, use only put_device() drop the refcount, then the name will be freed in kobejct_cleanup(). device_del() and put_device() can be replaced with device_unregister(), so call it to unregister the added successfully devices, and just call put_device() to the not added device. Add a release() function to device to avoid null release() function WARNING in device_release(), it's empty, because the context devices are freed together in host1x_memory_context_list_free(). Fixes: 8aa5bcb61612 ("gpu: host1x: Add context device management code") Signed-off-by: Yang Yingliang Reviewed-by: Mikko Perttunen Signed-off-by: Thierry Reding --- drivers/gpu/host1x/context.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/host1x/context.c b/drivers/gpu/host1x/context.c index 5ec18315ff9f..9ad89d22c0ca 100644 --- a/drivers/gpu/host1x/context.c +++ b/drivers/gpu/host1x/context.c @@ -13,6 +13,11 @@ #include "context.h" #include "dev.h" +static void host1x_memory_context_release(struct device *dev) +{ + /* context device is freed in host1x_memory_context_list_free() */ +} + int host1x_memory_context_list_init(struct host1x *host1x) { struct host1x_memory_context_list *cdl = &host1x->context_list; @@ -51,36 +56,38 @@ int host1x_memory_context_list_init(struct host1x *host1x) dev_set_name(&ctx->dev, "host1x-ctx.%d", i); ctx->dev.bus = &host1x_context_device_bus_type; ctx->dev.parent = host1x->dev; + ctx->dev.release = host1x_memory_context_release; dma_set_max_seg_size(&ctx->dev, UINT_MAX); err = device_add(&ctx->dev); if (err) { dev_err(host1x->dev, "could not add context device %d: %d\n", i, err); - goto del_devices; + put_device(&ctx->dev); + goto unreg_devices; } err = of_dma_configure_id(&ctx->dev, node, true, &i); if (err) { dev_err(host1x->dev, "IOMMU configuration failed for context device %d: %d\n", i, err); - device_del(&ctx->dev); - goto del_devices; + device_unregister(&ctx->dev); + goto unreg_devices; } if (!tegra_dev_iommu_get_stream_id(&ctx->dev, &ctx->stream_id) || !device_iommu_mapped(&ctx->dev)) { dev_err(host1x->dev, "Context device %d has no IOMMU!\n", i); - device_del(&ctx->dev); - goto del_devices; + device_unregister(&ctx->dev); + goto unreg_devices; } } return 0; -del_devices: +unreg_devices: while (i--) - device_del(&cdl->devs[i].dev); + device_unregister(&cdl->devs[i].dev); kfree(cdl->devs); cdl->devs = NULL; @@ -94,7 +101,7 @@ void host1x_memory_context_list_free(struct host1x_memory_context_list *cdl) unsigned int i; for (i = 0; i < cdl->len; i++) - device_del(&cdl->devs[i].dev); + device_unregister(&cdl->devs[i].dev); kfree(cdl->devs); cdl->len = 0; From 437405403ab4496cee65add5733f45a40b08c8c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 22 Mar 2023 18:02:13 +0100 Subject: [PATCH 07/33] drm/tegra: rgb: Make tegra_dc_rgb_remove() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function returned zero unconditionally. Make it return no value and simplify all callers accordingly. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 7 +------ drivers/gpu/drm/tegra/dc.h | 2 +- drivers/gpu/drm/tegra/rgb.c | 6 ++---- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index bd108159fc2c..6bf1b2bc43b1 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -3266,15 +3266,10 @@ disable_pm: static int tegra_dc_remove(struct platform_device *pdev) { struct tegra_dc *dc = platform_get_drvdata(pdev); - int err; host1x_client_unregister(&dc->client); - err = tegra_dc_rgb_remove(dc); - if (err < 0) { - dev_err(&pdev->dev, "failed to remove RGB output: %d\n", err); - return err; - } + tegra_dc_rgb_remove(dc); pm_runtime_disable(&pdev->dev); diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index f902794d42cc..0559fa6b1bf7 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -169,7 +169,7 @@ void tegra_crtc_atomic_post_commit(struct drm_crtc *crtc, /* from rgb.c */ int tegra_dc_rgb_probe(struct tegra_dc *dc); -int tegra_dc_rgb_remove(struct tegra_dc *dc); +void tegra_dc_rgb_remove(struct tegra_dc *dc); int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc); int tegra_dc_rgb_exit(struct tegra_dc *dc); diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index ff8fce36d2aa..da2d9baca214 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -250,12 +250,12 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc) return 0; } -int tegra_dc_rgb_remove(struct tegra_dc *dc) +void tegra_dc_rgb_remove(struct tegra_dc *dc) { struct tegra_rgb *rgb; if (!dc->rgb) - return 0; + return; rgb = to_rgb(dc->rgb); clk_put(rgb->pll_d2_out0); @@ -263,8 +263,6 @@ int tegra_dc_rgb_remove(struct tegra_dc *dc) tegra_output_remove(dc->rgb); dc->rgb = NULL; - - return 0; } int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc) From 30d92e0fcd902bb8b1e465f5a0c7ea9596a9e381 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 22 Mar 2023 18:02:14 +0100 Subject: [PATCH 08/33] drm/tegra: dc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 6bf1b2bc43b1..53630b673029 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -3263,7 +3263,7 @@ disable_pm: return err; } -static int tegra_dc_remove(struct platform_device *pdev) +static void tegra_dc_remove(struct platform_device *pdev) { struct tegra_dc *dc = platform_get_drvdata(pdev); @@ -3272,8 +3272,6 @@ static int tegra_dc_remove(struct platform_device *pdev) tegra_dc_rgb_remove(dc); pm_runtime_disable(&pdev->dev); - - return 0; } struct platform_driver tegra_dc_driver = { @@ -3282,5 +3280,5 @@ struct platform_driver tegra_dc_driver = { .of_match_table = tegra_dc_of_match, }, .probe = tegra_dc_probe, - .remove = tegra_dc_remove, + .remove_new = tegra_dc_remove, }; From 4b9aeb8d4a96567ae25ac9f4f42f8682f45c7b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 22 Mar 2023 18:02:15 +0100 Subject: [PATCH 09/33] drm/tegra: dpaux: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dpaux.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index 3c84e73d5051..4d2677dcd831 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -579,7 +579,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) return 0; } -static int tegra_dpaux_remove(struct platform_device *pdev) +static void tegra_dpaux_remove(struct platform_device *pdev) { struct tegra_dpaux *dpaux = platform_get_drvdata(pdev); @@ -594,8 +594,6 @@ static int tegra_dpaux_remove(struct platform_device *pdev) mutex_lock(&dpaux_lock); list_del(&dpaux->list); mutex_unlock(&dpaux_lock); - - return 0; } static int tegra_dpaux_suspend(struct device *dev) @@ -695,7 +693,7 @@ struct platform_driver tegra_dpaux_driver = { .pm = pm_ptr(&tegra_dpaux_pm_ops), }, .probe = tegra_dpaux_probe, - .remove = tegra_dpaux_remove, + .remove_new = tegra_dpaux_remove, }; struct drm_dp_aux *drm_dp_aux_find_by_of_node(struct device_node *np) From 50a2a987c2a29f738885d9a9ebc7985c6a7e4e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 22 Mar 2023 18:02:16 +0100 Subject: [PATCH 10/33] drm/tegra: dsi: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dsi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index c8a02a1024bc..7781e69e1ff7 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1659,7 +1659,7 @@ mipi_free: return err; } -static int tegra_dsi_remove(struct platform_device *pdev) +static void tegra_dsi_remove(struct platform_device *pdev) { struct tegra_dsi *dsi = platform_get_drvdata(pdev); @@ -1671,8 +1671,6 @@ static int tegra_dsi_remove(struct platform_device *pdev) mipi_dsi_host_unregister(&dsi->host); tegra_mipi_free(dsi->mipi); - - return 0; } static const struct of_device_id tegra_dsi_of_match[] = { @@ -1690,5 +1688,5 @@ struct platform_driver tegra_dsi_driver = { .of_match_table = tegra_dsi_of_match, }, .probe = tegra_dsi_probe, - .remove = tegra_dsi_remove, + .remove_new = tegra_dsi_remove, }; From e12ce931bd4dc1040025e18ff08a872912542057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 22 Mar 2023 18:02:17 +0100 Subject: [PATCH 11/33] drm/tegra: gr2d: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/gr2d.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index 49b8d4953e7f..50f77fddda54 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -295,13 +295,11 @@ static int gr2d_probe(struct platform_device *pdev) return 0; } -static int gr2d_remove(struct platform_device *pdev) +static void gr2d_remove(struct platform_device *pdev) { struct gr2d *gr2d = platform_get_drvdata(pdev); host1x_client_unregister(&gr2d->client.base); - - return 0; } static int __maybe_unused gr2d_runtime_suspend(struct device *dev) @@ -397,5 +395,5 @@ struct platform_driver tegra_gr2d_driver = { .pm = &tegra_gr2d_pm, }, .probe = gr2d_probe, - .remove = gr2d_remove, + .remove_new = gr2d_remove, }; From de9fce20c020db33d85f87687e6b30855d8d3e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 22 Mar 2023 18:02:18 +0100 Subject: [PATCH 12/33] drm/tegra: gr3d: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/gr3d.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index cd3679d8eef9..c026c2c916c1 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -550,13 +550,11 @@ static int gr3d_probe(struct platform_device *pdev) return 0; } -static int gr3d_remove(struct platform_device *pdev) +static void gr3d_remove(struct platform_device *pdev) { struct gr3d *gr3d = platform_get_drvdata(pdev); host1x_client_unregister(&gr3d->client.base); - - return 0; } static int __maybe_unused gr3d_runtime_suspend(struct device *dev) @@ -632,5 +630,5 @@ struct platform_driver tegra_gr3d_driver = { .pm = &tegra_gr3d_pm, }, .probe = gr3d_probe, - .remove = gr3d_remove, + .remove_new = gr3d_remove, }; From 4ef19206b23b49041a3eeb4ea132a213e4f7b78c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 22 Mar 2023 18:02:19 +0100 Subject: [PATCH 13/33] drm/tegra: hdmi: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/hdmi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 6798eea317df..6eac54ae1205 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1874,15 +1874,13 @@ static int tegra_hdmi_probe(struct platform_device *pdev) return 0; } -static int tegra_hdmi_remove(struct platform_device *pdev) +static void tegra_hdmi_remove(struct platform_device *pdev) { struct tegra_hdmi *hdmi = platform_get_drvdata(pdev); host1x_client_unregister(&hdmi->client); tegra_output_remove(&hdmi->output); - - return 0; } struct platform_driver tegra_hdmi_driver = { @@ -1891,5 +1889,5 @@ struct platform_driver tegra_hdmi_driver = { .of_match_table = tegra_hdmi_of_match, }, .probe = tegra_hdmi_probe, - .remove = tegra_hdmi_remove, + .remove_new = tegra_hdmi_remove, }; From f9998eef32ad1128240e70861bcafc3bfb588719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 22 Mar 2023 18:02:20 +0100 Subject: [PATCH 14/33] drm/tegra: hub: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/hub.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index 2c91dc444085..916857361a91 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -1174,7 +1174,7 @@ unregister: return err; } -static int tegra_display_hub_remove(struct platform_device *pdev) +static void tegra_display_hub_remove(struct platform_device *pdev) { struct tegra_display_hub *hub = platform_get_drvdata(pdev); unsigned int i; @@ -1188,8 +1188,6 @@ static int tegra_display_hub_remove(struct platform_device *pdev) } pm_runtime_disable(&pdev->dev); - - return 0; } static const struct tegra_display_hub_soc tegra186_display_hub = { @@ -1221,5 +1219,5 @@ struct platform_driver tegra_display_hub_driver = { .of_match_table = tegra_display_hub_of_match, }, .probe = tegra_display_hub_probe, - .remove = tegra_display_hub_remove, + .remove_new = tegra_display_hub_remove, }; From 312f9e92e7749ecb565023aa3004cb8edec80c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 22 Mar 2023 18:02:21 +0100 Subject: [PATCH 15/33] drm/tegra: nvdec: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/nvdec.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/nvdec.c b/drivers/gpu/drm/tegra/nvdec.c index 077f3af0d0b6..ae78a81e5eef 100644 --- a/drivers/gpu/drm/tegra/nvdec.c +++ b/drivers/gpu/drm/tegra/nvdec.c @@ -547,15 +547,13 @@ exit_falcon: return err; } -static int nvdec_remove(struct platform_device *pdev) +static void nvdec_remove(struct platform_device *pdev) { struct nvdec *nvdec = platform_get_drvdata(pdev); host1x_client_unregister(&nvdec->client.base); falcon_exit(&nvdec->falcon); - - return 0; } static const struct dev_pm_ops nvdec_pm_ops = { @@ -571,7 +569,7 @@ struct platform_driver tegra_nvdec_driver = { .pm = &nvdec_pm_ops }, .probe = nvdec_probe, - .remove = nvdec_remove, + .remove_new = nvdec_remove, }; #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) From 3b6f890043d22955f860ec31710c746bc45955fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 22 Mar 2023 18:02:22 +0100 Subject: [PATCH 16/33] drm/tegra: sor: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/sor.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index d067b2d01b2e..e617d55f6f3c 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -3978,7 +3978,7 @@ put_aux: return err; } -static int tegra_sor_remove(struct platform_device *pdev) +static void tegra_sor_remove(struct platform_device *pdev) { struct tegra_sor *sor = platform_get_drvdata(pdev); @@ -3992,8 +3992,6 @@ static int tegra_sor_remove(struct platform_device *pdev) } tegra_output_remove(&sor->output); - - return 0; } static int __maybe_unused tegra_sor_suspend(struct device *dev) @@ -4053,5 +4051,5 @@ struct platform_driver tegra_sor_driver = { .pm = &tegra_sor_pm_ops, }, .probe = tegra_sor_probe, - .remove = tegra_sor_remove, + .remove_new = tegra_sor_remove, }; From 9eb75fbf0569cc3280d545e138d6137da671d3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 22 Mar 2023 18:02:23 +0100 Subject: [PATCH 17/33] drm/tegra: vic: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/vic.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index fd614756ecf8..da7a038dca20 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -537,15 +537,13 @@ exit_falcon: return err; } -static int vic_remove(struct platform_device *pdev) +static void vic_remove(struct platform_device *pdev) { struct vic *vic = platform_get_drvdata(pdev); host1x_client_unregister(&vic->client.base); falcon_exit(&vic->falcon); - - return 0; } static const struct dev_pm_ops vic_pm_ops = { @@ -560,7 +558,7 @@ struct platform_driver tegra_vic_driver = { .pm = &vic_pm_ops }, .probe = vic_probe, - .remove = vic_remove, + .remove_new = vic_remove, }; #if IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) From f75d19827b731c6f24930ef77e5a46cf2242bc68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 22 Mar 2023 11:39:15 +0100 Subject: [PATCH 18/33] drm/tegra: Allow compile test on !ARM v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This compile tests on x86 just perfectly fine. v2: fix missing include complained by kernel test robot Signed-off-by: Christian König CC: Thierry Reding CC: Jonathan Hunter CC: linux-tegra@vger.kernel.org Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/Kconfig | 2 +- drivers/gpu/drm/tegra/gem.c | 1 + drivers/gpu/host1x/Kconfig | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig index c36323f1c7e6..56453ca277c2 100644 --- a/drivers/gpu/drm/tegra/Kconfig +++ b/drivers/gpu/drm/tegra/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_TEGRA tristate "NVIDIA Tegra DRM" - depends on ARCH_TEGRA || (ARM && COMPILE_TEST) + depends on ARCH_TEGRA || COMPILE_TEST depends on COMMON_CLK depends on DRM depends on OF diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index bce991a2ccc0..dea38892d6e6 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff --git a/drivers/gpu/host1x/Kconfig b/drivers/gpu/host1x/Kconfig index 1861a8180d3f..e6c78ae2003a 100644 --- a/drivers/gpu/host1x/Kconfig +++ b/drivers/gpu/host1x/Kconfig @@ -5,7 +5,7 @@ config TEGRA_HOST1X_CONTEXT_BUS config TEGRA_HOST1X tristate "NVIDIA Tegra host1x driver" - depends on ARCH_TEGRA || (ARM && COMPILE_TEST) + depends on ARCH_TEGRA || COMPILE_TEST select DMA_SHARED_BUFFER select TEGRA_HOST1X_CONTEXT_BUS select IOMMU_IOVA From 13fcbcb97d05be14c5ada46b5b6cf71f8c96ad50 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 17 Mar 2023 08:16:50 +0000 Subject: [PATCH 19/33] drm/tegra: dc: Remove set but unused variable 'state' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/gpu/drm/tegra/dc.c: In function ‘tegra_crtc_calculate_memory_bandwidth’: drivers/gpu/drm/tegra/dc.c:2384:38: warning: variable ‘old_state’ set but not used [-Wunused-but-set-variable] Cc: Thierry Reding Cc: David Airlie Cc: Daniel Vetter Cc: Jonathan Hunter Cc: Philipp Zabel Cc: dri-devel@lists.freedesktop.org Cc: linux-tegra@vger.kernel.org Signed-off-by: Lee Jones Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 53630b673029..6e78416e64b0 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -2381,7 +2381,6 @@ static int tegra_crtc_calculate_memory_bandwidth(struct drm_crtc *crtc, const struct tegra_plane_state *tegra_state; const struct drm_plane_state *plane_state; struct tegra_dc *dc = to_tegra_dc(crtc); - const struct drm_crtc_state *old_state; struct drm_crtc_state *new_state; struct tegra_plane *tegra; struct drm_plane *plane; @@ -2396,7 +2395,6 @@ static int tegra_crtc_calculate_memory_bandwidth(struct drm_crtc *crtc, return 0; new_state = drm_atomic_get_new_crtc_state(state, crtc); - old_state = drm_atomic_get_old_crtc_state(state, crtc); /* * For overlapping planes pixel's data is fetched for each plane at From 3105e42c75e0f80a6933e29291a94f669b869dbd Mon Sep 17 00:00:00 2001 From: Deepak R Varma Date: Thu, 2 Mar 2023 01:18:06 +0530 Subject: [PATCH 20/33] drm/tegra: sor: Remove redundant error logging A call to platform_get_irq() already prints an error on failure within its own implementation. So printing another error based on its return value in the caller is redundant and should be removed. The clean up also makes if condition block braces unnecessary. Remove that as well. Issue identified using platform_get_irq.cocci coccicheck script. Signed-off-by: Deepak R Varma Reviewed-by: Ashutosh Dixit Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/sor.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index e617d55f6f3c..8eafbdd3620c 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -3799,10 +3799,8 @@ static int tegra_sor_probe(struct platform_device *pdev) } err = platform_get_irq(pdev, 0); - if (err < 0) { - dev_err(&pdev->dev, "failed to get IRQ: %d\n", err); + if (err < 0) goto remove; - } sor->irq = err; From d4281c016d84d56abd5fc19eb0e24ca7c5138e8c Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Fri, 17 Sep 2021 10:07:41 +0800 Subject: [PATCH 21/33] drm/tegra: sor: Make use of the helper function dev_err_probe() When possible use dev_err_probe help to properly deal with the PROBE_DEFER error, the benefit is that DEFER issue will be logged in the devices_deferred debugfs file. And using dev_err_probe() can reduce code size, the error value gets printed. Reported-by: kernel test robot Signed-off-by: Cai Huoqing Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/sor.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 8eafbdd3620c..cd25f409979c 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -2964,11 +2964,9 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor) int err; sor->avdd_io_supply = devm_regulator_get(sor->dev, "avdd-io-hdmi-dp"); - if (IS_ERR(sor->avdd_io_supply)) { - dev_err(sor->dev, "cannot get AVDD I/O supply: %ld\n", - PTR_ERR(sor->avdd_io_supply)); - return PTR_ERR(sor->avdd_io_supply); - } + if (IS_ERR(sor->avdd_io_supply)) + return dev_err_probe(sor->dev, PTR_ERR(sor->avdd_io_supply), + "cannot get AVDD I/O supply\n"); err = tegra_sor_enable_regulator(sor, sor->avdd_io_supply); if (err < 0) { @@ -2978,11 +2976,9 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor) } sor->vdd_pll_supply = devm_regulator_get(sor->dev, "vdd-hdmi-dp-pll"); - if (IS_ERR(sor->vdd_pll_supply)) { - dev_err(sor->dev, "cannot get VDD PLL supply: %ld\n", - PTR_ERR(sor->vdd_pll_supply)); - return PTR_ERR(sor->vdd_pll_supply); - } + if (IS_ERR(sor->vdd_pll_supply)) + return dev_err_probe(sor->dev, PTR_ERR(sor->vdd_pll_supply), + "cannot get VDD PLL supply\n"); err = tegra_sor_enable_regulator(sor, sor->vdd_pll_supply); if (err < 0) { @@ -2992,11 +2988,9 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor) } sor->hdmi_supply = devm_regulator_get(sor->dev, "hdmi"); - if (IS_ERR(sor->hdmi_supply)) { - dev_err(sor->dev, "cannot get HDMI supply: %ld\n", - PTR_ERR(sor->hdmi_supply)); - return PTR_ERR(sor->hdmi_supply); - } + if (IS_ERR(sor->hdmi_supply)) + return dev_err_probe(sor->dev, PTR_ERR(sor->hdmi_supply), + "cannot get HDMI supply\n"); err = tegra_sor_enable_regulator(sor, sor->hdmi_supply); if (err < 0) { From fc75e4fcbd1e4252a0481ebb23cd4516c127a8e2 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Thu, 16 Sep 2021 18:56:40 +0800 Subject: [PATCH 22/33] drm/tegra: dsi: Make use of the helper function dev_err_probe() When possible use dev_err_probe help to properly deal with the PROBE_DEFER error, the benefit is that DEFER issue will be logged in the devices_deferred debugfs file. And using dev_err_probe() can reduce code size, the error value gets printed. Signed-off-by: Cai Huoqing Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dsi.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 7781e69e1ff7..49f0bc270e14 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1589,28 +1589,24 @@ static int tegra_dsi_probe(struct platform_device *pdev) } dsi->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(dsi->clk)) { - dev_err(&pdev->dev, "cannot get DSI clock\n"); - return PTR_ERR(dsi->clk); - } + if (IS_ERR(dsi->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk), + "cannot get DSI clock\n"); dsi->clk_lp = devm_clk_get(&pdev->dev, "lp"); - if (IS_ERR(dsi->clk_lp)) { - dev_err(&pdev->dev, "cannot get low-power clock\n"); - return PTR_ERR(dsi->clk_lp); - } + if (IS_ERR(dsi->clk_lp)) + return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp), + "cannot get low-power clock\n"); dsi->clk_parent = devm_clk_get(&pdev->dev, "parent"); - if (IS_ERR(dsi->clk_parent)) { - dev_err(&pdev->dev, "cannot get parent clock\n"); - return PTR_ERR(dsi->clk_parent); - } + if (IS_ERR(dsi->clk_parent)) + return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_parent), + "cannot get parent clock\n"); dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi"); - if (IS_ERR(dsi->vdd)) { - dev_err(&pdev->dev, "cannot get VDD supply\n"); - return PTR_ERR(dsi->vdd); - } + if (IS_ERR(dsi->vdd)) + return dev_err_probe(&pdev->dev, PTR_ERR(dsi->vdd), + "cannot get VDD supply\n"); err = tegra_dsi_setup_clocks(dsi); if (err < 0) { From e752eef028c363445f3fc06221ed479e71a0e971 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Thu, 16 Sep 2021 15:37:21 +0800 Subject: [PATCH 23/33] drm/tegra: plane: Improve use of dev_err_probe() Return dev_err_probe() directly, because the return value of dev_err_probe() is the appropriate error code, and it can reduce code size, simplify the code. Signed-off-by: Cai Huoqing Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/plane.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index 10090116895f..ffe5f06b770d 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -777,21 +777,17 @@ int tegra_plane_interconnect_init(struct tegra_plane *plane) plane->icc_mem = devm_of_icc_get(dev, icc_name); err = PTR_ERR_OR_ZERO(plane->icc_mem); - if (err) { - dev_err_probe(dev, err, "failed to get %s interconnect\n", - icc_name); - return err; - } + if (err) + return dev_err_probe(dev, err, "failed to get %s interconnect\n", + icc_name); /* plane B on T20/30 has a dedicated memory client for a 6-tap vertical filter */ if (plane->index == 1 && dc->soc->has_win_b_vfilter_mem_client) { plane->icc_mem_vfilter = devm_of_icc_get(dev, "winb-vfilter"); err = PTR_ERR_OR_ZERO(plane->icc_mem_vfilter); - if (err) { - dev_err_probe(dev, err, "failed to get %s interconnect\n", - "winb-vfilter"); - return err; - } + if (err) + return dev_err_probe(dev, err, "failed to get %s interconnect\n", + "winb-vfilter"); } return 0; From b22fd0b9639ed61e379b3b9bba00629ebf8e6946 Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Mon, 28 Nov 2022 16:28:49 +0000 Subject: [PATCH 24/33] drm/tegra: dsi: Clear enable register if powered by bootloader In cases where the DSI module is left on by the bootloader some panels may fail to initialize if the enable register is not cleared before the panel's initialization sequence is sent, so clear it if that is the case. Signed-off-by: Diogo Ivo Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dsi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 49f0bc270e14..a9870c828374 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -912,6 +912,15 @@ static void tegra_dsi_encoder_enable(struct drm_encoder *encoder) u32 value; int err; + /* If the bootloader enabled DSI it needs to be disabled + * in order for the panel initialization commands to be + * properly sent. + */ + value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); + + if (value & DSI_POWER_CONTROL_ENABLE) + tegra_dsi_disable(dsi); + err = tegra_dsi_prepare(dsi); if (err < 0) { dev_err(dsi->dev, "failed to prepare: %d\n", err); From bd3fd923121dfadc834b3a8a803b51f066987dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 5 Apr 2023 13:44:43 +0200 Subject: [PATCH 25/33] drm/tegra: Fix another missing include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since Tegra now compile tests on other platforms the kernel test robot started to complain that this here is not pulled in under all conditions. Signed-off-by: Christian König Reported-by: kernel test robot Link: https://lore.kernel.org/oe-kbuild-all/202304050946.yGGTKkcr-lkp@intel.com/ Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/fb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index bfebe2786d61..35b90fac5a47 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -8,6 +8,7 @@ */ #include +#include #include #include From f68b63ebc433e8715b400f8dadf93a6ed02e2d3b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 30 Mar 2023 10:36:01 +0200 Subject: [PATCH 26/33] drm/tegra: Include Include to get the contained declarations. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Sui Jingfeng Reviewed-by: Sui Jingfeng --- drivers/gpu/drm/tegra/output.c | 2 ++ drivers/gpu/drm/tegra/rgb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index a8925dcd7edd..d31c87f48da0 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -4,6 +4,8 @@ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. */ +#include + #include #include #include diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index da2d9baca214..79566c9ea8ff 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -5,6 +5,7 @@ */ #include +#include #include #include From dc06f4a495df1cf88c7cb0a383a97bdd8eddcf95 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 30 Mar 2023 10:36:02 +0200 Subject: [PATCH 27/33] drm/tegra: Include Include to get the contained declarations. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Sui Jingfeng --- drivers/gpu/drm/tegra/output.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index d31c87f48da0..dc2dcb5ca1c8 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -4,6 +4,7 @@ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. */ +#include #include #include From 08263e91f26025cbaa7049a322f7f9b13c56f2ee Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 30 Mar 2023 10:36:03 +0200 Subject: [PATCH 28/33] drm/tegra: Removed fb from struct tegra_fbdev Fbdev's struct fb_helper stores a pointer to the framebuffer. Remove struct tegra_fbdev.fb, which contains the same value. No functional changes. Signed-off-by: Thomas Zimmermann Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/drm.h | 1 - drivers/gpu/drm/tegra/fb.c | 23 ++++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 845e60f144c7..8f8e5cda78da 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -32,7 +32,6 @@ struct reset_control; #ifdef CONFIG_DRM_FBDEV_EMULATION struct tegra_fbdev { struct drm_fb_helper base; - struct drm_framebuffer *fb; }; #endif diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 35b90fac5a47..44051fc44325 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -218,7 +218,6 @@ static const struct fb_ops tegra_fb_ops = { static int tegra_fbdev_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { - struct tegra_fbdev *fbdev = to_tegra_fbdev(helper); struct tegra_drm *tegra = helper->dev->dev_private; struct drm_device *drm = helper->dev; struct drm_mode_fb_cmd2 cmd = { 0 }; @@ -253,16 +252,15 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, return PTR_ERR(info); } - fbdev->fb = tegra_fb_alloc(drm, &cmd, &bo, 1); - if (IS_ERR(fbdev->fb)) { - err = PTR_ERR(fbdev->fb); + fb = tegra_fb_alloc(drm, &cmd, &bo, 1); + if (IS_ERR(fb)) { + err = PTR_ERR(fb); dev_err(drm->dev, "failed to allocate DRM framebuffer: %d\n", err); drm_gem_object_put(&bo->gem); - return PTR_ERR(fbdev->fb); + return PTR_ERR(fb); } - fb = fbdev->fb; helper->fb = fb; helper->info = info; @@ -350,10 +348,13 @@ fini: static void tegra_fbdev_exit(struct tegra_fbdev *fbdev) { - drm_fb_helper_unregister_info(&fbdev->base); + struct drm_fb_helper *helper = &fbdev->base; + struct drm_framebuffer *fb = helper->fb; - if (fbdev->fb) { - struct tegra_bo *bo = tegra_fb_get_plane(fbdev->fb, 0); + drm_fb_helper_unregister_info(helper); + + if (fb) { + struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); /* Undo the special mapping we made in fbdev probe. */ if (bo && bo->pages) { @@ -361,10 +362,10 @@ static void tegra_fbdev_exit(struct tegra_fbdev *fbdev) bo->vaddr = NULL; } - drm_framebuffer_remove(fbdev->fb); + drm_framebuffer_remove(fb); } - drm_fb_helper_fini(&fbdev->base); + drm_fb_helper_fini(helper); tegra_fbdev_free(fbdev); } #endif From 434434608a918f33dbb613995f2b18d3007968c1 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 30 Mar 2023 10:36:04 +0200 Subject: [PATCH 29/33] drm/tegra: Remove struct tegra_fbdev Remove struct tegra_fbdev, which is an empty wrapper around struct drm_fb_helper. Use the latter directly. No functional changes. Signed-off-by: Thomas Zimmermann Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/drm.h | 10 ------- drivers/gpu/drm/tegra/fb.c | 59 ++++++++++++++----------------------- 2 files changed, 22 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 8f8e5cda78da..593a60b03189 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -29,12 +29,6 @@ struct reset_control; -#ifdef CONFIG_DRM_FBDEV_EMULATION -struct tegra_fbdev { - struct drm_fb_helper base; -}; -#endif - struct tegra_drm { struct drm_device *drm; @@ -52,10 +46,6 @@ struct tegra_drm { struct mutex clients_lock; struct list_head clients; -#ifdef CONFIG_DRM_FBDEV_EMULATION - struct tegra_fbdev *fbdev; -#endif - unsigned int hmask, vmask; unsigned int pitch_align; unsigned int num_crtcs; diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 44051fc44325..8e6078abcb67 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -18,13 +18,6 @@ #include "drm.h" #include "gem.h" -#ifdef CONFIG_DRM_FBDEV_EMULATION -static inline struct tegra_fbdev *to_tegra_fbdev(struct drm_fb_helper *helper) -{ - return container_of(helper, struct tegra_fbdev, base); -} -#endif - struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, unsigned int index) { @@ -297,42 +290,42 @@ static const struct drm_fb_helper_funcs tegra_fb_helper_funcs = { .fb_probe = tegra_fbdev_probe, }; -static struct tegra_fbdev *tegra_fbdev_create(struct drm_device *drm) +static struct drm_fb_helper *tegra_fbdev_create(struct drm_device *drm) { - struct tegra_fbdev *fbdev; + struct drm_fb_helper *helper; - fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); - if (!fbdev) { + helper = kzalloc(sizeof(*helper), GFP_KERNEL); + if (!helper) { dev_err(drm->dev, "failed to allocate DRM fbdev\n"); return ERR_PTR(-ENOMEM); } - drm_fb_helper_prepare(drm, &fbdev->base, 32, &tegra_fb_helper_funcs); + drm_fb_helper_prepare(drm, helper, 32, &tegra_fb_helper_funcs); - return fbdev; + return helper; } -static void tegra_fbdev_free(struct tegra_fbdev *fbdev) +static void tegra_fbdev_free(struct drm_fb_helper *helper) { - drm_fb_helper_unprepare(&fbdev->base); - kfree(fbdev); + drm_fb_helper_unprepare(helper); + kfree(helper); } -static int tegra_fbdev_init(struct tegra_fbdev *fbdev, +static int tegra_fbdev_init(struct drm_fb_helper *helper, unsigned int num_crtc, unsigned int max_connectors) { - struct drm_device *drm = fbdev->base.dev; + struct drm_device *drm = helper->dev; int err; - err = drm_fb_helper_init(drm, &fbdev->base); + err = drm_fb_helper_init(drm, helper); if (err < 0) { dev_err(drm->dev, "failed to initialize DRM FB helper: %d\n", err); return err; } - err = drm_fb_helper_initial_config(&fbdev->base); + err = drm_fb_helper_initial_config(helper); if (err < 0) { dev_err(drm->dev, "failed to set initial configuration: %d\n", err); @@ -342,13 +335,12 @@ static int tegra_fbdev_init(struct tegra_fbdev *fbdev, return 0; fini: - drm_fb_helper_fini(&fbdev->base); + drm_fb_helper_fini(helper); return err; } -static void tegra_fbdev_exit(struct tegra_fbdev *fbdev) +static void tegra_fbdev_exit(struct drm_fb_helper *helper) { - struct drm_fb_helper *helper = &fbdev->base; struct drm_framebuffer *fb = helper->fb; drm_fb_helper_unregister_info(helper); @@ -366,18 +358,16 @@ static void tegra_fbdev_exit(struct tegra_fbdev *fbdev) } drm_fb_helper_fini(helper); - tegra_fbdev_free(fbdev); + tegra_fbdev_free(helper); } #endif int tegra_drm_fb_prepare(struct drm_device *drm) { #ifdef CONFIG_DRM_FBDEV_EMULATION - struct tegra_drm *tegra = drm->dev_private; - - tegra->fbdev = tegra_fbdev_create(drm); - if (IS_ERR(tegra->fbdev)) - return PTR_ERR(tegra->fbdev); + drm->fb_helper = tegra_fbdev_create(drm); + if (IS_ERR(drm->fb_helper)) + return PTR_ERR(drm->fb_helper); #endif return 0; @@ -386,19 +376,16 @@ int tegra_drm_fb_prepare(struct drm_device *drm) void tegra_drm_fb_free(struct drm_device *drm) { #ifdef CONFIG_DRM_FBDEV_EMULATION - struct tegra_drm *tegra = drm->dev_private; - - tegra_fbdev_free(tegra->fbdev); + tegra_fbdev_free(drm->fb_helper); #endif } int tegra_drm_fb_init(struct drm_device *drm) { #ifdef CONFIG_DRM_FBDEV_EMULATION - struct tegra_drm *tegra = drm->dev_private; int err; - err = tegra_fbdev_init(tegra->fbdev, drm->mode_config.num_crtc, + err = tegra_fbdev_init(drm->fb_helper, drm->mode_config.num_crtc, drm->mode_config.num_connector); if (err < 0) return err; @@ -410,8 +397,6 @@ int tegra_drm_fb_init(struct drm_device *drm) void tegra_drm_fb_exit(struct drm_device *drm) { #ifdef CONFIG_DRM_FBDEV_EMULATION - struct tegra_drm *tegra = drm->dev_private; - - tegra_fbdev_exit(tegra->fbdev); + tegra_fbdev_exit(drm->fb_helper); #endif } From 1ac45068af9d6994dd6679bfbd0ff6cb0fc076da Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 30 Mar 2023 10:36:05 +0200 Subject: [PATCH 30/33] drm/tegra: Hide fbdev support behind config option Only build tegra's fbdev emulation if CONFIG_DRM_FBDEV_EMULATION has been enabled. As part of this change, move the code into its own source file. No functional changes. Signed-off-by: Thomas Zimmermann Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/Makefile | 2 + drivers/gpu/drm/tegra/drm.h | 20 +++ drivers/gpu/drm/tegra/fb.c | 229 +-------------------------------- drivers/gpu/drm/tegra/fbdev.c | 227 ++++++++++++++++++++++++++++++++ 4 files changed, 253 insertions(+), 225 deletions(-) create mode 100644 drivers/gpu/drm/tegra/fbdev.c diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile index bb0d2c144b55..6fc4b504e786 100644 --- a/drivers/gpu/drm/tegra/Makefile +++ b/drivers/gpu/drm/tegra/Makefile @@ -29,4 +29,6 @@ tegra-drm-y := \ tegra-drm-y += trace.o +tegra-drm-$(CONFIG_DRM_FBDEV_EMULATION) += fbdev.o + obj-$(CONFIG_DRM_TEGRA) += tegra-drm.o diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 593a60b03189..576f03b8434e 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -185,13 +185,33 @@ struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer); int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, struct tegra_bo_tiling *tiling); +struct drm_framebuffer *tegra_fb_alloc(struct drm_device *drm, + const struct drm_mode_fb_cmd2 *mode_cmd, + struct tegra_bo **planes, + unsigned int num_planes); struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, struct drm_file *file, const struct drm_mode_fb_cmd2 *cmd); + +#ifdef CONFIG_DRM_FBDEV_EMULATION int tegra_drm_fb_prepare(struct drm_device *drm); void tegra_drm_fb_free(struct drm_device *drm); int tegra_drm_fb_init(struct drm_device *drm); void tegra_drm_fb_exit(struct drm_device *drm); +#else +static inline int tegra_drm_fb_prepare(struct drm_device *drm) +{ + return 0; +} +static inline void tegra_drm_fb_free(struct drm_device *drm) +{ } +static inline int tegra_drm_fb_init(struct drm_device *drm) +{ + return 0; +} +static inline void tegra_drm_fb_exit(struct drm_device *drm) +{ } +#endif extern struct platform_driver tegra_display_hub_driver; extern struct platform_driver tegra_dc_driver; diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 8e6078abcb67..a719af1dc9a5 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -8,7 +8,6 @@ */ #include -#include #include #include @@ -102,10 +101,10 @@ static const struct drm_framebuffer_funcs tegra_fb_funcs = { .create_handle = drm_gem_fb_create_handle, }; -static struct drm_framebuffer *tegra_fb_alloc(struct drm_device *drm, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct tegra_bo **planes, - unsigned int num_planes) +struct drm_framebuffer *tegra_fb_alloc(struct drm_device *drm, + const struct drm_mode_fb_cmd2 *mode_cmd, + struct tegra_bo **planes, + unsigned int num_planes) { struct drm_framebuffer *fb; unsigned int i; @@ -180,223 +179,3 @@ unreference: return ERR_PTR(err); } - -#ifdef CONFIG_DRM_FBDEV_EMULATION -static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) -{ - struct drm_fb_helper *helper = info->par; - struct tegra_bo *bo; - int err; - - bo = tegra_fb_get_plane(helper->fb, 0); - - err = drm_gem_mmap_obj(&bo->gem, bo->gem.size, vma); - if (err < 0) - return err; - - return __tegra_gem_mmap(&bo->gem, vma); -} - -static const struct fb_ops tegra_fb_ops = { - .owner = THIS_MODULE, - DRM_FB_HELPER_DEFAULT_OPS, - .fb_read = drm_fb_helper_sys_read, - .fb_write = drm_fb_helper_sys_write, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_mmap = tegra_fb_mmap, -}; - -static int tegra_fbdev_probe(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct tegra_drm *tegra = helper->dev->dev_private; - struct drm_device *drm = helper->dev; - struct drm_mode_fb_cmd2 cmd = { 0 }; - unsigned int bytes_per_pixel; - struct drm_framebuffer *fb; - unsigned long offset; - struct fb_info *info; - struct tegra_bo *bo; - size_t size; - int err; - - bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); - - cmd.width = sizes->surface_width; - cmd.height = sizes->surface_height; - cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel, - tegra->pitch_align); - - cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = cmd.pitches[0] * cmd.height; - - bo = tegra_bo_create(drm, size, 0); - if (IS_ERR(bo)) - return PTR_ERR(bo); - - info = drm_fb_helper_alloc_info(helper); - if (IS_ERR(info)) { - dev_err(drm->dev, "failed to allocate framebuffer info\n"); - drm_gem_object_put(&bo->gem); - return PTR_ERR(info); - } - - fb = tegra_fb_alloc(drm, &cmd, &bo, 1); - if (IS_ERR(fb)) { - err = PTR_ERR(fb); - dev_err(drm->dev, "failed to allocate DRM framebuffer: %d\n", - err); - drm_gem_object_put(&bo->gem); - return PTR_ERR(fb); - } - - helper->fb = fb; - helper->info = info; - - info->fbops = &tegra_fb_ops; - - drm_fb_helper_fill_info(info, helper, sizes); - - offset = info->var.xoffset * bytes_per_pixel + - info->var.yoffset * fb->pitches[0]; - - if (bo->pages) { - bo->vaddr = vmap(bo->pages, bo->num_pages, VM_MAP, - pgprot_writecombine(PAGE_KERNEL)); - if (!bo->vaddr) { - dev_err(drm->dev, "failed to vmap() framebuffer\n"); - err = -ENOMEM; - goto destroy; - } - } - - info->screen_base = (void __iomem *)bo->vaddr + offset; - info->screen_size = size; - info->fix.smem_start = (unsigned long)(bo->iova + offset); - info->fix.smem_len = size; - - return 0; - -destroy: - drm_framebuffer_remove(fb); - return err; -} - -static const struct drm_fb_helper_funcs tegra_fb_helper_funcs = { - .fb_probe = tegra_fbdev_probe, -}; - -static struct drm_fb_helper *tegra_fbdev_create(struct drm_device *drm) -{ - struct drm_fb_helper *helper; - - helper = kzalloc(sizeof(*helper), GFP_KERNEL); - if (!helper) { - dev_err(drm->dev, "failed to allocate DRM fbdev\n"); - return ERR_PTR(-ENOMEM); - } - - drm_fb_helper_prepare(drm, helper, 32, &tegra_fb_helper_funcs); - - return helper; -} - -static void tegra_fbdev_free(struct drm_fb_helper *helper) -{ - drm_fb_helper_unprepare(helper); - kfree(helper); -} - -static int tegra_fbdev_init(struct drm_fb_helper *helper, - unsigned int num_crtc, - unsigned int max_connectors) -{ - struct drm_device *drm = helper->dev; - int err; - - err = drm_fb_helper_init(drm, helper); - if (err < 0) { - dev_err(drm->dev, "failed to initialize DRM FB helper: %d\n", - err); - return err; - } - - err = drm_fb_helper_initial_config(helper); - if (err < 0) { - dev_err(drm->dev, "failed to set initial configuration: %d\n", - err); - goto fini; - } - - return 0; - -fini: - drm_fb_helper_fini(helper); - return err; -} - -static void tegra_fbdev_exit(struct drm_fb_helper *helper) -{ - struct drm_framebuffer *fb = helper->fb; - - drm_fb_helper_unregister_info(helper); - - if (fb) { - struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); - - /* Undo the special mapping we made in fbdev probe. */ - if (bo && bo->pages) { - vunmap(bo->vaddr); - bo->vaddr = NULL; - } - - drm_framebuffer_remove(fb); - } - - drm_fb_helper_fini(helper); - tegra_fbdev_free(helper); -} -#endif - -int tegra_drm_fb_prepare(struct drm_device *drm) -{ -#ifdef CONFIG_DRM_FBDEV_EMULATION - drm->fb_helper = tegra_fbdev_create(drm); - if (IS_ERR(drm->fb_helper)) - return PTR_ERR(drm->fb_helper); -#endif - - return 0; -} - -void tegra_drm_fb_free(struct drm_device *drm) -{ -#ifdef CONFIG_DRM_FBDEV_EMULATION - tegra_fbdev_free(drm->fb_helper); -#endif -} - -int tegra_drm_fb_init(struct drm_device *drm) -{ -#ifdef CONFIG_DRM_FBDEV_EMULATION - int err; - - err = tegra_fbdev_init(drm->fb_helper, drm->mode_config.num_crtc, - drm->mode_config.num_connector); - if (err < 0) - return err; -#endif - - return 0; -} - -void tegra_drm_fb_exit(struct drm_device *drm) -{ -#ifdef CONFIG_DRM_FBDEV_EMULATION - tegra_fbdev_exit(drm->fb_helper); -#endif -} diff --git a/drivers/gpu/drm/tegra/fbdev.c b/drivers/gpu/drm/tegra/fbdev.c new file mode 100644 index 000000000000..1c22d0fb4055 --- /dev/null +++ b/drivers/gpu/drm/tegra/fbdev.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012-2013 Avionic Design GmbH + * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. + * + * Based on the KMS/FB DMA helpers + * Copyright (C) 2012 Analog Devices Inc. + */ + +#include +#include + +#include +#include +#include +#include + +#include "drm.h" +#include "gem.h" + +static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct drm_fb_helper *helper = info->par; + struct tegra_bo *bo; + int err; + + bo = tegra_fb_get_plane(helper->fb, 0); + + err = drm_gem_mmap_obj(&bo->gem, bo->gem.size, vma); + if (err < 0) + return err; + + return __tegra_gem_mmap(&bo->gem, vma); +} + +static const struct fb_ops tegra_fb_ops = { + .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, + .fb_read = drm_fb_helper_sys_read, + .fb_write = drm_fb_helper_sys_write, + .fb_fillrect = drm_fb_helper_sys_fillrect, + .fb_copyarea = drm_fb_helper_sys_copyarea, + .fb_imageblit = drm_fb_helper_sys_imageblit, + .fb_mmap = tegra_fb_mmap, +}; + +static int tegra_fbdev_probe(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct tegra_drm *tegra = helper->dev->dev_private; + struct drm_device *drm = helper->dev; + struct drm_mode_fb_cmd2 cmd = { 0 }; + unsigned int bytes_per_pixel; + struct drm_framebuffer *fb; + unsigned long offset; + struct fb_info *info; + struct tegra_bo *bo; + size_t size; + int err; + + bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); + + cmd.width = sizes->surface_width; + cmd.height = sizes->surface_height; + cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel, + tegra->pitch_align); + + cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth); + + size = cmd.pitches[0] * cmd.height; + + bo = tegra_bo_create(drm, size, 0); + if (IS_ERR(bo)) + return PTR_ERR(bo); + + info = drm_fb_helper_alloc_info(helper); + if (IS_ERR(info)) { + dev_err(drm->dev, "failed to allocate framebuffer info\n"); + drm_gem_object_put(&bo->gem); + return PTR_ERR(info); + } + + fb = tegra_fb_alloc(drm, &cmd, &bo, 1); + if (IS_ERR(fb)) { + err = PTR_ERR(fb); + dev_err(drm->dev, "failed to allocate DRM framebuffer: %d\n", + err); + drm_gem_object_put(&bo->gem); + return PTR_ERR(fb); + } + + helper->fb = fb; + helper->info = info; + + info->fbops = &tegra_fb_ops; + + drm_fb_helper_fill_info(info, helper, sizes); + + offset = info->var.xoffset * bytes_per_pixel + + info->var.yoffset * fb->pitches[0]; + + if (bo->pages) { + bo->vaddr = vmap(bo->pages, bo->num_pages, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); + if (!bo->vaddr) { + dev_err(drm->dev, "failed to vmap() framebuffer\n"); + err = -ENOMEM; + goto destroy; + } + } + + info->screen_base = (void __iomem *)bo->vaddr + offset; + info->screen_size = size; + info->fix.smem_start = (unsigned long)(bo->iova + offset); + info->fix.smem_len = size; + + return 0; + +destroy: + drm_framebuffer_remove(fb); + return err; +} + +static const struct drm_fb_helper_funcs tegra_fb_helper_funcs = { + .fb_probe = tegra_fbdev_probe, +}; + +static struct drm_fb_helper *tegra_fbdev_create(struct drm_device *drm) +{ + struct drm_fb_helper *helper; + + helper = kzalloc(sizeof(*helper), GFP_KERNEL); + if (!helper) + return ERR_PTR(-ENOMEM); + + drm_fb_helper_prepare(drm, helper, 32, &tegra_fb_helper_funcs); + + return helper; +} + +static void tegra_fbdev_free(struct drm_fb_helper *helper) +{ + drm_fb_helper_unprepare(helper); + kfree(helper); +} + +static int tegra_fbdev_init(struct drm_fb_helper *helper, + unsigned int num_crtc, + unsigned int max_connectors) +{ + struct drm_device *drm = helper->dev; + int err; + + err = drm_fb_helper_init(drm, helper); + if (err < 0) { + dev_err(drm->dev, "failed to initialize DRM FB helper: %d\n", + err); + return err; + } + + err = drm_fb_helper_initial_config(helper); + if (err < 0) { + dev_err(drm->dev, "failed to set initial configuration: %d\n", + err); + goto fini; + } + + return 0; + +fini: + drm_fb_helper_fini(helper); + return err; +} + +static void tegra_fbdev_exit(struct drm_fb_helper *helper) +{ + struct drm_framebuffer *fb = helper->fb; + + drm_fb_helper_unregister_info(helper); + + if (fb) { + struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); + + /* Undo the special mapping we made in fbdev probe. */ + if (bo && bo->pages) { + vunmap(bo->vaddr); + bo->vaddr = NULL; + } + + drm_framebuffer_remove(fb); + } + + drm_fb_helper_fini(helper); + tegra_fbdev_free(helper); +} + +int tegra_drm_fb_prepare(struct drm_device *drm) +{ + drm->fb_helper = tegra_fbdev_create(drm); + if (IS_ERR(drm->fb_helper)) + return PTR_ERR(drm->fb_helper); + + return 0; +} + +void tegra_drm_fb_free(struct drm_device *drm) +{ + tegra_fbdev_free(drm->fb_helper); +} + +int tegra_drm_fb_init(struct drm_device *drm) +{ + int err; + + err = tegra_fbdev_init(drm->fb_helper, drm->mode_config.num_crtc, + drm->mode_config.num_connector); + if (err < 0) + return err; + + return 0; +} + +void tegra_drm_fb_exit(struct drm_device *drm) +{ + tegra_fbdev_exit(drm->fb_helper); +} From 25dda38e0b07941f291a442ac470b0637b7b3e60 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 30 Mar 2023 10:36:06 +0200 Subject: [PATCH 31/33] drm/tegra: Initialize fbdev DRM client Initialize the fbdev client in the fbdev code with empty helper functions. Also clean up the client. The helpers will later implement various functionality of the DRM client. No functional changes. Signed-off-by: Thomas Zimmermann Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/fbdev.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/fbdev.c b/drivers/gpu/drm/tegra/fbdev.c index 1c22d0fb4055..6ff7106f440e 100644 --- a/drivers/gpu/drm/tegra/fbdev.c +++ b/drivers/gpu/drm/tegra/fbdev.c @@ -126,6 +126,30 @@ static const struct drm_fb_helper_funcs tegra_fb_helper_funcs = { .fb_probe = tegra_fbdev_probe, }; +/* + * struct drm_client + */ + +static void tegra_fbdev_client_unregister(struct drm_client_dev *client) +{ } + +static int tregra_fbdev_client_restore(struct drm_client_dev *client) +{ + return 0; +} + +static int tegra_fbdev_client_hotplug(struct drm_client_dev *client) +{ + return 0; +} + +static const struct drm_client_funcs tegra_fbdev_client_funcs = { + .owner = THIS_MODULE, + .unregister = tegra_fbdev_client_unregister, + .restore = tegra_fbdev_client_restore, + .hotplug = tegra_fbdev_client_hotplug, +}; + static struct drm_fb_helper *tegra_fbdev_create(struct drm_device *drm) { struct drm_fb_helper *helper; @@ -152,11 +176,15 @@ static int tegra_fbdev_init(struct drm_fb_helper *helper, struct drm_device *drm = helper->dev; int err; + err = drm_client_init(dev, &helper->client, "fbdev", &tegra_fbdev_client_funcs); + if (err) + return err; + err = drm_fb_helper_init(drm, helper); if (err < 0) { dev_err(drm->dev, "failed to initialize DRM FB helper: %d\n", err); - return err; + goto err_drm_client_release; } err = drm_fb_helper_initial_config(helper); @@ -170,6 +198,8 @@ static int tegra_fbdev_init(struct drm_fb_helper *helper, fini: drm_fb_helper_fini(helper); +err_drm_client_release: + drm_client_release(&helper->client); return err; } @@ -192,6 +222,7 @@ static void tegra_fbdev_exit(struct drm_fb_helper *helper) } drm_fb_helper_fini(helper); + drm_client_release(&helper->client); tegra_fbdev_free(helper); } From 71ec16f45ef8d10e20c58e85f7d3644e324d3c13 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 30 Mar 2023 10:36:07 +0200 Subject: [PATCH 32/33] drm/tegra: Implement fbdev emulation as in-kernel client Move code from ad-hoc fbdev callbacks into DRM client functions and remove the old callbacks. The functions instruct the client to poll for changed output or restore the display. The DRM core calls both, the old callbacks and the new client helpers, from the same places. The new functions perform the same operation as before, so there's no change in functionality. Replace all code that initializes or releases fbdev emulation throughout the driver. Instead initialize the fbdev client by a single call to tegra_fbdev_setup() after tegra has registered its DRM device. As in most drivers, tegra's fbdev emulation now acts like a regular DRM client. The fbdev client setup consists of the initial preparation and the hot-plugging of the display. The latter creates the fbdev device and sets up the fbdev framebuffer. The setup performs display hot-plugging once. If no display can be detected, DRM probe helpers re-run the detection on each hotplug event. A call to drm_dev_unregister() releases the client automatically. No further action is required within tegra. If the fbdev framebuffer has been fully set up, struct fb_ops.fb_destroy implements the release. For partially initialized emulation, the fbdev client reverts the initial setup. Signed-off-by: Thomas Zimmermann Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/drm.c | 23 +---- drivers/gpu/drm/tegra/drm.h | 18 +--- drivers/gpu/drm/tegra/fbdev.c | 179 +++++++++++++++------------------- 3 files changed, 87 insertions(+), 133 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 6ca9f396e55b..85ba96cddd51 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -56,9 +56,6 @@ static int tegra_atomic_check(struct drm_device *drm, static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { .fb_create = tegra_fb_create, -#ifdef CONFIG_DRM_FBDEV_EMULATION - .output_poll_changed = drm_fb_helper_output_poll_changed, -#endif .atomic_check = tegra_atomic_check, .atomic_commit = drm_atomic_helper_commit, }; @@ -885,7 +882,6 @@ static const struct drm_driver tegra_drm_driver = { DRIVER_ATOMIC | DRIVER_RENDER | DRIVER_SYNCOBJ, .open = tegra_drm_open, .postclose = tegra_drm_postclose, - .lastclose = drm_fb_helper_lastclose, #if defined(CONFIG_DEBUG_FS) .debugfs_init = tegra_debugfs_init, @@ -1185,15 +1181,11 @@ static int host1x_drm_probe(struct host1x_device *dev) drm->mode_config.funcs = &tegra_drm_mode_config_funcs; drm->mode_config.helper_private = &tegra_drm_mode_config_helpers; - err = tegra_drm_fb_prepare(drm); - if (err < 0) - goto config; - drm_kms_helper_poll_init(drm); err = host1x_device_init(dev); if (err < 0) - goto fbdev; + goto poll; /* * Now that all display controller have been initialized, the maximum @@ -1256,18 +1248,14 @@ static int host1x_drm_probe(struct host1x_device *dev) if (err < 0) goto hub; - err = tegra_drm_fb_init(drm); + err = drm_dev_register(drm, 0); if (err < 0) goto hub; - err = drm_dev_register(drm, 0); - if (err < 0) - goto fb; + tegra_fbdev_setup(drm); return 0; -fb: - tegra_drm_fb_exit(drm); hub: if (tegra->hub) tegra_display_hub_cleanup(tegra->hub); @@ -1280,10 +1268,8 @@ device: } host1x_device_exit(dev); -fbdev: +poll: drm_kms_helper_poll_fini(drm); - tegra_drm_fb_free(drm); -config: drm_mode_config_cleanup(drm); domain: if (tegra->domain) @@ -1304,7 +1290,6 @@ static int host1x_drm_remove(struct host1x_device *dev) drm_dev_unregister(drm); drm_kms_helper_poll_fini(drm); - tegra_drm_fb_exit(drm); drm_atomic_helper_shutdown(drm); drm_mode_config_cleanup(drm); diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 576f03b8434e..f9d18e8cf6ab 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -194,22 +193,9 @@ struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, const struct drm_mode_fb_cmd2 *cmd); #ifdef CONFIG_DRM_FBDEV_EMULATION -int tegra_drm_fb_prepare(struct drm_device *drm); -void tegra_drm_fb_free(struct drm_device *drm); -int tegra_drm_fb_init(struct drm_device *drm); -void tegra_drm_fb_exit(struct drm_device *drm); +void tegra_fbdev_setup(struct drm_device *drm); #else -static inline int tegra_drm_fb_prepare(struct drm_device *drm) -{ - return 0; -} -static inline void tegra_drm_fb_free(struct drm_device *drm) -{ } -static inline int tegra_drm_fb_init(struct drm_device *drm) -{ - return 0; -} -static inline void tegra_drm_fb_exit(struct drm_device *drm) +static inline void tegra_fbdev_setup(struct drm_device *drm) { } #endif diff --git a/drivers/gpu/drm/tegra/fbdev.c b/drivers/gpu/drm/tegra/fbdev.c index 6ff7106f440e..dca9eccae466 100644 --- a/drivers/gpu/drm/tegra/fbdev.c +++ b/drivers/gpu/drm/tegra/fbdev.c @@ -10,6 +10,9 @@ #include #include +#include +#include +#include #include #include #include @@ -33,6 +36,26 @@ static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) return __tegra_gem_mmap(&bo->gem, vma); } +static void tegra_fbdev_fb_destroy(struct fb_info *info) +{ + struct drm_fb_helper *helper = info->par; + struct drm_framebuffer *fb = helper->fb; + struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); + + drm_fb_helper_fini(helper); + + /* Undo the special mapping we made in fbdev probe. */ + if (bo->pages) { + vunmap(bo->vaddr); + bo->vaddr = NULL; + } + drm_framebuffer_remove(fb); + + drm_client_release(&helper->client); + drm_fb_helper_unprepare(helper); + kfree(helper); +} + static const struct fb_ops tegra_fb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, @@ -42,6 +65,7 @@ static const struct fb_ops tegra_fb_ops = { .fb_copyarea = drm_fb_helper_sys_copyarea, .fb_imageblit = drm_fb_helper_sys_imageblit, .fb_mmap = tegra_fb_mmap, + .fb_destroy = tegra_fbdev_fb_destroy, }; static int tegra_fbdev_probe(struct drm_fb_helper *helper, @@ -131,16 +155,52 @@ static const struct drm_fb_helper_funcs tegra_fb_helper_funcs = { */ static void tegra_fbdev_client_unregister(struct drm_client_dev *client) -{ } - -static int tregra_fbdev_client_restore(struct drm_client_dev *client) { + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); + + if (fb_helper->info) { + drm_fb_helper_unregister_info(fb_helper); + } else { + drm_client_release(&fb_helper->client); + drm_fb_helper_unprepare(fb_helper); + kfree(fb_helper); + } +} + +static int tegra_fbdev_client_restore(struct drm_client_dev *client) +{ + drm_fb_helper_lastclose(client->dev); + return 0; } static int tegra_fbdev_client_hotplug(struct drm_client_dev *client) { + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); + struct drm_device *dev = client->dev; + int ret; + + if (dev->fb_helper) + return drm_fb_helper_hotplug_event(dev->fb_helper); + + ret = drm_fb_helper_init(dev, fb_helper); + if (ret) + goto err_drm_err; + + if (!drm_drv_uses_atomic_modeset(dev)) + drm_helper_disable_unused_functions(dev); + + ret = drm_fb_helper_initial_config(fb_helper); + if (ret) + goto err_drm_fb_helper_fini; + return 0; + +err_drm_fb_helper_fini: + drm_fb_helper_fini(fb_helper); +err_drm_err: + drm_err(dev, "Failed to setup fbdev emulation (ret=%d)\n", ret); + return ret; } static const struct drm_client_funcs tegra_fbdev_client_funcs = { @@ -150,109 +210,32 @@ static const struct drm_client_funcs tegra_fbdev_client_funcs = { .hotplug = tegra_fbdev_client_hotplug, }; -static struct drm_fb_helper *tegra_fbdev_create(struct drm_device *drm) +void tegra_fbdev_setup(struct drm_device *dev) { struct drm_fb_helper *helper; + int ret; + + drm_WARN(dev, !dev->registered, "Device has not been registered.\n"); + drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n"); helper = kzalloc(sizeof(*helper), GFP_KERNEL); if (!helper) - return ERR_PTR(-ENOMEM); + return; + drm_fb_helper_prepare(dev, helper, 32, &tegra_fb_helper_funcs); - drm_fb_helper_prepare(drm, helper, 32, &tegra_fb_helper_funcs); + ret = drm_client_init(dev, &helper->client, "fbdev", &tegra_fbdev_client_funcs); + if (ret) + goto err_drm_client_init; - return helper; -} + ret = tegra_fbdev_client_hotplug(&helper->client); + if (ret) + drm_dbg_kms(dev, "client hotplug ret=%d\n", ret); -static void tegra_fbdev_free(struct drm_fb_helper *helper) -{ + drm_client_register(&helper->client); + + return; + +err_drm_client_init: drm_fb_helper_unprepare(helper); kfree(helper); } - -static int tegra_fbdev_init(struct drm_fb_helper *helper, - unsigned int num_crtc, - unsigned int max_connectors) -{ - struct drm_device *drm = helper->dev; - int err; - - err = drm_client_init(dev, &helper->client, "fbdev", &tegra_fbdev_client_funcs); - if (err) - return err; - - err = drm_fb_helper_init(drm, helper); - if (err < 0) { - dev_err(drm->dev, "failed to initialize DRM FB helper: %d\n", - err); - goto err_drm_client_release; - } - - err = drm_fb_helper_initial_config(helper); - if (err < 0) { - dev_err(drm->dev, "failed to set initial configuration: %d\n", - err); - goto fini; - } - - return 0; - -fini: - drm_fb_helper_fini(helper); -err_drm_client_release: - drm_client_release(&helper->client); - return err; -} - -static void tegra_fbdev_exit(struct drm_fb_helper *helper) -{ - struct drm_framebuffer *fb = helper->fb; - - drm_fb_helper_unregister_info(helper); - - if (fb) { - struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); - - /* Undo the special mapping we made in fbdev probe. */ - if (bo && bo->pages) { - vunmap(bo->vaddr); - bo->vaddr = NULL; - } - - drm_framebuffer_remove(fb); - } - - drm_fb_helper_fini(helper); - drm_client_release(&helper->client); - tegra_fbdev_free(helper); -} - -int tegra_drm_fb_prepare(struct drm_device *drm) -{ - drm->fb_helper = tegra_fbdev_create(drm); - if (IS_ERR(drm->fb_helper)) - return PTR_ERR(drm->fb_helper); - - return 0; -} - -void tegra_drm_fb_free(struct drm_device *drm) -{ - tegra_fbdev_free(drm->fb_helper); -} - -int tegra_drm_fb_init(struct drm_device *drm) -{ - int err; - - err = tegra_fbdev_init(drm->fb_helper, drm->mode_config.num_crtc, - drm->mode_config.num_connector); - if (err < 0) - return err; - - return 0; -} - -void tegra_drm_fb_exit(struct drm_device *drm) -{ - tegra_fbdev_exit(drm->fb_helper); -} From 2429b3c529da29d4277d519bd66d034842dcd70c Mon Sep 17 00:00:00 2001 From: Nur Hussein Date: Thu, 6 Apr 2023 04:25:59 +0800 Subject: [PATCH 33/33] drm/tegra: Avoid potential 32-bit integer overflow In tegra_sor_compute_config(), the 32-bit value mode->clock is multiplied by 1000, and assigned to the u64 variable pclk. We can avoid a potential 32-bit integer overflow by casting mode->clock to u64 before we do the arithmetic and assignment. Signed-off-by: Nur Hussein Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/sor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index cd25f409979c..8d910695775c 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -1153,7 +1153,7 @@ static int tegra_sor_compute_config(struct tegra_sor *sor, struct drm_dp_link *link) { const u64 f = 100000, link_rate = link->rate * 1000; - const u64 pclk = mode->clock * 1000; + const u64 pclk = (u64)mode->clock * 1000; u64 input, output, watermark, num; struct tegra_sor_params params; u32 num_syms_per_line;