From 55b51c88c5167ba0c95919cdd25b0bd376a3f0ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 18 Apr 2013 15:25:59 +0200 Subject: drm/radeon: raise UVD clocks only on demand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That not only saves some power, but also solves problems with older chips where an idle UVD block on higher clocks can cause problems. Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon.h | 2 ++ drivers/gpu/drm/radeon/radeon_cs.c | 4 ++++ drivers/gpu/drm/radeon/radeon_uvd.c | 30 ++++++++++++++++++++++++++++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5020c7c9b7cb..7935370f01af 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1143,6 +1143,7 @@ struct radeon_uvd { uint64_t gpu_addr; atomic_t handles[RADEON_MAX_UVD_HANDLES]; struct drm_file *filp[RADEON_MAX_UVD_HANDLES]; + struct delayed_work idle_work; }; int radeon_uvd_init(struct radeon_device *rdev); @@ -1157,6 +1158,7 @@ void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo); void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp); int radeon_uvd_cs_parse(struct radeon_cs_parser *parser); +void radeon_uvd_note_usage(struct radeon_device *rdev); struct r600_audio { int channels; diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index c7407074c09b..7e265a58141f 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -549,6 +549,10 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) r = radeon_cs_handle_lockup(rdev, r); return r; } + + if (parser.ring == R600_RING_TYPE_UVD_INDEX) + radeon_uvd_note_usage(rdev); + r = radeon_cs_ib_chunk(rdev, &parser); if (r) { goto out; diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 15580fb8546e..0312a7f4d768 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -36,6 +36,9 @@ #include "radeon.h" #include "r600d.h" +/* 1 second timeout */ +#define UVD_IDLE_TIMEOUT_MS 1000 + /* Firmware Names */ #define FIRMWARE_RV710 "radeon/RV710_uvd.bin" #define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin" @@ -47,6 +50,8 @@ MODULE_FIRMWARE(FIRMWARE_CYPRESS); MODULE_FIRMWARE(FIRMWARE_SUMO); MODULE_FIRMWARE(FIRMWARE_TAHITI); +static void radeon_uvd_idle_work_handler(struct work_struct *work); + int radeon_uvd_init(struct radeon_device *rdev) { struct platform_device *pdev; @@ -54,6 +59,8 @@ int radeon_uvd_init(struct radeon_device *rdev) const char *fw_name; int i, r; + INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler); + pdev = platform_device_register_simple("radeon_uvd", 0, NULL, 0); r = IS_ERR(pdev); if (r) { @@ -188,8 +195,6 @@ int radeon_uvd_resume(struct radeon_device *rdev) radeon_bo_unreserve(rdev->uvd.vcpu_bo); - radeon_set_uvd_clocks(rdev, 53300, 40000); - return 0; } @@ -666,3 +671,24 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, return radeon_uvd_send_msg(rdev, ring, bo, fence); } + +static void radeon_uvd_idle_work_handler(struct work_struct *work) +{ + struct radeon_device *rdev = + container_of(work, struct radeon_device, uvd.idle_work.work); + + if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0) + radeon_set_uvd_clocks(rdev, 0, 0); + else + schedule_delayed_work(&rdev->uvd.idle_work, + msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS)); +} + +void radeon_uvd_note_usage(struct radeon_device *rdev) +{ + bool set_clocks = !cancel_delayed_work_sync(&rdev->uvd.idle_work); + set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work, + msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS)); + if (set_clocks) + radeon_set_uvd_clocks(rdev, 53300, 40000); +} -- cgit v1.2.3