dri-devel Archive mirror
 help / color / mirror / Atom feed
* [PATCH] drm/msm/mdp5: high precision vblank timestamp support
@ 2015-10-26  9:54 Archit Taneja
  2015-10-27  0:03 ` Rob Clark
  0 siblings, 1 reply; 3+ messages in thread
From: Archit Taneja @ 2015-10-26  9:54 UTC (permalink / raw
  To: robdclark; +Cc: linux-arm-msm, dri-devel

MDP5 has line count and frame count registers for each interface. Enable
these counters and use them to implement the get_vblank_timestamp drm
driver op.

The line counter starts with the value 1 at the beginning of the VSYNC
pulse and ends with value VTOTAL at the end of VFP. This value is used
to determine whether we're in blanking period or not, and an adjusted
value of this counter is used to get vpos as expected by
get_scanout_position. Since there is no way to calculate hpos, we always
set it to 0.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c |  18 ++++
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c     | 129 ++++++++++++++++++++++++++++
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h     |   2 +
 3 files changed, 149 insertions(+)

diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
index c9e32b0..a019656 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
@@ -293,6 +293,24 @@ static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
 	.enable = mdp5_encoder_enable,
 };
 
+int mdp5_encoder_get_linecount(struct drm_encoder *encoder)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	struct mdp5_kms *mdp5_kms = get_kms(encoder);
+	int intf = mdp5_encoder->intf.num;
+
+	return mdp5_read(mdp5_kms, REG_MDP5_INTF_LINE_COUNT(intf));
+}
+
+u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	struct mdp5_kms *mdp5_kms = get_kms(encoder);
+	int intf = mdp5_encoder->intf.num;
+
+	return mdp5_read(mdp5_kms, REG_MDP5_INTF_FRAME_COUNT(intf));
+}
+
 int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
 					struct drm_encoder *slave_encoder)
 {
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
index b532faa..e115318 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
@@ -468,6 +468,127 @@ static int get_clk(struct platform_device *pdev, struct clk **clkp,
 	return 0;
 }
 
+static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_encoder *encoder;
+
+	drm_for_each_encoder(encoder, dev)
+		if (encoder->crtc == crtc)
+			return encoder;
+
+	return NULL;
+}
+
+static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
+			       unsigned int flags, int *vpos, int *hpos,
+			       ktime_t *stime, ktime_t *etime,
+			       const struct drm_display_mode *mode)
+{
+	struct msm_drm_private *priv = dev->dev_private;
+	struct drm_crtc *crtc;
+	struct drm_encoder *encoder;
+	int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
+	int ret = 0;
+
+	crtc = priv->crtcs[pipe];
+	if (!crtc) {
+		DRM_ERROR("Invalid crtc %d\n", pipe);
+		return 0;
+	}
+
+	encoder = get_encoder_from_crtc(crtc);
+	if (!encoder) {
+		DRM_ERROR("no encoder found for crtc %d\n", pipe);
+		return 0;
+	}
+
+	ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
+
+	vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
+	vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
+
+	/*
+	 * the line counter is 1 at the start of the VSYNC pulse and VTOTAL at
+	 * the end of VFP. Translate the porch values relative to the line
+	 * counter positions.
+	 */
+
+	vactive_start = vsw + vbp + 1;
+
+	vactive_end = vactive_start + mode->crtc_vdisplay;
+
+	/* last scan line before VSYNC */
+	vfp_end = mode->crtc_vtotal;
+
+	if (stime)
+		*stime = ktime_get();
+
+	line = mdp5_encoder_get_linecount(encoder);
+
+	if (line < vactive_start) {
+		line -= vactive_start;
+		ret |= DRM_SCANOUTPOS_IN_VBLANK;
+	} else if (line > vactive_end) {
+		line = line - vfp_end - vactive_start;
+		ret |= DRM_SCANOUTPOS_IN_VBLANK;
+	} else {
+		line -= vactive_start;
+	}
+
+	*vpos = line;
+	*hpos = 0;
+
+	if (etime)
+		*etime = ktime_get();
+
+	return ret;
+}
+
+static int mdp5_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
+				     int *max_error,
+				     struct timeval *vblank_time,
+				     unsigned flags)
+{
+	struct msm_drm_private *priv = dev->dev_private;
+	struct drm_crtc *crtc;
+
+	if (pipe < 0 || pipe >= priv->num_crtcs) {
+		DRM_ERROR("Invalid crtc %d\n", pipe);
+		return -EINVAL;
+	}
+
+	crtc = priv->crtcs[pipe];
+	if (!crtc) {
+		DRM_ERROR("Invalid crtc %d\n", pipe);
+		return -EINVAL;
+	}
+
+	return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
+						     vblank_time, flags,
+						     &crtc->mode);
+}
+
+static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
+{
+	struct msm_drm_private *priv = dev->dev_private;
+	struct drm_crtc *crtc;
+	struct drm_encoder *encoder;
+
+	if (pipe < 0 || pipe >= priv->num_crtcs)
+		return 0;
+
+	crtc = priv->crtcs[pipe];
+	if (!crtc)
+		return 0;
+
+	encoder = get_encoder_from_crtc(crtc);
+	if (!encoder)
+		return 0;
+
+	return mdp5_encoder_get_framecount(encoder);
+}
+
 struct msm_kms *mdp5_kms_init(struct drm_device *dev)
 {
 	struct platform_device *pdev = dev->platformdev;
@@ -590,6 +711,8 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
 				!config->hw->intf.base[i])
 			continue;
 		mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
+
+		mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3);
 	}
 	mdp5_disable(mdp5_kms);
 	mdelay(16);
@@ -635,6 +758,12 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
 	dev->mode_config.max_width = config->hw->lm.max_width;
 	dev->mode_config.max_height = config->hw->lm.max_height;
 
+	dev->driver->get_vblank_timestamp = mdp5_get_vblank_timestamp;
+	dev->driver->get_scanout_position = mdp5_get_scanoutpos;
+	dev->driver->get_vblank_counter = mdp5_get_vblank_counter;
+	dev->max_vblank_count = 0xffffffff;
+	dev->vblank_disable_immediate = true;
+
 	return kms;
 
 fail:
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
index 84f65d4..00730ba 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
@@ -222,6 +222,8 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
 		struct mdp5_interface *intf, struct mdp5_ctl *ctl);
 int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
 					struct drm_encoder *slave_encoder);
+int mdp5_encoder_get_linecount(struct drm_encoder *encoder);
+u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder);
 
 #ifdef CONFIG_DRM_MSM_DSI
 struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH] drm/msm/mdp5: high precision vblank timestamp support
  2015-10-26  9:54 [PATCH] drm/msm/mdp5: high precision vblank timestamp support Archit Taneja
@ 2015-10-27  0:03 ` Rob Clark
  2015-10-27  5:16   ` Archit Taneja
  0 siblings, 1 reply; 3+ messages in thread
From: Rob Clark @ 2015-10-27  0:03 UTC (permalink / raw
  To: Archit Taneja; +Cc: linux-arm-msm, dri-devel@lists.freedesktop.org

On Mon, Oct 26, 2015 at 5:54 AM, Archit Taneja <architt@codeaurora.org> wrote:
> MDP5 has line count and frame count registers for each interface. Enable
> these counters and use them to implement the get_vblank_timestamp drm
> driver op.
>
> The line counter starts with the value 1 at the beginning of the VSYNC
> pulse and ends with value VTOTAL at the end of VFP. This value is used
> to determine whether we're in blanking period or not, and an adjusted
> value of this counter is used to get vpos as expected by
> get_scanout_position. Since there is no way to calculate hpos, we always
> set it to 0.

What are the odds that mdp(n!=5) could support the same?  If/when that
ever happens I could see making some of this helpers to duplicate a
bit less in mdpN backend.. but I guess also fine to cross that bridge
when we come to it.  Other than that, lgtm, thanks

BR,
-R

> Signed-off-by: Archit Taneja <architt@codeaurora.org>
> ---
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c |  18 ++++
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c     | 129 ++++++++++++++++++++++++++++
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h     |   2 +
>  3 files changed, 149 insertions(+)
>
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
> index c9e32b0..a019656 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
> @@ -293,6 +293,24 @@ static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
>         .enable = mdp5_encoder_enable,
>  };
>
> +int mdp5_encoder_get_linecount(struct drm_encoder *encoder)
> +{
> +       struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
> +       struct mdp5_kms *mdp5_kms = get_kms(encoder);
> +       int intf = mdp5_encoder->intf.num;
> +
> +       return mdp5_read(mdp5_kms, REG_MDP5_INTF_LINE_COUNT(intf));
> +}
> +
> +u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder)
> +{
> +       struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
> +       struct mdp5_kms *mdp5_kms = get_kms(encoder);
> +       int intf = mdp5_encoder->intf.num;
> +
> +       return mdp5_read(mdp5_kms, REG_MDP5_INTF_FRAME_COUNT(intf));
> +}
> +
>  int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
>                                         struct drm_encoder *slave_encoder)
>  {
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
> index b532faa..e115318 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
> @@ -468,6 +468,127 @@ static int get_clk(struct platform_device *pdev, struct clk **clkp,
>         return 0;
>  }
>
> +static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc)
> +{
> +       struct drm_device *dev = crtc->dev;
> +       struct drm_encoder *encoder;
> +
> +       drm_for_each_encoder(encoder, dev)
> +               if (encoder->crtc == crtc)
> +                       return encoder;
> +
> +       return NULL;
> +}
> +
> +static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
> +                              unsigned int flags, int *vpos, int *hpos,
> +                              ktime_t *stime, ktime_t *etime,
> +                              const struct drm_display_mode *mode)
> +{
> +       struct msm_drm_private *priv = dev->dev_private;
> +       struct drm_crtc *crtc;
> +       struct drm_encoder *encoder;
> +       int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
> +       int ret = 0;
> +
> +       crtc = priv->crtcs[pipe];
> +       if (!crtc) {
> +               DRM_ERROR("Invalid crtc %d\n", pipe);
> +               return 0;
> +       }
> +
> +       encoder = get_encoder_from_crtc(crtc);
> +       if (!encoder) {
> +               DRM_ERROR("no encoder found for crtc %d\n", pipe);
> +               return 0;
> +       }
> +
> +       ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
> +
> +       vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
> +       vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
> +
> +       /*
> +        * the line counter is 1 at the start of the VSYNC pulse and VTOTAL at
> +        * the end of VFP. Translate the porch values relative to the line
> +        * counter positions.
> +        */
> +
> +       vactive_start = vsw + vbp + 1;
> +
> +       vactive_end = vactive_start + mode->crtc_vdisplay;
> +
> +       /* last scan line before VSYNC */
> +       vfp_end = mode->crtc_vtotal;
> +
> +       if (stime)
> +               *stime = ktime_get();
> +
> +       line = mdp5_encoder_get_linecount(encoder);
> +
> +       if (line < vactive_start) {
> +               line -= vactive_start;
> +               ret |= DRM_SCANOUTPOS_IN_VBLANK;
> +       } else if (line > vactive_end) {
> +               line = line - vfp_end - vactive_start;
> +               ret |= DRM_SCANOUTPOS_IN_VBLANK;
> +       } else {
> +               line -= vactive_start;
> +       }
> +
> +       *vpos = line;
> +       *hpos = 0;
> +
> +       if (etime)
> +               *etime = ktime_get();
> +
> +       return ret;
> +}
> +
> +static int mdp5_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
> +                                    int *max_error,
> +                                    struct timeval *vblank_time,
> +                                    unsigned flags)
> +{
> +       struct msm_drm_private *priv = dev->dev_private;
> +       struct drm_crtc *crtc;
> +
> +       if (pipe < 0 || pipe >= priv->num_crtcs) {
> +               DRM_ERROR("Invalid crtc %d\n", pipe);
> +               return -EINVAL;
> +       }
> +
> +       crtc = priv->crtcs[pipe];
> +       if (!crtc) {
> +               DRM_ERROR("Invalid crtc %d\n", pipe);
> +               return -EINVAL;
> +       }
> +
> +       return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
> +                                                    vblank_time, flags,
> +                                                    &crtc->mode);
> +}
> +
> +static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
> +{
> +       struct msm_drm_private *priv = dev->dev_private;
> +       struct drm_crtc *crtc;
> +       struct drm_encoder *encoder;
> +
> +       if (pipe < 0 || pipe >= priv->num_crtcs)
> +               return 0;
> +
> +       crtc = priv->crtcs[pipe];
> +       if (!crtc)
> +               return 0;
> +
> +       encoder = get_encoder_from_crtc(crtc);
> +       if (!encoder)
> +               return 0;
> +
> +       return mdp5_encoder_get_framecount(encoder);
> +}
> +
>  struct msm_kms *mdp5_kms_init(struct drm_device *dev)
>  {
>         struct platform_device *pdev = dev->platformdev;
> @@ -590,6 +711,8 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
>                                 !config->hw->intf.base[i])
>                         continue;
>                 mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
> +
> +               mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3);
>         }
>         mdp5_disable(mdp5_kms);
>         mdelay(16);
> @@ -635,6 +758,12 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
>         dev->mode_config.max_width = config->hw->lm.max_width;
>         dev->mode_config.max_height = config->hw->lm.max_height;
>
> +       dev->driver->get_vblank_timestamp = mdp5_get_vblank_timestamp;
> +       dev->driver->get_scanout_position = mdp5_get_scanoutpos;
> +       dev->driver->get_vblank_counter = mdp5_get_vblank_counter;
> +       dev->max_vblank_count = 0xffffffff;
> +       dev->vblank_disable_immediate = true;
> +
>         return kms;
>
>  fail:
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
> index 84f65d4..00730ba 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
> @@ -222,6 +222,8 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
>                 struct mdp5_interface *intf, struct mdp5_ctl *ctl);
>  int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
>                                         struct drm_encoder *slave_encoder);
> +int mdp5_encoder_get_linecount(struct drm_encoder *encoder);
> +u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder);
>
>  #ifdef CONFIG_DRM_MSM_DSI
>  struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> hosted by The Linux Foundation
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH] drm/msm/mdp5: high precision vblank timestamp support
  2015-10-27  0:03 ` Rob Clark
@ 2015-10-27  5:16   ` Archit Taneja
  0 siblings, 0 replies; 3+ messages in thread
From: Archit Taneja @ 2015-10-27  5:16 UTC (permalink / raw
  To: Rob Clark; +Cc: linux-arm-msm, dri-devel@lists.freedesktop.org



On 10/27/2015 05:33 AM, Rob Clark wrote:
> On Mon, Oct 26, 2015 at 5:54 AM, Archit Taneja <architt@codeaurora.org> wrote:
>> MDP5 has line count and frame count registers for each interface. Enable
>> these counters and use them to implement the get_vblank_timestamp drm
>> driver op.
>>
>> The line counter starts with the value 1 at the beginning of the VSYNC
>> pulse and ends with value VTOTAL at the end of VFP. This value is used
>> to determine whether we're in blanking period or not, and an adjusted
>> value of this counter is used to get vpos as expected by
>> get_scanout_position. Since there is no way to calculate hpos, we always
>> set it to 0.
>
> What are the odds that mdp(n!=5) could support the same?  If/when that
> ever happens I could see making some of this helpers to duplicate a
> bit less in mdpN backend.. but I guess also fine to cross that bridge
> when we come to it.  Other than that, lgtm, thanks

The MDP4 line counter only loops within the active region, making it 
sort of ineffective. That's the main reason why I didn't attempt to 
implement it for mdp4.

There seems to be a 12 bit frame counter available to implement a
vblank counter, but without the line counter, I'm not sure if that'll
be any better than using the software vblank counter.

Archit

>
> BR,
> -R
>
>> Signed-off-by: Archit Taneja <architt@codeaurora.org>
>> ---
>>   drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c |  18 ++++
>>   drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c     | 129 ++++++++++++++++++++++++++++
>>   drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h     |   2 +
>>   3 files changed, 149 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
>> index c9e32b0..a019656 100644
>> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
>> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
>> @@ -293,6 +293,24 @@ static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
>>          .enable = mdp5_encoder_enable,
>>   };
>>
>> +int mdp5_encoder_get_linecount(struct drm_encoder *encoder)
>> +{
>> +       struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
>> +       struct mdp5_kms *mdp5_kms = get_kms(encoder);
>> +       int intf = mdp5_encoder->intf.num;
>> +
>> +       return mdp5_read(mdp5_kms, REG_MDP5_INTF_LINE_COUNT(intf));
>> +}
>> +
>> +u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder)
>> +{
>> +       struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
>> +       struct mdp5_kms *mdp5_kms = get_kms(encoder);
>> +       int intf = mdp5_encoder->intf.num;
>> +
>> +       return mdp5_read(mdp5_kms, REG_MDP5_INTF_FRAME_COUNT(intf));
>> +}
>> +
>>   int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
>>                                          struct drm_encoder *slave_encoder)
>>   {
>> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
>> index b532faa..e115318 100644
>> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
>> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
>> @@ -468,6 +468,127 @@ static int get_clk(struct platform_device *pdev, struct clk **clkp,
>>          return 0;
>>   }
>>
>> +static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc)
>> +{
>> +       struct drm_device *dev = crtc->dev;
>> +       struct drm_encoder *encoder;
>> +
>> +       drm_for_each_encoder(encoder, dev)
>> +               if (encoder->crtc == crtc)
>> +                       return encoder;
>> +
>> +       return NULL;
>> +}
>> +
>> +static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
>> +                              unsigned int flags, int *vpos, int *hpos,
>> +                              ktime_t *stime, ktime_t *etime,
>> +                              const struct drm_display_mode *mode)
>> +{
>> +       struct msm_drm_private *priv = dev->dev_private;
>> +       struct drm_crtc *crtc;
>> +       struct drm_encoder *encoder;
>> +       int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
>> +       int ret = 0;
>> +
>> +       crtc = priv->crtcs[pipe];
>> +       if (!crtc) {
>> +               DRM_ERROR("Invalid crtc %d\n", pipe);
>> +               return 0;
>> +       }
>> +
>> +       encoder = get_encoder_from_crtc(crtc);
>> +       if (!encoder) {
>> +               DRM_ERROR("no encoder found for crtc %d\n", pipe);
>> +               return 0;
>> +       }
>> +
>> +       ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
>> +
>> +       vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
>> +       vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
>> +
>> +       /*
>> +        * the line counter is 1 at the start of the VSYNC pulse and VTOTAL at
>> +        * the end of VFP. Translate the porch values relative to the line
>> +        * counter positions.
>> +        */
>> +
>> +       vactive_start = vsw + vbp + 1;
>> +
>> +       vactive_end = vactive_start + mode->crtc_vdisplay;
>> +
>> +       /* last scan line before VSYNC */
>> +       vfp_end = mode->crtc_vtotal;
>> +
>> +       if (stime)
>> +               *stime = ktime_get();
>> +
>> +       line = mdp5_encoder_get_linecount(encoder);
>> +
>> +       if (line < vactive_start) {
>> +               line -= vactive_start;
>> +               ret |= DRM_SCANOUTPOS_IN_VBLANK;
>> +       } else if (line > vactive_end) {
>> +               line = line - vfp_end - vactive_start;
>> +               ret |= DRM_SCANOUTPOS_IN_VBLANK;
>> +       } else {
>> +               line -= vactive_start;
>> +       }
>> +
>> +       *vpos = line;
>> +       *hpos = 0;
>> +
>> +       if (etime)
>> +               *etime = ktime_get();
>> +
>> +       return ret;
>> +}
>> +
>> +static int mdp5_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
>> +                                    int *max_error,
>> +                                    struct timeval *vblank_time,
>> +                                    unsigned flags)
>> +{
>> +       struct msm_drm_private *priv = dev->dev_private;
>> +       struct drm_crtc *crtc;
>> +
>> +       if (pipe < 0 || pipe >= priv->num_crtcs) {
>> +               DRM_ERROR("Invalid crtc %d\n", pipe);
>> +               return -EINVAL;
>> +       }
>> +
>> +       crtc = priv->crtcs[pipe];
>> +       if (!crtc) {
>> +               DRM_ERROR("Invalid crtc %d\n", pipe);
>> +               return -EINVAL;
>> +       }
>> +
>> +       return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
>> +                                                    vblank_time, flags,
>> +                                                    &crtc->mode);
>> +}
>> +
>> +static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
>> +{
>> +       struct msm_drm_private *priv = dev->dev_private;
>> +       struct drm_crtc *crtc;
>> +       struct drm_encoder *encoder;
>> +
>> +       if (pipe < 0 || pipe >= priv->num_crtcs)
>> +               return 0;
>> +
>> +       crtc = priv->crtcs[pipe];
>> +       if (!crtc)
>> +               return 0;
>> +
>> +       encoder = get_encoder_from_crtc(crtc);
>> +       if (!encoder)
>> +               return 0;
>> +
>> +       return mdp5_encoder_get_framecount(encoder);
>> +}
>> +
>>   struct msm_kms *mdp5_kms_init(struct drm_device *dev)
>>   {
>>          struct platform_device *pdev = dev->platformdev;
>> @@ -590,6 +711,8 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
>>                                  !config->hw->intf.base[i])
>>                          continue;
>>                  mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
>> +
>> +               mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3);
>>          }
>>          mdp5_disable(mdp5_kms);
>>          mdelay(16);
>> @@ -635,6 +758,12 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
>>          dev->mode_config.max_width = config->hw->lm.max_width;
>>          dev->mode_config.max_height = config->hw->lm.max_height;
>>
>> +       dev->driver->get_vblank_timestamp = mdp5_get_vblank_timestamp;
>> +       dev->driver->get_scanout_position = mdp5_get_scanoutpos;
>> +       dev->driver->get_vblank_counter = mdp5_get_vblank_counter;
>> +       dev->max_vblank_count = 0xffffffff;
>> +       dev->vblank_disable_immediate = true;
>> +
>>          return kms;
>>
>>   fail:
>> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
>> index 84f65d4..00730ba 100644
>> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
>> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
>> @@ -222,6 +222,8 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
>>                  struct mdp5_interface *intf, struct mdp5_ctl *ctl);
>>   int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
>>                                          struct drm_encoder *slave_encoder);
>> +int mdp5_encoder_get_linecount(struct drm_encoder *encoder);
>> +u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder);
>>
>>   #ifdef CONFIG_DRM_MSM_DSI
>>   struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
>> --
>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
>> hosted by The Linux Foundation
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum, hosted by The Linux Foundation

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

end of thread, other threads:[~2015-10-27  5:16 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-26  9:54 [PATCH] drm/msm/mdp5: high precision vblank timestamp support Archit Taneja
2015-10-27  0:03 ` Rob Clark
2015-10-27  5:16   ` Archit Taneja

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 read-only IMAP folder(s) and NNTP newsgroup(s).