linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] drm/bridge: nwl-dsi: Get MIPI DSI controller and PHY ready in ->mode_set()
@ 2021-04-22  5:14 Liu Ying
  2021-04-22  8:48 ` Neil Armstrong
  0 siblings, 1 reply; 5+ messages in thread
From: Liu Ying @ 2021-04-22  5:14 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-kernel, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
	Daniel Vetter, Guido Günther, Robert Chiras, NXP Linux Team

Some MIPI DSI panel drivers like 'raydium,rm68200' send
MIPI_DCS_SET_DISPLAY_ON commands in panel_funcs->prepare(), which
requires the MIPI DSI controller and PHY to be ready beforehand.
Without this patch, the nwl-dsi driver gets the MIPI DSI controller
and PHY ready in bridge_funcs->pre_enable(), which happens after
the panel_funcs->prepare(). So, this patch shifts the bridge operation
ealier from bridge_funcs->pre_enable() to bridge_funcs->mode_set().
This way, more MIPI DSI panels can connect to this nwl-dsi bridge.
Care is taken to make sure bridge_funcs->mode_set()/atomic_disable()
are called in pairs, which includes removing a check on unchanged HS
clock rate and forcing a full modeset when only connector's DPMS is
brought out of "Off" status.

Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Neil Armstrong <narmstrong@baylibre.com>
Cc: Robert Foss <robert.foss@linaro.org>
Cc: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
Cc: Jonas Karlman <jonas@kwiboo.se>
Cc: Jernej Skrabec <jernej.skrabec@siol.net>
Cc: David Airlie <airlied@linux.ie>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Guido Günther <agx@sigxcpu.org>
Cc: Robert Chiras <robert.chiras@nxp.com>
Cc: NXP Linux Team <linux-imx@nxp.com>
Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
v1->v2:
* Fix commit message typo - s/unchange/unchanged/

 drivers/gpu/drm/bridge/nwl-dsi.c | 86 +++++++++++++++++++++-------------------
 1 file changed, 46 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c
index be6bfc5..229f0b1 100644
--- a/drivers/gpu/drm/bridge/nwl-dsi.c
+++ b/drivers/gpu/drm/bridge/nwl-dsi.c
@@ -21,6 +21,7 @@
 #include <linux/sys_soc.h>
 #include <linux/time64.h>
 
+#include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
@@ -661,7 +662,7 @@ static irqreturn_t nwl_dsi_irq_handler(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int nwl_dsi_enable(struct nwl_dsi *dsi)
+static int nwl_dsi_mode_set(struct nwl_dsi *dsi)
 {
 	struct device *dev = dsi->dev;
 	union phy_configure_opts *phy_cfg = &dsi->phy_cfg;
@@ -748,7 +749,9 @@ static int nwl_dsi_disable(struct nwl_dsi *dsi)
 	return 0;
 }
 
-static void nwl_dsi_bridge_disable(struct drm_bridge *bridge)
+static void
+nwl_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
+			      struct drm_bridge_state *old_bridge_state)
 {
 	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
 	int ret;
@@ -809,17 +812,6 @@ static int nwl_dsi_get_dphy_params(struct nwl_dsi *dsi,
 	return 0;
 }
 
-static bool nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
-				      const struct drm_display_mode *mode,
-				      struct drm_display_mode *adjusted_mode)
-{
-	/* At least LCDIF + NWL needs active high sync */
-	adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
-	adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
-
-	return true;
-}
-
 static enum drm_mode_status
 nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge,
 			  const struct drm_display_info *info,
@@ -837,6 +829,29 @@ nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge,
 	return MODE_OK;
 }
 
+static int nwl_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 drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+
+	/* At least LCDIF + NWL needs active high sync */
+	adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
+	adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
+
+	/*
+	 * Do a full modeset if crtc_state->active is changed to be true.
+	 * This ensures our ->mode_set() is called to get the DSI controller
+	 * and the PHY ready to send DCS commands, when only the connector's
+	 * DPMS is brought out of "Off" status.
+	 */
+	if (crtc_state->active_changed && crtc_state->active)
+		crtc_state->mode_changed = true;
+
+	return 0;
+}
+
 static void
 nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
 			const struct drm_display_mode *mode,
@@ -852,13 +867,6 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
 	if (ret < 0)
 		return;
 
-	/*
-	 * If hs clock is unchanged, we're all good - all parameters are
-	 * derived from it atm.
-	 */
-	if (new_cfg.mipi_dphy.hs_clk_rate == dsi->phy_cfg.mipi_dphy.hs_clk_rate)
-		return;
-
 	phy_ref_rate = clk_get_rate(dsi->phy_ref_clk);
 	DRM_DEV_DEBUG_DRIVER(dev, "PHY at ref rate: %lu\n", phy_ref_rate);
 	/* Save the new desired phy config */
@@ -866,14 +874,8 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
 
 	memcpy(&dsi->mode, adjusted_mode, sizeof(dsi->mode));
 	drm_mode_debug_printmodeline(adjusted_mode);
-}
 
-static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge)
-{
-	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
-	int ret;
-
-	pm_runtime_get_sync(dsi->dev);
+	pm_runtime_get_sync(dev);
 
 	if (clk_prepare_enable(dsi->lcdif_clk) < 0)
 		return;
@@ -883,27 +885,29 @@ static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge)
 	/* Step 1 from DSI reset-out instructions */
 	ret = reset_control_deassert(dsi->rst_pclk);
 	if (ret < 0) {
-		DRM_DEV_ERROR(dsi->dev, "Failed to deassert PCLK: %d\n", ret);
+		DRM_DEV_ERROR(dev, "Failed to deassert PCLK: %d\n", ret);
 		return;
 	}
 
 	/* Step 2 from DSI reset-out instructions */
-	nwl_dsi_enable(dsi);
+	nwl_dsi_mode_set(dsi);
 
 	/* Step 3 from DSI reset-out instructions */
 	ret = reset_control_deassert(dsi->rst_esc);
 	if (ret < 0) {
-		DRM_DEV_ERROR(dsi->dev, "Failed to deassert ESC: %d\n", ret);
+		DRM_DEV_ERROR(dev, "Failed to deassert ESC: %d\n", ret);
 		return;
 	}
 	ret = reset_control_deassert(dsi->rst_byte);
 	if (ret < 0) {
-		DRM_DEV_ERROR(dsi->dev, "Failed to deassert BYTE: %d\n", ret);
+		DRM_DEV_ERROR(dev, "Failed to deassert BYTE: %d\n", ret);
 		return;
 	}
 }
 
-static void nwl_dsi_bridge_enable(struct drm_bridge *bridge)
+static void
+nwl_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
+			     struct drm_bridge_state *old_bridge_state)
 {
 	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
 	int ret;
@@ -948,14 +952,16 @@ static void nwl_dsi_bridge_detach(struct drm_bridge *bridge)
 }
 
 static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = {
-	.pre_enable = nwl_dsi_bridge_pre_enable,
-	.enable     = nwl_dsi_bridge_enable,
-	.disable    = nwl_dsi_bridge_disable,
-	.mode_fixup = nwl_dsi_bridge_mode_fixup,
-	.mode_set   = nwl_dsi_bridge_mode_set,
-	.mode_valid = nwl_dsi_bridge_mode_valid,
-	.attach	    = nwl_dsi_bridge_attach,
-	.detach	    = nwl_dsi_bridge_detach,
+	.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		= nwl_dsi_bridge_atomic_check,
+	.atomic_enable		= nwl_dsi_bridge_atomic_enable,
+	.atomic_disable		= nwl_dsi_bridge_atomic_disable,
+	.mode_set		= nwl_dsi_bridge_mode_set,
+	.mode_valid		= nwl_dsi_bridge_mode_valid,
+	.attach			= nwl_dsi_bridge_attach,
+	.detach			= nwl_dsi_bridge_detach,
 };
 
 static int nwl_dsi_parse_dt(struct nwl_dsi *dsi)
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v2] drm/bridge: nwl-dsi: Get MIPI DSI controller and PHY ready in ->mode_set()
  2021-04-22  5:14 [PATCH v2] drm/bridge: nwl-dsi: Get MIPI DSI controller and PHY ready in ->mode_set() Liu Ying
@ 2021-04-22  8:48 ` Neil Armstrong
  2021-04-22  9:31   ` Liu Ying
  0 siblings, 1 reply; 5+ messages in thread
From: Neil Armstrong @ 2021-04-22  8:48 UTC (permalink / raw)
  To: Liu Ying, dri-devel
  Cc: linux-kernel, Andrzej Hajda, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, David Airlie, Daniel Vetter,
	Guido Günther, Robert Chiras, NXP Linux Team

Hi,

On 22/04/2021 07:14, Liu Ying wrote:
> Some MIPI DSI panel drivers like 'raydium,rm68200' send
> MIPI_DCS_SET_DISPLAY_ON commands in panel_funcs->prepare(), which
> requires the MIPI DSI controller and PHY to be ready beforehand.
> Without this patch, the nwl-dsi driver gets the MIPI DSI controller
> and PHY ready in bridge_funcs->pre_enable(), which happens after
> the panel_funcs->prepare(). So, this patch shifts the bridge operation
> ealier from bridge_funcs->pre_enable() to bridge_funcs->mode_set().

This makes sense, this is how we do on the synopsys dw mipi dsi driver.

> This way, more MIPI DSI panels can connect to this nwl-dsi bridge.
> Care is taken to make sure bridge_funcs->mode_set()/atomic_disable()
> are called in pairs, which includes removing a check on unchanged HS
> clock rate and forcing a full modeset when only connector's DPMS is
> brought out of "Off" status.

I would split the changes in multiple patches to clarify the changes.

Neil

> 
> Cc: Andrzej Hajda <a.hajda@samsung.com>
> Cc: Neil Armstrong <narmstrong@baylibre.com>
> Cc: Robert Foss <robert.foss@linaro.org>
> Cc: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
> Cc: Jonas Karlman <jonas@kwiboo.se>
> Cc: Jernej Skrabec <jernej.skrabec@siol.net>
> Cc: David Airlie <airlied@linux.ie>
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Cc: Guido Günther <agx@sigxcpu.org>
> Cc: Robert Chiras <robert.chiras@nxp.com>
> Cc: NXP Linux Team <linux-imx@nxp.com>
> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> ---
> v1->v2:
> * Fix commit message typo - s/unchange/unchanged/
> 
>  drivers/gpu/drm/bridge/nwl-dsi.c | 86 +++++++++++++++++++++-------------------
>  1 file changed, 46 insertions(+), 40 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c
> index be6bfc5..229f0b1 100644
> --- a/drivers/gpu/drm/bridge/nwl-dsi.c
> +++ b/drivers/gpu/drm/bridge/nwl-dsi.c
> @@ -21,6 +21,7 @@
>  #include <linux/sys_soc.h>
>  #include <linux/time64.h>
>  
> +#include <drm/drm_atomic_state_helper.h>
>  #include <drm/drm_bridge.h>
>  #include <drm/drm_mipi_dsi.h>
>  #include <drm/drm_of.h>
> @@ -661,7 +662,7 @@ static irqreturn_t nwl_dsi_irq_handler(int irq, void *data)
>  	return IRQ_HANDLED;
>  }
>  
> -static int nwl_dsi_enable(struct nwl_dsi *dsi)
> +static int nwl_dsi_mode_set(struct nwl_dsi *dsi)
>  {
>  	struct device *dev = dsi->dev;
>  	union phy_configure_opts *phy_cfg = &dsi->phy_cfg;
> @@ -748,7 +749,9 @@ static int nwl_dsi_disable(struct nwl_dsi *dsi)
>  	return 0;
>  }
>  
> -static void nwl_dsi_bridge_disable(struct drm_bridge *bridge)
> +static void
> +nwl_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> +			      struct drm_bridge_state *old_bridge_state)
>  {
>  	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
>  	int ret;
> @@ -809,17 +812,6 @@ static int nwl_dsi_get_dphy_params(struct nwl_dsi *dsi,
>  	return 0;
>  }
>  
> -static bool nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
> -				      const struct drm_display_mode *mode,
> -				      struct drm_display_mode *adjusted_mode)
> -{
> -	/* At least LCDIF + NWL needs active high sync */
> -	adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
> -	adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
> -
> -	return true;
> -}
> -
>  static enum drm_mode_status
>  nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge,
>  			  const struct drm_display_info *info,
> @@ -837,6 +829,29 @@ nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge,
>  	return MODE_OK;
>  }
>  
> +static int nwl_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 drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
> +
> +	/* At least LCDIF + NWL needs active high sync */
> +	adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
> +	adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
> +
> +	/*
> +	 * Do a full modeset if crtc_state->active is changed to be true.
> +	 * This ensures our ->mode_set() is called to get the DSI controller
> +	 * and the PHY ready to send DCS commands, when only the connector's
> +	 * DPMS is brought out of "Off" status.
> +	 */
> +	if (crtc_state->active_changed && crtc_state->active)
> +		crtc_state->mode_changed = true;
> +
> +	return 0;
> +}
> +
>  static void
>  nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
>  			const struct drm_display_mode *mode,
> @@ -852,13 +867,6 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
>  	if (ret < 0)
>  		return;
>  
> -	/*
> -	 * If hs clock is unchanged, we're all good - all parameters are
> -	 * derived from it atm.
> -	 */
> -	if (new_cfg.mipi_dphy.hs_clk_rate == dsi->phy_cfg.mipi_dphy.hs_clk_rate)
> -		return;
> -
>  	phy_ref_rate = clk_get_rate(dsi->phy_ref_clk);
>  	DRM_DEV_DEBUG_DRIVER(dev, "PHY at ref rate: %lu\n", phy_ref_rate);
>  	/* Save the new desired phy config */
> @@ -866,14 +874,8 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
>  
>  	memcpy(&dsi->mode, adjusted_mode, sizeof(dsi->mode));
>  	drm_mode_debug_printmodeline(adjusted_mode);
> -}
>  
> -static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge)
> -{
> -	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
> -	int ret;
> -
> -	pm_runtime_get_sync(dsi->dev);
> +	pm_runtime_get_sync(dev);
>  
>  	if (clk_prepare_enable(dsi->lcdif_clk) < 0)
>  		return;
> @@ -883,27 +885,29 @@ static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge)
>  	/* Step 1 from DSI reset-out instructions */
>  	ret = reset_control_deassert(dsi->rst_pclk);
>  	if (ret < 0) {
> -		DRM_DEV_ERROR(dsi->dev, "Failed to deassert PCLK: %d\n", ret);
> +		DRM_DEV_ERROR(dev, "Failed to deassert PCLK: %d\n", ret);
>  		return;
>  	}
>  
>  	/* Step 2 from DSI reset-out instructions */
> -	nwl_dsi_enable(dsi);
> +	nwl_dsi_mode_set(dsi);
>  
>  	/* Step 3 from DSI reset-out instructions */
>  	ret = reset_control_deassert(dsi->rst_esc);
>  	if (ret < 0) {
> -		DRM_DEV_ERROR(dsi->dev, "Failed to deassert ESC: %d\n", ret);
> +		DRM_DEV_ERROR(dev, "Failed to deassert ESC: %d\n", ret);
>  		return;
>  	}
>  	ret = reset_control_deassert(dsi->rst_byte);
>  	if (ret < 0) {
> -		DRM_DEV_ERROR(dsi->dev, "Failed to deassert BYTE: %d\n", ret);
> +		DRM_DEV_ERROR(dev, "Failed to deassert BYTE: %d\n", ret);
>  		return;
>  	}
>  }
>  
> -static void nwl_dsi_bridge_enable(struct drm_bridge *bridge)
> +static void
> +nwl_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> +			     struct drm_bridge_state *old_bridge_state)
>  {
>  	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
>  	int ret;
> @@ -948,14 +952,16 @@ static void nwl_dsi_bridge_detach(struct drm_bridge *bridge)
>  }
>  
>  static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = {
> -	.pre_enable = nwl_dsi_bridge_pre_enable,
> -	.enable     = nwl_dsi_bridge_enable,
> -	.disable    = nwl_dsi_bridge_disable,
> -	.mode_fixup = nwl_dsi_bridge_mode_fixup,
> -	.mode_set   = nwl_dsi_bridge_mode_set,
> -	.mode_valid = nwl_dsi_bridge_mode_valid,
> -	.attach	    = nwl_dsi_bridge_attach,
> -	.detach	    = nwl_dsi_bridge_detach,
> +	.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		= nwl_dsi_bridge_atomic_check,
> +	.atomic_enable		= nwl_dsi_bridge_atomic_enable,
> +	.atomic_disable		= nwl_dsi_bridge_atomic_disable,
> +	.mode_set		= nwl_dsi_bridge_mode_set,
> +	.mode_valid		= nwl_dsi_bridge_mode_valid,
> +	.attach			= nwl_dsi_bridge_attach,
> +	.detach			= nwl_dsi_bridge_detach,
>  };
>  
>  static int nwl_dsi_parse_dt(struct nwl_dsi *dsi)
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2] drm/bridge: nwl-dsi: Get MIPI DSI controller and PHY ready in ->mode_set()
  2021-04-22  8:48 ` Neil Armstrong
@ 2021-04-22  9:31   ` Liu Ying
  2021-04-22 12:07     ` Neil Armstrong
  0 siblings, 1 reply; 5+ messages in thread
From: Liu Ying @ 2021-04-22  9:31 UTC (permalink / raw)
  To: Neil Armstrong, dri-devel
  Cc: linux-kernel, Andrzej Hajda, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, David Airlie, Daniel Vetter,
	Guido Günther, Robert Chiras, NXP Linux Team

Hi Neil,

On Thu, 2021-04-22 at 10:48 +0200, Neil Armstrong wrote:
> Hi,
> 
> On 22/04/2021 07:14, Liu Ying wrote:
> > Some MIPI DSI panel drivers like 'raydium,rm68200' send
> > MIPI_DCS_SET_DISPLAY_ON commands in panel_funcs->prepare(), which
> > requires the MIPI DSI controller and PHY to be ready beforehand.
> > Without this patch, the nwl-dsi driver gets the MIPI DSI controller
> > and PHY ready in bridge_funcs->pre_enable(), which happens after
> > the panel_funcs->prepare(). So, this patch shifts the bridge operation
> > ealier from bridge_funcs->pre_enable() to bridge_funcs->mode_set().
> 
> This makes sense, this is how we do on the synopsys dw mipi dsi driver.
> 
> > This way, more MIPI DSI panels can connect to this nwl-dsi bridge.
> > Care is taken to make sure bridge_funcs->mode_set()/atomic_disable()
> > are called in pairs, which includes removing a check on unchanged HS
> > clock rate and forcing a full modeset when only connector's DPMS is
> > brought out of "Off" status.
> 
> I would split the changes in multiple patches to clarify the changes.

Maybe, I can split this into the below 3 patches:
1) Remove a check on unchanged HS clock rate from ->mode_set().
2) Force a full modeset when only connector's DPMS is brought out of
"Off" status. This will be done in ->atomic_check() together with the
fixup for H/VSYNC polarities.
3) Shift the bridge operation as the last step.

I'll mention that 1) & 2) are needed by 3) in their commit message.

Does this split-up sound reasonable?

Thanks,
Liu Ying

> 
> Neil
> 
> > Cc: Andrzej Hajda <a.hajda@samsung.com>
> > Cc: Neil Armstrong <narmstrong@baylibre.com>
> > Cc: Robert Foss <robert.foss@linaro.org>
> > Cc: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
> > Cc: Jonas Karlman <jonas@kwiboo.se>
> > Cc: Jernej Skrabec <jernej.skrabec@siol.net>
> > Cc: David Airlie <airlied@linux.ie>
> > Cc: Daniel Vetter <daniel@ffwll.ch>
> > Cc: Guido Günther <agx@sigxcpu.org>
> > Cc: Robert Chiras <robert.chiras@nxp.com>
> > Cc: NXP Linux Team <linux-imx@nxp.com>
> > Signed-off-by: Liu Ying <victor.liu@nxp.com>
> > ---
> > v1->v2:
> > * Fix commit message typo - s/unchange/unchanged/
> > 
> >  drivers/gpu/drm/bridge/nwl-dsi.c | 86 +++++++++++++++++++++-------------------
> >  1 file changed, 46 insertions(+), 40 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c
> > index be6bfc5..229f0b1 100644
> > --- a/drivers/gpu/drm/bridge/nwl-dsi.c
> > +++ b/drivers/gpu/drm/bridge/nwl-dsi.c
> > @@ -21,6 +21,7 @@
> >  #include <linux/sys_soc.h>
> >  #include <linux/time64.h>
> >  
> > +#include <drm/drm_atomic_state_helper.h>
> >  #include <drm/drm_bridge.h>
> >  #include <drm/drm_mipi_dsi.h>
> >  #include <drm/drm_of.h>
> > @@ -661,7 +662,7 @@ static irqreturn_t nwl_dsi_irq_handler(int irq, void *data)
> >  	return IRQ_HANDLED;
> >  }
> >  
> > -static int nwl_dsi_enable(struct nwl_dsi *dsi)
> > +static int nwl_dsi_mode_set(struct nwl_dsi *dsi)
> >  {
> >  	struct device *dev = dsi->dev;
> >  	union phy_configure_opts *phy_cfg = &dsi->phy_cfg;
> > @@ -748,7 +749,9 @@ static int nwl_dsi_disable(struct nwl_dsi *dsi)
> >  	return 0;
> >  }
> >  
> > -static void nwl_dsi_bridge_disable(struct drm_bridge *bridge)
> > +static void
> > +nwl_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > +			      struct drm_bridge_state *old_bridge_state)
> >  {
> >  	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
> >  	int ret;
> > @@ -809,17 +812,6 @@ static int nwl_dsi_get_dphy_params(struct nwl_dsi *dsi,
> >  	return 0;
> >  }
> >  
> > -static bool nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
> > -				      const struct drm_display_mode *mode,
> > -				      struct drm_display_mode *adjusted_mode)
> > -{
> > -	/* At least LCDIF + NWL needs active high sync */
> > -	adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
> > -	adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
> > -
> > -	return true;
> > -}
> > -
> >  static enum drm_mode_status
> >  nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge,
> >  			  const struct drm_display_info *info,
> > @@ -837,6 +829,29 @@ nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge,
> >  	return MODE_OK;
> >  }
> >  
> > +static int nwl_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 drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
> > +
> > +	/* At least LCDIF + NWL needs active high sync */
> > +	adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
> > +	adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
> > +
> > +	/*
> > +	 * Do a full modeset if crtc_state->active is changed to be true.
> > +	 * This ensures our ->mode_set() is called to get the DSI controller
> > +	 * and the PHY ready to send DCS commands, when only the connector's
> > +	 * DPMS is brought out of "Off" status.
> > +	 */
> > +	if (crtc_state->active_changed && crtc_state->active)
> > +		crtc_state->mode_changed = true;
> > +
> > +	return 0;
> > +}
> > +
> >  static void
> >  nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
> >  			const struct drm_display_mode *mode,
> > @@ -852,13 +867,6 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
> >  	if (ret < 0)
> >  		return;
> >  
> > -	/*
> > -	 * If hs clock is unchanged, we're all good - all parameters are
> > -	 * derived from it atm.
> > -	 */
> > -	if (new_cfg.mipi_dphy.hs_clk_rate == dsi->phy_cfg.mipi_dphy.hs_clk_rate)
> > -		return;
> > -
> >  	phy_ref_rate = clk_get_rate(dsi->phy_ref_clk);
> >  	DRM_DEV_DEBUG_DRIVER(dev, "PHY at ref rate: %lu\n", phy_ref_rate);
> >  	/* Save the new desired phy config */
> > @@ -866,14 +874,8 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
> >  
> >  	memcpy(&dsi->mode, adjusted_mode, sizeof(dsi->mode));
> >  	drm_mode_debug_printmodeline(adjusted_mode);
> > -}
> >  
> > -static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge)
> > -{
> > -	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
> > -	int ret;
> > -
> > -	pm_runtime_get_sync(dsi->dev);
> > +	pm_runtime_get_sync(dev);
> >  
> >  	if (clk_prepare_enable(dsi->lcdif_clk) < 0)
> >  		return;
> > @@ -883,27 +885,29 @@ static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge)
> >  	/* Step 1 from DSI reset-out instructions */
> >  	ret = reset_control_deassert(dsi->rst_pclk);
> >  	if (ret < 0) {
> > -		DRM_DEV_ERROR(dsi->dev, "Failed to deassert PCLK: %d\n", ret);
> > +		DRM_DEV_ERROR(dev, "Failed to deassert PCLK: %d\n", ret);
> >  		return;
> >  	}
> >  
> >  	/* Step 2 from DSI reset-out instructions */
> > -	nwl_dsi_enable(dsi);
> > +	nwl_dsi_mode_set(dsi);
> >  
> >  	/* Step 3 from DSI reset-out instructions */
> >  	ret = reset_control_deassert(dsi->rst_esc);
> >  	if (ret < 0) {
> > -		DRM_DEV_ERROR(dsi->dev, "Failed to deassert ESC: %d\n", ret);
> > +		DRM_DEV_ERROR(dev, "Failed to deassert ESC: %d\n", ret);
> >  		return;
> >  	}
> >  	ret = reset_control_deassert(dsi->rst_byte);
> >  	if (ret < 0) {
> > -		DRM_DEV_ERROR(dsi->dev, "Failed to deassert BYTE: %d\n", ret);
> > +		DRM_DEV_ERROR(dev, "Failed to deassert BYTE: %d\n", ret);
> >  		return;
> >  	}
> >  }
> >  
> > -static void nwl_dsi_bridge_enable(struct drm_bridge *bridge)
> > +static void
> > +nwl_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > +			     struct drm_bridge_state *old_bridge_state)
> >  {
> >  	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
> >  	int ret;
> > @@ -948,14 +952,16 @@ static void nwl_dsi_bridge_detach(struct drm_bridge *bridge)
> >  }
> >  
> >  static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = {
> > -	.pre_enable = nwl_dsi_bridge_pre_enable,
> > -	.enable     = nwl_dsi_bridge_enable,
> > -	.disable    = nwl_dsi_bridge_disable,
> > -	.mode_fixup = nwl_dsi_bridge_mode_fixup,
> > -	.mode_set   = nwl_dsi_bridge_mode_set,
> > -	.mode_valid = nwl_dsi_bridge_mode_valid,
> > -	.attach	    = nwl_dsi_bridge_attach,
> > -	.detach	    = nwl_dsi_bridge_detach,
> > +	.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		= nwl_dsi_bridge_atomic_check,
> > +	.atomic_enable		= nwl_dsi_bridge_atomic_enable,
> > +	.atomic_disable		= nwl_dsi_bridge_atomic_disable,
> > +	.mode_set		= nwl_dsi_bridge_mode_set,
> > +	.mode_valid		= nwl_dsi_bridge_mode_valid,
> > +	.attach			= nwl_dsi_bridge_attach,
> > +	.detach			= nwl_dsi_bridge_detach,
> >  };
> >  
> >  static int nwl_dsi_parse_dt(struct nwl_dsi *dsi)
> > 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2] drm/bridge: nwl-dsi: Get MIPI DSI controller and PHY ready in ->mode_set()
  2021-04-22  9:31   ` Liu Ying
@ 2021-04-22 12:07     ` Neil Armstrong
  2021-04-23  9:47       ` Liu Ying
  0 siblings, 1 reply; 5+ messages in thread
From: Neil Armstrong @ 2021-04-22 12:07 UTC (permalink / raw)
  To: Liu Ying, dri-devel
  Cc: linux-kernel, Andrzej Hajda, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, David Airlie, Daniel Vetter,
	Guido Günther, Robert Chiras, NXP Linux Team

Hi,

On 22/04/2021 11:31, Liu Ying wrote:
> Hi Neil,
> 
> On Thu, 2021-04-22 at 10:48 +0200, Neil Armstrong wrote:
>> Hi,
>>
>> On 22/04/2021 07:14, Liu Ying wrote:
>>> Some MIPI DSI panel drivers like 'raydium,rm68200' send
>>> MIPI_DCS_SET_DISPLAY_ON commands in panel_funcs->prepare(), which
>>> requires the MIPI DSI controller and PHY to be ready beforehand.
>>> Without this patch, the nwl-dsi driver gets the MIPI DSI controller
>>> and PHY ready in bridge_funcs->pre_enable(), which happens after
>>> the panel_funcs->prepare(). So, this patch shifts the bridge operation
>>> ealier from bridge_funcs->pre_enable() to bridge_funcs->mode_set().
>>
>> This makes sense, this is how we do on the synopsys dw mipi dsi driver.
>>
>>> This way, more MIPI DSI panels can connect to this nwl-dsi bridge.
>>> Care is taken to make sure bridge_funcs->mode_set()/atomic_disable()
>>> are called in pairs, which includes removing a check on unchanged HS
>>> clock rate and forcing a full modeset when only connector's DPMS is
>>> brought out of "Off" status.
>>
>> I would split the changes in multiple patches to clarify the changes.
> 
> Maybe, I can split this into the below 3 patches:
> 1) Remove a check on unchanged HS clock rate from ->mode_set().
> 2) Force a full modeset when only connector's DPMS is brought out of
> "Off" status. This will be done in ->atomic_check() together with the
> fixup for H/VSYNC polarities.
> 3) Shift the bridge operation as the last step.
> 
> I'll mention that 1) & 2) are needed by 3) in their commit message.

Sure, you can also put this split explanation in the cover letter.

> 
> Does this split-up sound reasonable?

Yes makes sense, thanks

Neil

> 
> Thanks,
> Liu Ying
> 
>>
>> Neil
>>
>>> Cc: Andrzej Hajda <a.hajda@samsung.com>
>>> Cc: Neil Armstrong <narmstrong@baylibre.com>
>>> Cc: Robert Foss <robert.foss@linaro.org>
>>> Cc: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
>>> Cc: Jonas Karlman <jonas@kwiboo.se>
>>> Cc: Jernej Skrabec <jernej.skrabec@siol.net>
>>> Cc: David Airlie <airlied@linux.ie>
>>> Cc: Daniel Vetter <daniel@ffwll.ch>
>>> Cc: Guido Günther <agx@sigxcpu.org>
>>> Cc: Robert Chiras <robert.chiras@nxp.com>
>>> Cc: NXP Linux Team <linux-imx@nxp.com>
>>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
>>> ---
>>> v1->v2:
>>> * Fix commit message typo - s/unchange/unchanged/
>>>
>>>  drivers/gpu/drm/bridge/nwl-dsi.c | 86 +++++++++++++++++++++-------------------
>>>  1 file changed, 46 insertions(+), 40 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c
>>> index be6bfc5..229f0b1 100644
>>> --- a/drivers/gpu/drm/bridge/nwl-dsi.c
>>> +++ b/drivers/gpu/drm/bridge/nwl-dsi.c
>>> @@ -21,6 +21,7 @@
>>>  #include <linux/sys_soc.h>
>>>  #include <linux/time64.h>
>>>  
>>> +#include <drm/drm_atomic_state_helper.h>
>>>  #include <drm/drm_bridge.h>
>>>  #include <drm/drm_mipi_dsi.h>
>>>  #include <drm/drm_of.h>
>>> @@ -661,7 +662,7 @@ static irqreturn_t nwl_dsi_irq_handler(int irq, void *data)
>>>  	return IRQ_HANDLED;
>>>  }
>>>  
>>> -static int nwl_dsi_enable(struct nwl_dsi *dsi)
>>> +static int nwl_dsi_mode_set(struct nwl_dsi *dsi)
>>>  {
>>>  	struct device *dev = dsi->dev;
>>>  	union phy_configure_opts *phy_cfg = &dsi->phy_cfg;
>>> @@ -748,7 +749,9 @@ static int nwl_dsi_disable(struct nwl_dsi *dsi)
>>>  	return 0;
>>>  }
>>>  
>>> -static void nwl_dsi_bridge_disable(struct drm_bridge *bridge)
>>> +static void
>>> +nwl_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
>>> +			      struct drm_bridge_state *old_bridge_state)
>>>  {
>>>  	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
>>>  	int ret;
>>> @@ -809,17 +812,6 @@ static int nwl_dsi_get_dphy_params(struct nwl_dsi *dsi,
>>>  	return 0;
>>>  }
>>>  
>>> -static bool nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
>>> -				      const struct drm_display_mode *mode,
>>> -				      struct drm_display_mode *adjusted_mode)
>>> -{
>>> -	/* At least LCDIF + NWL needs active high sync */
>>> -	adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
>>> -	adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
>>> -
>>> -	return true;
>>> -}
>>> -
>>>  static enum drm_mode_status
>>>  nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge,
>>>  			  const struct drm_display_info *info,
>>> @@ -837,6 +829,29 @@ nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge,
>>>  	return MODE_OK;
>>>  }
>>>  
>>> +static int nwl_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 drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
>>> +
>>> +	/* At least LCDIF + NWL needs active high sync */
>>> +	adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
>>> +	adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
>>> +
>>> +	/*
>>> +	 * Do a full modeset if crtc_state->active is changed to be true.
>>> +	 * This ensures our ->mode_set() is called to get the DSI controller
>>> +	 * and the PHY ready to send DCS commands, when only the connector's
>>> +	 * DPMS is brought out of "Off" status.
>>> +	 */
>>> +	if (crtc_state->active_changed && crtc_state->active)
>>> +		crtc_state->mode_changed = true;
>>> +
>>> +	return 0;
>>> +}
>>> +
>>>  static void
>>>  nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
>>>  			const struct drm_display_mode *mode,
>>> @@ -852,13 +867,6 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
>>>  	if (ret < 0)
>>>  		return;
>>>  
>>> -	/*
>>> -	 * If hs clock is unchanged, we're all good - all parameters are
>>> -	 * derived from it atm.
>>> -	 */
>>> -	if (new_cfg.mipi_dphy.hs_clk_rate == dsi->phy_cfg.mipi_dphy.hs_clk_rate)
>>> -		return;
>>> -
>>>  	phy_ref_rate = clk_get_rate(dsi->phy_ref_clk);
>>>  	DRM_DEV_DEBUG_DRIVER(dev, "PHY at ref rate: %lu\n", phy_ref_rate);
>>>  	/* Save the new desired phy config */
>>> @@ -866,14 +874,8 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
>>>  
>>>  	memcpy(&dsi->mode, adjusted_mode, sizeof(dsi->mode));
>>>  	drm_mode_debug_printmodeline(adjusted_mode);
>>> -}
>>>  
>>> -static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge)
>>> -{
>>> -	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
>>> -	int ret;
>>> -
>>> -	pm_runtime_get_sync(dsi->dev);
>>> +	pm_runtime_get_sync(dev);
>>>  
>>>  	if (clk_prepare_enable(dsi->lcdif_clk) < 0)
>>>  		return;
>>> @@ -883,27 +885,29 @@ static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge)
>>>  	/* Step 1 from DSI reset-out instructions */
>>>  	ret = reset_control_deassert(dsi->rst_pclk);
>>>  	if (ret < 0) {
>>> -		DRM_DEV_ERROR(dsi->dev, "Failed to deassert PCLK: %d\n", ret);
>>> +		DRM_DEV_ERROR(dev, "Failed to deassert PCLK: %d\n", ret);
>>>  		return;
>>>  	}
>>>  
>>>  	/* Step 2 from DSI reset-out instructions */
>>> -	nwl_dsi_enable(dsi);
>>> +	nwl_dsi_mode_set(dsi);
>>>  
>>>  	/* Step 3 from DSI reset-out instructions */
>>>  	ret = reset_control_deassert(dsi->rst_esc);
>>>  	if (ret < 0) {
>>> -		DRM_DEV_ERROR(dsi->dev, "Failed to deassert ESC: %d\n", ret);
>>> +		DRM_DEV_ERROR(dev, "Failed to deassert ESC: %d\n", ret);
>>>  		return;
>>>  	}
>>>  	ret = reset_control_deassert(dsi->rst_byte);
>>>  	if (ret < 0) {
>>> -		DRM_DEV_ERROR(dsi->dev, "Failed to deassert BYTE: %d\n", ret);
>>> +		DRM_DEV_ERROR(dev, "Failed to deassert BYTE: %d\n", ret);
>>>  		return;
>>>  	}
>>>  }
>>>  
>>> -static void nwl_dsi_bridge_enable(struct drm_bridge *bridge)
>>> +static void
>>> +nwl_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
>>> +			     struct drm_bridge_state *old_bridge_state)
>>>  {
>>>  	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
>>>  	int ret;
>>> @@ -948,14 +952,16 @@ static void nwl_dsi_bridge_detach(struct drm_bridge *bridge)
>>>  }
>>>  
>>>  static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = {
>>> -	.pre_enable = nwl_dsi_bridge_pre_enable,
>>> -	.enable     = nwl_dsi_bridge_enable,
>>> -	.disable    = nwl_dsi_bridge_disable,
>>> -	.mode_fixup = nwl_dsi_bridge_mode_fixup,
>>> -	.mode_set   = nwl_dsi_bridge_mode_set,
>>> -	.mode_valid = nwl_dsi_bridge_mode_valid,
>>> -	.attach	    = nwl_dsi_bridge_attach,
>>> -	.detach	    = nwl_dsi_bridge_detach,
>>> +	.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		= nwl_dsi_bridge_atomic_check,
>>> +	.atomic_enable		= nwl_dsi_bridge_atomic_enable,
>>> +	.atomic_disable		= nwl_dsi_bridge_atomic_disable,
>>> +	.mode_set		= nwl_dsi_bridge_mode_set,
>>> +	.mode_valid		= nwl_dsi_bridge_mode_valid,
>>> +	.attach			= nwl_dsi_bridge_attach,
>>> +	.detach			= nwl_dsi_bridge_detach,
>>>  };
>>>  
>>>  static int nwl_dsi_parse_dt(struct nwl_dsi *dsi)
>>>
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2] drm/bridge: nwl-dsi: Get MIPI DSI controller and PHY ready in ->mode_set()
  2021-04-22 12:07     ` Neil Armstrong
@ 2021-04-23  9:47       ` Liu Ying
  0 siblings, 0 replies; 5+ messages in thread
From: Liu Ying @ 2021-04-23  9:47 UTC (permalink / raw)
  To: Neil Armstrong, dri-devel
  Cc: linux-kernel, Andrzej Hajda, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, David Airlie, Daniel Vetter,
	Guido Günther, Robert Chiras, NXP Linux Team

Hi Neil,

On Thu, 2021-04-22 at 14:07 +0200, Neil Armstrong wrote:
> Hi,
> 
> On 22/04/2021 11:31, Liu Ying wrote:
> > Hi Neil,
> > 
> > On Thu, 2021-04-22 at 10:48 +0200, Neil Armstrong wrote:
> > > Hi,
> > > 
> > > On 22/04/2021 07:14, Liu Ying wrote:
> > > > Some MIPI DSI panel drivers like 'raydium,rm68200' send
> > > > MIPI_DCS_SET_DISPLAY_ON commands in panel_funcs->prepare(), which
> > > > requires the MIPI DSI controller and PHY to be ready beforehand.
> > > > Without this patch, the nwl-dsi driver gets the MIPI DSI controller
> > > > and PHY ready in bridge_funcs->pre_enable(), which happens after
> > > > the panel_funcs->prepare(). So, this patch shifts the bridge operation
> > > > ealier from bridge_funcs->pre_enable() to bridge_funcs->mode_set().
> > > 
> > > This makes sense, this is how we do on the synopsys dw mipi dsi driver.
> > > 
> > > > This way, more MIPI DSI panels can connect to this nwl-dsi bridge.
> > > > Care is taken to make sure bridge_funcs->mode_set()/atomic_disable()
> > > > are called in pairs, which includes removing a check on unchanged HS
> > > > clock rate and forcing a full modeset when only connector's DPMS is
> > > > brought out of "Off" status.
> > > 
> > > I would split the changes in multiple patches to clarify the changes.
> > 
> > Maybe, I can split this into the below 3 patches:
> > 1) Remove a check on unchanged HS clock rate from ->mode_set().
> > 2) Force a full modeset when only connector's DPMS is brought out of
> > "Off" status. This will be done in ->atomic_check() together with the
> > fixup for H/VSYNC polarities.
> > 3) Shift the bridge operation as the last step.
> > 
> > I'll mention that 1) & 2) are needed by 3) in their commit message.
> 
> Sure, you can also put this split explanation in the cover letter.
> 
> > Does this split-up sound reasonable?
> 
> Yes makes sense, thanks

I've sent v3 to do the split-up.
I actually swap 1) and 2), which is trivial I assume.

Regards,
Liu Ying

> 
> Neil
> 
> > Thanks,
> > Liu Ying
> > 
> > > Neil
> > > 
> > > > Cc: Andrzej Hajda <a.hajda@samsung.com>
> > > > Cc: Neil Armstrong <narmstrong@baylibre.com>
> > > > Cc: Robert Foss <robert.foss@linaro.org>
> > > > Cc: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
> > > > Cc: Jonas Karlman <jonas@kwiboo.se>
> > > > Cc: Jernej Skrabec <jernej.skrabec@siol.net>
> > > > Cc: David Airlie <airlied@linux.ie>
> > > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > > Cc: Guido Günther <agx@sigxcpu.org>
> > > > Cc: Robert Chiras <robert.chiras@nxp.com>
> > > > Cc: NXP Linux Team <linux-imx@nxp.com>
> > > > Signed-off-by: Liu Ying <victor.liu@nxp.com>
> > > > ---
> > > > v1->v2:
> > > > * Fix commit message typo - s/unchange/unchanged/
> > > > 
> > > >  drivers/gpu/drm/bridge/nwl-dsi.c | 86 +++++++++++++++++++++-------------------
> > > >  1 file changed, 46 insertions(+), 40 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c
> > > > index be6bfc5..229f0b1 100644
> > > > --- a/drivers/gpu/drm/bridge/nwl-dsi.c
> > > > +++ b/drivers/gpu/drm/bridge/nwl-dsi.c
> > > > @@ -21,6 +21,7 @@
> > > >  #include <linux/sys_soc.h>
> > > >  #include <linux/time64.h>
> > > >  
> > > > +#include <drm/drm_atomic_state_helper.h>
> > > >  #include <drm/drm_bridge.h>
> > > >  #include <drm/drm_mipi_dsi.h>
> > > >  #include <drm/drm_of.h>
> > > > @@ -661,7 +662,7 @@ static irqreturn_t nwl_dsi_irq_handler(int irq, void *data)
> > > >  	return IRQ_HANDLED;
> > > >  }
> > > >  
> > > > -static int nwl_dsi_enable(struct nwl_dsi *dsi)
> > > > +static int nwl_dsi_mode_set(struct nwl_dsi *dsi)
> > > >  {
> > > >  	struct device *dev = dsi->dev;
> > > >  	union phy_configure_opts *phy_cfg = &dsi->phy_cfg;
> > > > @@ -748,7 +749,9 @@ static int nwl_dsi_disable(struct nwl_dsi *dsi)
> > > >  	return 0;
> > > >  }
> > > >  
> > > > -static void nwl_dsi_bridge_disable(struct drm_bridge *bridge)
> > > > +static void
> > > > +nwl_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > > > +			      struct drm_bridge_state *old_bridge_state)
> > > >  {
> > > >  	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
> > > >  	int ret;
> > > > @@ -809,17 +812,6 @@ static int nwl_dsi_get_dphy_params(struct nwl_dsi *dsi,
> > > >  	return 0;
> > > >  }
> > > >  
> > > > -static bool nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
> > > > -				      const struct drm_display_mode *mode,
> > > > -				      struct drm_display_mode *adjusted_mode)
> > > > -{
> > > > -	/* At least LCDIF + NWL needs active high sync */
> > > > -	adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
> > > > -	adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
> > > > -
> > > > -	return true;
> > > > -}
> > > > -
> > > >  static enum drm_mode_status
> > > >  nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge,
> > > >  			  const struct drm_display_info *info,
> > > > @@ -837,6 +829,29 @@ nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge,
> > > >  	return MODE_OK;
> > > >  }
> > > >  
> > > > +static int nwl_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 drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
> > > > +
> > > > +	/* At least LCDIF + NWL needs active high sync */
> > > > +	adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
> > > > +	adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
> > > > +
> > > > +	/*
> > > > +	 * Do a full modeset if crtc_state->active is changed to be true.
> > > > +	 * This ensures our ->mode_set() is called to get the DSI controller
> > > > +	 * and the PHY ready to send DCS commands, when only the connector's
> > > > +	 * DPMS is brought out of "Off" status.
> > > > +	 */
> > > > +	if (crtc_state->active_changed && crtc_state->active)
> > > > +		crtc_state->mode_changed = true;
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > >  static void
> > > >  nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
> > > >  			const struct drm_display_mode *mode,
> > > > @@ -852,13 +867,6 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
> > > >  	if (ret < 0)
> > > >  		return;
> > > >  
> > > > -	/*
> > > > -	 * If hs clock is unchanged, we're all good - all parameters are
> > > > -	 * derived from it atm.
> > > > -	 */
> > > > -	if (new_cfg.mipi_dphy.hs_clk_rate == dsi->phy_cfg.mipi_dphy.hs_clk_rate)
> > > > -		return;
> > > > -
> > > >  	phy_ref_rate = clk_get_rate(dsi->phy_ref_clk);
> > > >  	DRM_DEV_DEBUG_DRIVER(dev, "PHY at ref rate: %lu\n", phy_ref_rate);
> > > >  	/* Save the new desired phy config */
> > > > @@ -866,14 +874,8 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
> > > >  
> > > >  	memcpy(&dsi->mode, adjusted_mode, sizeof(dsi->mode));
> > > >  	drm_mode_debug_printmodeline(adjusted_mode);
> > > > -}
> > > >  
> > > > -static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge)
> > > > -{
> > > > -	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
> > > > -	int ret;
> > > > -
> > > > -	pm_runtime_get_sync(dsi->dev);
> > > > +	pm_runtime_get_sync(dev);
> > > >  
> > > >  	if (clk_prepare_enable(dsi->lcdif_clk) < 0)
> > > >  		return;
> > > > @@ -883,27 +885,29 @@ static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge)
> > > >  	/* Step 1 from DSI reset-out instructions */
> > > >  	ret = reset_control_deassert(dsi->rst_pclk);
> > > >  	if (ret < 0) {
> > > > -		DRM_DEV_ERROR(dsi->dev, "Failed to deassert PCLK: %d\n", ret);
> > > > +		DRM_DEV_ERROR(dev, "Failed to deassert PCLK: %d\n", ret);
> > > >  		return;
> > > >  	}
> > > >  
> > > >  	/* Step 2 from DSI reset-out instructions */
> > > > -	nwl_dsi_enable(dsi);
> > > > +	nwl_dsi_mode_set(dsi);
> > > >  
> > > >  	/* Step 3 from DSI reset-out instructions */
> > > >  	ret = reset_control_deassert(dsi->rst_esc);
> > > >  	if (ret < 0) {
> > > > -		DRM_DEV_ERROR(dsi->dev, "Failed to deassert ESC: %d\n", ret);
> > > > +		DRM_DEV_ERROR(dev, "Failed to deassert ESC: %d\n", ret);
> > > >  		return;
> > > >  	}
> > > >  	ret = reset_control_deassert(dsi->rst_byte);
> > > >  	if (ret < 0) {
> > > > -		DRM_DEV_ERROR(dsi->dev, "Failed to deassert BYTE: %d\n", ret);
> > > > +		DRM_DEV_ERROR(dev, "Failed to deassert BYTE: %d\n", ret);
> > > >  		return;
> > > >  	}
> > > >  }
> > > >  
> > > > -static void nwl_dsi_bridge_enable(struct drm_bridge *bridge)
> > > > +static void
> > > > +nwl_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > > > +			     struct drm_bridge_state *old_bridge_state)
> > > >  {
> > > >  	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
> > > >  	int ret;
> > > > @@ -948,14 +952,16 @@ static void nwl_dsi_bridge_detach(struct drm_bridge *bridge)
> > > >  }
> > > >  
> > > >  static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = {
> > > > -	.pre_enable = nwl_dsi_bridge_pre_enable,
> > > > -	.enable     = nwl_dsi_bridge_enable,
> > > > -	.disable    = nwl_dsi_bridge_disable,
> > > > -	.mode_fixup = nwl_dsi_bridge_mode_fixup,
> > > > -	.mode_set   = nwl_dsi_bridge_mode_set,
> > > > -	.mode_valid = nwl_dsi_bridge_mode_valid,
> > > > -	.attach	    = nwl_dsi_bridge_attach,
> > > > -	.detach	    = nwl_dsi_bridge_detach,
> > > > +	.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		= nwl_dsi_bridge_atomic_check,
> > > > +	.atomic_enable		= nwl_dsi_bridge_atomic_enable,
> > > > +	.atomic_disable		= nwl_dsi_bridge_atomic_disable,
> > > > +	.mode_set		= nwl_dsi_bridge_mode_set,
> > > > +	.mode_valid		= nwl_dsi_bridge_mode_valid,
> > > > +	.attach			= nwl_dsi_bridge_attach,
> > > > +	.detach			= nwl_dsi_bridge_detach,
> > > >  };
> > > >  
> > > >  static int nwl_dsi_parse_dt(struct nwl_dsi *dsi)
> > > > 


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-04-23  9:48 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-22  5:14 [PATCH v2] drm/bridge: nwl-dsi: Get MIPI DSI controller and PHY ready in ->mode_set() Liu Ying
2021-04-22  8:48 ` Neil Armstrong
2021-04-22  9:31   ` Liu Ying
2021-04-22 12:07     ` Neil Armstrong
2021-04-23  9:47       ` Liu Ying

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).