* [PATCH v8 01/13] drm/bridge: cdns-dsi: Fix connecting to next bridge
2025-01-26 19:15 [PATCH v8 00/13] drm/bridge: cdns-dsi: Fix the color-shift issue Aradhya Bhatia
@ 2025-01-26 19:15 ` Aradhya Bhatia
2025-01-26 21:48 ` Dmitry Baryshkov
2025-01-26 19:15 ` [PATCH v8 02/13] drm/bridge: cdns-dsi: Fix phy de-init and flag it so Aradhya Bhatia
` (11 subsequent siblings)
12 siblings, 1 reply; 25+ messages in thread
From: Aradhya Bhatia @ 2025-01-26 19:15 UTC (permalink / raw)
To: Tomi Valkeinen, Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda,
Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Aradhya Bhatia,
Stable List
From: Aradhya Bhatia <a-bhatia1@ti.com>
Fix the OF node pointer passed to the of_drm_find_bridge() call to find
the next bridge in the display chain.
The code to find the next panel (and create its panel-bridge) works
fine, but to find the next (non-panel) bridge does not.
To find the next bridge in the pipeline, we need to pass "np" - the OF
node pointer of the next entity in the devicetree chain. Passing
"of_node" to of_drm_find_bridge (which is what the code does currently)
will fetch the bridge for the cdns-dsi which is not what's required.
Fix that.
Fixes: e19233955d9e ("drm/bridge: Add Cadence DSI driver")
Cc: Stable List <stable@vger.kernel.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
---
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index c7a0247e06ad..2f897ea5e80a 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -952,7 +952,7 @@ static int cdns_dsi_attach(struct mipi_dsi_host *host,
bridge = drm_panel_bridge_add_typed(panel,
DRM_MODE_CONNECTOR_DSI);
} else {
- bridge = of_drm_find_bridge(dev->dev.of_node);
+ bridge = of_drm_find_bridge(np);
if (!bridge)
bridge = ERR_PTR(-EINVAL);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH v8 01/13] drm/bridge: cdns-dsi: Fix connecting to next bridge
2025-01-26 19:15 ` [PATCH v8 01/13] drm/bridge: cdns-dsi: Fix connecting to next bridge Aradhya Bhatia
@ 2025-01-26 21:48 ` Dmitry Baryshkov
0 siblings, 0 replies; 25+ messages in thread
From: Dmitry Baryshkov @ 2025-01-26 21:48 UTC (permalink / raw)
To: Aradhya Bhatia
Cc: Tomi Valkeinen, Laurent Pinchart, Andrzej Hajda, Neil Armstrong,
Robert Foss, Jonas Karlman, Jernej Skrabec, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Stable List
On Mon, Jan 27, 2025 at 12:45:39AM +0530, Aradhya Bhatia wrote:
> From: Aradhya Bhatia <a-bhatia1@ti.com>
>
> Fix the OF node pointer passed to the of_drm_find_bridge() call to find
> the next bridge in the display chain.
>
> The code to find the next panel (and create its panel-bridge) works
> fine, but to find the next (non-panel) bridge does not.
>
> To find the next bridge in the pipeline, we need to pass "np" - the OF
> node pointer of the next entity in the devicetree chain. Passing
> "of_node" to of_drm_find_bridge (which is what the code does currently)
> will fetch the bridge for the cdns-dsi which is not what's required.
>
> Fix that.
>
> Fixes: e19233955d9e ("drm/bridge: Add Cadence DSI driver")
> Cc: Stable List <stable@vger.kernel.org>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
> ---
> drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v8 02/13] drm/bridge: cdns-dsi: Fix phy de-init and flag it so
2025-01-26 19:15 [PATCH v8 00/13] drm/bridge: cdns-dsi: Fix the color-shift issue Aradhya Bhatia
2025-01-26 19:15 ` [PATCH v8 01/13] drm/bridge: cdns-dsi: Fix connecting to next bridge Aradhya Bhatia
@ 2025-01-26 19:15 ` Aradhya Bhatia
2025-01-26 21:52 ` Dmitry Baryshkov
2025-02-04 13:24 ` Tomi Valkeinen
2025-01-26 19:15 ` [PATCH v8 03/13] drm/bridge: cdns-dsi: Fix the clock variable for mode_valid() Aradhya Bhatia
` (10 subsequent siblings)
12 siblings, 2 replies; 25+ messages in thread
From: Aradhya Bhatia @ 2025-01-26 19:15 UTC (permalink / raw)
To: Tomi Valkeinen, Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda,
Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Aradhya Bhatia,
Stable List
From: Aradhya Bhatia <a-bhatia1@ti.com>
The driver code doesn't have a Phy de-initialization path as yet, and so
it does not clear the phy_initialized flag while suspending. This is a
problem because after resume the driver looks at this flag to determine
if a Phy re-initialization is required or not. It is in fact required
because the hardware is resuming from a suspend, but the driver does not
carry out any re-initialization causing the D-Phy to not work at all.
Call the counterparts of phy_init() and phy_power_on(), that are
phy_exit() and phy_power_off(), from _bridge_post_disable(), and clear
the flags so that the Phy can be initialized again when required.
Fixes: fced5a364dee ("drm/bridge: cdns: Convert to phy framework")
Cc: Stable List <stable@vger.kernel.org>
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index 2f897ea5e80a..b0a1a6774ea6 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -680,6 +680,11 @@ static void cdns_dsi_bridge_post_disable(struct drm_bridge *bridge)
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
+ dsi->phy_initialized = false;
+ dsi->link_initialized = false;
+ phy_power_off(dsi->dphy);
+ phy_exit(dsi->dphy);
+
pm_runtime_put(dsi->base.dev);
}
@@ -1152,7 +1157,6 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev)
clk_disable_unprepare(dsi->dsi_sys_clk);
clk_disable_unprepare(dsi->dsi_p_clk);
reset_control_assert(dsi->dsi_p_rst);
- dsi->link_initialized = false;
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH v8 02/13] drm/bridge: cdns-dsi: Fix phy de-init and flag it so
2025-01-26 19:15 ` [PATCH v8 02/13] drm/bridge: cdns-dsi: Fix phy de-init and flag it so Aradhya Bhatia
@ 2025-01-26 21:52 ` Dmitry Baryshkov
2025-02-04 13:24 ` Tomi Valkeinen
1 sibling, 0 replies; 25+ messages in thread
From: Dmitry Baryshkov @ 2025-01-26 21:52 UTC (permalink / raw)
To: Aradhya Bhatia
Cc: Tomi Valkeinen, Laurent Pinchart, Andrzej Hajda, Neil Armstrong,
Robert Foss, Jonas Karlman, Jernej Skrabec, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Stable List
On Mon, Jan 27, 2025 at 12:45:40AM +0530, Aradhya Bhatia wrote:
> From: Aradhya Bhatia <a-bhatia1@ti.com>
>
> The driver code doesn't have a Phy de-initialization path as yet, and so
> it does not clear the phy_initialized flag while suspending. This is a
> problem because after resume the driver looks at this flag to determine
> if a Phy re-initialization is required or not. It is in fact required
> because the hardware is resuming from a suspend, but the driver does not
> carry out any re-initialization causing the D-Phy to not work at all.
>
> Call the counterparts of phy_init() and phy_power_on(), that are
> phy_exit() and phy_power_off(), from _bridge_post_disable(), and clear
> the flags so that the Phy can be initialized again when required.
>
> Fixes: fced5a364dee ("drm/bridge: cdns: Convert to phy framework")
> Cc: Stable List <stable@vger.kernel.org>
> Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
> Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
> ---
> drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 6 +++++-
> 1 file changed, 5 insertions(+), 1 deletion(-)
>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCH v8 02/13] drm/bridge: cdns-dsi: Fix phy de-init and flag it so
2025-01-26 19:15 ` [PATCH v8 02/13] drm/bridge: cdns-dsi: Fix phy de-init and flag it so Aradhya Bhatia
2025-01-26 21:52 ` Dmitry Baryshkov
@ 2025-02-04 13:24 ` Tomi Valkeinen
1 sibling, 0 replies; 25+ messages in thread
From: Tomi Valkeinen @ 2025-02-04 13:24 UTC (permalink / raw)
To: Aradhya Bhatia
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Stable List,
Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda, Neil Armstrong,
Robert Foss, Jonas Karlman, Jernej Skrabec, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
On 26/01/2025 21:15, Aradhya Bhatia wrote:
> From: Aradhya Bhatia <a-bhatia1@ti.com>
>
> The driver code doesn't have a Phy de-initialization path as yet, and so
> it does not clear the phy_initialized flag while suspending. This is a
> problem because after resume the driver looks at this flag to determine
> if a Phy re-initialization is required or not. It is in fact required
> because the hardware is resuming from a suspend, but the driver does not
> carry out any re-initialization causing the D-Phy to not work at all.
>
> Call the counterparts of phy_init() and phy_power_on(), that are
> phy_exit() and phy_power_off(), from _bridge_post_disable(), and clear
> the flags so that the Phy can be initialized again when required.
>
> Fixes: fced5a364dee ("drm/bridge: cdns: Convert to phy framework")
> Cc: Stable List <stable@vger.kernel.org>
> Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
> Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
> ---
> drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 6 +++++-
> 1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
> index 2f897ea5e80a..b0a1a6774ea6 100644
> --- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
> +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
> @@ -680,6 +680,11 @@ static void cdns_dsi_bridge_post_disable(struct drm_bridge *bridge)
> struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
> struct cdns_dsi *dsi = input_to_dsi(input);
>
> + dsi->phy_initialized = false;
> + dsi->link_initialized = false;
> + phy_power_off(dsi->dphy);
> + phy_exit(dsi->dphy);
> +
> pm_runtime_put(dsi->base.dev);
> }
>
> @@ -1152,7 +1157,6 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev)
> clk_disable_unprepare(dsi->dsi_sys_clk);
> clk_disable_unprepare(dsi->dsi_p_clk);
> reset_control_assert(dsi->dsi_p_rst);
> - dsi->link_initialized = false;
> return 0;
> }
>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Tomi
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v8 03/13] drm/bridge: cdns-dsi: Fix the clock variable for mode_valid()
2025-01-26 19:15 [PATCH v8 00/13] drm/bridge: cdns-dsi: Fix the color-shift issue Aradhya Bhatia
2025-01-26 19:15 ` [PATCH v8 01/13] drm/bridge: cdns-dsi: Fix connecting to next bridge Aradhya Bhatia
2025-01-26 19:15 ` [PATCH v8 02/13] drm/bridge: cdns-dsi: Fix phy de-init and flag it so Aradhya Bhatia
@ 2025-01-26 19:15 ` Aradhya Bhatia
2025-01-26 19:15 ` [PATCH v8 04/13] drm/bridge: cdns-dsi: Check return value when getting default PHY config Aradhya Bhatia
` (9 subsequent siblings)
12 siblings, 0 replies; 25+ messages in thread
From: Aradhya Bhatia @ 2025-01-26 19:15 UTC (permalink / raw)
To: Tomi Valkeinen, Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda,
Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Aradhya Bhatia,
Stable List
From: Aradhya Bhatia <a-bhatia1@ti.com>
The crtc_* mode parameters do not get generated (duplicated in this
case) from the regular parameters before the mode validation phase
begins.
The rest of the code conditionally uses the crtc_* parameters only
during the bridge enable phase, but sticks to the regular parameters
for mode validation. In this singular instance, however, the driver
tries to use the crtc_clock parameter even during the mode validation,
causing the validation to fail.
Allow the D-Phy config checks to use mode->clock instead of
mode->crtc_clock during mode_valid checks, like everywhere else in the
driver.
Fixes: fced5a364dee ("drm/bridge: cdns: Convert to phy framework")
Cc: Stable List <stable@vger.kernel.org>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index b0a1a6774ea6..19cc8734a4c8 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -568,13 +568,14 @@ static int cdns_dsi_check_conf(struct cdns_dsi *dsi,
struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy;
unsigned long dsi_hss_hsa_hse_hbp;
unsigned int nlanes = output->dev->lanes;
+ int mode_clock = (mode_valid_check ? mode->clock : mode->crtc_clock);
int ret;
ret = cdns_dsi_mode2cfg(dsi, mode, dsi_cfg, mode_valid_check);
if (ret)
return ret;
- phy_mipi_dphy_get_default_config(mode->crtc_clock * 1000,
+ phy_mipi_dphy_get_default_config(mode_clock * 1000,
mipi_dsi_pixel_format_to_bpp(output->dev->format),
nlanes, phy_cfg);
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v8 04/13] drm/bridge: cdns-dsi: Check return value when getting default PHY config
2025-01-26 19:15 [PATCH v8 00/13] drm/bridge: cdns-dsi: Fix the color-shift issue Aradhya Bhatia
` (2 preceding siblings ...)
2025-01-26 19:15 ` [PATCH v8 03/13] drm/bridge: cdns-dsi: Fix the clock variable for mode_valid() Aradhya Bhatia
@ 2025-01-26 19:15 ` Aradhya Bhatia
2025-01-26 19:15 ` [PATCH v8 05/13] drm/bridge: cdns-dsi: Wait for Clk and Data Lanes to be ready Aradhya Bhatia
` (8 subsequent siblings)
12 siblings, 0 replies; 25+ messages in thread
From: Aradhya Bhatia @ 2025-01-26 19:15 UTC (permalink / raw)
To: Tomi Valkeinen, Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda,
Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Aradhya Bhatia,
Stable List
From: Aradhya Bhatia <a-bhatia1@ti.com>
Check for the return value of the phy_mipi_dphy_get_default_config()
call, and incase of an error, return back the same.
Fixes: fced5a364dee ("drm/bridge: cdns: Convert to phy framework")
Cc: Stable List <stable@vger.kernel.org>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index 19cc8734a4c8..87921a748cdb 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -575,9 +575,11 @@ static int cdns_dsi_check_conf(struct cdns_dsi *dsi,
if (ret)
return ret;
- phy_mipi_dphy_get_default_config(mode_clock * 1000,
- mipi_dsi_pixel_format_to_bpp(output->dev->format),
- nlanes, phy_cfg);
+ ret = phy_mipi_dphy_get_default_config(mode_clock * 1000,
+ mipi_dsi_pixel_format_to_bpp(output->dev->format),
+ nlanes, phy_cfg);
+ if (ret)
+ return ret;
ret = cdns_dsi_adjust_phy_config(dsi, dsi_cfg, phy_cfg, mode, mode_valid_check);
if (ret)
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v8 05/13] drm/bridge: cdns-dsi: Wait for Clk and Data Lanes to be ready
2025-01-26 19:15 [PATCH v8 00/13] drm/bridge: cdns-dsi: Fix the color-shift issue Aradhya Bhatia
` (3 preceding siblings ...)
2025-01-26 19:15 ` [PATCH v8 04/13] drm/bridge: cdns-dsi: Check return value when getting default PHY config Aradhya Bhatia
@ 2025-01-26 19:15 ` Aradhya Bhatia
2025-01-26 19:15 ` [PATCH v8 06/13] drm/bridge: cdns-dsi: Move to devm_drm_of_get_bridge() Aradhya Bhatia
` (7 subsequent siblings)
12 siblings, 0 replies; 25+ messages in thread
From: Aradhya Bhatia @ 2025-01-26 19:15 UTC (permalink / raw)
To: Tomi Valkeinen, Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda,
Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Aradhya Bhatia,
Stable List, Dominik Haller
From: Aradhya Bhatia <a-bhatia1@ti.com>
Once the DSI Link and DSI Phy are initialized, the code needs to wait
for Clk and Data Lanes to be ready, before continuing configuration.
This is in accordance with the DSI Start-up procedure, found in the
Technical Reference Manual of Texas Instrument's J721E SoC[0] which
houses this DSI TX controller.
If the previous bridge (or crtc/encoder) are configured pre-maturely,
the input signal FIFO gets corrupt. This introduces a color-shift on the
display.
Allow the driver to wait for the clk and data lanes to get ready during
DSI enable.
[0]: See section 12.6.5.7.3 "Start-up Procedure" in J721E SoC TRM
TRM Link: http://www.ti.com/lit/pdf/spruil1
Fixes: e19233955d9e ("drm/bridge: Add Cadence DSI driver")
Cc: Stable List <stable@vger.kernel.org>
Tested-by: Dominik Haller <d.haller@phytec.de>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index 87921a748cdb..6a77ca36cb9d 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -769,7 +769,7 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy;
unsigned long tx_byte_period;
struct cdns_dsi_cfg dsi_cfg;
- u32 tmp, reg_wakeup, div;
+ u32 tmp, reg_wakeup, div, status;
int nlanes;
if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0))
@@ -786,6 +786,19 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
cdns_dsi_hs_init(dsi);
cdns_dsi_init_link(dsi);
+ /*
+ * Now that the DSI Link and DSI Phy are initialized,
+ * wait for the CLK and Data Lanes to be ready.
+ */
+ tmp = CLK_LANE_RDY;
+ for (int i = 0; i < nlanes; i++)
+ tmp |= DATA_LANE_RDY(i);
+
+ if (readl_poll_timeout(dsi->regs + MCTL_MAIN_STS, status,
+ (tmp == (status & tmp)), 100, 500000))
+ dev_err(dsi->base.dev,
+ "Timed Out: DSI-DPhy Clock and Data Lanes not ready.\n");
+
writel(HBP_LEN(dsi_cfg.hbp) | HSA_LEN(dsi_cfg.hsa),
dsi->regs + VID_HSIZE1);
writel(HFP_LEN(dsi_cfg.hfp) | HACT_LEN(dsi_cfg.hact),
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v8 06/13] drm/bridge: cdns-dsi: Move to devm_drm_of_get_bridge()
2025-01-26 19:15 [PATCH v8 00/13] drm/bridge: cdns-dsi: Fix the color-shift issue Aradhya Bhatia
` (4 preceding siblings ...)
2025-01-26 19:15 ` [PATCH v8 05/13] drm/bridge: cdns-dsi: Wait for Clk and Data Lanes to be ready Aradhya Bhatia
@ 2025-01-26 19:15 ` Aradhya Bhatia
2025-01-26 19:15 ` [PATCH v8 07/13] drm/mipi-dsi: Add helper to find input format Aradhya Bhatia
` (6 subsequent siblings)
12 siblings, 0 replies; 25+ messages in thread
From: Aradhya Bhatia @ 2025-01-26 19:15 UTC (permalink / raw)
To: Tomi Valkeinen, Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda,
Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Aradhya Bhatia
From: Aradhya Bhatia <a-bhatia1@ti.com>
Instead of manually finding the next bridge/panel, and maintaining the
panel-bridge (in-case the next entity is a panel), switch to using the
automatically managing devm_drm_of_get_bridge() API.
Drop the drm_panel support completely from the driver while at it.
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
.../gpu/drm/bridge/cadence/cdns-dsi-core.c | 28 ++-----------------
.../gpu/drm/bridge/cadence/cdns-dsi-core.h | 2 --
2 files changed, 3 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index 6a77ca36cb9d..c2512342139c 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -941,8 +941,6 @@ static int cdns_dsi_attach(struct mipi_dsi_host *host,
struct cdns_dsi_output *output = &dsi->output;
struct cdns_dsi_input *input = &dsi->input;
struct drm_bridge *bridge;
- struct drm_panel *panel;
- struct device_node *np;
int ret;
/*
@@ -960,26 +958,10 @@ static int cdns_dsi_attach(struct mipi_dsi_host *host,
/*
* The host <-> device link might be described using an OF-graph
* representation, in this case we extract the device of_node from
- * this representation, otherwise we use dsidev->dev.of_node which
- * should have been filled by the core.
+ * this representation.
*/
- np = of_graph_get_remote_node(dsi->base.dev->of_node, DSI_OUTPUT_PORT,
- dev->channel);
- if (!np)
- np = of_node_get(dev->dev.of_node);
-
- panel = of_drm_find_panel(np);
- if (!IS_ERR(panel)) {
- bridge = drm_panel_bridge_add_typed(panel,
- DRM_MODE_CONNECTOR_DSI);
- } else {
- bridge = of_drm_find_bridge(np);
- if (!bridge)
- bridge = ERR_PTR(-EINVAL);
- }
-
- of_node_put(np);
-
+ bridge = devm_drm_of_get_bridge(dsi->base.dev, dsi->base.dev->of_node,
+ DSI_OUTPUT_PORT, dev->channel);
if (IS_ERR(bridge)) {
ret = PTR_ERR(bridge);
dev_err(host->dev, "failed to add DSI device %s (err = %d)",
@@ -989,7 +971,6 @@ static int cdns_dsi_attach(struct mipi_dsi_host *host,
output->dev = dev;
output->bridge = bridge;
- output->panel = panel;
/*
* The DSI output has been properly configured, we can now safely
@@ -1005,12 +986,9 @@ static int cdns_dsi_detach(struct mipi_dsi_host *host,
struct mipi_dsi_device *dev)
{
struct cdns_dsi *dsi = to_cdns_dsi(host);
- struct cdns_dsi_output *output = &dsi->output;
struct cdns_dsi_input *input = &dsi->input;
drm_bridge_remove(&input->bridge);
- if (output->panel)
- drm_panel_bridge_remove(output->bridge);
return 0;
}
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
index ca7ea2da635c..5db5dbbbcaad 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
@@ -10,7 +10,6 @@
#include <drm/drm_bridge.h>
#include <drm/drm_mipi_dsi.h>
-#include <drm/drm_panel.h>
#include <linux/bits.h>
#include <linux/completion.h>
@@ -21,7 +20,6 @@ struct reset_control;
struct cdns_dsi_output {
struct mipi_dsi_device *dev;
- struct drm_panel *panel;
struct drm_bridge *bridge;
union phy_configure_opts phy_opts;
};
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v8 07/13] drm/mipi-dsi: Add helper to find input format
2025-01-26 19:15 [PATCH v8 00/13] drm/bridge: cdns-dsi: Fix the color-shift issue Aradhya Bhatia
` (5 preceding siblings ...)
2025-01-26 19:15 ` [PATCH v8 06/13] drm/bridge: cdns-dsi: Move to devm_drm_of_get_bridge() Aradhya Bhatia
@ 2025-01-26 19:15 ` Aradhya Bhatia
2025-01-26 19:15 ` [PATCH v8 08/13] drm/bridge: cdns-dsi: Support atomic bridge APIs Aradhya Bhatia
` (5 subsequent siblings)
12 siblings, 0 replies; 25+ messages in thread
From: Aradhya Bhatia @ 2025-01-26 19:15 UTC (permalink / raw)
To: Tomi Valkeinen, Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda,
Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Aradhya Bhatia
From: Aradhya Bhatia <a-bhatia1@ti.com>
Add a helper API that can be used by the DSI hosts to find the required
input bus format for the given output dsi pixel format.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
drivers/gpu/drm/drm_mipi_dsi.c | 37 ++++++++++++++++++++++++++++++++++
include/drm/drm_mipi_dsi.h | 1 +
2 files changed, 38 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index 5e5c5f84daac..076826f2445a 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -36,6 +36,8 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_print.h>
+#include <linux/media-bus-format.h>
+
#include <video/mipi_display.h>
/**
@@ -870,6 +872,41 @@ ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
}
EXPORT_SYMBOL(mipi_dsi_generic_read);
+/**
+ * drm_mipi_dsi_get_input_bus_fmt() - Get the required MEDIA_BUS_FMT_* based
+ * input pixel format for a given DSI output
+ * pixel format
+ * @dsi_format: pixel format that a DSI host needs to output
+ *
+ * Various DSI hosts can use this function during their
+ * &drm_bridge_funcs.atomic_get_input_bus_fmts operation to ascertain
+ * the MEDIA_BUS_FMT_* pixel format required as input.
+ *
+ * RETURNS:
+ * a 32-bit MEDIA_BUS_FMT_* value on success or 0 in case of failure.
+ */
+u32 drm_mipi_dsi_get_input_bus_fmt(enum mipi_dsi_pixel_format dsi_format)
+{
+ switch (dsi_format) {
+ case MIPI_DSI_FMT_RGB888:
+ return MEDIA_BUS_FMT_RGB888_1X24;
+
+ case MIPI_DSI_FMT_RGB666:
+ return MEDIA_BUS_FMT_RGB666_1X24_CPADHI;
+
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ return MEDIA_BUS_FMT_RGB666_1X18;
+
+ case MIPI_DSI_FMT_RGB565:
+ return MEDIA_BUS_FMT_RGB565_1X16;
+
+ default:
+ /* Unsupported DSI Format */
+ return 0;
+ }
+}
+EXPORT_SYMBOL(drm_mipi_dsi_get_input_bus_fmt);
+
/**
* mipi_dsi_dcs_write_buffer() - transmit a DCS command with payload
* @dsi: DSI peripheral device
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 94400a78031f..9e2804e3a2b0 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -293,6 +293,7 @@ void mipi_dsi_generic_write_multi(struct mipi_dsi_multi_context *ctx,
const void *payload, size_t size);
ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
size_t num_params, void *data, size_t size);
+u32 drm_mipi_dsi_get_input_bus_fmt(enum mipi_dsi_pixel_format dsi_format);
#define mipi_dsi_msleep(ctx, delay) \
do { \
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v8 08/13] drm/bridge: cdns-dsi: Support atomic bridge APIs
2025-01-26 19:15 [PATCH v8 00/13] drm/bridge: cdns-dsi: Fix the color-shift issue Aradhya Bhatia
` (6 preceding siblings ...)
2025-01-26 19:15 ` [PATCH v8 07/13] drm/mipi-dsi: Add helper to find input format Aradhya Bhatia
@ 2025-01-26 19:15 ` Aradhya Bhatia
2025-01-26 19:15 ` [PATCH v8 09/13] drm/bridge: cdns-dsi: Move DSI mode check to _atomic_check() Aradhya Bhatia
` (4 subsequent siblings)
12 siblings, 0 replies; 25+ messages in thread
From: Aradhya Bhatia @ 2025-01-26 19:15 UTC (permalink / raw)
To: Tomi Valkeinen, Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda,
Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Aradhya Bhatia
From: Aradhya Bhatia <a-bhatia1@ti.com>
Change the existing (and deprecated) bridge hooks, to the bridge
atomic APIs.
Add drm helpers for duplicate_state, destroy_state, and bridge_reset
bridge hooks.
Further add support for the input format negotiation hook.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
.../gpu/drm/bridge/cadence/cdns-dsi-core.c | 51 ++++++++++++++++---
1 file changed, 43 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index c2512342139c..20a0309bb813 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -658,7 +658,8 @@ cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge,
return MODE_OK;
}
-static void cdns_dsi_bridge_disable(struct drm_bridge *bridge)
+static void cdns_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
@@ -678,7 +679,8 @@ static void cdns_dsi_bridge_disable(struct drm_bridge *bridge)
pm_runtime_put(dsi->base.dev);
}
-static void cdns_dsi_bridge_post_disable(struct drm_bridge *bridge)
+static void cdns_dsi_bridge_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
@@ -760,7 +762,8 @@ static void cdns_dsi_init_link(struct cdns_dsi *dsi)
dsi->link_initialized = true;
}
-static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
+static void cdns_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
@@ -913,7 +916,8 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
writel(tmp, dsi->regs + MCTL_MAIN_EN);
}
-static void cdns_dsi_bridge_pre_enable(struct drm_bridge *bridge)
+static void cdns_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
@@ -925,13 +929,44 @@ static void cdns_dsi_bridge_pre_enable(struct drm_bridge *bridge)
cdns_dsi_hs_init(dsi);
}
+static u32 *cdns_dsi_bridge_get_input_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ u32 output_fmt,
+ unsigned int *num_input_fmts)
+{
+ struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
+ struct cdns_dsi *dsi = input_to_dsi(input);
+ struct cdns_dsi_output *output = &dsi->output;
+ u32 *input_fmts;
+
+ *num_input_fmts = 0;
+
+ input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL);
+ if (!input_fmts)
+ return NULL;
+
+ input_fmts[0] = drm_mipi_dsi_get_input_bus_fmt(output->dev->format);
+ if (!input_fmts[0])
+ return NULL;
+
+ *num_input_fmts = 1;
+
+ return input_fmts;
+}
+
static const struct drm_bridge_funcs cdns_dsi_bridge_funcs = {
.attach = cdns_dsi_bridge_attach,
.mode_valid = cdns_dsi_bridge_mode_valid,
- .disable = cdns_dsi_bridge_disable,
- .pre_enable = cdns_dsi_bridge_pre_enable,
- .enable = cdns_dsi_bridge_enable,
- .post_disable = cdns_dsi_bridge_post_disable,
+ .atomic_disable = cdns_dsi_bridge_atomic_disable,
+ .atomic_pre_enable = cdns_dsi_bridge_atomic_pre_enable,
+ .atomic_enable = cdns_dsi_bridge_atomic_enable,
+ .atomic_post_disable = cdns_dsi_bridge_atomic_post_disable,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .atomic_get_input_bus_fmts = cdns_dsi_bridge_get_input_bus_fmts,
};
static int cdns_dsi_attach(struct mipi_dsi_host *host,
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v8 09/13] drm/bridge: cdns-dsi: Move DSI mode check to _atomic_check()
2025-01-26 19:15 [PATCH v8 00/13] drm/bridge: cdns-dsi: Fix the color-shift issue Aradhya Bhatia
` (7 preceding siblings ...)
2025-01-26 19:15 ` [PATCH v8 08/13] drm/bridge: cdns-dsi: Support atomic bridge APIs Aradhya Bhatia
@ 2025-01-26 19:15 ` Aradhya Bhatia
2025-01-26 19:15 ` [PATCH v8 10/13] drm/atomic-helper: Refactor crtc & encoder-bridge op loops into separate functions Aradhya Bhatia
` (3 subsequent siblings)
12 siblings, 0 replies; 25+ messages in thread
From: Aradhya Bhatia @ 2025-01-26 19:15 UTC (permalink / raw)
To: Tomi Valkeinen, Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda,
Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Aradhya Bhatia
From: Aradhya Bhatia <a-bhatia1@ti.com>
At present, the DSI mode configuration check happens during the
_atomic_enable() phase, which is not really the best place for this.
Moreover, if the mode is not valid, the driver gives a warning and
continues the hardware configuration.
Move the DSI mode configuration check to _atomic_check() instead, which
can properly report back any invalid mode, before the _enable phase even
begins.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
.../gpu/drm/bridge/cadence/cdns-dsi-core.c | 94 ++++++++++++++++++-
1 file changed, 89 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index 20a0309bb813..12457f712c94 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -425,6 +425,17 @@
#define DSI_NULL_FRAME_OVERHEAD 6
#define DSI_EOT_PKT_SIZE 4
+struct cdns_dsi_bridge_state {
+ struct drm_bridge_state base;
+ struct cdns_dsi_cfg dsi_cfg;
+};
+
+static inline struct cdns_dsi_bridge_state *
+to_cdns_dsi_bridge_state(struct drm_bridge_state *bridge_state)
+{
+ return container_of(bridge_state, struct cdns_dsi_bridge_state, base);
+}
+
static inline struct cdns_dsi *input_to_dsi(struct cdns_dsi_input *input)
{
return container_of(input, struct cdns_dsi, input);
@@ -768,6 +779,9 @@ static void cdns_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
struct cdns_dsi_output *output = &dsi->output;
+ struct drm_atomic_state *state = old_bridge_state->base.state;
+ struct cdns_dsi_bridge_state *dsi_state;
+ struct drm_bridge_state *new_bridge_state;
struct drm_display_mode *mode;
struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy;
unsigned long tx_byte_period;
@@ -778,14 +792,19 @@ static void cdns_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0))
return;
+ new_bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
+ if (WARN_ON(!new_bridge_state))
+ return;
+
+ dsi_state = to_cdns_dsi_bridge_state(new_bridge_state);
+ dsi_cfg = dsi_state->dsi_cfg;
+
if (dsi->platform_ops && dsi->platform_ops->enable)
dsi->platform_ops->enable(dsi);
mode = &bridge->encoder->crtc->state->adjusted_mode;
nlanes = output->dev->lanes;
- WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, false));
-
cdns_dsi_hs_init(dsi);
cdns_dsi_init_link(dsi);
@@ -956,6 +975,70 @@ static u32 *cdns_dsi_bridge_get_input_bus_fmts(struct drm_bridge *bridge,
return input_fmts;
}
+static int cdns_dsi_bridge_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
+ struct cdns_dsi *dsi = input_to_dsi(input);
+ struct cdns_dsi_bridge_state *dsi_state = to_cdns_dsi_bridge_state(bridge_state);
+ const struct drm_display_mode *mode = &crtc_state->mode;
+ struct cdns_dsi_cfg *dsi_cfg = &dsi_state->dsi_cfg;
+
+ return cdns_dsi_check_conf(dsi, mode, dsi_cfg, false);
+}
+
+static struct drm_bridge_state *
+cdns_dsi_bridge_atomic_duplicate_state(struct drm_bridge *bridge)
+{
+ struct cdns_dsi_bridge_state *dsi_state, *old_dsi_state;
+ struct drm_bridge_state *bridge_state;
+
+ if (WARN_ON(!bridge->base.state))
+ return NULL;
+
+ bridge_state = drm_priv_to_bridge_state(bridge->base.state);
+ old_dsi_state = to_cdns_dsi_bridge_state(bridge_state);
+
+ dsi_state = kzalloc(sizeof(*dsi_state), GFP_KERNEL);
+ if (!dsi_state)
+ return NULL;
+
+ __drm_atomic_helper_bridge_duplicate_state(bridge, &dsi_state->base);
+
+ memcpy(&dsi_state->dsi_cfg, &old_dsi_state->dsi_cfg,
+ sizeof(dsi_state->dsi_cfg));
+
+ return &dsi_state->base;
+}
+
+static void
+cdns_dsi_bridge_atomic_destroy_state(struct drm_bridge *bridge,
+ struct drm_bridge_state *state)
+{
+ struct cdns_dsi_bridge_state *dsi_state;
+
+ dsi_state = to_cdns_dsi_bridge_state(state);
+
+ kfree(dsi_state);
+}
+
+static struct drm_bridge_state *
+cdns_dsi_bridge_atomic_reset(struct drm_bridge *bridge)
+{
+ struct cdns_dsi_bridge_state *dsi_state;
+
+ dsi_state = kzalloc(sizeof(*dsi_state), GFP_KERNEL);
+ if (!dsi_state)
+ return NULL;
+
+ memset(dsi_state, 0, sizeof(*dsi_state));
+ dsi_state->base.bridge = bridge;
+
+ return &dsi_state->base;
+}
+
static const struct drm_bridge_funcs cdns_dsi_bridge_funcs = {
.attach = cdns_dsi_bridge_attach,
.mode_valid = cdns_dsi_bridge_mode_valid,
@@ -963,9 +1046,10 @@ static const struct drm_bridge_funcs cdns_dsi_bridge_funcs = {
.atomic_pre_enable = cdns_dsi_bridge_atomic_pre_enable,
.atomic_enable = cdns_dsi_bridge_atomic_enable,
.atomic_post_disable = cdns_dsi_bridge_atomic_post_disable,
- .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
- .atomic_reset = drm_atomic_helper_bridge_reset,
+ .atomic_check = cdns_dsi_bridge_atomic_check,
+ .atomic_duplicate_state = cdns_dsi_bridge_atomic_duplicate_state,
+ .atomic_destroy_state = cdns_dsi_bridge_atomic_destroy_state,
+ .atomic_reset = cdns_dsi_bridge_atomic_reset,
.atomic_get_input_bus_fmts = cdns_dsi_bridge_get_input_bus_fmts,
};
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v8 10/13] drm/atomic-helper: Refactor crtc & encoder-bridge op loops into separate functions
2025-01-26 19:15 [PATCH v8 00/13] drm/bridge: cdns-dsi: Fix the color-shift issue Aradhya Bhatia
` (8 preceding siblings ...)
2025-01-26 19:15 ` [PATCH v8 09/13] drm/bridge: cdns-dsi: Move DSI mode check to _atomic_check() Aradhya Bhatia
@ 2025-01-26 19:15 ` Aradhya Bhatia
2025-01-26 21:53 ` Dmitry Baryshkov
2025-02-04 13:40 ` Tomi Valkeinen
2025-01-26 19:15 ` [PATCH v8 11/13] drm/atomic-helper: Separate out bridge pre_enable/post_disable from enable/disable Aradhya Bhatia
` (2 subsequent siblings)
12 siblings, 2 replies; 25+ messages in thread
From: Aradhya Bhatia @ 2025-01-26 19:15 UTC (permalink / raw)
To: Tomi Valkeinen, Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda,
Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Aradhya Bhatia
From: Aradhya Bhatia <a-bhatia1@ti.com>
The way any singular display pipeline, in need of a modeset, gets
enabled is as follows -
crtc enable
(all) bridge pre-enable
encoder enable
(all) bridge enable
- and the disable sequence is exactly the reverse of this.
The crtc operations occur by looping over the old and new crtc states,
while the encoder and bridge operations occur together, by looping over
the connector states of the display pipelines.
Refactor these operations - crtc enable/disable, and encoder & bridge
(pre/post) enable/disable - into separate functions each, to make way
for the re-ordering of the enable/disable sequences.
This patch doesn't alter the sequence of crtc/encoder/bridge operations
in any way, but helps to cleanly pave the way for the next two patches,
by maintaining logical bisectability.
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
drivers/gpu/drm/drm_atomic_helper.c | 69 ++++++++++++++++++++---------
1 file changed, 49 insertions(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 5186d2114a50..e805fd0a54c5 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1122,11 +1122,10 @@ crtc_needs_disable(struct drm_crtc_state *old_state,
}
static void
-disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
+encoder_bridge_disable(struct drm_device *dev, struct drm_atomic_state *old_state)
{
struct drm_connector *connector;
struct drm_connector_state *old_conn_state, *new_conn_state;
- struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
int i;
@@ -1189,6 +1188,14 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
drm_atomic_bridge_chain_post_disable(bridge, old_state);
}
+}
+
+static void
+crtc_disable(struct drm_device *dev, struct drm_atomic_state *old_state)
+{
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+ int i;
for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
const struct drm_crtc_helper_funcs *funcs;
@@ -1236,6 +1243,14 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
}
}
+static void
+disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
+{
+ encoder_bridge_disable(dev, old_state);
+
+ crtc_disable(dev, old_state);
+}
+
/**
* drm_atomic_helper_update_legacy_modeset_state - update legacy modeset state
* @dev: DRM device
@@ -1445,28 +1460,12 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
}
}
-/**
- * drm_atomic_helper_commit_modeset_enables - modeset commit to enable outputs
- * @dev: DRM device
- * @old_state: atomic state object with old state structures
- *
- * This function enables all the outputs with the new configuration which had to
- * be turned off for the update.
- *
- * For compatibility with legacy CRTC helpers this should be called after
- * drm_atomic_helper_commit_planes(), which is what the default commit function
- * does. But drivers with different needs can group the modeset commits together
- * and do the plane commits at the end. This is useful for drivers doing runtime
- * PM since planes updates then only happen when the CRTC is actually enabled.
- */
-void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
- struct drm_atomic_state *old_state)
+static void
+crtc_enable(struct drm_device *dev, struct drm_atomic_state *old_state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
struct drm_crtc_state *new_crtc_state;
- struct drm_connector *connector;
- struct drm_connector_state *new_conn_state;
int i;
for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
@@ -1490,6 +1489,14 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
funcs->commit(crtc);
}
}
+}
+
+static void
+encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *old_state)
+{
+ struct drm_connector *connector;
+ struct drm_connector_state *new_conn_state;
+ int i;
for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
const struct drm_encoder_helper_funcs *funcs;
@@ -1527,6 +1534,28 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
drm_atomic_bridge_chain_enable(bridge, old_state);
}
+}
+
+/**
+ * drm_atomic_helper_commit_modeset_enables - modeset commit to enable outputs
+ * @dev: DRM device
+ * @old_state: atomic state object with old state structures
+ *
+ * This function enables all the outputs with the new configuration which had to
+ * be turned off for the update.
+ *
+ * For compatibility with legacy CRTC helpers this should be called after
+ * drm_atomic_helper_commit_planes(), which is what the default commit function
+ * does. But drivers with different needs can group the modeset commits together
+ * and do the plane commits at the end. This is useful for drivers doing runtime
+ * PM since planes updates then only happen when the CRTC is actually enabled.
+ */
+void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
+ struct drm_atomic_state *old_state)
+{
+ crtc_enable(dev, old_state);
+
+ encoder_bridge_enable(dev, old_state);
drm_atomic_helper_commit_writebacks(dev, old_state);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH v8 10/13] drm/atomic-helper: Refactor crtc & encoder-bridge op loops into separate functions
2025-01-26 19:15 ` [PATCH v8 10/13] drm/atomic-helper: Refactor crtc & encoder-bridge op loops into separate functions Aradhya Bhatia
@ 2025-01-26 21:53 ` Dmitry Baryshkov
2025-02-04 13:40 ` Tomi Valkeinen
1 sibling, 0 replies; 25+ messages in thread
From: Dmitry Baryshkov @ 2025-01-26 21:53 UTC (permalink / raw)
To: Aradhya Bhatia
Cc: Tomi Valkeinen, Laurent Pinchart, Andrzej Hajda, Neil Armstrong,
Robert Foss, Jonas Karlman, Jernej Skrabec, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List
On Mon, Jan 27, 2025 at 12:45:48AM +0530, Aradhya Bhatia wrote:
> From: Aradhya Bhatia <a-bhatia1@ti.com>
>
> The way any singular display pipeline, in need of a modeset, gets
> enabled is as follows -
>
> crtc enable
> (all) bridge pre-enable
> encoder enable
> (all) bridge enable
>
> - and the disable sequence is exactly the reverse of this.
>
> The crtc operations occur by looping over the old and new crtc states,
> while the encoder and bridge operations occur together, by looping over
> the connector states of the display pipelines.
>
> Refactor these operations - crtc enable/disable, and encoder & bridge
> (pre/post) enable/disable - into separate functions each, to make way
> for the re-ordering of the enable/disable sequences.
>
> This patch doesn't alter the sequence of crtc/encoder/bridge operations
> in any way, but helps to cleanly pave the way for the next two patches,
> by maintaining logical bisectability.
>
> Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
> Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
> ---
> drivers/gpu/drm/drm_atomic_helper.c | 69 ++++++++++++++++++++---------
> 1 file changed, 49 insertions(+), 20 deletions(-)
>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v8 10/13] drm/atomic-helper: Refactor crtc & encoder-bridge op loops into separate functions
2025-01-26 19:15 ` [PATCH v8 10/13] drm/atomic-helper: Refactor crtc & encoder-bridge op loops into separate functions Aradhya Bhatia
2025-01-26 21:53 ` Dmitry Baryshkov
@ 2025-02-04 13:40 ` Tomi Valkeinen
1 sibling, 0 replies; 25+ messages in thread
From: Tomi Valkeinen @ 2025-02-04 13:40 UTC (permalink / raw)
To: Aradhya Bhatia
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Dmitry Baryshkov,
Laurent Pinchart, Andrzej Hajda, Neil Armstrong, Robert Foss,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Hi,
On 26/01/2025 21:15, Aradhya Bhatia wrote:
> From: Aradhya Bhatia <a-bhatia1@ti.com>
>
> The way any singular display pipeline, in need of a modeset, gets
> enabled is as follows -
>
> crtc enable
> (all) bridge pre-enable
> encoder enable
> (all) bridge enable
>
> - and the disable sequence is exactly the reverse of this.
>
> The crtc operations occur by looping over the old and new crtc states,
> while the encoder and bridge operations occur together, by looping over
> the connector states of the display pipelines.
>
> Refactor these operations - crtc enable/disable, and encoder & bridge
> (pre/post) enable/disable - into separate functions each, to make way
> for the re-ordering of the enable/disable sequences.
>
> This patch doesn't alter the sequence of crtc/encoder/bridge operations
> in any way, but helps to cleanly pave the way for the next two patches,
> by maintaining logical bisectability.
>
> Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
> Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
> ---
> drivers/gpu/drm/drm_atomic_helper.c | 69 ++++++++++++++++++++---------
> 1 file changed, 49 insertions(+), 20 deletions(-)
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Tomi
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v8 11/13] drm/atomic-helper: Separate out bridge pre_enable/post_disable from enable/disable
2025-01-26 19:15 [PATCH v8 00/13] drm/bridge: cdns-dsi: Fix the color-shift issue Aradhya Bhatia
` (9 preceding siblings ...)
2025-01-26 19:15 ` [PATCH v8 10/13] drm/atomic-helper: Refactor crtc & encoder-bridge op loops into separate functions Aradhya Bhatia
@ 2025-01-26 19:15 ` Aradhya Bhatia
2025-01-26 21:54 ` Dmitry Baryshkov
` (2 more replies)
2025-01-26 19:15 ` [PATCH v8 12/13] drm/atomic-helper: Re-order bridge chain pre-enable and post-disable Aradhya Bhatia
2025-01-26 19:15 ` [PATCH v8 13/13] drm/bridge: cdns-dsi: Use pre_enable/post_disable to enable/disable Aradhya Bhatia
12 siblings, 3 replies; 25+ messages in thread
From: Aradhya Bhatia @ 2025-01-26 19:15 UTC (permalink / raw)
To: Tomi Valkeinen, Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda,
Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Aradhya Bhatia
The encoder-bridge ops occur by looping over the new connector states of
the display pipelines. The enable sequence runs as follows -
- pre_enable(bridge),
- enable(encoder),
- enable(bridge),
while the disable sequnce runs as follows -
- disable(bridge),
- disable(encoder),
- post_disable(bridge).
Separate out the pre_enable(bridge), and the post_disable(bridge)
operations into separate functions each.
This patch keeps the sequence same for any singular disaplay pipe, but
changes the sequence across multiple display pipelines.
This patch is meant to be an interim patch, to cleanly pave the way for
the sequence re-ordering patch, and maintain bisectability in the
process.
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
drivers/gpu/drm/drm_atomic_helper.c | 92 +++++++++++++++++++++++++++--
1 file changed, 88 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index e805fd0a54c5..f5532e3646e1 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1185,8 +1185,6 @@ encoder_bridge_disable(struct drm_device *dev, struct drm_atomic_state *old_stat
else if (funcs->dpms)
funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
}
-
- drm_atomic_bridge_chain_post_disable(bridge, old_state);
}
}
@@ -1243,11 +1241,65 @@ crtc_disable(struct drm_device *dev, struct drm_atomic_state *old_state)
}
}
+static void
+encoder_bridge_post_disable(struct drm_device *dev, struct drm_atomic_state *old_state)
+{
+ struct drm_connector *connector;
+ struct drm_connector_state *old_conn_state, *new_conn_state;
+ struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+ int i;
+
+ for_each_oldnew_connector_in_state(old_state, connector, old_conn_state, new_conn_state, i) {
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
+
+ /*
+ * Shut down everything that's in the changeset and currently
+ * still on. So need to check the old, saved state.
+ */
+ if (!old_conn_state->crtc)
+ continue;
+
+ old_crtc_state = drm_atomic_get_old_crtc_state(old_state, old_conn_state->crtc);
+
+ if (new_conn_state->crtc)
+ new_crtc_state = drm_atomic_get_new_crtc_state(
+ old_state,
+ new_conn_state->crtc);
+ else
+ new_crtc_state = NULL;
+
+ if (!crtc_needs_disable(old_crtc_state, new_crtc_state) ||
+ !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state))
+ continue;
+
+ encoder = old_conn_state->best_encoder;
+
+ /* We shouldn't get this far if we didn't previously have
+ * an encoder.. but WARN_ON() rather than explode.
+ */
+ if (WARN_ON(!encoder))
+ continue;
+
+ drm_dbg_atomic(dev, "post-disabling bridges [ENCODER:%d:%s]\n",
+ encoder->base.id, encoder->name);
+
+ /*
+ * Each encoder has at most one connector (since we always steal
+ * it away), so we won't call disable hooks twice.
+ */
+ bridge = drm_bridge_chain_get_first_bridge(encoder);
+ drm_atomic_bridge_chain_post_disable(bridge, old_state);
+ }
+}
+
static void
disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
{
encoder_bridge_disable(dev, old_state);
+ encoder_bridge_post_disable(dev, old_state);
+
crtc_disable(dev, old_state);
}
@@ -1460,6 +1512,38 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
}
}
+static void
+encoder_bridge_pre_enable(struct drm_device *dev, struct drm_atomic_state *old_state)
+{
+ struct drm_connector *connector;
+ struct drm_connector_state *new_conn_state;
+ int i;
+
+ for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
+
+ if (!new_conn_state->best_encoder)
+ continue;
+
+ if (!new_conn_state->crtc->state->active ||
+ !drm_atomic_crtc_needs_modeset(new_conn_state->crtc->state))
+ continue;
+
+ encoder = new_conn_state->best_encoder;
+
+ drm_dbg_atomic(dev, "pre-enabling bridges [ENCODER:%d:%s]\n",
+ encoder->base.id, encoder->name);
+
+ /*
+ * Each encoder has at most one connector (since we always steal
+ * it away), so we won't call enable hooks twice.
+ */
+ bridge = drm_bridge_chain_get_first_bridge(encoder);
+ drm_atomic_bridge_chain_pre_enable(bridge, old_state);
+ }
+}
+
static void
crtc_enable(struct drm_device *dev, struct drm_atomic_state *old_state)
{
@@ -1531,8 +1615,6 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *old_state
else if (funcs->commit)
funcs->commit(encoder);
}
-
- drm_atomic_bridge_chain_enable(bridge, old_state);
}
}
@@ -1555,6 +1637,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
{
crtc_enable(dev, old_state);
+ encoder_bridge_pre_enable(dev, old_state);
+
encoder_bridge_enable(dev, old_state);
drm_atomic_helper_commit_writebacks(dev, old_state);
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH v8 11/13] drm/atomic-helper: Separate out bridge pre_enable/post_disable from enable/disable
2025-01-26 19:15 ` [PATCH v8 11/13] drm/atomic-helper: Separate out bridge pre_enable/post_disable from enable/disable Aradhya Bhatia
@ 2025-01-26 21:54 ` Dmitry Baryshkov
2025-02-04 12:29 ` Jayesh Choudhary
2025-02-04 13:40 ` Tomi Valkeinen
2 siblings, 0 replies; 25+ messages in thread
From: Dmitry Baryshkov @ 2025-01-26 21:54 UTC (permalink / raw)
To: Aradhya Bhatia
Cc: Tomi Valkeinen, Laurent Pinchart, Andrzej Hajda, Neil Armstrong,
Robert Foss, Jonas Karlman, Jernej Skrabec, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List
On Mon, Jan 27, 2025 at 12:45:49AM +0530, Aradhya Bhatia wrote:
> The encoder-bridge ops occur by looping over the new connector states of
> the display pipelines. The enable sequence runs as follows -
>
> - pre_enable(bridge),
> - enable(encoder),
> - enable(bridge),
>
> while the disable sequnce runs as follows -
>
> - disable(bridge),
> - disable(encoder),
> - post_disable(bridge).
>
> Separate out the pre_enable(bridge), and the post_disable(bridge)
> operations into separate functions each.
>
> This patch keeps the sequence same for any singular disaplay pipe, but
> changes the sequence across multiple display pipelines.
>
> This patch is meant to be an interim patch, to cleanly pave the way for
> the sequence re-ordering patch, and maintain bisectability in the
> process.
>
> Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
> ---
> drivers/gpu/drm/drm_atomic_helper.c | 92 +++++++++++++++++++++++++++--
> 1 file changed, 88 insertions(+), 4 deletions(-)
>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v8 11/13] drm/atomic-helper: Separate out bridge pre_enable/post_disable from enable/disable
2025-01-26 19:15 ` [PATCH v8 11/13] drm/atomic-helper: Separate out bridge pre_enable/post_disable from enable/disable Aradhya Bhatia
2025-01-26 21:54 ` Dmitry Baryshkov
@ 2025-02-04 12:29 ` Jayesh Choudhary
2025-02-09 12:30 ` Aradhya Bhatia
2025-02-04 13:40 ` Tomi Valkeinen
2 siblings, 1 reply; 25+ messages in thread
From: Jayesh Choudhary @ 2025-02-04 12:29 UTC (permalink / raw)
To: Aradhya Bhatia, Tomi Valkeinen, Dmitry Baryshkov,
Laurent Pinchart, Andrzej Hajda, Neil Armstrong, Robert Foss,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, DRI Development List,
Linux Kernel List
Hello Aradhya,
On 27/01/25 00:45, Aradhya Bhatia wrote:
> The encoder-bridge ops occur by looping over the new connector states of
> the display pipelines. The enable sequence runs as follows -
>
> - pre_enable(bridge),
> - enable(encoder),
> - enable(bridge),
>
> while the disable sequnce runs as follows -
>
> - disable(bridge),
> - disable(encoder),
> - post_disable(bridge).
>
> Separate out the pre_enable(bridge), and the post_disable(bridge)
> operations into separate functions each.
>
> This patch keeps the sequence same for any singular disaplay pipe, but
> changes the sequence across multiple display pipelines.
>
> This patch is meant to be an interim patch, to cleanly pave the way for
> the sequence re-ordering patch, and maintain bisectability in the
> process.
>
> Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
> ---
> drivers/gpu/drm/drm_atomic_helper.c | 92 +++++++++++++++++++++++++++--
> 1 file changed, 88 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index e805fd0a54c5..f5532e3646e1 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1185,8 +1185,6 @@ encoder_bridge_disable(struct drm_device *dev, struct drm_atomic_state *old_stat
> else if (funcs->dpms)
> funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
> }
> -
> - drm_atomic_bridge_chain_post_disable(bridge, old_state);
> }
> }
>
> @@ -1243,11 +1241,65 @@ crtc_disable(struct drm_device *dev, struct drm_atomic_state *old_state)
> }
> }
>
> +static void
> +encoder_bridge_post_disable(struct drm_device *dev, struct drm_atomic_state *old_state)
> +{
> + struct drm_connector *connector;
> + struct drm_connector_state *old_conn_state, *new_conn_state;
> + struct drm_crtc_state *old_crtc_state, *new_crtc_state;
> + int i;
> +
> + for_each_oldnew_connector_in_state(old_state, connector, old_conn_state, new_conn_state, i) {
> + struct drm_encoder *encoder;
> + struct drm_bridge *bridge;
> +
> + /*
> + * Shut down everything that's in the changeset and currently
> + * still on. So need to check the old, saved state.
> + */
> + if (!old_conn_state->crtc)
> + continue;
> +
> + old_crtc_state = drm_atomic_get_old_crtc_state(old_state, old_conn_state->crtc);
> +
> + if (new_conn_state->crtc)
> + new_crtc_state = drm_atomic_get_new_crtc_state(
> + old_state,
> + new_conn_state->crtc);
> + else
> + new_crtc_state = NULL;
> +
> + if (!crtc_needs_disable(old_crtc_state, new_crtc_state) ||
> + !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state))
> + continue;
> +
> + encoder = old_conn_state->best_encoder;
> +
> + /* We shouldn't get this far if we didn't previously have
> + * an encoder.. but WARN_ON() rather than explode.
> + */
> + if (WARN_ON(!encoder))
> + continue;
> +
> + drm_dbg_atomic(dev, "post-disabling bridges [ENCODER:%d:%s]\n",
> + encoder->base.id, encoder->name);
> +
> + /*
> + * Each encoder has at most one connector (since we always steal
> + * it away), so we won't call disable hooks twice.
> + */
> + bridge = drm_bridge_chain_get_first_bridge(encoder);
> + drm_atomic_bridge_chain_post_disable(bridge, old_state);
> + }
> +}
> +
> static void
> disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
> {
> encoder_bridge_disable(dev, old_state);
>
> + encoder_bridge_post_disable(dev, old_state);
> +
> crtc_disable(dev, old_state);
> }
>
> @@ -1460,6 +1512,38 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
> }
> }
>
> +static void
> +encoder_bridge_pre_enable(struct drm_device *dev, struct drm_atomic_state *old_state)
> +{
> + struct drm_connector *connector;
> + struct drm_connector_state *new_conn_state;
> + int i;
> +
> + for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
> + struct drm_encoder *encoder;
> + struct drm_bridge *bridge;
> +
> + if (!new_conn_state->best_encoder)
> + continue;
> +
> + if (!new_conn_state->crtc->state->active ||
> + !drm_atomic_crtc_needs_modeset(new_conn_state->crtc->state))
> + continue;
> +
> + encoder = new_conn_state->best_encoder;
> +
> + drm_dbg_atomic(dev, "pre-enabling bridges [ENCODER:%d:%s]\n",
> + encoder->base.id, encoder->name);
> +
> + /*
> + * Each encoder has at most one connector (since we always steal
> + * it away), so we won't call enable hooks twice.
> + */
> + bridge = drm_bridge_chain_get_first_bridge(encoder);
> + drm_atomic_bridge_chain_pre_enable(bridge, old_state);
> + }
> +}
> +
> static void
> crtc_enable(struct drm_device *dev, struct drm_atomic_state *old_state)
> {
> @@ -1531,8 +1615,6 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *old_state
> else if (funcs->commit)
> funcs->commit(encoder);
> }
> -
> - drm_atomic_bridge_chain_enable(bridge, old_state);
> }
> }
>
> @@ -1555,6 +1637,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
> {
> crtc_enable(dev, old_state);
>
> + encoder_bridge_pre_enable(dev, old_state);
> +
> encoder_bridge_enable(dev, old_state);
>
After separating enable and pre_enable, bridge_chain_enable hook is not
called. This breaks display.
In encoder_bridge_enable call, you need to call
bridge_chain_enable call instead of bridge_chain_pre_enable.
diff --git a/drivers/gpu/drm/drm_atomic_helper.c
b/drivers/gpu/drm/drm_atomic_helper.c
index d2f19df9f418..1b580dc068bf 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1605,7 +1605,7 @@ encoder_bridge_enable(struct drm_device *dev,
struct drm_atomic_state *old_state
* it away), so we won't call enable hooks twice.
*/
bridge = drm_bridge_chain_get_first_bridge(encoder);
- drm_atomic_bridge_chain_pre_enable(bridge, old_state);
+ drm_atomic_bridge_chain_enable(bridge, old_state);
if (funcs) {
if (funcs->atomic_enable)
I have tested display on J784S4-EVM for MHDP and DSI with this diff on
top of your series.
With the above change addressed,
Reviewed-by: Jayesh Choudhary <j-choudhary@ti.com>
> drm_atomic_helper_commit_writebacks(dev, old_state);
Warm Regards,
Jayesh
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH v8 11/13] drm/atomic-helper: Separate out bridge pre_enable/post_disable from enable/disable
2025-02-04 12:29 ` Jayesh Choudhary
@ 2025-02-09 12:30 ` Aradhya Bhatia
0 siblings, 0 replies; 25+ messages in thread
From: Aradhya Bhatia @ 2025-02-09 12:30 UTC (permalink / raw)
To: Jayesh Choudhary, Tomi Valkeinen, Dmitry Baryshkov,
Laurent Pinchart, Andrzej Hajda, Neil Armstrong, Robert Foss,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, DRI Development List,
Linux Kernel List
Hi Jayesh,
Thank you for testing this out, and reporting the error I had
overlooked.
On 04/02/25 17:59, Jayesh Choudhary wrote:
> Hello Aradhya,
>
> On 27/01/25 00:45, Aradhya Bhatia wrote:
>> The encoder-bridge ops occur by looping over the new connector states of
>> the display pipelines. The enable sequence runs as follows -
>>
>> - pre_enable(bridge),
>> - enable(encoder),
>> - enable(bridge),
>>
>> while the disable sequnce runs as follows -
>>
>> - disable(bridge),
>> - disable(encoder),
>> - post_disable(bridge).
>>
>> Separate out the pre_enable(bridge), and the post_disable(bridge)
>> operations into separate functions each.
>>
>> This patch keeps the sequence same for any singular disaplay pipe, but
>> changes the sequence across multiple display pipelines.
>>
>> This patch is meant to be an interim patch, to cleanly pave the way for
>> the sequence re-ordering patch, and maintain bisectability in the
>> process.
>>
>> Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
>> ---
>> drivers/gpu/drm/drm_atomic_helper.c | 92 +++++++++++++++++++++++++++--
>> 1 file changed, 88 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/
>> drm_atomic_helper.c
>> index e805fd0a54c5..f5532e3646e1 100644
>> --- a/drivers/gpu/drm/drm_atomic_helper.c
>> +++ b/drivers/gpu/drm/drm_atomic_helper.c
>> @@ -1185,8 +1185,6 @@ encoder_bridge_disable(struct drm_device *dev,
>> struct drm_atomic_state *old_stat
>> else if (funcs->dpms)
>> funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
>> }
>> -
>> - drm_atomic_bridge_chain_post_disable(bridge, old_state);
>> }
>> }
>> @@ -1243,11 +1241,65 @@ crtc_disable(struct drm_device *dev, struct
>> drm_atomic_state *old_state)
>> }
>> }
>> +static void
>> +encoder_bridge_post_disable(struct drm_device *dev, struct
>> drm_atomic_state *old_state)
>> +{
>> + struct drm_connector *connector;
>> + struct drm_connector_state *old_conn_state, *new_conn_state;
>> + struct drm_crtc_state *old_crtc_state, *new_crtc_state;
>> + int i;
>> +
>> + for_each_oldnew_connector_in_state(old_state, connector,
>> old_conn_state, new_conn_state, i) {
>> + struct drm_encoder *encoder;
>> + struct drm_bridge *bridge;
>> +
>> + /*
>> + * Shut down everything that's in the changeset and currently
>> + * still on. So need to check the old, saved state.
>> + */
>> + if (!old_conn_state->crtc)
>> + continue;
>> +
>> + old_crtc_state = drm_atomic_get_old_crtc_state(old_state,
>> old_conn_state->crtc);
>> +
>> + if (new_conn_state->crtc)
>> + new_crtc_state = drm_atomic_get_new_crtc_state(
>> + old_state,
>> + new_conn_state->crtc);
>> + else
>> + new_crtc_state = NULL;
>> +
>> + if (!crtc_needs_disable(old_crtc_state, new_crtc_state) ||
>> + !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state))
>> + continue;
>> +
>> + encoder = old_conn_state->best_encoder;
>> +
>> + /* We shouldn't get this far if we didn't previously have
>> + * an encoder.. but WARN_ON() rather than explode.
>> + */
>> + if (WARN_ON(!encoder))
>> + continue;
>> +
>> + drm_dbg_atomic(dev, "post-disabling bridges [ENCODER:%d:%s]\n",
>> + encoder->base.id, encoder->name);
>> +
>> + /*
>> + * Each encoder has at most one connector (since we always steal
>> + * it away), so we won't call disable hooks twice.
>> + */
>> + bridge = drm_bridge_chain_get_first_bridge(encoder);
>> + drm_atomic_bridge_chain_post_disable(bridge, old_state);
>> + }
>> +}
>> +
>> static void
>> disable_outputs(struct drm_device *dev, struct drm_atomic_state
>> *old_state)
>> {
>> encoder_bridge_disable(dev, old_state);
>> + encoder_bridge_post_disable(dev, old_state);
>> +
>> crtc_disable(dev, old_state);
>> }
>> @@ -1460,6 +1512,38 @@ static void
>> drm_atomic_helper_commit_writebacks(struct drm_device *dev,
>> }
>> }
>> +static void
>> +encoder_bridge_pre_enable(struct drm_device *dev, struct
>> drm_atomic_state *old_state)
>> +{
>> + struct drm_connector *connector;
>> + struct drm_connector_state *new_conn_state;
>> + int i;
>> +
>> + for_each_new_connector_in_state(old_state, connector,
>> new_conn_state, i) {
>> + struct drm_encoder *encoder;
>> + struct drm_bridge *bridge;
>> +
>> + if (!new_conn_state->best_encoder)
>> + continue;
>> +
>> + if (!new_conn_state->crtc->state->active ||
>> + !drm_atomic_crtc_needs_modeset(new_conn_state->crtc->state))
>> + continue;
>> +
>> + encoder = new_conn_state->best_encoder;
>> +
>> + drm_dbg_atomic(dev, "pre-enabling bridges [ENCODER:%d:%s]\n",
>> + encoder->base.id, encoder->name);
>> +
>> + /*
>> + * Each encoder has at most one connector (since we always steal
>> + * it away), so we won't call enable hooks twice.
>> + */
>> + bridge = drm_bridge_chain_get_first_bridge(encoder);
>> + drm_atomic_bridge_chain_pre_enable(bridge, old_state);
>> + }
>> +}
>> +
>> static void
>> crtc_enable(struct drm_device *dev, struct drm_atomic_state *old_state)
>> {
>> @@ -1531,8 +1615,6 @@ encoder_bridge_enable(struct drm_device *dev,
>> struct drm_atomic_state *old_state
>> else if (funcs->commit)
>> funcs->commit(encoder);
>> }
>> -
>> - drm_atomic_bridge_chain_enable(bridge, old_state);
>> }
>> }
>> @@ -1555,6 +1637,8 @@ void
>> drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
>> {
>> crtc_enable(dev, old_state);
>> + encoder_bridge_pre_enable(dev, old_state);
>> +
>> encoder_bridge_enable(dev, old_state);
>>
>
> After separating enable and pre_enable, bridge_chain_enable hook is not
> called. This breaks display.
That is true.
>
> In encoder_bridge_enable call, you need to call
> bridge_chain_enable call instead of bridge_chain_pre_enable.
Yes, the encoder_bridge_enable() is supposed to call
bridge_chain_enable() instead of bridge_chain_pre_enable().
>
>
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/
> drm_atomic_helper.c
> index d2f19df9f418..1b580dc068bf 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1605,7 +1605,7 @@ encoder_bridge_enable(struct drm_device *dev,
> struct drm_atomic_state *old_state
> * it away), so we won't call enable hooks twice.
> */
> bridge = drm_bridge_chain_get_first_bridge(encoder);
> - drm_atomic_bridge_chain_pre_enable(bridge, old_state);
> + drm_atomic_bridge_chain_enable(bridge, old_state);
While your report is right, I couldn't take this diff as is. The
bridge_chain_enable has to still happen _after_ all the encoders are
enabled inside this function (unlike the bridge_chain_pre_enable that
would happen before the encoder_enable).
>
> if (funcs) {
> if (funcs->atomic_enable)
>
> I have tested display on J784S4-EVM for MHDP and DSI with this diff on
> top of your series.
>
> With the above change addressed,
>
> Reviewed-by: Jayesh Choudhary <j-choudhary@ti.com>
Thank you!
I have posted the patch[0], and I have taken the liberty to accept the
tag despite the change in the way I have fixed the error. If that is
unacceptable, please do let me know and I will remove it in a newer
revision.
--
Regards
Aradhya
[0]: [PATCH v9 11/13] drm/atomic-helper: Separate out bridge pre_enable/
post_disable from enable/disable
https://lore.kernel.org/all/20250209121621.34677-4-aradhya.bhatia@linux.dev/
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v8 11/13] drm/atomic-helper: Separate out bridge pre_enable/post_disable from enable/disable
2025-01-26 19:15 ` [PATCH v8 11/13] drm/atomic-helper: Separate out bridge pre_enable/post_disable from enable/disable Aradhya Bhatia
2025-01-26 21:54 ` Dmitry Baryshkov
2025-02-04 12:29 ` Jayesh Choudhary
@ 2025-02-04 13:40 ` Tomi Valkeinen
2 siblings, 0 replies; 25+ messages in thread
From: Tomi Valkeinen @ 2025-02-04 13:40 UTC (permalink / raw)
To: Aradhya Bhatia
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Dmitry Baryshkov,
Laurent Pinchart, Andrzej Hajda, Neil Armstrong, Robert Foss,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Hi,
On 26/01/2025 21:15, Aradhya Bhatia wrote:
> The encoder-bridge ops occur by looping over the new connector states of
> the display pipelines. The enable sequence runs as follows -
>
> - pre_enable(bridge),
> - enable(encoder),
> - enable(bridge),
>
> while the disable sequnce runs as follows -
>
> - disable(bridge),
> - disable(encoder),
> - post_disable(bridge).
>
> Separate out the pre_enable(bridge), and the post_disable(bridge)
> operations into separate functions each.
>
> This patch keeps the sequence same for any singular disaplay pipe, but
> changes the sequence across multiple display pipelines.
>
> This patch is meant to be an interim patch, to cleanly pave the way for
> the sequence re-ordering patch, and maintain bisectability in the
> process.
>
> Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
> ---
> drivers/gpu/drm/drm_atomic_helper.c | 92 +++++++++++++++++++++++++++--
> 1 file changed, 88 insertions(+), 4 deletions(-)
With the issue Jayesh pointed out fixed:
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Tomi
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v8 12/13] drm/atomic-helper: Re-order bridge chain pre-enable and post-disable
2025-01-26 19:15 [PATCH v8 00/13] drm/bridge: cdns-dsi: Fix the color-shift issue Aradhya Bhatia
` (10 preceding siblings ...)
2025-01-26 19:15 ` [PATCH v8 11/13] drm/atomic-helper: Separate out bridge pre_enable/post_disable from enable/disable Aradhya Bhatia
@ 2025-01-26 19:15 ` Aradhya Bhatia
2025-01-26 21:55 ` Dmitry Baryshkov
2025-02-04 13:41 ` Tomi Valkeinen
2025-01-26 19:15 ` [PATCH v8 13/13] drm/bridge: cdns-dsi: Use pre_enable/post_disable to enable/disable Aradhya Bhatia
12 siblings, 2 replies; 25+ messages in thread
From: Aradhya Bhatia @ 2025-01-26 19:15 UTC (permalink / raw)
To: Tomi Valkeinen, Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda,
Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Aradhya Bhatia
Move the bridge pre_enable call before crtc enable, and the bridge
post_disable call after the crtc disable.
The sequence of enable after this patch will look like:
bridge[n]_pre_enable
...
bridge[1]_pre_enable
crtc_enable
encoder_enable
bridge[1]_enable
...
bridge[n]_enable
And, the disable sequence for the display pipeline will look like:
bridge[n]_disable
...
bridge[1]_disable
encoder_disable
crtc_disable
bridge[1]_post_disable
...
bridge[n]_post_disable
The definition of bridge pre_enable hook says that,
"The display pipe (i.e. clocks and timing signals) feeding this bridge
will not yet be running when this callback is called".
Since CRTC is also a source feeding the bridge, it should not be enabled
before the bridges in the pipeline are pre_enabled. Fix that by
re-ordering the sequence of bridge pre_enable and bridge post_disable.
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
drivers/gpu/drm/drm_atomic_helper.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index f5532e3646e1..d2f19df9f418 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1298,9 +1298,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
{
encoder_bridge_disable(dev, old_state);
- encoder_bridge_post_disable(dev, old_state);
-
crtc_disable(dev, old_state);
+
+ encoder_bridge_post_disable(dev, old_state);
}
/**
@@ -1635,10 +1635,10 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *old_state
void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
struct drm_atomic_state *old_state)
{
- crtc_enable(dev, old_state);
-
encoder_bridge_pre_enable(dev, old_state);
+ crtc_enable(dev, old_state);
+
encoder_bridge_enable(dev, old_state);
drm_atomic_helper_commit_writebacks(dev, old_state);
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH v8 12/13] drm/atomic-helper: Re-order bridge chain pre-enable and post-disable
2025-01-26 19:15 ` [PATCH v8 12/13] drm/atomic-helper: Re-order bridge chain pre-enable and post-disable Aradhya Bhatia
@ 2025-01-26 21:55 ` Dmitry Baryshkov
2025-02-04 13:41 ` Tomi Valkeinen
1 sibling, 0 replies; 25+ messages in thread
From: Dmitry Baryshkov @ 2025-01-26 21:55 UTC (permalink / raw)
To: Aradhya Bhatia
Cc: Tomi Valkeinen, Laurent Pinchart, Andrzej Hajda, Neil Armstrong,
Robert Foss, Jonas Karlman, Jernej Skrabec, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List
On Mon, Jan 27, 2025 at 12:45:50AM +0530, Aradhya Bhatia wrote:
> Move the bridge pre_enable call before crtc enable, and the bridge
> post_disable call after the crtc disable.
>
> The sequence of enable after this patch will look like:
>
> bridge[n]_pre_enable
> ...
> bridge[1]_pre_enable
>
> crtc_enable
> encoder_enable
>
> bridge[1]_enable
> ...
> bridge[n]_enable
>
> And, the disable sequence for the display pipeline will look like:
>
> bridge[n]_disable
> ...
> bridge[1]_disable
>
> encoder_disable
> crtc_disable
>
> bridge[1]_post_disable
> ...
> bridge[n]_post_disable
>
> The definition of bridge pre_enable hook says that,
> "The display pipe (i.e. clocks and timing signals) feeding this bridge
> will not yet be running when this callback is called".
>
> Since CRTC is also a source feeding the bridge, it should not be enabled
> before the bridges in the pipeline are pre_enabled. Fix that by
> re-ordering the sequence of bridge pre_enable and bridge post_disable.
>
> Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
> Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
> ---
> drivers/gpu/drm/drm_atomic_helper.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
I don't feel confident enough to say that I understand all the
consequences of this change. On the other hand it sounds pretty logical,
isolated and can be tested separately.
Acked-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v8 12/13] drm/atomic-helper: Re-order bridge chain pre-enable and post-disable
2025-01-26 19:15 ` [PATCH v8 12/13] drm/atomic-helper: Re-order bridge chain pre-enable and post-disable Aradhya Bhatia
2025-01-26 21:55 ` Dmitry Baryshkov
@ 2025-02-04 13:41 ` Tomi Valkeinen
1 sibling, 0 replies; 25+ messages in thread
From: Tomi Valkeinen @ 2025-02-04 13:41 UTC (permalink / raw)
To: Aradhya Bhatia
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Dmitry Baryshkov,
Laurent Pinchart, Andrzej Hajda, Neil Armstrong, Robert Foss,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Hi,
On 26/01/2025 21:15, Aradhya Bhatia wrote:
> Move the bridge pre_enable call before crtc enable, and the bridge
> post_disable call after the crtc disable.
>
> The sequence of enable after this patch will look like:
>
> bridge[n]_pre_enable
> ...
> bridge[1]_pre_enable
>
> crtc_enable
> encoder_enable
>
> bridge[1]_enable
> ...
> bridge[n]_enable
>
> And, the disable sequence for the display pipeline will look like:
>
> bridge[n]_disable
> ...
> bridge[1]_disable
>
> encoder_disable
> crtc_disable
>
> bridge[1]_post_disable
> ...
> bridge[n]_post_disable
>
> The definition of bridge pre_enable hook says that,
> "The display pipe (i.e. clocks and timing signals) feeding this bridge
> will not yet be running when this callback is called".
>
> Since CRTC is also a source feeding the bridge, it should not be enabled
> before the bridges in the pipeline are pre_enabled. Fix that by
> re-ordering the sequence of bridge pre_enable and bridge post_disable.
>
> Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
> Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
> ---
> drivers/gpu/drm/drm_atomic_helper.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index f5532e3646e1..d2f19df9f418 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1298,9 +1298,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
> {
> encoder_bridge_disable(dev, old_state);
>
> - encoder_bridge_post_disable(dev, old_state);
> -
> crtc_disable(dev, old_state);
> +
> + encoder_bridge_post_disable(dev, old_state);
> }
>
> /**
> @@ -1635,10 +1635,10 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *old_state
> void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
> struct drm_atomic_state *old_state)
> {
> - crtc_enable(dev, old_state);
> -
> encoder_bridge_pre_enable(dev, old_state);
>
> + crtc_enable(dev, old_state);
> +
> encoder_bridge_enable(dev, old_state);
>
> drm_atomic_helper_commit_writebacks(dev, old_state);
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Tomi
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v8 13/13] drm/bridge: cdns-dsi: Use pre_enable/post_disable to enable/disable
2025-01-26 19:15 [PATCH v8 00/13] drm/bridge: cdns-dsi: Fix the color-shift issue Aradhya Bhatia
` (11 preceding siblings ...)
2025-01-26 19:15 ` [PATCH v8 12/13] drm/atomic-helper: Re-order bridge chain pre-enable and post-disable Aradhya Bhatia
@ 2025-01-26 19:15 ` Aradhya Bhatia
12 siblings, 0 replies; 25+ messages in thread
From: Aradhya Bhatia @ 2025-01-26 19:15 UTC (permalink / raw)
To: Tomi Valkeinen, Dmitry Baryshkov, Laurent Pinchart, Andrzej Hajda,
Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Praneeth Bajjuri, Udit Kumar, Jayesh Choudhary,
DRI Development List, Linux Kernel List, Aradhya Bhatia
From: Aradhya Bhatia <a-bhatia1@ti.com>
The cdns-dsi controller requires that it be turned on completely before
the input DPI's source has begun streaming[0]. Not having that, allows
for a small window before cdns-dsi enable and after cdns-dsi disable
where the previous entity (in this case tidss's videoport) to continue
streaming DPI video signals. This small window where cdns-dsi is
disabled but is still receiving signals causes the input FIFO of
cdns-dsi to get corrupted. This causes the colors to shift on the output
display. The colors can either shift by one color component (R->G, G->B,
B->R), or by two color components (R->B, G->R, B->G).
Since tidss's videoport starts streaming via crtc enable hooks, we need
cdns-dsi to be up and running before that. Now that the bridges are
pre_enabled before crtc is enabled, and post_disabled after crtc is
disabled, use the pre_enable and post_disable hooks to get cdns-dsi
ready and running before the tidss videoport to get pass the color shift
issues.
[0]: See section 12.6.5.7.3 "Start-up Procedure" in J721E SoC TRM
TRM Link: http://www.ti.com/lit/pdf/spruil1
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
.../gpu/drm/bridge/cadence/cdns-dsi-core.c | 64 ++++++++++---------
1 file changed, 35 insertions(+), 29 deletions(-)
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index 12457f712c94..4fb4e5bd17f0 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -669,13 +669,28 @@ cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge,
return MODE_OK;
}
-static void cdns_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+static void cdns_dsi_bridge_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
u32 val;
+ /*
+ * The cdns-dsi controller needs to be disabled after it's DPI source
+ * has stopped streaming. If this is not followed, there is a brief
+ * window before DPI source is disabled and after cdns-dsi controller
+ * has been disabled where the DPI stream is still on, but the cdns-dsi
+ * controller is not ready anymore to accept the incoming signals. This
+ * is one of the reasons why a shift in pixel colors is observed on
+ * displays that have cdns-dsi as one of the bridges.
+ *
+ * To mitigate this, disable this bridge from the bridge post_disable()
+ * hook, instead of the bridge _disable() hook. The bridge post_disable()
+ * hook gets called after the CRTC disable, where often many DPI sources
+ * disable their streams.
+ */
+
val = readl(dsi->regs + MCTL_MAIN_DATA_CTL);
val &= ~(IF_VID_SELECT_MASK | IF_VID_MODE | VID_EN | HOST_EOT_GEN |
DISP_EOT_GEN);
@@ -687,15 +702,6 @@ static void cdns_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
if (dsi->platform_ops && dsi->platform_ops->disable)
dsi->platform_ops->disable(dsi);
- pm_runtime_put(dsi->base.dev);
-}
-
-static void cdns_dsi_bridge_atomic_post_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
-{
- struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
- struct cdns_dsi *dsi = input_to_dsi(input);
-
dsi->phy_initialized = false;
dsi->link_initialized = false;
phy_power_off(dsi->dphy);
@@ -773,8 +779,8 @@ static void cdns_dsi_init_link(struct cdns_dsi *dsi)
dsi->link_initialized = true;
}
-static void cdns_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+static void cdns_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
@@ -789,6 +795,21 @@ static void cdns_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
u32 tmp, reg_wakeup, div, status;
int nlanes;
+ /*
+ * The cdns-dsi controller needs to be enabled before it's DPI source
+ * has begun streaming. If this is not followed, there is a brief window
+ * after DPI source enable and before cdns-dsi controller enable where
+ * the DPI stream is on, but the cdns-dsi controller is not ready to
+ * accept the incoming signals. This is one of the reasons why a shift
+ * in pixel colors is observed on displays that have cdns-dsi as one of
+ * the bridges.
+ *
+ * To mitigate this, enable this bridge from the bridge pre_enable()
+ * hook, instead of the bridge _enable() hook. The bridge pre_enable()
+ * hook gets called before the CRTC enable, where often many DPI sources
+ * enable their streams.
+ */
+
if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0))
return;
@@ -805,8 +826,8 @@ static void cdns_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
mode = &bridge->encoder->crtc->state->adjusted_mode;
nlanes = output->dev->lanes;
- cdns_dsi_hs_init(dsi);
cdns_dsi_init_link(dsi);
+ cdns_dsi_hs_init(dsi);
/*
* Now that the DSI Link and DSI Phy are initialized,
@@ -935,19 +956,6 @@ static void cdns_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
writel(tmp, dsi->regs + MCTL_MAIN_EN);
}
-static void cdns_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
-{
- struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
- struct cdns_dsi *dsi = input_to_dsi(input);
-
- if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0))
- return;
-
- cdns_dsi_init_link(dsi);
- cdns_dsi_hs_init(dsi);
-}
-
static u32 *cdns_dsi_bridge_get_input_bus_fmts(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
@@ -1042,9 +1050,7 @@ cdns_dsi_bridge_atomic_reset(struct drm_bridge *bridge)
static const struct drm_bridge_funcs cdns_dsi_bridge_funcs = {
.attach = cdns_dsi_bridge_attach,
.mode_valid = cdns_dsi_bridge_mode_valid,
- .atomic_disable = cdns_dsi_bridge_atomic_disable,
.atomic_pre_enable = cdns_dsi_bridge_atomic_pre_enable,
- .atomic_enable = cdns_dsi_bridge_atomic_enable,
.atomic_post_disable = cdns_dsi_bridge_atomic_post_disable,
.atomic_check = cdns_dsi_bridge_atomic_check,
.atomic_duplicate_state = cdns_dsi_bridge_atomic_duplicate_state,
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread