| From 5a0495490066e05b9caa7dbd9c3d44c6df27ae3e Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 9 Nov 2023 09:38:01 +0200 |
| Subject: drm/tidss: Fix dss reset |
| |
| From: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> |
| |
| [ Upstream commit bc288a927815efcf9d7f4a54d4d89c5df478c635 ] |
| |
| The probe function calls dispc_softreset() before runtime PM is enabled |
| and without enabling any of the DSS clocks. This happens to work by |
| luck, and we need to make sure the DSS HW is active and the fclk is |
| enabled. |
| |
| To fix the above, add a new function, dispc_init_hw(), which does: |
| |
| - pm_runtime_set_active() |
| - clk_prepare_enable(fclk) |
| - dispc_softreset(). |
| |
| This ensures that the reset can be successfully accomplished. |
| |
| Note that we use pm_runtime_set_active(), not the normal |
| pm_runtime_get(). The reason for this is that at this point we haven't |
| enabled the runtime PM yet and also we don't want the normal resume |
| callback to be called: the dispc resume callback does some initial HW |
| setup, and it expects that the HW was off (no video ports are |
| streaming). If the bootloader has enabled the DSS and has set up a |
| boot time splash-screen, the DSS would be enabled and streaming which |
| might lead to issues with the normal resume callback. |
| |
| Fixes: c9b2d923befd ("drm/tidss: Soft Reset DISPC on startup") |
| Reviewed-by: Aradhya Bhatia <a-bhatia1@ti.com> |
| Link: https://lore.kernel.org/r/20231109-tidss-probe-v2-8-ac91b5ea35c0@ideasonboard.com |
| Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/gpu/drm/tidss/tidss_dispc.c | 45 ++++++++++++++++++++++++++++- |
| 1 file changed, 44 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c |
| index 4bdd4c7b4991..95b75236fe5e 100644 |
| --- a/drivers/gpu/drm/tidss/tidss_dispc.c |
| +++ b/drivers/gpu/drm/tidss/tidss_dispc.c |
| @@ -2675,6 +2675,49 @@ static int dispc_softreset(struct dispc_device *dispc) |
| return 0; |
| } |
| |
| +static int dispc_init_hw(struct dispc_device *dispc) |
| +{ |
| + struct device *dev = dispc->dev; |
| + int ret; |
| + |
| + ret = pm_runtime_set_active(dev); |
| + if (ret) { |
| + dev_err(dev, "Failed to set DSS PM to active\n"); |
| + return ret; |
| + } |
| + |
| + ret = clk_prepare_enable(dispc->fclk); |
| + if (ret) { |
| + dev_err(dev, "Failed to enable DSS fclk\n"); |
| + goto err_runtime_suspend; |
| + } |
| + |
| + ret = dispc_softreset(dispc); |
| + if (ret) |
| + goto err_clk_disable; |
| + |
| + clk_disable_unprepare(dispc->fclk); |
| + ret = pm_runtime_set_suspended(dev); |
| + if (ret) { |
| + dev_err(dev, "Failed to set DSS PM to suspended\n"); |
| + return ret; |
| + } |
| + |
| + return 0; |
| + |
| +err_clk_disable: |
| + clk_disable_unprepare(dispc->fclk); |
| + |
| +err_runtime_suspend: |
| + ret = pm_runtime_set_suspended(dev); |
| + if (ret) { |
| + dev_err(dev, "Failed to set DSS PM to suspended\n"); |
| + return ret; |
| + } |
| + |
| + return ret; |
| +} |
| + |
| int dispc_init(struct tidss_device *tidss) |
| { |
| struct device *dev = tidss->dev; |
| @@ -2782,7 +2825,7 @@ int dispc_init(struct tidss_device *tidss) |
| of_property_read_u32(dispc->dev->of_node, "max-memory-bandwidth", |
| &dispc->memory_bandwidth_limit); |
| |
| - r = dispc_softreset(dispc); |
| + r = dispc_init_hw(dispc); |
| if (r) |
| return r; |
| |
| -- |
| 2.43.0 |
| |