drm/radeon: Support DRM_MODE_PAGE_FLIP_ASYNC
authorMichel Dänzer <michel.daenzer@amd.com>
Fri, 1 Apr 2016 09:51:34 +0000 (18:51 +0900)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 5 May 2016 00:19:03 +0000 (20:19 -0400)
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).

Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Michel Dänzer <michel.daenzer@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rv770.c

index b80b08f71cb46e8d69d7bd94f6d951008267500e..bdc7b9ee193022672a53b930a71464ce34af68fd 100644 (file)
@@ -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);
 
index 501633be8ea2db97966509558581444e8ab199d5..9217d202e94d5164037c4eab42671063e66050ea 100644 (file)
@@ -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,
index af985b951d008401aa0417c9eaa12b032507b25b..f25994b3afa633db491737d0afa9684b6a8eda67 100644 (file)
@@ -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;
index 4192f60df98a33c0db1192fa380c03e593a4c69d..170e69111d1bb00f6a617cc4933ca3efbc4ac24c 100644 (file)
@@ -746,6 +746,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 {
@@ -2000,7 +2001,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;
 };
@@ -2777,7 +2778,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))
index 7675dfaaa005e9b7ebcd13ce5a136a0cbd69a1da..e3f036c20d64d97f2943dfc4c66723fcc5556765 100644 (file)
@@ -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);
index fcc7483d3f7b90e6a2153aba13fddd509fa76173..7f176ecfc58313e71fb573f373142485d01e7ae7 100644 (file)
@@ -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;
index 0051c4288725686df0f29acc37a9e0ef3c3b9816..f16af119c688c297210a6813122afedadd46a7c4 100644 (file)
@@ -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,
index fa0b03c482270b6dcce725bc116850d88ac79e84..1c120a4c3c9781f6f2892318cf1a968197c51c0b 100644 (file)
@@ -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));