diff options
author | Matthew Garrett <mjg@redhat.com> | 2010-04-28 12:13:06 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-05-18 18:21:29 +1000 |
commit | f81f202402640c27b38e1452dcb4d3e447043f48 (patch) | |
tree | 7f081e491e256d792c7b9c5e9df817894227fe05 /drivers/gpu/drm/radeon | |
parent | 612e06ce9c78840c3a1a207dfbe489a059d87c28 (diff) |
radeon: Try harder to ensure we reclock in vblank
The vblank interrupt on r600 doesn't seem to be especially reliable, so
perform some sanity checks before the actual reclock.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon')
-rw-r--r-- | drivers/gpu/drm/radeon/r500_reg.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r600.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 11 |
4 files changed, 39 insertions, 1 deletions
diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index f5adf42a9d1..93c9a2bbccf 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -351,6 +351,7 @@ #define AVIVO_D1CRTC_BLANK_CONTROL 0x6084 #define AVIVO_D1CRTC_INTERLACE_CONTROL 0x6088 #define AVIVO_D1CRTC_INTERLACE_STATUS 0x608c +#define AVIVO_D1CRTC_STATUS_POSITION 0x60a0 #define AVIVO_D1CRTC_FRAME_COUNT 0x60a4 #define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4 @@ -489,6 +490,7 @@ #define AVIVO_D2CRTC_BLANK_CONTROL 0x6884 #define AVIVO_D2CRTC_INTERLACE_CONTROL 0x6888 #define AVIVO_D2CRTC_INTERLACE_STATUS 0x688c +#define AVIVO_D2CRTC_STATUS_POSITION 0x68a0 #define AVIVO_D2CRTC_FRAME_COUNT 0x68a4 #define AVIVO_D2CRTC_STEREO_CONTROL 0x68c4 diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1696cc277d8..d3a79e0a912 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -289,8 +289,34 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) } } else { + u32 position; + u32 vbl; + radeon_sync_with_vblank(rdev); + if (!radeon_pm_in_vbl(rdev)) + return; + + if (rdev->pm.active_crtcs & (1 << 0)) { + vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END); + position = RREG32(AVIVO_D1CRTC_STATUS_POSITION); + position &= 0xfff; + vbl &= 0xfff; + + if (position < vbl && position > 1) + return; + } + + if (rdev->pm.active_crtcs & (1 << 1)) { + vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END); + position = RREG32(AVIVO_D2CRTC_STATUS_POSITION); + position &= 0xfff; + vbl &= 0xfff; + + if (position < vbl && position > 1) + return; + } + if (sclk != rdev->pm.current_sclk) { radeon_pm_debug_check_in_vbl(rdev, false); radeon_set_engine_clock(rdev, sclk); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index bed84b316bb..93ac88eb6b3 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -175,6 +175,7 @@ void radeon_pm_fini(struct radeon_device *rdev); void radeon_pm_compute_clocks(struct radeon_device *rdev); void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); +bool radeon_pm_in_vbl(struct radeon_device *rdev); bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); void radeon_sync_with_vblank(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 134b19537d1..88163e043fc 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -387,7 +387,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) mutex_unlock(&rdev->pm.mutex); } -bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) +bool radeon_pm_in_vbl(struct radeon_device *rdev) { u32 stat_crtc = 0; bool in_vbl = true; @@ -446,6 +446,15 @@ bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) in_vbl = false; } } + + return in_vbl; +} + +bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) +{ + u32 stat_crtc = 0; + bool in_vbl = radeon_pm_in_vbl(rdev); + if (in_vbl == false) DRM_INFO("not in vbl for pm change %08x at %s\n", stat_crtc, finish ? "exit" : "entry"); |