From 920169041baa0a7497ed702aa97d6a2d6285efd3 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 14 Jun 2022 02:31:00 -0500 Subject: drm/sun4i: dw-hdmi: Fix ddc-en GPIO consumer conflict commit 6de79dd3a920 ("drm/bridge: display-connector: add ddc-en gpio support") added a consumer for this GPIO in the HDMI connector device. This new consumer conflicts with the pre-existing GPIO consumer in the sun8i HDMI controller driver, which prevents the driver from probing: [ 4.983358] display-connector connector: GPIO lookup for consumer ddc-en [ 4.983364] display-connector connector: using device tree for GPIO lookup [ 4.983392] gpio-226 (ddc-en): gpiod_request: status -16 [ 4.983399] sun8i-dw-hdmi 6000000.hdmi: Couldn't get ddc-en gpio [ 4.983618] sun4i-drm display-engine: failed to bind 6000000.hdmi (ops sun8i_dw_hdmi_ops [sun8i_drm_hdmi]): -16 [ 4.984082] sun4i-drm display-engine: Couldn't bind all pipelines components [ 4.984171] sun4i-drm display-engine: adev bind failed: -16 [ 4.984179] sun8i-dw-hdmi: probe of 6000000.hdmi failed with error -16 Both drivers have the same behavior: they leave the GPIO active for the life of the device. Let's take advantage of the new implementation, and drop the now-obsolete code from the HDMI controller driver. Fixes: 6de79dd3a920 ("drm/bridge: display-connector: add ddc-en gpio support") Signed-off-by: Samuel Holland Reviewed-by: Jernej Skrabec Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20220614073100.11550-1-samuel@sholland.org --- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 54 +++-------------------------------- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 2 -- 2 files changed, 4 insertions(+), 52 deletions(-) (limited to 'drivers/gpu/drm/sun4i') diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index a8d75fd7e9f4..477cb6985b4d 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -93,34 +93,10 @@ crtcs_exit: return crtcs; } -static int sun8i_dw_hdmi_find_connector_pdev(struct device *dev, - struct platform_device **pdev_out) -{ - struct platform_device *pdev; - struct device_node *remote; - - remote = of_graph_get_remote_node(dev->of_node, 1, -1); - if (!remote) - return -ENODEV; - - if (!of_device_is_compatible(remote, "hdmi-connector")) { - of_node_put(remote); - return -ENODEV; - } - - pdev = of_find_device_by_node(remote); - of_node_put(remote); - if (!pdev) - return -ENODEV; - - *pdev_out = pdev; - return 0; -} - static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, void *data) { - struct platform_device *pdev = to_platform_device(dev), *connector_pdev; + struct platform_device *pdev = to_platform_device(dev); struct dw_hdmi_plat_data *plat_data; struct drm_device *drm = data; struct device_node *phy_node; @@ -167,30 +143,16 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, return dev_err_probe(dev, PTR_ERR(hdmi->regulator), "Couldn't get regulator\n"); - ret = sun8i_dw_hdmi_find_connector_pdev(dev, &connector_pdev); - if (!ret) { - hdmi->ddc_en = gpiod_get_optional(&connector_pdev->dev, - "ddc-en", GPIOD_OUT_HIGH); - platform_device_put(connector_pdev); - - if (IS_ERR(hdmi->ddc_en)) { - dev_err(dev, "Couldn't get ddc-en gpio\n"); - return PTR_ERR(hdmi->ddc_en); - } - } - ret = regulator_enable(hdmi->regulator); if (ret) { dev_err(dev, "Failed to enable regulator\n"); - goto err_unref_ddc_en; + return ret; } - gpiod_set_value(hdmi->ddc_en, 1); - ret = reset_control_deassert(hdmi->rst_ctrl); if (ret) { dev_err(dev, "Could not deassert ctrl reset control\n"); - goto err_disable_ddc_en; + goto err_disable_regulator; } ret = clk_prepare_enable(hdmi->clk_tmds); @@ -245,12 +207,8 @@ err_disable_clk_tmds: clk_disable_unprepare(hdmi->clk_tmds); err_assert_ctrl_reset: reset_control_assert(hdmi->rst_ctrl); -err_disable_ddc_en: - gpiod_set_value(hdmi->ddc_en, 0); +err_disable_regulator: regulator_disable(hdmi->regulator); -err_unref_ddc_en: - if (hdmi->ddc_en) - gpiod_put(hdmi->ddc_en); return ret; } @@ -264,11 +222,7 @@ static void sun8i_dw_hdmi_unbind(struct device *dev, struct device *master, sun8i_hdmi_phy_deinit(hdmi->phy); clk_disable_unprepare(hdmi->clk_tmds); reset_control_assert(hdmi->rst_ctrl); - gpiod_set_value(hdmi->ddc_en, 0); regulator_disable(hdmi->regulator); - - if (hdmi->ddc_en) - gpiod_put(hdmi->ddc_en); } static const struct component_ops sun8i_dw_hdmi_ops = { diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index bffe1b9cd3dc..9ad09522947a 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -193,7 +192,6 @@ struct sun8i_dw_hdmi { struct regulator *regulator; const struct sun8i_dw_hdmi_quirks *quirks; struct reset_control *rst_ctrl; - struct gpio_desc *ddc_en; }; extern struct platform_driver sun8i_hdmi_phy_driver; -- cgit v1.2.3 From 1342b5b23da9559a1578978eaff7f797d8a87d91 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 15 Jun 2022 00:42:53 -0500 Subject: drm/sun4i: Fix crash during suspend after component bind failure If the component driver fails to bind, or is unbound, the driver data for the top-level platform device points to a freed drm_device. If the system is then suspended, the driver passes this dangling pointer to drm_mode_config_helper_suspend(), which crashes. Fix this by only setting the driver data while the platform driver holds a reference to the drm_device. Fixes: 624b4b48d9d8 ("drm: sun4i: Add support for suspending the display driver") Signed-off-by: Samuel Holland Reviewed-by: Jernej Skrabec Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20220615054254.16352-1-samuel@sholland.org --- drivers/gpu/drm/sun4i/sun4i_drv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/sun4i') diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 275f7e4a03ae..8841dba989ee 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -73,7 +73,6 @@ static int sun4i_drv_bind(struct device *dev) goto free_drm; } - dev_set_drvdata(dev, drm); drm->dev_private = drv; INIT_LIST_HEAD(&drv->frontend_list); INIT_LIST_HEAD(&drv->engine_list); @@ -114,6 +113,8 @@ static int sun4i_drv_bind(struct device *dev) drm_fbdev_generic_setup(drm, 32); + dev_set_drvdata(dev, drm); + return 0; finish_poll: @@ -130,6 +131,7 @@ static void sun4i_drv_unbind(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); + dev_set_drvdata(dev, NULL); drm_dev_unregister(drm); drm_kms_helper_poll_fini(drm); drm_atomic_helper_shutdown(drm); -- cgit v1.2.3 From f5aa16807aa4f99293044944590dde81364f434f Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Mon, 20 Jun 2022 20:13:33 +0200 Subject: drm/sun4i: Add DMA mask and segment size Kernel occasionally complains that there is mismatch in segment size when trying to render HW decoded videos and rendering them directly with sun4i DRM driver. Following message can be observed on H6 SoC: [ 184.298308] ------------[ cut here ]------------ [ 184.298326] DMA-API: sun4i-drm display-engine: mapping sg segment longer than device claims to support [len=6144000] [max=65536] [ 184.298364] WARNING: CPU: 1 PID: 382 at kernel/dma/debug.c:1162 debug_dma_map_sg+0x2b0/0x350 [ 184.322997] CPU: 1 PID: 382 Comm: ffmpeg Not tainted 5.19.0-rc1+ #1331 [ 184.329533] Hardware name: Tanix TX6 (DT) [ 184.333544] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 184.340512] pc : debug_dma_map_sg+0x2b0/0x350 [ 184.344882] lr : debug_dma_map_sg+0x2b0/0x350 [ 184.349250] sp : ffff800009f33a50 [ 184.352567] x29: ffff800009f33a50 x28: 0000000000010000 x27: ffff000001b86c00 [ 184.359725] x26: ffffffffffffffff x25: ffff000005d8cc80 x24: 0000000000000000 [ 184.366879] x23: ffff80000939ab18 x22: 0000000000000001 x21: 0000000000000001 [ 184.374031] x20: 0000000000000000 x19: ffff0000018a7410 x18: ffffffffffffffff [ 184.381186] x17: 0000000000000000 x16: 0000000000000000 x15: ffffffffffffffff [ 184.388338] x14: 0000000000000001 x13: ffff800009534e86 x12: 6f70707573206f74 [ 184.395493] x11: 20736d69616c6320 x10: 000000000000000a x9 : 0000000000010000 [ 184.402647] x8 : ffff8000093b6d40 x7 : ffff800009f33850 x6 : 000000000000000c [ 184.409800] x5 : ffff0000bf997940 x4 : 0000000000000000 x3 : 0000000000000027 [ 184.416953] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff000003960e80 [ 184.424106] Call trace: [ 184.426556] debug_dma_map_sg+0x2b0/0x350 [ 184.430580] __dma_map_sg_attrs+0xa0/0x110 [ 184.434687] dma_map_sgtable+0x28/0x4c [ 184.438447] vb2_dc_dmabuf_ops_map+0x60/0xcc [ 184.442729] __map_dma_buf+0x2c/0xd4 [ 184.446321] dma_buf_map_attachment+0xa0/0x130 [ 184.450777] drm_gem_prime_import_dev+0x7c/0x18c [ 184.455410] drm_gem_prime_fd_to_handle+0x1b8/0x214 [ 184.460300] drm_prime_fd_to_handle_ioctl+0x2c/0x40 [ 184.465190] drm_ioctl_kernel+0xc4/0x174 [ 184.469123] drm_ioctl+0x204/0x420 [ 184.472534] __arm64_sys_ioctl+0xac/0xf0 [ 184.476474] invoke_syscall+0x48/0x114 [ 184.480240] el0_svc_common.constprop.0+0x44/0xec [ 184.484956] do_el0_svc+0x2c/0xc0 [ 184.488283] el0_svc+0x2c/0x84 [ 184.491354] el0t_64_sync_handler+0x11c/0x150 [ 184.495723] el0t_64_sync+0x18c/0x190 [ 184.499397] ---[ end trace 0000000000000000 ]--- Fix that by setting DMA mask and segment size. Signed-off-by: Jernej Skrabec Reviewed-by: Samuel Holland Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20220620181333.650301-1-jernej.skrabec@gmail.com --- drivers/gpu/drm/sun4i/sun4i_drv.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpu/drm/sun4i') diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 8841dba989ee..6eb1aabdb161 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -369,6 +370,13 @@ static int sun4i_drv_probe(struct platform_device *pdev) INIT_KFIFO(list.fifo); + /* + * DE2 and DE3 cores actually supports 40-bit addresses, but + * driver does not. + */ + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + dma_set_max_seg_size(&pdev->dev, UINT_MAX); + for (i = 0;; i++) { struct device_node *pipeline = of_parse_phandle(np, "allwinner,pipelines", -- cgit v1.2.3 From 85016f66af8506cb601fd4f4fde23ed327a266be Mon Sep 17 00:00:00 2001 From: Saud Farooqui Date: Wed, 22 Jun 2022 13:59:17 +0500 Subject: drm/sun4i: Return if frontend is not present Added return statement in sun4i_layer_format_mod_supported() in case frontend is not present. Signed-off-by: Saud Farooqui Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/PA4P189MB1421E93EF5F8E8E00E71B7878BB29@PA4P189MB1421.EURP189.PROD.OUTLOOK.COM --- drivers/gpu/drm/sun4i/sun4i_layer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/sun4i') diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 6d43080791a0..85fb9e800ddf 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -117,7 +117,7 @@ static bool sun4i_layer_format_mod_supported(struct drm_plane *plane, struct sun4i_layer *layer = plane_to_sun4i_layer(plane); if (IS_ERR_OR_NULL(layer->backend->frontend)) - sun4i_backend_format_is_supported(format, modifier); + return sun4i_backend_format_is_supported(format, modifier); return sun4i_backend_format_is_supported(format, modifier) || sun4i_frontend_format_is_supported(format, modifier); -- cgit v1.2.3