All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] drm/nouveau: Use drm_vblank_count_and_time() for pageflip completion events.
@ 2012-04-25 22:26 Lucas Stach
       [not found] ` <1335392782-2141-1-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
  0 siblings, 1 reply; 6+ messages in thread
From: Lucas Stach @ 2012-04-25 22:26 UTC (permalink / raw)
  To: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW; +Cc: Ben Skeggs, Mario Kleiner

From: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>

Emit kms pageflip completion events with proper vblank count
and timestamp for the vblank interval in which the pageflip
completed. This makes the timestamps and counts consistent with
what the OML_sync_control spec defines.

v2 Lucas Stach: rebased on top of nouveau tree and resolved trivial
conflict.

Signed-off-by: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>

Conflicts:

	drivers/gpu/drm/nouveau/nouveau_display.c
---
 drivers/gpu/drm/nouveau/nouveau_display.c |   29 +++++++++++++++++++++++------
 drivers/gpu/drm/nouveau/nouveau_drv.h     |    1 +
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 71379f8..2c0f415 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -504,7 +504,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	*s = (struct nouveau_page_flip_state)
 		{ { }, event, nouveau_crtc(crtc)->index,
 		  fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y,
-		  new_bo->bo.offset };
+		  new_bo->bo.offset, crtc->framedur_ns };
 
 	/* Choose the channel the flip will be handled in */
 	chan = nouveau_fence_channel(new_bo->bo.sync_obj);
@@ -550,6 +550,9 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
 	struct drm_device *dev = chan->dev;
 	struct nouveau_page_flip_state *s;
 	unsigned long flags;
+	struct timeval tnow, tvbl;
+
+	do_gettimeofday(&tnow);
 
 	spin_lock_irqsave(&dev->event_lock, flags);
 
@@ -563,12 +566,26 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
 			     struct nouveau_page_flip_state, head);
 	if (s->event) {
 		struct drm_pending_vblank_event *e = s->event;
-		struct timeval now;
 
-		do_gettimeofday(&now);
-		e->event.sequence = 0;
-		e->event.tv_sec = now.tv_sec;
-		e->event.tv_usec = now.tv_usec;
+		e->event.sequence = drm_vblank_count_and_time(dev, s->crtc, &tvbl);
+
+		/* Called before vblank count and timestamp have
+		 * been updated for the vblank interval of flip
+		 * completion? If so, need to increment vblank count and
+		 * add one videorefresh duration to returned timestamp
+		 * to account for this. We assume this happened if we
+		 * get called over 0.9 frame durations after the last
+		 * timestamped vblank.
+		 */
+		if (10 * (timeval_to_ns(&tnow) - timeval_to_ns(&tvbl)) >
+		     9 * s->framedur_ns) {
+			e->event.sequence++;
+			tvbl = ns_to_timeval(timeval_to_ns(&tvbl) +
+			s->framedur_ns);
+		}
+
+		e->event.tv_sec = tvbl.tv_sec;
+		e->event.tv_usec = tvbl.tv_usec;
 		list_add_tail(&e->base.link, &e->base.file_priv->event_list);
 		wake_up_interruptible(&e->base.file_priv->event_wait);
 	}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index ab9f9e0..ba10ad7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -203,6 +203,7 @@ struct nouveau_page_flip_state {
 	struct drm_pending_vblank_event *event;
 	int crtc, bpp, pitch, x, y;
 	uint64_t offset;
+	s64 framedur_ns;
 };
 
 enum nouveau_channel_mutex_class {
-- 
1.7.10

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

* [PATCH 2/2] drm/nouveau: implement precise vblank timestamping
       [not found] ` <1335392782-2141-1-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
@ 2012-04-25 22:26   ` Lucas Stach
       [not found]     ` <1335392782-2141-2-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
  0 siblings, 1 reply; 6+ messages in thread
From: Lucas Stach @ 2012-04-25 22:26 UTC (permalink / raw)
  To: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW; +Cc: Ben Skeggs, Mario Kleiner

This patch implements the driver hooks needed for precise vblank
timestamping. This is a complementary patch to Mario Kleiner's
patches to improve swap scheduling. With the complete
patchset applied nouveau will be able to provide correct and
precise pageflip timestamps (compliant to OML_sync_control spec)

v2: - Rebase on top of nouveau tree and update to reflect Ben's
      review feedback.

v3: - Split nv04+ and nv50+ paths into separate functions.
    - Do not advertise precise vblank timestamping on nvd9+,
      as it's not confirmed to work and the nv50 codepath may
      not work due to moved regs.

Kudos to Mario for his many helpful comments and testing.

Signed-off-by: Lucas Stach <dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
Reviewed-by: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>
Tested-by: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>
---
 drivers/gpu/drm/nouveau/nouveau_display.c |   25 ++++++++++
 drivers/gpu/drm/nouveau/nouveau_reg.h     |    9 +++-
 drivers/gpu/drm/nouveau/nv04_display.c    |   55 ++++++++++++++++++++++
 drivers/gpu/drm/nouveau/nv50_crtc.c       |   19 ++++++++
 drivers/gpu/drm/nouveau/nv50_display.c    |   71 +++++++++++++++++++++++++++++
 drivers/gpu/drm/nouveau/nvreg.h           |    1 +
 6 files changed, 179 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 2c0f415..810ba72 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -258,6 +258,27 @@ nouveau_display_fini(struct drm_device *dev)
 }
 
 int
+nouveau_get_vblank_timestamp(struct drm_device *dev, int crtc,
+			     int *max_error, struct timeval *vblank_time,
+			     unsigned flags)
+{
+	struct drm_crtc *drmcrtc;
+
+	if (crtc < 0 || crtc >= dev->num_crtcs) {
+		DRM_ERROR("Invalid crtc %d\n", crtc);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(drmcrtc, &dev->mode_config.crtc_list, head) {
+		if(nouveau_crtc(drmcrtc)->index == crtc)
+			break;
+	}
+
+	return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
+				vblank_time, flags, drmcrtc);
+}
+
+int
 nouveau_display_create(struct drm_device *dev)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -327,6 +348,10 @@ nouveau_display_create(struct drm_device *dev)
 	if (ret)
 		goto disp_create_err;
 
+	if (dev->driver->get_scanout_position)
+		dev->driver->get_vblank_timestamp =
+		nouveau_get_vblank_timestamp;
+
 	if (dev->mode_config.num_crtc) {
 		ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
 		if (ret)
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 43a96b9..0ec1945 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -762,7 +762,7 @@
 #define NV50_PDISPLAY_CRTC_CLOCK                                     0x00610ad0
 #define NV50_PDISPLAY_CRTC_COLOR_CTRL                                0x00610ae0
 #define NV50_PDISPLAY_CRTC_SYNC_START_TO_BLANK_END                   0x00610ae8
-#define NV50_PDISPLAY_CRTC_MODE_UNK1                                 0x00610af0
+#define NV50_PDISPLAY_CRTC_VBL_START                                 0x00610af0
 #define NV50_PDISPLAY_CRTC_DISPLAY_TOTAL                             0x00610af8
 #define NV50_PDISPLAY_CRTC_SYNC_DURATION                             0x00610b00
 #define NV50_PDISPLAY_CRTC_MODE_UNK2                                 0x00610b08
@@ -800,6 +800,13 @@
 #define NV50_PDISPLAY_SOR_CLK                                        0x00614000
 #define NV50_PDISPLAY_SOR_CLK_CTRL2(i)                  ((i) * 0x800 + 0x614300)
 
+#define NV50_PDISPLAY_CRTC_STAT_VERT(i0)		       (0x00616340 + 0x800*(i0))
+#define NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK		0x0000ffff
+#define NV50_PDISPLAY_CRTC_STAT_VERT_VBLANK_COUNT__MASK		0xffff0000
+#define NV50_PDISPLAY_CRTC_STAT_VERT_VBLANK_COUNT__SHIFT	16
+#define NV50_PDISPLAY_CRTC_STAT_HORZ(i0)		       (0x00616344 + 0x800*(i0))
+#define NV50_PDISPLAY_CRTC_STAT_HORZ_HLINE__MASK		0x0000ffff
+
 #define NV50_PDISPLAY_VGACRTC(r)                                ((r) + 0x619400)
 
 #define NV50_PDISPLAY_DAC                                            0x0061a000
diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c
index 7047d37..2622953 100644
--- a/drivers/gpu/drm/nouveau/nv04_display.c
+++ b/drivers/gpu/drm/nouveau/nv04_display.c
@@ -26,6 +26,7 @@
 #include "drm.h"
 #include "drm_crtc_helper.h"
 
+#include "nouveau_crtc.h"
 #include "nouveau_drv.h"
 #include "nouveau_fb.h"
 #include "nouveau_hw.h"
@@ -35,6 +36,58 @@
 static void nv04_vblank_crtc0_isr(struct drm_device *);
 static void nv04_vblank_crtc1_isr(struct drm_device *);
 
+int
+nv04_display_scanoutpos_get(struct drm_device *dev, int crtc,
+		            int *vpos, int *hpos)
+{
+	int vline, ret = 0;
+	u32 vbl_start, vbl_end;
+	struct drm_crtc *drmcrtc;
+
+	if (crtc < 0 || crtc >= dev->num_crtcs) {
+		DRM_ERROR("Invalid crtc %d\n", crtc);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(drmcrtc, &dev->mode_config.crtc_list, head) {
+		if (nouveau_crtc(drmcrtc)->index == crtc)
+			break;
+	}
+
+	/* get vsync area from PRAMDAC */
+	vbl_start = NVReadRAMDAC(dev, crtc, NV_PRAMDAC_FP_VDISPLAY_END)
+		    & 0xffff;
+	vbl_end = (NVReadRAMDAC(dev, crtc, NV_PRAMDAC_FP_VTOTAL)
+		   & 0xffff) + 1;
+
+	/* get current scanout position from PCRTC */
+	vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0xffff;
+
+	/*
+	 * vline == 0 could be invalid:
+	 * Some gpu's get stuck on that value inside vblank. Try again
+	 * after one scanline duration, if it still reads 0 give up.
+	 */
+	if (vline == 0) {
+		ndelay(drmcrtc->linedur_ns & 0xffff);
+		vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0xffff;
+	}
+
+	if (vline > 0)
+		ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
+
+	/* are we in vblank? if yes: do neg countdown */
+	if ((vline >= vbl_start) && (vline < vbl_end)) {
+		ret |= DRM_SCANOUTPOS_INVBL;
+		vline -= vbl_end;
+	}
+
+	*vpos = vline;
+	*hpos = 0; /* don't use hline as it's unreliable */
+
+	return ret;
+}
+
 static void
 nv04_display_store_initial_head_owner(struct drm_device *dev)
 {
@@ -179,6 +232,8 @@ nv04_display_create(struct drm_device *dev)
 		func->save(encoder);
 	}
 
+	dev->driver->get_scanout_position = nv04_display_scanoutpos_get;
+
 	nouveau_irq_register(dev, 24, nv04_vblank_crtc0_isr);
 	nouveau_irq_register(dev, 25, nv04_vblank_crtc1_isr);
 	return 0;
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index e021b1c..0652675 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -530,6 +530,25 @@ static bool
 nv50_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
 		     struct drm_display_mode *adjusted_mode)
 {
+	/* crtc_xxx fields are needed by drm core. Init them with the
+	 * settings we actually use for mode programming. */
+	adjusted_mode->synth_clock = adjusted_mode->clock;
+	adjusted_mode->crtc_hdisplay = adjusted_mode->hdisplay;
+	adjusted_mode->crtc_hblank_start = 0;
+	adjusted_mode->crtc_hblank_end = 0;
+	adjusted_mode->crtc_hsync_start = adjusted_mode->hsync_start;
+	adjusted_mode->crtc_hsync_end = adjusted_mode->hsync_end;
+	adjusted_mode->crtc_htotal = adjusted_mode->htotal;
+	adjusted_mode->crtc_hskew = adjusted_mode->hskew;
+	adjusted_mode->crtc_vdisplay = adjusted_mode->vdisplay;
+	adjusted_mode->crtc_vblank_start = 0;
+	adjusted_mode->crtc_vblank_end = 0;
+	adjusted_mode->crtc_vsync_start = adjusted_mode->vsync_start;
+	adjusted_mode->crtc_vsync_end = adjusted_mode->vsync_end;
+	adjusted_mode->crtc_vtotal = adjusted_mode->vtotal;
+	adjusted_mode->crtc_hadjusted = 0;
+	adjusted_mode->crtc_vadjusted = 0;
+
 	return true;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index b526e3f..86042f9 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -37,6 +37,75 @@
 static void nv50_display_isr(struct drm_device *);
 static void nv50_display_bh(unsigned long);
 
+int
+nv50_display_scanoutpos_get(struct drm_device *dev, int crtc,
+		            int *vpos, int *hpos)
+{
+	int vline, hline, ret = 0;
+	u32 vbias, hbias, reg, vbl_start, vbl_end;
+	struct drm_crtc *drmcrtc;
+
+	if (crtc < 0 || crtc >= dev->num_crtcs) {
+		DRM_ERROR("Invalid crtc %d\n", crtc);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(drmcrtc, &dev->mode_config.crtc_list, head) {
+		if (nouveau_crtc(drmcrtc)->index == crtc)
+			break;
+	}
+
+	/* get vsync and hsync area */
+	reg = nv_rd32(dev, NV50_PDISPLAY_CRTC_C(crtc,
+	                   SYNC_START_TO_BLANK_END));
+	vbias = (reg >> 16) & 0xffff;
+	hbias = reg & 0xffff;
+
+	/* get vertical display size including bias as vbl_start
+	 * and vtotal as vbl_end */
+	vbl_start = (nv_rd32(dev, NV50_PDISPLAY_CRTC_C(crtc,
+	                          VBL_START)) >> 16) & 0xffff;
+	vbl_end = (nv_rd32(dev, NV50_PDISPLAY_CRTC_C(crtc,
+	                        DISPLAY_TOTAL)) >> 16) & 0xffff;
+
+	/* get current scanout position from PDISPLAY */
+	vline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_VERT(crtc))
+	                & NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK;
+
+	/*
+	 * vline == 0 could be invalid:
+	 * Some gpu's get stuck on that value inside vblank. Try again
+	 * after one scanline duration, if it still reads 0 give up.
+	 */
+	if (vline == 0) {
+		ndelay(drmcrtc->linedur_ns & 0xffff);
+		vline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_VERT(crtc))
+		        & NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK;
+	}
+
+	hline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_HORZ(crtc))
+	                & NV50_PDISPLAY_CRTC_STAT_HORZ_HLINE__MASK;
+
+	if ((vline > 0) && (vline < vbl_end))
+		ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
+
+	if ((vline >= vbl_start) || (vline < vbias)) {
+		/* we are in vblank so do a neg countdown */
+		ret |= DRM_SCANOUTPOS_INVBL;
+		vline -= (vline < vbias) ? vbias : (vbl_end + vbias);
+		hline -= hbias;
+	} else {
+		/* apply corrective offset */
+		vline -= vbias;
+		hline -= hbias;
+	}
+
+	*vpos = vline;
+	*hpos = hline;
+
+	return ret;
+}
+
 static inline int
 nv50_sor_nr(struct drm_device *dev)
 {
@@ -411,6 +480,8 @@ nv50_display_create(struct drm_device *dev)
 		return ret;
 	}
 
+	dev->driver->get_scanout_position = nv50_display_scanoutpos_get;
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h
index bbfb1a6..e8281c4 100644
--- a/drivers/gpu/drm/nouveau/nvreg.h
+++ b/drivers/gpu/drm/nouveau/nvreg.h
@@ -172,6 +172,7 @@
 #define NV_PCRTC_834					0x00600834
 #define NV_PCRTC_850					0x00600850
 #define NV_PCRTC_ENGINE_CTRL				0x00600860
+#define NV_PCRTC_STAT(i0)			(0x00600868 + 0x2000*(i0))
 #	define NV_CRTC_FSEL_I2C					(1 << 4)
 #	define NV_CRTC_FSEL_OVERLAY				(1 << 12)
 
-- 
1.7.10

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

* Re: [PATCH 2/2] drm/nouveau: implement precise vblank timestamping
       [not found]     ` <1335392782-2141-2-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
@ 2012-04-26 21:25       ` Maarten Maathuis
       [not found]         ` <CAGZ4FEQkr9jt6cpius9DDrk_oPiQehxNnGV_UBBqCzqZomc-ag-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 6+ messages in thread
From: Maarten Maathuis @ 2012-04-26 21:25 UTC (permalink / raw)
  To: Lucas Stach
  Cc: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Ben Skeggs, Mario Kleiner

It seems a bit strange to go in between a register and defines that
probably belong to that register.

On Thu, Apr 26, 2012 at 12:26 AM, Lucas Stach <dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org> wrote:
>  #define NV_PCRTC_ENGINE_CTRL                           0x00600860
> +#define NV_PCRTC_STAT(i0)                      (0x00600868 + 0x2000*(i0))
>  #      define NV_CRTC_FSEL_I2C                                 (1 << 4)
>  #      define NV_CRTC_FSEL_OVERLAY                             (1 << 12)



-- 
Far away from the primal instinct, the song seems to fade away, the
river get wider between your thoughts and the things we do and say.

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

* Re: [PATCH 2/2] drm/nouveau: implement precise vblank timestamping
       [not found]         ` <CAGZ4FEQkr9jt6cpius9DDrk_oPiQehxNnGV_UBBqCzqZomc-ag-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-04-26 21:31           ` Lucas Stach
  0 siblings, 0 replies; 6+ messages in thread
From: Lucas Stach @ 2012-04-26 21:31 UTC (permalink / raw)
  To: Maarten Maathuis
  Cc: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Ben Skeggs, Kleiner,
	Mario-CC+yJ3UmIYqDUpFQwHEjaQ

Hi Maarten,

Am Donnerstag, den 26.04.2012, 23:25 +0200 schrieb Maarten Maathuis:
> It seems a bit strange to go in between a register and defines that
> probably belong to that register.
> 
Yes, you are right. Thanks for catching this. I will fix this up, but
will wait for Ben's comments and/or other review feedback before
spamming the list with just another version of this patch.

-- Lucas
> On Thu, Apr 26, 2012 at 12:26 AM, Lucas Stach <dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org> wrote:
> >  #define NV_PCRTC_ENGINE_CTRL                           0x00600860
> > +#define NV_PCRTC_STAT(i0)                      (0x00600868 + 0x2000*(i0))
> >  #      define NV_CRTC_FSEL_I2C                                 (1 << 4)
> >  #      define NV_CRTC_FSEL_OVERLAY                             (1 << 12)
> 
> 
> 

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

* [PATCH 2/2] drm/nouveau: implement precise vblank timestamping
       [not found]   ` <1329722667-2240-1-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
@ 2012-02-20  7:24     ` Lucas Stach
  0 siblings, 0 replies; 6+ messages in thread
From: Lucas Stach @ 2012-02-20  7:24 UTC (permalink / raw)
  To: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: bskeggs-H+wXaHxf7aLQT0dZR+AlfA, mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ

This patch implements the driver hooks needed for precise vblank
timestamping. This is a complementary patch to Mario Kleiner's
patches to improve swap scheduling. With the complete
patchset applied nouveau will be able to provide correct and
precise pageflip timestamps (compliant to OML_sync_control spec)

v2: Rebase on top of nouveau tree and update to reflect Ben's
review feedback.

Kudos to Mario for his many helpful comments and testing.

Signed-off-by: Lucas Stach <dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
Reviewed-by: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>
Tested-by: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>
---
 drivers/gpu/drm/nouveau/nouveau_display.c |  124 +++++++++++++++++++++++++++++
 drivers/gpu/drm/nouveau/nouveau_drv.c     |    2 +
 drivers/gpu/drm/nouveau/nouveau_drv.h     |    5 +
 drivers/gpu/drm/nouveau/nouveau_reg.h     |    9 ++-
 drivers/gpu/drm/nouveau/nv50_crtc.c       |   19 +++++
 drivers/gpu/drm/nouveau/nvreg.h           |    1 +
 6 files changed, 159 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 818cfc9..b0cae44 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -635,3 +635,127 @@ nouveau_display_dumb_map_offset(struct drm_file *file_priv,
 
 	return -ENOENT;
 }
+
+int
+nouveau_get_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	int vline, hline, ret = 0;
+	u32 vbias, hbias, reg, vbl_start, vbl_end;
+	struct drm_crtc *drmcrtc;
+
+	if (crtc < 0 || crtc >= dev->num_crtcs) {
+		DRM_ERROR("Invalid crtc %d\n", crtc);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(drmcrtc, &dev->mode_config.crtc_list, head) {
+		if (nouveau_crtc(drmcrtc)->index == crtc)
+			/* stop if we have found crtc with matching index */
+			break;
+	}
+
+	if (dev_priv->card_type >= NV_50) {
+		/* get vsync and hsync area */
+		reg = nv_rd32(dev, NV50_PDISPLAY_CRTC_C(crtc,
+		                   SYNC_START_TO_BLANK_END));
+		vbias = (reg >> 16) & 0xffff;
+		hbias = reg & 0xffff;
+
+		/* get vertical display size including bias as vbl_start
+		 * and vtotal as vbl_end */
+		vbl_start = (nv_rd32(dev, NV50_PDISPLAY_CRTC_C(crtc,
+		                          VBL_START)) >> 16) & 0xffff;
+		vbl_end = (nv_rd32(dev, NV50_PDISPLAY_CRTC_C(crtc,
+		                        DISPLAY_TOTAL)) >> 16) & 0xffff;
+
+		/* get current scanout position from PDISPLAY */
+		vline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_VERT(crtc))
+		                & NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK;
+
+		/*
+		 * vline == 0 could be invalid:
+		 * Some gpu's get stuck on that value inside vblank. Try again
+		 * after one scanline duration, if it still reads 0 give up.
+		 */
+		if (vline == 0) {
+			ndelay(drmcrtc->linedur_ns & 0xffff);
+			vline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_VERT(crtc))
+			        & NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK;
+		}
+
+		hline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_HORZ(crtc))
+		                & NV50_PDISPLAY_CRTC_STAT_HORZ_HLINE__MASK;
+
+		if ((vline > 0) && (vline < vbl_end))
+			ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
+
+		if ((vline >= vbl_start) || (vline < vbias)) {
+			/* we are in vblank so do a neg countdown */
+			ret |= DRM_SCANOUTPOS_INVBL;
+			vline -= (vline < vbias) ? vbias : (vbl_end + vbias);
+			hline -= hbias;
+		} else {
+			/* apply corrective offset */
+			vline -= vbias;
+			hline -= hbias;
+		}
+	} else {
+		/* get vsync area from PRAMDAC */
+		vbl_start = NVReadRAMDAC(dev, crtc, NV_PRAMDAC_FP_VDISPLAY_END)
+		            & 0xffff;
+		vbl_end = (NVReadRAMDAC(dev, crtc, NV_PRAMDAC_FP_VTOTAL)
+			   & 0xffff) + 1;
+
+		/* get current scanout position from PCRTC */
+		vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0xffff;
+
+		/*
+		 * vline == 0 could be invalid:
+		 * Some gpu's get stuck on that value inside vblank. Try again
+		 * after one scanline duration, if it still reads 0 give up.
+		 */
+		if (vline == 0) {
+			ndelay(drmcrtc->linedur_ns & 0xffff);
+			vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0xffff;
+		}
+
+		if (vline > 0)
+			ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
+
+		/* are we in vblank? if yes: do neg countdown */
+		if ((vline >= vbl_start) && (vline < vbl_end)) {
+			ret |= DRM_SCANOUTPOS_INVBL;
+			vline -= vbl_end;
+		}
+
+		hline = 0; /* don't use hline as it's unreliable */
+	}
+
+	*vpos = vline;
+	*hpos = hline;
+
+	return ret;
+}
+
+int
+nouveau_get_vblank_timestamp(struct drm_device *dev, int crtc,
+			     int *max_error, struct timeval *vblank_time,
+			     unsigned flags)
+{
+	struct drm_crtc *drmcrtc;
+
+	if (crtc < 0 || crtc >= dev->num_crtcs) {
+		DRM_ERROR("Invalid crtc %d\n", crtc);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(drmcrtc, &dev->mode_config.crtc_list, head) {
+		if (nouveau_crtc(drmcrtc)->index == crtc)
+			/* stop if we have found crtc with matching index */
+			break;
+	}
+
+	return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
+				vblank_time, flags, drmcrtc);
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 4f2030b..4513bdf 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -427,6 +427,8 @@ static struct drm_driver driver = {
 	.get_vblank_counter = drm_vblank_count,
 	.enable_vblank = nouveau_vblank_enable,
 	.disable_vblank = nouveau_vblank_disable,
+	.get_vblank_timestamp = nouveau_get_vblank_timestamp,
+	.get_scanout_position = nouveau_get_scanoutpos,
 	.reclaim_buffers = drm_core_reclaim_buffers,
 	.ioctls = nouveau_ioctls,
 	.fops = &nouveau_driver_fops,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 72c015d..dd281fa 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -1523,6 +1523,11 @@ int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 			   struct drm_pending_vblank_event *event);
 int nouveau_finish_page_flip(struct nouveau_channel *,
 			     struct nouveau_page_flip_state *);
+int nouveau_get_scanoutpos(struct drm_device *dev, int crtc,
+                            int *vpos, int *hpos);
+int nouveau_get_vblank_timestamp(struct drm_device *dev, int crtc,
+				 int *max_error, struct timeval *vblank_time,
+				 unsigned flags);
 int nouveau_display_dumb_create(struct drm_file *, struct drm_device *,
 				struct drm_mode_create_dumb *args);
 int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *,
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 43a96b9..0ec1945 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -762,7 +762,7 @@
 #define NV50_PDISPLAY_CRTC_CLOCK                                     0x00610ad0
 #define NV50_PDISPLAY_CRTC_COLOR_CTRL                                0x00610ae0
 #define NV50_PDISPLAY_CRTC_SYNC_START_TO_BLANK_END                   0x00610ae8
-#define NV50_PDISPLAY_CRTC_MODE_UNK1                                 0x00610af0
+#define NV50_PDISPLAY_CRTC_VBL_START                                 0x00610af0
 #define NV50_PDISPLAY_CRTC_DISPLAY_TOTAL                             0x00610af8
 #define NV50_PDISPLAY_CRTC_SYNC_DURATION                             0x00610b00
 #define NV50_PDISPLAY_CRTC_MODE_UNK2                                 0x00610b08
@@ -800,6 +800,13 @@
 #define NV50_PDISPLAY_SOR_CLK                                        0x00614000
 #define NV50_PDISPLAY_SOR_CLK_CTRL2(i)                  ((i) * 0x800 + 0x614300)
 
+#define NV50_PDISPLAY_CRTC_STAT_VERT(i0)		       (0x00616340 + 0x800*(i0))
+#define NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK		0x0000ffff
+#define NV50_PDISPLAY_CRTC_STAT_VERT_VBLANK_COUNT__MASK		0xffff0000
+#define NV50_PDISPLAY_CRTC_STAT_VERT_VBLANK_COUNT__SHIFT	16
+#define NV50_PDISPLAY_CRTC_STAT_HORZ(i0)		       (0x00616344 + 0x800*(i0))
+#define NV50_PDISPLAY_CRTC_STAT_HORZ_HLINE__MASK		0x0000ffff
+
 #define NV50_PDISPLAY_VGACRTC(r)                                ((r) + 0x619400)
 
 #define NV50_PDISPLAY_DAC                                            0x0061a000
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index 701b927..7f72431 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -538,6 +538,25 @@ static bool
 nv50_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
 		     struct drm_display_mode *adjusted_mode)
 {
+	/* crtc_xxx fields are needed by drm core. Init them with the
+	 * settings we actually use for mode programming. */
+	adjusted_mode->synth_clock = adjusted_mode->clock;
+	adjusted_mode->crtc_hdisplay = adjusted_mode->hdisplay;
+	adjusted_mode->crtc_hblank_start = 0;
+	adjusted_mode->crtc_hblank_end = 0;
+	adjusted_mode->crtc_hsync_start = adjusted_mode->hsync_start;
+	adjusted_mode->crtc_hsync_end = adjusted_mode->hsync_end;
+	adjusted_mode->crtc_htotal = adjusted_mode->htotal;
+	adjusted_mode->crtc_hskew = adjusted_mode->hskew;
+	adjusted_mode->crtc_vdisplay = adjusted_mode->vdisplay;
+	adjusted_mode->crtc_vblank_start = 0;
+	adjusted_mode->crtc_vblank_end = 0;
+	adjusted_mode->crtc_vsync_start = adjusted_mode->vsync_start;
+	adjusted_mode->crtc_vsync_end = adjusted_mode->vsync_end;
+	adjusted_mode->crtc_vtotal = adjusted_mode->vtotal;
+	adjusted_mode->crtc_hadjusted = 0;
+	adjusted_mode->crtc_vadjusted = 0;
+
 	return true;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h
index bbfb1a6..e8281c4 100644
--- a/drivers/gpu/drm/nouveau/nvreg.h
+++ b/drivers/gpu/drm/nouveau/nvreg.h
@@ -172,6 +172,7 @@
 #define NV_PCRTC_834					0x00600834
 #define NV_PCRTC_850					0x00600850
 #define NV_PCRTC_ENGINE_CTRL				0x00600860
+#define NV_PCRTC_STAT(i0)			(0x00600868 + 0x2000*(i0))
 #	define NV_CRTC_FSEL_I2C					(1 << 4)
 #	define NV_CRTC_FSEL_OVERLAY				(1 << 12)
 
-- 
1.7.7.6

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

* [PATCH 2/2] drm/nouveau: implement precise vblank timestamping
       [not found]   ` <1329434903-19977-1-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
@ 2012-02-16 23:28     ` Lucas Stach
  0 siblings, 0 replies; 6+ messages in thread
From: Lucas Stach @ 2012-02-16 23:28 UTC (permalink / raw)
  To: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: bskeggs-H+wXaHxf7aLQT0dZR+AlfA, mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ

This patch implements the driver hooks needed for precise vblank
timestamping. This is a complementary patch to Mario Kleiner's
patches to improve swap scheduling. With the complete
patchset applied nouveau will be able to provide correct and
precise pageflip timestamps (compliant to OML_sync_control spec)

v2: Rebase on top of nouveau tree and update to reflect Ben's
review feedback.

Kudos to Mario for his many helpful comments and testing.

Signed-off-by: Lucas Stach <dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
Reviewed-by: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>
Tested-by: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>
---
 drivers/gpu/drm/nouveau/nouveau_display.c |  124 +++++++++++++++++++++++++++++
 drivers/gpu/drm/nouveau/nouveau_drv.c     |    2 +
 drivers/gpu/drm/nouveau/nouveau_drv.h     |    5 +
 drivers/gpu/drm/nouveau/nouveau_reg.h     |    9 ++-
 drivers/gpu/drm/nouveau/nv50_crtc.c       |   19 +++++
 drivers/gpu/drm/nouveau/nvreg.h           |    1 +
 6 files changed, 159 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 818cfc9..1f836cd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -635,3 +635,127 @@ nouveau_display_dumb_map_offset(struct drm_file *file_priv,
 
 	return -ENOENT;
 }
+
+int
+nouveau_get_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	int vline, hline, ret = 0;
+	u32 vbias, hbias, reg, vbl_start, vbl_end;
+	struct drm_crtc *drmcrtc;
+
+	if (crtc < 0 || crtc >= dev->num_crtcs) {
+		DRM_ERROR("Invalid crtc %d\n", crtc);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(drmcrtc, &dev->mode_config.crtc_list, head) {
+		if(nouveau_crtc(drmcrtc)->index == crtc)
+			/* stop if we have found crtc with matching index */
+			break;
+	}
+
+	if(dev_priv->card_type >= NV_50) {
+		/* get vsync and hsync area */
+		reg = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc,
+		                   SYNC_START_TO_BLANK_END));
+		vbias = (reg >> 16) & 0xffff;
+		hbias = reg & 0xffff;
+
+		/* get vertical display size including bias as vbl_start
+		 * and vtotal as vbl_end */
+		vbl_start = (nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc,
+		                          VBL_START)) >> 16) & 0xffff;
+		vbl_end = (nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc,
+		                        DISPLAY_TOTAL)) >> 16) & 0xffff;
+
+		/* get current scanout position from PDISPLAY */
+		vline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_VERT(crtc))
+		                & NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK;
+
+		/*
+		 * vline == 0 could be invalid:
+		 * Some gpu's get stuck on that value inside vblank. Try again
+		 * after one scanline duration, if it still reads 0 give up.
+		 */
+		if (vline == 0) {
+			ndelay(drmcrtc->linedur_ns & 0xffff);
+			vline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_VERT(crtc))
+			        & NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK;
+		}
+
+		hline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_HORZ(crtc))
+		                & NV50_PDISPLAY_CRTC_STAT_HORZ_HLINE__MASK;
+
+		if((vline > 0) && (vline < vbl_end))
+			ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
+
+		if((vline >= vbl_start) || (vline < vbias)) {
+			/* we are in vblank so do a neg countdown */
+			ret |= DRM_SCANOUTPOS_INVBL;
+			vline -= (vline < vbias) ? vbias : (vbl_end + vbias);
+			hline -= hbias;
+		} else {
+			/* apply corrective offset */
+			vline -= vbias;
+			hline -= hbias;
+		}
+	} else {
+		/* get vsync area from PRAMDAC */
+		vbl_start = NVReadRAMDAC(dev, crtc, NV_PRAMDAC_FP_VDISPLAY_END)
+		            & 0xffff;
+		vbl_end = (NVReadRAMDAC(dev, crtc, NV_PRAMDAC_FP_VTOTAL)
+			   & 0xffff) + 1;
+
+		/* get current scanout position from PCRTC */
+		vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0xffff;
+
+		/*
+		 * vline == 0 could be invalid:
+		 * Some gpu's get stuck on that value inside vblank. Try again
+		 * after one scanline duration, if it still reads 0 give up.
+		 */
+		if (vline == 0) {
+			ndelay(drmcrtc->linedur_ns & 0xffff);
+			vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0xffff;
+		}
+
+		if(vline > 0)
+			ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
+
+		/* are we in vblank? if yes: do neg countdown */
+		if((vline >= vbl_start) && (vline < vbl_end)) {
+			ret |= DRM_SCANOUTPOS_INVBL;
+			vline -= vbl_end;
+		}
+
+		hline = 0; /* don't use hline as it's unreliable */
+	}
+
+	*vpos = vline;
+	*hpos = hline;
+
+	return ret;
+}
+
+int
+nouveau_get_vblank_timestamp(struct drm_device *dev, int crtc,
+			     int *max_error, struct timeval *vblank_time,
+			     unsigned flags)
+{
+	struct drm_crtc *drmcrtc;
+
+	if (crtc < 0 || crtc >= dev->num_crtcs) {
+		DRM_ERROR("Invalid crtc %d\n", crtc);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(drmcrtc, &dev->mode_config.crtc_list, head) {
+		if(nouveau_crtc(drmcrtc)->index == crtc)
+			/* stop if we have found crtc with matching index */
+			break;
+	}
+
+	return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
+				vblank_time, flags, drmcrtc);
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 4f2030b..4513bdf 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -427,6 +427,8 @@ static struct drm_driver driver = {
 	.get_vblank_counter = drm_vblank_count,
 	.enable_vblank = nouveau_vblank_enable,
 	.disable_vblank = nouveau_vblank_disable,
+	.get_vblank_timestamp = nouveau_get_vblank_timestamp,
+	.get_scanout_position = nouveau_get_scanoutpos,
 	.reclaim_buffers = drm_core_reclaim_buffers,
 	.ioctls = nouveau_ioctls,
 	.fops = &nouveau_driver_fops,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 72c015d..dd281fa 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -1523,6 +1523,11 @@ int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 			   struct drm_pending_vblank_event *event);
 int nouveau_finish_page_flip(struct nouveau_channel *,
 			     struct nouveau_page_flip_state *);
+int nouveau_get_scanoutpos(struct drm_device *dev, int crtc,
+                            int *vpos, int *hpos);
+int nouveau_get_vblank_timestamp(struct drm_device *dev, int crtc,
+				 int *max_error, struct timeval *vblank_time,
+				 unsigned flags);
 int nouveau_display_dumb_create(struct drm_file *, struct drm_device *,
 				struct drm_mode_create_dumb *args);
 int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *,
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 43a96b9..0ec1945 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -762,7 +762,7 @@
 #define NV50_PDISPLAY_CRTC_CLOCK                                     0x00610ad0
 #define NV50_PDISPLAY_CRTC_COLOR_CTRL                                0x00610ae0
 #define NV50_PDISPLAY_CRTC_SYNC_START_TO_BLANK_END                   0x00610ae8
-#define NV50_PDISPLAY_CRTC_MODE_UNK1                                 0x00610af0
+#define NV50_PDISPLAY_CRTC_VBL_START                                 0x00610af0
 #define NV50_PDISPLAY_CRTC_DISPLAY_TOTAL                             0x00610af8
 #define NV50_PDISPLAY_CRTC_SYNC_DURATION                             0x00610b00
 #define NV50_PDISPLAY_CRTC_MODE_UNK2                                 0x00610b08
@@ -800,6 +800,13 @@
 #define NV50_PDISPLAY_SOR_CLK                                        0x00614000
 #define NV50_PDISPLAY_SOR_CLK_CTRL2(i)                  ((i) * 0x800 + 0x614300)
 
+#define NV50_PDISPLAY_CRTC_STAT_VERT(i0)		       (0x00616340 + 0x800*(i0))
+#define NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK		0x0000ffff
+#define NV50_PDISPLAY_CRTC_STAT_VERT_VBLANK_COUNT__MASK		0xffff0000
+#define NV50_PDISPLAY_CRTC_STAT_VERT_VBLANK_COUNT__SHIFT	16
+#define NV50_PDISPLAY_CRTC_STAT_HORZ(i0)		       (0x00616344 + 0x800*(i0))
+#define NV50_PDISPLAY_CRTC_STAT_HORZ_HLINE__MASK		0x0000ffff
+
 #define NV50_PDISPLAY_VGACRTC(r)                                ((r) + 0x619400)
 
 #define NV50_PDISPLAY_DAC                                            0x0061a000
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index 701b927..7f72431 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -538,6 +538,25 @@ static bool
 nv50_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
 		     struct drm_display_mode *adjusted_mode)
 {
+	/* crtc_xxx fields are needed by drm core. Init them with the
+	 * settings we actually use for mode programming. */
+	adjusted_mode->synth_clock = adjusted_mode->clock;
+	adjusted_mode->crtc_hdisplay = adjusted_mode->hdisplay;
+	adjusted_mode->crtc_hblank_start = 0;
+	adjusted_mode->crtc_hblank_end = 0;
+	adjusted_mode->crtc_hsync_start = adjusted_mode->hsync_start;
+	adjusted_mode->crtc_hsync_end = adjusted_mode->hsync_end;
+	adjusted_mode->crtc_htotal = adjusted_mode->htotal;
+	adjusted_mode->crtc_hskew = adjusted_mode->hskew;
+	adjusted_mode->crtc_vdisplay = adjusted_mode->vdisplay;
+	adjusted_mode->crtc_vblank_start = 0;
+	adjusted_mode->crtc_vblank_end = 0;
+	adjusted_mode->crtc_vsync_start = adjusted_mode->vsync_start;
+	adjusted_mode->crtc_vsync_end = adjusted_mode->vsync_end;
+	adjusted_mode->crtc_vtotal = adjusted_mode->vtotal;
+	adjusted_mode->crtc_hadjusted = 0;
+	adjusted_mode->crtc_vadjusted = 0;
+
 	return true;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h
index bbfb1a6..e8281c4 100644
--- a/drivers/gpu/drm/nouveau/nvreg.h
+++ b/drivers/gpu/drm/nouveau/nvreg.h
@@ -172,6 +172,7 @@
 #define NV_PCRTC_834					0x00600834
 #define NV_PCRTC_850					0x00600850
 #define NV_PCRTC_ENGINE_CTRL				0x00600860
+#define NV_PCRTC_STAT(i0)			(0x00600868 + 0x2000*(i0))
 #	define NV_CRTC_FSEL_I2C					(1 << 4)
 #	define NV_CRTC_FSEL_OVERLAY				(1 << 12)
 
-- 
1.7.7.6

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

end of thread, other threads:[~2012-04-26 21:31 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-25 22:26 [PATCH 1/2] drm/nouveau: Use drm_vblank_count_and_time() for pageflip completion events Lucas Stach
     [not found] ` <1335392782-2141-1-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
2012-04-25 22:26   ` [PATCH 2/2] drm/nouveau: implement precise vblank timestamping Lucas Stach
     [not found]     ` <1335392782-2141-2-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
2012-04-26 21:25       ` Maarten Maathuis
     [not found]         ` <CAGZ4FEQkr9jt6cpius9DDrk_oPiQehxNnGV_UBBqCzqZomc-ag-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-04-26 21:31           ` Lucas Stach
     [not found] <[Patches][nouveau/kms]: Precise Vblank and pageflip timestamping v2>
2012-02-20  7:24 ` [Patches][nouveau/kms]: Precise Vblank and pageflip timestamping v2 Lucas Stach
     [not found]   ` <1329722667-2240-1-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
2012-02-20  7:24     ` [PATCH 2/2] drm/nouveau: implement precise vblank timestamping Lucas Stach
     [not found] <[Patches][nouveau/kms]: Precise Vblank and pageflip timestamping>
2012-02-16 23:28 ` [Patches][nouveau/kms]: Precise Vblank and pageflip timestamping v2 Lucas Stach
     [not found]   ` <1329434903-19977-1-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
2012-02-16 23:28     ` [PATCH 2/2] drm/nouveau: implement precise vblank timestamping Lucas Stach

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.