mbox series

[v2,0/8] drm/msm/dpu: handle non-default TE source pins

Message ID 20240613-dpu-handle-te-signal-v2-0-67a0116b5366@linaro.org
Headers show
Series drm/msm/dpu: handle non-default TE source pins | expand

Message

Dmitry Baryshkov June 13, 2024, 5:05 p.m. UTC
Command-mode DSI panels need to signal the display controlller when
vsync happens, so that the device can start sending the next frame. Some
devices (Google Pixel 3) use a non-default pin, so additional
configuration is required. Add a way to specify this information in DT
and handle it in the DSI and DPU drivers.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
Changes in v2:
- In DT bindings renamed mdp_gpioN to mdp_vsync_p/_s/_e per pins name (Abhinav)
- Extended bindings to include default: mdp_vsync_p (Rob)
- Renamed dpu_hw_setup_vsync_source() and
  dpu_hw_setup_vsync_source_and_vsync_sel() to match the implementation
  (Abhinav)
- Link to v1: https://lore.kernel.org/r/20240520-dpu-handle-te-signal-v1-0-f273b42a089c@linaro.org

---
Dmitry Baryshkov (8):
      dt-bindings: display/msm/dsi: allow specifying TE source
      drm/msm/dpu: convert vsync source defines to the enum
      drm/msm/dsi: drop unused GPIOs handling
      drm/msm/dpu: pull the is_cmd_mode out of _dpu_encoder_update_vsync_source()
      drm/msm/dpu: rework vsync_source handling
      drm/msm/dsi: parse vsync source from device tree
      drm/msm/dpu: support setting the TE source
      drm/msm/dpu: rename dpu_hw_setup_vsync_source functions

 .../bindings/display/msm/dsi-controller-main.yaml  | 17 ++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        | 11 ++---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h        |  5 +--
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c        |  2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h        |  2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h        | 26 ++++++------
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c         | 14 +++----
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h         |  2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c            | 44 ++++++++++++++++++++
 drivers/gpu/drm/msm/dsi/dsi.h                      |  1 +
 drivers/gpu/drm/msm/dsi/dsi_host.c                 | 48 +++++-----------------
 drivers/gpu/drm/msm/dsi/dsi_manager.c              |  5 +++
 drivers/gpu/drm/msm/msm_drv.h                      |  6 +++
 13 files changed, 114 insertions(+), 69 deletions(-)
---
base-commit: 03d44168cbd7fc57d5de56a3730427db758fc7f6
change-id: 20240514-dpu-handle-te-signal-82663c0211bd

Best regards,

Comments

Marijn Suijten June 13, 2024, 6:14 p.m. UTC | #1
On 2024-06-13 20:05:10, Dmitry Baryshkov wrote:
> Make the DPU driver use the TE source specified in the DT. If none is
> specified, the driver defaults to the first GPIO (mdp_vsync0).

mdp_vsync_p?

> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 44 ++++++++++++++++++++++++++++++++-
>  1 file changed, 43 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> index e9991f3756d4..6fcb3cf4a382 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> @@ -505,6 +505,44 @@ static void dpu_kms_wait_flush(struct msm_kms *kms, unsigned crtc_mask)
>  		dpu_kms_wait_for_commit_done(kms, crtc);
>  }
>  
> +static const char *dpu_vsync_sources[] = {
> +	[DPU_VSYNC_SOURCE_GPIO_0] = "mdp_vsync_p",
> +	[DPU_VSYNC_SOURCE_GPIO_1] = "mdp_vsync_s",
> +	[DPU_VSYNC_SOURCE_GPIO_2] = "mdp_vsync_e",
> +	[DPU_VSYNC_SOURCE_INTF_0] = "mdp_intf0",
> +	[DPU_VSYNC_SOURCE_INTF_1] = "mdp_intf1",
> +	[DPU_VSYNC_SOURCE_INTF_2] = "mdp_intf2",
> +	[DPU_VSYNC_SOURCE_INTF_3] = "mdp_intf3",
> +	[DPU_VSYNC_SOURCE_WD_TIMER_0] = "timer0",
> +	[DPU_VSYNC_SOURCE_WD_TIMER_1] = "timer1",
> +	[DPU_VSYNC_SOURCE_WD_TIMER_2] = "timer2",
> +	[DPU_VSYNC_SOURCE_WD_TIMER_3] = "timer3",
> +	[DPU_VSYNC_SOURCE_WD_TIMER_4] = "timer4",
> +};
> +
> +static int dpu_kms_dsi_set_te_source(struct msm_display_info *info,
> +				     struct msm_dsi *dsi)
> +{
> +	const char *te_source = msm_dsi_get_te_source(dsi);

Just checking: if the TE source is different and one has dual-DSI, it must be
set on both controllers?

> +	int i;
> +
> +	if (!te_source) {
> +		info->vsync_source = DPU_VSYNC_SOURCE_GPIO_0;
> +		return 0;
> +	}
> +
> +	/* we can not use match_string since dpu_vsync_sources is a sparse array */

Instead of having gaps in the array, you could also store both the vsync_source
and name as the array elements?

> +	for (i = 0; i < ARRAY_SIZE(dpu_vsync_sources); i++) {
> +		if (dpu_vsync_sources[i] &&
> +		    !strcmp(dpu_vsync_sources[i], te_source)) {
> +			info->vsync_source = i;
> +			return 0;
> +		}
> +	}
> +
> +	return -EINVAL;
> +}
> +
>  static int _dpu_kms_initialize_dsi(struct drm_device *dev,
>  				    struct msm_drm_private *priv,
>  				    struct dpu_kms *dpu_kms)
> @@ -543,7 +581,11 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev,
>  
>  		info.is_cmd_mode = msm_dsi_is_cmd_mode(priv->dsi[i]);
>  
> -		info.vsync_source = DPU_VSYNC_SOURCE_GPIO_0;
> +		rc = dpu_kms_dsi_set_te_source(&info, priv->dsi[i]);
> +		if (rc) {
> +			DPU_ERROR("failed to identify TE source for dsi display\n");
> +			return rc;
> +		}
>  
>  		encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_DSI, &info);
>  		if (IS_ERR(encoder)) {
> 
> -- 
> 2.39.2
>
Marijn Suijten June 13, 2024, 6:16 p.m. UTC | #2
On 2024-06-13 20:05:04, Dmitry Baryshkov wrote:
> Command mode panels provide TE signal back to the DSI host to signal
> that the frame display has completed and update of the image will not
> cause tearing. Usually it is connected to the first GPIO with the
> mdp_vsync function, which is the default. In such case the property can
> be skipped.
> 
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
>  .../bindings/display/msm/dsi-controller-main.yaml       | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml
> index 1fa28e976559..e1cb3a1fee81 100644
> --- a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml
> +++ b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml
> @@ -162,6 +162,22 @@ properties:
>                  items:
>                    enum: [ 0, 1, 2, 3 ]
>  
> +              qcom,te-source:
> +                $ref: /schemas/types.yaml#/definitions/string
> +                description:
> +                  Specifies the source of vsync signal from the panel used for
> +                  tearing elimination.
> +                default: mdp_vsync_p
> +                enum:
> +                  - mdp_vsync_p
> +                  - mdp_vsync_s
> +                  - mdp_vsync_e

When discussing that these should be renamed, was it also documented what the
suffix means?  I can only guess something like primary/secondary/e...?

Are the mdp_intfX variants missing here that you're handling in patch 7/8?

> +                  - timer0
> +                  - timer1
> +                  - timer2
> +                  - timer3
> +                  - timer4
> +
>      required:
>        - port@0
>        - port@1
> @@ -452,6 +468,7 @@ examples:
>                            dsi0_out: endpoint {
>                                     remote-endpoint = <&sn65dsi86_in>;
>                                     data-lanes = <0 1 2 3>;
> +                                   qcom,te-source = "mdp_vsync_e";
>                            };
>                    };
>             };
> 
> -- 
> 2.39.2
>
Marijn Suijten June 13, 2024, 6:19 p.m. UTC | #3
On 2024-06-13 20:05:07, Dmitry Baryshkov wrote:
> Setting vsync source makes sense only for DSI CMD panels. Pull the
> is_cmd_mode condition out of the function into the calling code, so that
> it becomes more explicit.
> 
> Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

Reviewed-by: Marijn Suijten <marijn.suijten@somainline.org>

> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index 4988a1029431..bd37a56b4d03 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -736,8 +736,7 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc,
>  		return;
>  	}
>  
> -	if (hw_mdptop->ops.setup_vsync_source &&
> -			disp_info->is_cmd_mode) {
> +	if (hw_mdptop->ops.setup_vsync_source) {
>  		for (i = 0; i < dpu_enc->num_phys_encs; i++)
>  			vsync_cfg.ppnumber[i] = dpu_enc->hw_pp[i]->idx;
>  
> @@ -1226,7 +1225,8 @@ static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
>  		dpu_enc->cur_master->hw_mdptop->ops.intf_audio_select(
>  			dpu_enc->cur_master->hw_mdptop);
>  
> -	_dpu_encoder_update_vsync_source(dpu_enc, &dpu_enc->disp_info);
> +	if (dpu_enc->disp_info.is_cmd_mode)
> +		_dpu_encoder_update_vsync_source(dpu_enc, &dpu_enc->disp_info);
>  
>  	if (dpu_enc->disp_info.intf_type == INTF_DSI &&
>  			!WARN_ON(dpu_enc->num_phys_encs == 0)) {
> 
> -- 
> 2.39.2
>
Marijn Suijten June 13, 2024, 6:24 p.m. UTC | #4
On 2024-06-13 20:05:09, Dmitry Baryshkov wrote:
> Allow board's device tree to specify the vsync source (aka TE source).
> If the property is omitted, the display controller driver will use the
> default setting.

Well, that specific default handling is not really part of this patch, but
how a followup patch is going to respond when msm_dsi_get_te_source() returns
NULL. (Or how that followup patch is expected to deal with that - worth a
doc-comment?)

> 
> Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

Reviewed-by: Marijn Suijten <marijn.suijten@somainline.org>

> ---
>  drivers/gpu/drm/msm/dsi/dsi.h         |  1 +
>  drivers/gpu/drm/msm/dsi/dsi_host.c    | 11 +++++++++++
>  drivers/gpu/drm/msm/dsi/dsi_manager.c |  5 +++++
>  drivers/gpu/drm/msm/msm_drv.h         |  6 ++++++
>  4 files changed, 23 insertions(+)
> 
> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
> index afc290408ba4..87496db203d6 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi.h
> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
> @@ -37,6 +37,7 @@ struct msm_dsi {
>  
>  	struct mipi_dsi_host *host;
>  	struct msm_dsi_phy *phy;
> +	const char *te_source;
>  
>  	struct drm_bridge *next_bridge;
>  
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
> index c4d72562c95a..c26ad0fed54d 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> @@ -1786,9 +1786,11 @@ static int dsi_populate_dsc_params(struct msm_dsi_host *msm_host, struct drm_dsc
>  
>  static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
>  {
> +	struct msm_dsi *msm_dsi = platform_get_drvdata(msm_host->pdev);
>  	struct device *dev = &msm_host->pdev->dev;
>  	struct device_node *np = dev->of_node;
>  	struct device_node *endpoint;
> +	const char *te_source;
>  	int ret = 0;
>  
>  	/*
> @@ -1811,6 +1813,15 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
>  		goto err;
>  	}
>  
> +	ret = of_property_read_string(endpoint, "qcom,te-source", &te_source);
> +	if (ret && ret != -EINVAL) {
> +		DRM_DEV_ERROR(dev, "%s: invalid TE source configuration %d\n",
> +			__func__, ret);
> +		goto err;
> +	}
> +	if (!ret)
> +		msm_dsi->te_source = devm_kstrdup(dev, te_source, GFP_KERNEL);
> +
>  	if (of_property_read_bool(np, "syscon-sfpb")) {
>  		msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
>  					"syscon-sfpb");
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> index 5b3f3068fd92..a210b7c9e5ca 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> @@ -603,3 +603,8 @@ bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi)
>  {
>  	return IS_MASTER_DSI_LINK(msm_dsi->id);
>  }
> +
> +const char *msm_dsi_get_te_source(struct msm_dsi *msm_dsi)
> +{
> +	return msm_dsi->te_source;
> +}
> diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
> index 912ebaa5df84..afd98dffea99 100644
> --- a/drivers/gpu/drm/msm/msm_drv.h
> +++ b/drivers/gpu/drm/msm/msm_drv.h
> @@ -330,6 +330,7 @@ bool msm_dsi_is_bonded_dsi(struct msm_dsi *msm_dsi);
>  bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi);
>  bool msm_dsi_wide_bus_enabled(struct msm_dsi *msm_dsi);
>  struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi);
> +const char *msm_dsi_get_te_source(struct msm_dsi *msm_dsi);
>  #else
>  static inline void __init msm_dsi_register(void)
>  {
> @@ -367,6 +368,11 @@ static inline struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_
>  {
>  	return NULL;
>  }
> +
> +static inline const char *msm_dsi_get_te_source(struct msm_dsi *msm_dsi)
> +{
> +	return NULL;
> +}
>  #endif
>  
>  #ifdef CONFIG_DRM_MSM_DP
> 
> -- 
> 2.39.2
>
Abhinav Kumar June 19, 2024, 7:02 p.m. UTC | #5
On 6/13/2024 11:14 AM, Marijn Suijten wrote:
> On 2024-06-13 20:05:10, Dmitry Baryshkov wrote:
>> Make the DPU driver use the TE source specified in the DT. If none is
>> specified, the driver defaults to the first GPIO (mdp_vsync0).
> 
> mdp_vsync_p?
> 
>>
>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> ---
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 44 ++++++++++++++++++++++++++++++++-
>>   1 file changed, 43 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>> index e9991f3756d4..6fcb3cf4a382 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>> @@ -505,6 +505,44 @@ static void dpu_kms_wait_flush(struct msm_kms *kms, unsigned crtc_mask)
>>   		dpu_kms_wait_for_commit_done(kms, crtc);
>>   }
>>   
>> +static const char *dpu_vsync_sources[] = {
>> +	[DPU_VSYNC_SOURCE_GPIO_0] = "mdp_vsync_p",
>> +	[DPU_VSYNC_SOURCE_GPIO_1] = "mdp_vsync_s",
>> +	[DPU_VSYNC_SOURCE_GPIO_2] = "mdp_vsync_e",
>> +	[DPU_VSYNC_SOURCE_INTF_0] = "mdp_intf0",
>> +	[DPU_VSYNC_SOURCE_INTF_1] = "mdp_intf1",
>> +	[DPU_VSYNC_SOURCE_INTF_2] = "mdp_intf2",
>> +	[DPU_VSYNC_SOURCE_INTF_3] = "mdp_intf3",
>> +	[DPU_VSYNC_SOURCE_WD_TIMER_0] = "timer0",
>> +	[DPU_VSYNC_SOURCE_WD_TIMER_1] = "timer1",
>> +	[DPU_VSYNC_SOURCE_WD_TIMER_2] = "timer2",
>> +	[DPU_VSYNC_SOURCE_WD_TIMER_3] = "timer3",
>> +	[DPU_VSYNC_SOURCE_WD_TIMER_4] = "timer4",
>> +};
>> +
>> +static int dpu_kms_dsi_set_te_source(struct msm_display_info *info,
>> +				     struct msm_dsi *dsi)
>> +{
>> +	const char *te_source = msm_dsi_get_te_source(dsi);
> 
> Just checking: if the TE source is different and one has dual-DSI, it must be
> set on both controllers?
> 

If we use dual-dsi (in NON-bonded mode), then yes we will have two TE 
sources - one for each controller.

>> +	int i;
>> +
>> +	if (!te_source) {
>> +		info->vsync_source = DPU_VSYNC_SOURCE_GPIO_0;
>> +		return 0;
>> +	}
>> +
>> +	/* we can not use match_string since dpu_vsync_sources is a sparse array */
> 
> Instead of having gaps in the array, you could also store both the vsync_source
> and name as the array elements?
> 

Yes, there is a gap because the DPU_VSYNC_* macros have a gap.

Can you pls explain your suggestion to remove the gap a little more?
I didnt follow this part very well.

>> +	for (i = 0; i < ARRAY_SIZE(dpu_vsync_sources); i++) {
>> +		if (dpu_vsync_sources[i] &&
>> +		    !strcmp(dpu_vsync_sources[i], te_source)) {
>> +			info->vsync_source = i;
>> +			return 0;
>> +		}
>> +	}
>> +
>> +	return -EINVAL;
>> +}
>> +
>>   static int _dpu_kms_initialize_dsi(struct drm_device *dev,
>>   				    struct msm_drm_private *priv,
>>   				    struct dpu_kms *dpu_kms)
>> @@ -543,7 +581,11 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev,
>>   
>>   		info.is_cmd_mode = msm_dsi_is_cmd_mode(priv->dsi[i]);
>>   
>> -		info.vsync_source = DPU_VSYNC_SOURCE_GPIO_0;
>> +		rc = dpu_kms_dsi_set_te_source(&info, priv->dsi[i]);
>> +		if (rc) {
>> +			DPU_ERROR("failed to identify TE source for dsi display\n");
>> +			return rc;
>> +		}
>>   
>>   		encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_DSI, &info);
>>   		if (IS_ERR(encoder)) {
>>
>> -- 
>> 2.39.2
>>