Re: [Nouveau] [PATCH 2/2] drm/nouveau: implement precise vblank timestamping
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 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) > > > ___ Nouveau mailing list Nouveau@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/nouveau
Re: [Nouveau] [PATCH 2/2] drm/nouveau: implement precise vblank timestamping
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 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. ___ Nouveau mailing list Nouveau@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/nouveau
[Nouveau] [PATCH 2/2] drm/nouveau: implement precise vblank timestamping
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 Reviewed-by: Mario Kleiner Tested-by: Mario Kleiner --- 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_CTRL0x00610ae0 #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_CLK0x00614000 #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 0x +#define NV50_PDISPLAY_CRTC_STAT_VERT_VBLANK_COUNT__MASK 0x +#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 0x + #define NV50_PDISPLAY_VGACRTC(r)((r) + 0x619400) #define NV50_PDISPLAY_DAC0x0061a000 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
[Nouveau] [PATCH 2/2] drm/nouveau: implement precise vblank timestamping
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 Reviewed-by: Mario Kleiner Tested-by: Mario Kleiner --- 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) & 0x; + hbias = reg & 0x; + + /* 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) & 0x; + vbl_end = (nv_rd32(dev, NV50_PDISPLAY_CRTC_C(crtc, + DISPLAY_TOTAL)) >> 16) & 0x; + + /* 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 & 0x); + 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) + & 0x; + vbl_end = (NVReadRAMDAC(dev, crtc, NV_PRAMDAC_FP_VTOTAL) + & 0x) + 1; + + /* get current scanout position from PCRTC */ + vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0x; + + /* +* 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 & 0x); + vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0x; +
[Nouveau] [PATCH 2/2] drm/nouveau: implement precise vblank timestamping
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 Reviewed-by: Mario Kleiner Tested-by: Mario Kleiner --- 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) & 0x; + hbias = reg & 0x; + + /* 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) & 0x; + vbl_end = (nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, + DISPLAY_TOTAL)) >> 16) & 0x; + + /* 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 & 0x); + 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) + & 0x; + vbl_end = (NVReadRAMDAC(dev, crtc, NV_PRAMDAC_FP_VTOTAL) + & 0x) + 1; + + /* get current scanout position from PCRTC */ + vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0x; + + /* +* 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 & 0x); + vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0x; +