Reclocking the engine during screen refresh can cause corruption on some
hardware. Do it during vblank instead, and make sure that we're really
in vblank.

Signed-off-by: Matthew Garrett <m...@redhat.com>
---
 drivers/gpu/drm/radeon/r100.c            |   54 +++++++++++++++++++++--------
 drivers/gpu/drm/radeon/r600.c            |   54 ++++++++++++++++++++++--------
 drivers/gpu/drm/radeon/radeon.h          |    1 +
 drivers/gpu/drm/radeon/radeon_atombios.c |    2 +-
 4 files changed, 81 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 08e22fe..cdd55b2 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -189,11 +189,14 @@ void r100_set_power_state(struct radeon_device *rdev)
                /* reclocking the engine appears to be ok as long as the engine 
is idle
                 * no need for vblank waiting
                 */
-               if (sclk != rdev->pm.current_sclk) {
-                       radeon_set_engine_clock(rdev, sclk);
-                       rdev->pm.current_sclk = sclk;
-                       DRM_INFO("Setting: e: %d\n", sclk);
-               }
+                if (sclk != rdev->pm.current_sclk) {
+                        if (!rdev->pm.active_crtcs) {
+                                radeon_set_engine_clock(rdev, sclk);
+                                rdev->pm.current_sclk = sclk;
+                        } else {
+                                rdev->pm.new_mclk = sclk;
+                        }
+                }
 
                /* set memory clock */
                if (rdev->asic->set_memory_clock && (mclk != 
rdev->pm.current_mclk)) {
@@ -461,6 +464,7 @@ int r100_irq_process(struct radeon_device *rdev)
 {
        uint32_t status, msi_rearm;
        bool queue_hotplug = false;
+       int i = 0;
 
        /* reset gui idle ack.  the status bit is broken */
        rdev->irq.gui_idle_acked = false;
@@ -487,24 +491,44 @@ int r100_irq_process(struct radeon_device *rdev)
                if (status & RADEON_CRTC_VBLANK_STAT) {
                        drm_handle_vblank(rdev->ddev, 0);
                        rdev->pm.vblank_sync = true;
-                       if (rdev->pm.new_mclk) {
-                               radeon_pm_debug_check_in_vbl(rdev, false);
-                               radeon_set_memory_clock(rdev, 
rdev->pm.new_mclk);
+                       if (rdev->pm.new_mclk || rdev->pm.new_sclk) {
+                               while (!radeon_pm_debug_check_in_vbl(rdev, 
false) && i <100) {
+                                       udelay(1);
+                                       i++;
+                               }
+                               if (i==100) {
+                                       dev_err(rdev->dev, "Failed to sync with 
vblank\n");
+                               } else if (rdev->pm.new_mclk) {
+                                       radeon_set_memory_clock(rdev, 
rdev->pm.new_mclk);
+                                       rdev->pm.current_mclk = 
rdev->pm.new_mclk;
+                               } else if (rdev->pm.new_sclk) {
+                                       radeon_set_engine_clock(rdev, 
rdev->pm.new_sclk);
+                                       rdev->pm.current_sclk = 
rdev->pm.new_sclk;
+                               }
                                radeon_pm_debug_check_in_vbl(rdev, true);
-                               rdev->pm.current_mclk = rdev->pm.new_mclk;
-                               rdev->pm.new_mclk = 0;
+                               rdev->pm.new_mclk = rdev->pm.new_sclk = 0;
                        }
                        wake_up(&rdev->irq.vblank_queue);
                }
                if (status & RADEON_CRTC2_VBLANK_STAT) {
                        drm_handle_vblank(rdev->ddev, 1);
                        rdev->pm.vblank_sync = true;
-                       if (rdev->pm.new_mclk) {
-                               radeon_pm_debug_check_in_vbl(rdev, false);
-                               radeon_set_memory_clock(rdev, 
rdev->pm.new_mclk);
+                       if (rdev->pm.new_mclk || rdev->pm.new_sclk) {
+                               while (!radeon_pm_debug_check_in_vbl(rdev, 
false) && i <100) {
+                                       udelay(1);
+                                       i++;
+                               }
+                               if (i==100) {
+                                       dev_err(rdev->dev, "Failed to sync with 
vblank\n");
+                               } else if (rdev->pm.new_mclk) {
+                                       radeon_set_memory_clock(rdev, 
rdev->pm.new_mclk);
+                                       rdev->pm.current_mclk = 
rdev->pm.new_mclk;
+                               } else if (rdev->pm.new_sclk) {
+                                       radeon_set_engine_clock(rdev, 
rdev->pm.new_sclk);
+                                       rdev->pm.current_sclk = 
rdev->pm.new_sclk;
+                               }
                                radeon_pm_debug_check_in_vbl(rdev, true);
-                               rdev->pm.current_mclk = rdev->pm.new_mclk;
-                               rdev->pm.new_mclk = 0;
+                               rdev->pm.new_mclk = rdev->pm.new_sclk = 0;
                        }
                        wake_up(&rdev->irq.vblank_queue);
                }
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index a89821b..7bb1163 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -292,9 +292,12 @@ void r600_set_power_state(struct radeon_device *rdev)
                 * no need for vblank waiting
                 */
                if (sclk != rdev->pm.current_sclk) {
-                       radeon_set_engine_clock(rdev, sclk);
-                       rdev->pm.current_sclk = sclk;
-                       DRM_INFO("Setting: e: %d\n", sclk);
+                       if (!rdev->pm.active_crtcs) {
+                               radeon_set_engine_clock(rdev, sclk);
+                               rdev->pm.current_sclk = sclk;
+                       } else {
+                               rdev->pm.new_mclk = sclk;
+                       }
                }
 
                /* set memory clock */
@@ -305,10 +308,12 @@ void r600_set_power_state(struct radeon_device *rdev)
                        } else {
                                rdev->pm.new_mclk = mclk;
                        }
-                       radeon_sync_with_vblank(rdev);
                        DRM_INFO("Setting: m: %d\n", mclk);
                }
 
+               if (rdev->pm.new_mclk || rdev->pm.new_sclk)
+                       radeon_sync_with_vblank(rdev);
+
 #if 0
                if (radeon_gui_idle(rdev) &&
                    (rdev->pm.current_simd_mask != 
rdev->pm.requested_simd_mask)) {
@@ -2988,6 +2993,7 @@ int r600_irq_process(struct radeon_device *rdev)
        u32 ring_index, disp_int, disp_int_cont, disp_int_cont2;
        unsigned long flags;
        bool queue_hotplug = false;
+       int i = 0;
 
        DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
        if (!rdev->ih.enabled)
@@ -3022,12 +3028,22 @@ restart_ih:
                                if (disp_int & LB_D1_VBLANK_INTERRUPT) {
                                        drm_handle_vblank(rdev->ddev, 0);
                                        rdev->pm.vblank_sync = true;
-                                       if (rdev->pm.new_mclk) {
-                                               
radeon_pm_debug_check_in_vbl(rdev, false);
-                                               radeon_set_memory_clock(rdev, 
rdev->pm.new_mclk);
+                                       if (rdev->pm.new_mclk || 
rdev->pm.new_sclk) {
+                                               while 
(!radeon_pm_debug_check_in_vbl(rdev, false) && i <100) {
+                                                       udelay(1);
+                                                       i++;
+                                               }
+                                               if (i==100) {
+                                                       dev_err(rdev->dev, 
"Failed to sync with vblank\n");
+                                               } else if (rdev->pm.new_mclk) {
+                                                       
radeon_set_memory_clock(rdev, rdev->pm.new_mclk);
+                                                       rdev->pm.current_mclk = 
rdev->pm.new_mclk;
+                                               } else if (rdev->pm.new_sclk) {
+                                                       
radeon_set_engine_clock(rdev, rdev->pm.new_sclk);
+                                                       rdev->pm.current_sclk = 
rdev->pm.new_sclk;
+                                               }
                                                
radeon_pm_debug_check_in_vbl(rdev, true);
-                                               rdev->pm.current_mclk = 
rdev->pm.new_mclk;
-                                               rdev->pm.new_mclk = 0;
+                                               rdev->pm.new_mclk = 
rdev->pm.new_sclk = 0;
                                        }
                                        wake_up(&rdev->irq.vblank_queue);
                                        disp_int &= ~LB_D1_VBLANK_INTERRUPT;
@@ -3051,12 +3067,22 @@ restart_ih:
                                if (disp_int & LB_D2_VBLANK_INTERRUPT) {
                                        drm_handle_vblank(rdev->ddev, 1);
                                        rdev->pm.vblank_sync = true;
-                                       if (rdev->pm.new_mclk) {
-                                               
radeon_pm_debug_check_in_vbl(rdev, false);
-                                               radeon_set_memory_clock(rdev, 
rdev->pm.new_mclk);
+                                       if (rdev->pm.new_mclk || 
rdev->pm.new_sclk) {
+                                               while 
(!radeon_pm_debug_check_in_vbl(rdev, false) && i <100) {
+                                                       udelay(1);
+                                                       i++;
+                                               }
+                                               if (i==100) {
+                                                       dev_err(rdev->dev, 
"Failed to sync with vblank\n");
+                                               } else if (rdev->pm.new_mclk) {
+                                                       
radeon_set_memory_clock(rdev, rdev->pm.new_mclk);
+                                                       rdev->pm.current_mclk = 
rdev->pm.new_mclk;
+                                               } else if (rdev->pm.new_sclk) {
+                                                       
radeon_set_engine_clock(rdev, rdev->pm.new_sclk);
+                                                       rdev->pm.current_sclk = 
rdev->pm.new_sclk;
+                                               }
                                                
radeon_pm_debug_check_in_vbl(rdev, true);
-                                               rdev->pm.current_mclk = 
rdev->pm.new_mclk;
-                                               rdev->pm.new_mclk = 0;
+                                               rdev->pm.new_mclk = 
rdev->pm.new_sclk = 0;
                                        }
                                        wake_up(&rdev->irq.vblank_queue);
                                        disp_int &= ~LB_D2_VBLANK_INTERRUPT;
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index d706974..e3e4afc 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -729,6 +729,7 @@ struct radeon_pm {
        u32                     current_sclk;
        u32                     current_mclk;
        u32                     new_mclk;
+       u32                     new_sclk;
        u32                     *mc_arb_init_values;
        struct radeon_i2c_chan *i2c_bus;
        /* r6xx+ only */
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c 
b/drivers/gpu/drm/radeon/radeon_atombios.c
index 5b964e2..e68c320 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1940,7 +1940,7 @@ void radeon_atom_set_engine_clock(struct radeon_device 
*rdev,
 
        args.ulTargetEngineClock = eng_clock;   /* 10 khz */
 
-       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t 
*)&args);
+       atom_execute_table_atomic(rdev->mode_info.atom_context, index, 
(uint32_t *)&args);
 }
 
 void radeon_atom_set_memory_clock(struct radeon_device *rdev,
-- 
1.6.5.2


------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to