Am 01.04.2016 um 11:51 schrieb Michel Dänzer: > From: Michel Dänzer <michel.daenzer at amd.com> > > When this flag is set, we program the hardware to execute the flip > during horizontal blank (i.e. for the next scanline) instead of during > vertical blank (i.e. for the next frame). > > Currently this is only supported on ASICs which have a page flip > completion interrupt (>= R600), and only if the use_pflipirq parameter > has value 2 (the default). > > Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
Reviewed-by: Christian König <christian.koenig at amd.com> > --- > drivers/gpu/drm/radeon/atombios_crtc.c | 24 +++++++++++------------- > drivers/gpu/drm/radeon/evergreen.c | 5 ++++- > drivers/gpu/drm/radeon/r100.c | 2 +- > drivers/gpu/drm/radeon/radeon.h | 5 +++-- > drivers/gpu/drm/radeon/radeon_asic.h | 9 +++++---- > drivers/gpu/drm/radeon/radeon_display.c | 6 +++++- > drivers/gpu/drm/radeon/rs600.c | 4 +++- > drivers/gpu/drm/radeon/rv770.c | 4 +++- > 8 files changed, 35 insertions(+), 24 deletions(-) > > diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c > b/drivers/gpu/drm/radeon/atombios_crtc.c > index b80b08f..bdc7b9e 100644 > --- a/drivers/gpu/drm/radeon/atombios_crtc.c > +++ b/drivers/gpu/drm/radeon/atombios_crtc.c > @@ -1375,6 +1375,11 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, > break; > } > > + /* Make sure surface address is updated at vertical blank rather than > + * horizontal blank > + */ > + WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0); > + > WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + > radeon_crtc->crtc_offset, > upper_32_bits(fb_location)); > WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + > radeon_crtc->crtc_offset, > @@ -1427,12 +1432,6 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, > WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, > (viewport_w << 16) | viewport_h); > > - /* pageflip setup */ > - /* make sure flip is at vb rather than hb */ > - tmp = RREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); > - tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN; > - WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); > - > /* set pageflip to happen only at start of vblank interval (front > porch) */ > WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3); > > @@ -1466,7 +1465,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, > uint64_t fb_location; > uint32_t fb_format, fb_pitch_pixels, tiling_flags; > u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE; > - u32 tmp, viewport_w, viewport_h; > + u32 viewport_w, viewport_h; > int r; > bool bypass_lut = false; > > @@ -1581,6 +1580,11 @@ static int avivo_crtc_do_set_base(struct drm_crtc > *crtc, > else > WREG32(AVIVO_D2VGA_CONTROL, 0); > > + /* Make sure surface address is update at vertical blank rather than > + * horizontal blank > + */ > + WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0); > + > if (rdev->family >= CHIP_RV770) { > if (radeon_crtc->crtc_id) { > WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, > upper_32_bits(fb_location)); > @@ -1627,12 +1631,6 @@ static int avivo_crtc_do_set_base(struct drm_crtc > *crtc, > WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, > (viewport_w << 16) | viewport_h); > > - /* pageflip setup */ > - /* make sure flip is at vb rather than hb */ > - tmp = RREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); > - tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; > - WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); > - > /* set pageflip to happen only at start of vblank interval (front > porch) */ > WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3); > > diff --git a/drivers/gpu/drm/radeon/evergreen.c > b/drivers/gpu/drm/radeon/evergreen.c > index 76c4bdf..e109239 100644 > --- a/drivers/gpu/drm/radeon/evergreen.c > +++ b/drivers/gpu/drm/radeon/evergreen.c > @@ -1407,11 +1407,14 @@ void dce4_wait_for_vblank(struct radeon_device *rdev, > int crtc) > * Triggers the actual pageflip by updating the primary > * surface base address (evergreen+). > */ > -void evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 > crtc_base) > +void evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 > crtc_base, > + bool async) > { > struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; > > /* update the scanout addresses */ > + WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, > + async ? EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN : 0); > WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + > radeon_crtc->crtc_offset, > upper_32_bits(crtc_base)); > WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + > radeon_crtc->crtc_offset, > diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c > index 6e478a2..de11a7d 100644 > --- a/drivers/gpu/drm/radeon/r100.c > +++ b/drivers/gpu/drm/radeon/r100.c > @@ -153,7 +153,7 @@ void r100_wait_for_vblank(struct radeon_device *rdev, int > crtc) > * bit to go high, when it does, we release the lock, and allow the > * double buffered update to take place. > */ > -void r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) > +void r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base, > bool async) > { > struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; > u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK; > diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h > index 007be29..f836993 100644 > --- a/drivers/gpu/drm/radeon/radeon.h > +++ b/drivers/gpu/drm/radeon/radeon.h > @@ -744,6 +744,7 @@ struct radeon_flip_work { > struct drm_pending_vblank_event *event; > struct radeon_bo *old_rbo; > struct fence *fence; > + bool async; > }; > > struct r500_irq_stat_regs { > @@ -1998,7 +1999,7 @@ struct radeon_asic { > } dpm; > /* pageflipping */ > struct { > - void (*page_flip)(struct radeon_device *rdev, int crtc, u64 > crtc_base); > + void (*page_flip)(struct radeon_device *rdev, int crtc, u64 > crtc_base, bool async); > bool (*page_flip_pending)(struct radeon_device *rdev, int crtc); > } pflip; > }; > @@ -2775,7 +2776,7 @@ static inline void radeon_ring_write(struct radeon_ring > *ring, uint32_t v) > #define radeon_pm_finish(rdev) (rdev)->asic->pm.finish((rdev)) > #define radeon_pm_init_profile(rdev) (rdev)->asic->pm.init_profile((rdev)) > #define radeon_pm_get_dynpm_state(rdev) > (rdev)->asic->pm.get_dynpm_state((rdev)) > -#define radeon_page_flip(rdev, crtc, base) > (rdev)->asic->pflip.page_flip((rdev), (crtc), (base)) > +#define radeon_page_flip(rdev, crtc, base, async) > (rdev)->asic->pflip.page_flip((rdev), (crtc), (base), (async)) > #define radeon_page_flip_pending(rdev, crtc) > (rdev)->asic->pflip.page_flip_pending((rdev), (crtc)) > #define radeon_wait_for_vblank(rdev, crtc) > (rdev)->asic->display.wait_for_vblank((rdev), (crtc)) > #define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev)) > diff --git a/drivers/gpu/drm/radeon/radeon_asic.h > b/drivers/gpu/drm/radeon/radeon_asic.h > index e0aa332..a3deed90 100644 > --- a/drivers/gpu/drm/radeon/radeon_asic.h > +++ b/drivers/gpu/drm/radeon/radeon_asic.h > @@ -138,7 +138,7 @@ extern void r100_pm_finish(struct radeon_device *rdev); > extern void r100_pm_init_profile(struct radeon_device *rdev); > extern void r100_pm_get_dynpm_state(struct radeon_device *rdev); > extern void r100_page_flip(struct radeon_device *rdev, int crtc, > - u64 crtc_base); > + u64 crtc_base, bool async); > extern bool r100_page_flip_pending(struct radeon_device *rdev, int crtc); > extern void r100_wait_for_vblank(struct radeon_device *rdev, int crtc); > extern int r100_mc_wait_for_idle(struct radeon_device *rdev); > @@ -250,7 +250,7 @@ extern void rs600_pm_misc(struct radeon_device *rdev); > extern void rs600_pm_prepare(struct radeon_device *rdev); > extern void rs600_pm_finish(struct radeon_device *rdev); > extern void rs600_page_flip(struct radeon_device *rdev, int crtc, > - u64 crtc_base); > + u64 crtc_base, bool async); > extern bool rs600_page_flip_pending(struct radeon_device *rdev, int crtc); > void rs600_set_safe_registers(struct radeon_device *rdev); > extern void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc); > @@ -464,7 +464,8 @@ void rv770_fini(struct radeon_device *rdev); > int rv770_suspend(struct radeon_device *rdev); > int rv770_resume(struct radeon_device *rdev); > void rv770_pm_misc(struct radeon_device *rdev); > -void rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); > +void rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base, > + bool async); > bool rv770_page_flip_pending(struct radeon_device *rdev, int crtc); > void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc > *mc); > void r700_cp_stop(struct radeon_device *rdev); > @@ -534,7 +535,7 @@ extern void btc_pm_init_profile(struct radeon_device > *rdev); > int sumo_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); > int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 > dclk); > extern void evergreen_page_flip(struct radeon_device *rdev, int crtc, > - u64 crtc_base); > + u64 crtc_base, bool async); > extern bool evergreen_page_flip_pending(struct radeon_device *rdev, int > crtc); > extern void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc); > void evergreen_disable_interrupt_state(struct radeon_device *rdev); > diff --git a/drivers/gpu/drm/radeon/radeon_display.c > b/drivers/gpu/drm/radeon/radeon_display.c > index fcc7483..7f176ec 100644 > --- a/drivers/gpu/drm/radeon/radeon_display.c > +++ b/drivers/gpu/drm/radeon/radeon_display.c > @@ -490,7 +490,7 @@ static void radeon_flip_work_func(struct work_struct > *__work) > vblank->linedur_ns / 1000, stat, vpos, hpos); > > /* do the flip (mmio) */ > - radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base); > + radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base, work->async); > > radeon_crtc->flip_status = RADEON_FLIP_SUBMITTED; > spin_unlock_irqrestore(&crtc->dev->event_lock, flags); > @@ -525,6 +525,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, > work->rdev = rdev; > work->crtc_id = radeon_crtc->crtc_id; > work->event = event; > + work->async = (page_flip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0; > > /* schedule unpin of the old buffer */ > old_radeon_fb = to_radeon_framebuffer(crtc->primary->fb); > @@ -1630,6 +1631,9 @@ int radeon_modeset_init(struct radeon_device *rdev) > > rdev->ddev->mode_config.funcs = &radeon_mode_funcs; > > + if (radeon_use_pflipirq == 2 && rdev->family >= CHIP_R600) > + rdev->ddev->mode_config.async_page_flip = true; > + > if (ASIC_IS_DCE5(rdev)) { > rdev->ddev->mode_config.max_width = 16384; > rdev->ddev->mode_config.max_height = 16384; > diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c > index 6244f4e..90b04d0 100644 > --- a/drivers/gpu/drm/radeon/rs600.c > +++ b/drivers/gpu/drm/radeon/rs600.c > @@ -110,7 +110,7 @@ void avivo_wait_for_vblank(struct radeon_device *rdev, > int crtc) > } > } > > -void rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) > +void rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base, > bool async) > { > struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; > u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); > @@ -121,6 +121,8 @@ void rs600_page_flip(struct radeon_device *rdev, int > crtc_id, u64 crtc_base) > WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); > > /* update the scanout addresses */ > + WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, > + async ? AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN : 0); > WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + > radeon_crtc->crtc_offset, > (u32)crtc_base); > WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, > diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c > index 01ee96a..2df7901 100644 > --- a/drivers/gpu/drm/radeon/rv770.c > +++ b/drivers/gpu/drm/radeon/rv770.c > @@ -801,7 +801,7 @@ u32 rv770_get_xclk(struct radeon_device *rdev) > return reference_clock; > } > > -void rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) > +void rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base, > bool async) > { > struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; > u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); > @@ -812,6 +812,8 @@ void rv770_page_flip(struct radeon_device *rdev, int > crtc_id, u64 crtc_base) > WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); > > /* update the scanout addresses */ > + WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, > + async ? AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN : 0); > if (radeon_crtc->crtc_id) { > WREG32(D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, > upper_32_bits(crtc_base)); > WREG32(D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, > upper_32_bits(crtc_base));