: Precise Vblank and pageflip timestamping v2
Subsystems (3)
A message that is not in the archive (sent off-list or not yet received): [Patches][nouveau/kms]: Precise Vblank and pageflip timestamping
v2
PATCH 1/1 : Precise Vblank and pageflip timestamping v2
Just updated versions of the patches send by Mario Kleiner. This ones are rebased on top of the nouveau tree and updated according to the review feedback.
This time hopefully the right ones.
Regards,
Lucas
A message that is not in the archive (sent off-list or not yet received): 1329722667-2240-1-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org
PATCH 1/2 drm/nouveau: Use drm_vblank_count_and_time() for pageflip completion events.
From: Mario Kleiner <[email protected]>
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.
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(-)
drivers/gpu/drm/nouveau/nouveau_display.c +23 -6
@@ -496,7 +496,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);
@@ -542,6 +542,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);
@@ -555,12 +558,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); }
drivers/gpu/drm/nouveau/nouveau_drv.h +1 -0
@@ -205,6 +205,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 {
Signature · 1 line
1.7.7.6
PATCH 2/2 drm/nouveau: implement precise vblank timestamping
In reply to a message not in the archiveThis 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.
--- 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(-)
drivers/gpu/drm/nouveau/nouveau_display.c +124 -0
@@ -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); +}
drivers/gpu/drm/nouveau/nouveau_drv.c +2 -0
@@ -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,
drivers/gpu/drm/nouveau/nouveau_drv.h +5 -0
@@ -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 *,
drivers/gpu/drm/nouveau/nouveau_reg.h +8 -1
@@ -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
drivers/gpu/drm/nouveau/nv50_crtc.c +19 -0
@@ -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; }
drivers/gpu/drm/nouveau/nvreg.h +1 -0
@@ -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)
Signature · 1 line
1.7.7.6
Quoted 9 lines · Lucas Stach
Just updated versions of the patches send by Mario Kleiner. This ones are rebased on top of the nouveau tree and updated according to the review feedback.
This time hopefully the right ones.
Regards,
Lucas
Ben, thanks for the feedback. I've resteted the v2 of Lucas new reworked and rebased patches, everything fine and precise wrt. to timing precision.
For my personal education: Is my understanding correct that these registers are basically "double-buffered", and the NV50_PDISPLAY_CRTC_C macro accesses the current state, whereas the NV50_PDISPLAY_CRTC_P macro provides/sets the programmed values that will be latched into the _C registers at some later time, e.g., modeset?
thanks,
-mario
A message that is not in the archive (sent off-list or not yet received): F8CDD288-6434-4FDA-BC09-B7FB39E38650-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org
Quoted 22 lines · Mario Kleiner
Quoted 9 lines · Lucas Stach
Just updated versions of the patches send by Mario Kleiner. This ones are rebased on top of the nouveau tree and updated according to the review feedback.
This time hopefully the right ones.
Regards,
LucasBen, thanks for the feedback. I've resteted the v2 of Lucas new reworked and rebased patches, everything fine and precise wrt. to timing precision.
For my personal education: Is my understanding correct that these registers are basically "double-buffered", and the
NV50_PDISPLAY_CRTC_Cmacro accesses the current state, whereas theNV50_PDISPLAY_CRTC_Pmacro provides/sets the programmed values that will be latched into the _C registers at some later time, e.g., modeset?
Quoted 8 lines
thanks,
-mario_______________________________________________
Nouveau mailing list [email protected]
http://lists.freedesktop.org/mailman/listinfo/nouveau
The proposed registers show the value that has submitted (via the modesetting/display fifo), but they haven't been put into effect yet by the "update" command. The registers (both the current and proposed ones) are only intended for reading. At least that is my understanding, perhaps Ben can tell you more.
Signature · 2 lines
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.
A message that is not in the archive (sent off-list or not yet received): CAGZ4FETCDRqSDGobrtXJRsa6r6H8avB39LyGgdU3TFt7MdOqhg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org
Quoted 39 lines · Maarten Maathuis
Quoted 22 lines · Mario Kleiner
Quoted 9 lines · Lucas Stach
Just updated versions of the patches send by Mario Kleiner. This ones are rebased on top of the nouveau tree and updated according to the review feedback.
This time hopefully the right ones.
Regards,
LucasBen, thanks for the feedback. I've resteted the v2 of Lucas new reworked and rebased patches, everything fine and precise wrt. to timing precision.
For my personal education: Is my understanding correct that these registers are basically "double-buffered", and the
NV50_PDISPLAY_CRTC_Cmacro accesses the current state, whereas theNV50_PDISPLAY_CRTC_Pmacro provides/sets the programmed values that will be latched into the _C registers at some later time, e.g., modeset?Quoted 8 lines
thanks,
-mario_______________________________________________
Nouveau mailing list [email protected]
http://lists.freedesktop.org/mailman/listinfo/nouveauThe proposed registers show the value that has submitted (via the modesetting/display fifo), but they haven't been put into effect yet by the "update" command. The registers (both the current and proposed ones) are only intended for reading. At least that is my understanding, perhaps Ben can tell you more.
Quoted 3 lines
--
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.
That should be "have been submitted" not "has submitted".
Signature · 2 lines
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.