This is fast enough and rare enough that it's worth making sure that it
happens in the vblank, which means doing it in irq context. The alternative
is visual corruption and potential machine crashes.

Signed-off-by: Matthew Garrett <m...@redhat.com>
---
 drivers/gpu/drm/radeon/r100.c            |   26 +++++++++++++++++++++-----
 drivers/gpu/drm/radeon/r600.c            |   24 ++++++++++++++++++++----
 drivers/gpu/drm/radeon/radeon.h          |    1 +
 drivers/gpu/drm/radeon/radeon_atombios.c |    2 +-
 drivers/gpu/drm/radeon/rs600.c           |   14 ++++++++++++++
 5 files changed, 57 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 9a7d16b..08e22fe 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -197,11 +197,13 @@ void r100_set_power_state(struct radeon_device *rdev)
 
                /* set memory clock */
                if (rdev->asic->set_memory_clock && (mclk != 
rdev->pm.current_mclk)) {
-                       radeon_sync_with_vblank(rdev);
-                       radeon_pm_debug_check_in_vbl(rdev, false);
-                       radeon_set_memory_clock(rdev, mclk);
-                       radeon_pm_debug_check_in_vbl(rdev, true);
-                       rdev->pm.current_mclk = mclk;
+                        if (!rdev->pm.active_crtcs) {
+                                radeon_set_memory_clock(rdev, mclk);
+                                rdev->pm.current_mclk = mclk;
+                        } else {
+                                rdev->pm.new_mclk = mclk;
+                        }
+                        radeon_sync_with_vblank(rdev);
                        DRM_INFO("Setting: m: %d\n", mclk);
                }
 
@@ -485,11 +487,25 @@ 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);
+                               radeon_pm_debug_check_in_vbl(rdev, true);
+                               rdev->pm.current_mclk = rdev->pm.new_mclk;
+                               rdev->pm.new_mclk = 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);
+                               radeon_pm_debug_check_in_vbl(rdev, true);
+                               rdev->pm.current_mclk = rdev->pm.new_mclk;
+                               rdev->pm.new_mclk = 0;
+                       }
                        wake_up(&rdev->irq.vblank_queue);
                }
                if (status & RADEON_FP_DETECT_STAT) {
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index adc558b..a89821b 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -299,11 +299,13 @@ void r600_set_power_state(struct radeon_device *rdev)
 
                /* set memory clock */
                if (rdev->asic->set_memory_clock && (mclk != 
rdev->pm.current_mclk)) {
+                       if (!rdev->pm.active_crtcs) {
+                               radeon_set_memory_clock(rdev, mclk);
+                               rdev->pm.current_mclk = mclk;
+                       } else {
+                               rdev->pm.new_mclk = mclk;
+                       }
                        radeon_sync_with_vblank(rdev);
-                       radeon_pm_debug_check_in_vbl(rdev, false);
-                       radeon_set_memory_clock(rdev, mclk);
-                       radeon_pm_debug_check_in_vbl(rdev, true);
-                       rdev->pm.current_mclk = mclk;
                        DRM_INFO("Setting: m: %d\n", mclk);
                }
 
@@ -3020,6 +3022,13 @@ 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);
+                                               
radeon_pm_debug_check_in_vbl(rdev, true);
+                                               rdev->pm.current_mclk = 
rdev->pm.new_mclk;
+                                               rdev->pm.new_mclk = 0;
+                                       }
                                        wake_up(&rdev->irq.vblank_queue);
                                        disp_int &= ~LB_D1_VBLANK_INTERRUPT;
                                        DRM_DEBUG("IH: D1 vblank\n");
@@ -3042,6 +3051,13 @@ 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);
+                                               
radeon_pm_debug_check_in_vbl(rdev, true);
+                                               rdev->pm.current_mclk = 
rdev->pm.new_mclk;
+                                               rdev->pm.new_mclk = 0;
+                                       }
                                        wake_up(&rdev->irq.vblank_queue);
                                        disp_int &= ~LB_D2_VBLANK_INTERRUPT;
                                        DRM_DEBUG("IH: D2 vblank\n");
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index e8e2fe3..ac403e4 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -727,6 +727,7 @@ struct radeon_pm {
        int                     default_power_state_index;
        u32                     current_sclk;
        u32                     current_mclk;
+       u32                     new_mclk;
        struct radeon_i2c_chan *i2c_bus;
        /* r6xx+ only */
        u32 low_simd_mask;
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c 
b/drivers/gpu/drm/radeon/radeon_atombios.c
index 00bae31..0af81b7 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1941,7 +1941,7 @@ void radeon_atom_set_memory_clock(struct radeon_device 
*rdev,
 
        args.ulTargetMemoryClock = mem_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_initialize_bios_scratch_regs(struct drm_device *dev)
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 55f00a7..83eda0e 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -484,11 +484,25 @@ int rs600_irq_process(struct radeon_device *rdev)
                if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) {
                        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);
+                                radeon_pm_debug_check_in_vbl(rdev, true);
+                                rdev->pm.current_mclk = rdev->pm.new_mclk;
+                                rdev->pm.new_mclk = 0;
+                        }
                        wake_up(&rdev->irq.vblank_queue);
                }
                if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int)) {
                        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);
+                                radeon_pm_debug_check_in_vbl(rdev, true);
+                                rdev->pm.current_mclk = rdev->pm.new_mclk;
+                                rdev->pm.new_mclk = 0;
+                        }
                        wake_up(&rdev->irq.vblank_queue);
                }
                if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) {
-- 
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