drm/radeon: Support DRM_MODE_PAGE_FLIP_ASYNC
diff mbox

Message ID 1459504294-1802-1-git-send-email-michel@daenzer.net
State New
Headers show

Commit Message

Michel Dänzer April 1, 2016, 9:51 a.m. UTC
From: Michel Dänzer <michel.daenzer@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@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(-)

Comments

Christian König April 1, 2016, 12:39 p.m. UTC | #1
Am 01.04.2016 um 11:51 schrieb Michel Dänzer:
> From: Michel Dänzer <michel.daenzer@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@amd.com>

Reviewed-by: Christian König <christian.koenig@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));
Alex Deucher April 1, 2016, 3:08 p.m. UTC | #2
On Fri, Apr 1, 2016 at 8:39 AM, Christian König <deathsimple@vodafone.de> wrote:
> Am 01.04.2016 um 11:51 schrieb Michel Dänzer:
>>
>> From: Michel Dänzer <michel.daenzer@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@amd.com>
>
>
> Reviewed-by: Christian König <christian.koenig@amd.com>
>

Applied.  thanks!

Alex

>
>> ---
>>   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));
>
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

Patch
diff mbox

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));