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® 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