aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChristian König <christian.koenig@amd.com>2013-04-18 09:25:59 -0400
committerAlex Deucher <alexander.deucher@amd.com>2013-04-23 17:45:44 -0400
commit55b51c88c5167ba0c95919cdd25b0bd376a3f0ea (patch)
tree43ec2ca11ed770e74436a028a3c5d244f1902f72 /drivers
parent4ed108352d9b60a723a5071ed05e722826c2b72f (diff)
drm/radeon: raise UVD clocks only on demand
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 <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/radeon/radeon.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_uvd.c30
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 {
1143 uint64_t gpu_addr; 1143 uint64_t gpu_addr;
1144 atomic_t handles[RADEON_MAX_UVD_HANDLES]; 1144 atomic_t handles[RADEON_MAX_UVD_HANDLES];
1145 struct drm_file *filp[RADEON_MAX_UVD_HANDLES]; 1145 struct drm_file *filp[RADEON_MAX_UVD_HANDLES];
1146 struct delayed_work idle_work;
1146}; 1147};
1147 1148
1148int radeon_uvd_init(struct radeon_device *rdev); 1149int radeon_uvd_init(struct radeon_device *rdev);
@@ -1157,6 +1158,7 @@ void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo);
1157void radeon_uvd_free_handles(struct radeon_device *rdev, 1158void radeon_uvd_free_handles(struct radeon_device *rdev,
1158 struct drm_file *filp); 1159 struct drm_file *filp);
1159int radeon_uvd_cs_parse(struct radeon_cs_parser *parser); 1160int radeon_uvd_cs_parse(struct radeon_cs_parser *parser);
1161void radeon_uvd_note_usage(struct radeon_device *rdev);
1160 1162
1161struct r600_audio { 1163struct r600_audio {
1162 int channels; 1164 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)
549 r = radeon_cs_handle_lockup(rdev, r); 549 r = radeon_cs_handle_lockup(rdev, r);
550 return r; 550 return r;
551 } 551 }
552
553 if (parser.ring == R600_RING_TYPE_UVD_INDEX)
554 radeon_uvd_note_usage(rdev);
555
552 r = radeon_cs_ib_chunk(rdev, &parser); 556 r = radeon_cs_ib_chunk(rdev, &parser);
553 if (r) { 557 if (r) {
554 goto out; 558 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 @@
36#include "radeon.h" 36#include "radeon.h"
37#include "r600d.h" 37#include "r600d.h"
38 38
39/* 1 second timeout */
40#define UVD_IDLE_TIMEOUT_MS 1000
41
39/* Firmware Names */ 42/* Firmware Names */
40#define FIRMWARE_RV710 "radeon/RV710_uvd.bin" 43#define FIRMWARE_RV710 "radeon/RV710_uvd.bin"
41#define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin" 44#define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin"
@@ -47,6 +50,8 @@ MODULE_FIRMWARE(FIRMWARE_CYPRESS);
47MODULE_FIRMWARE(FIRMWARE_SUMO); 50MODULE_FIRMWARE(FIRMWARE_SUMO);
48MODULE_FIRMWARE(FIRMWARE_TAHITI); 51MODULE_FIRMWARE(FIRMWARE_TAHITI);
49 52
53static void radeon_uvd_idle_work_handler(struct work_struct *work);
54
50int radeon_uvd_init(struct radeon_device *rdev) 55int radeon_uvd_init(struct radeon_device *rdev)
51{ 56{
52 struct platform_device *pdev; 57 struct platform_device *pdev;
@@ -54,6 +59,8 @@ int radeon_uvd_init(struct radeon_device *rdev)
54 const char *fw_name; 59 const char *fw_name;
55 int i, r; 60 int i, r;
56 61
62 INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler);
63
57 pdev = platform_device_register_simple("radeon_uvd", 0, NULL, 0); 64 pdev = platform_device_register_simple("radeon_uvd", 0, NULL, 0);
58 r = IS_ERR(pdev); 65 r = IS_ERR(pdev);
59 if (r) { 66 if (r) {
@@ -188,8 +195,6 @@ int radeon_uvd_resume(struct radeon_device *rdev)
188 195
189 radeon_bo_unreserve(rdev->uvd.vcpu_bo); 196 radeon_bo_unreserve(rdev->uvd.vcpu_bo);
190 197
191 radeon_set_uvd_clocks(rdev, 53300, 40000);
192
193 return 0; 198 return 0;
194} 199}
195 200
@@ -666,3 +671,24 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
666 671
667 return radeon_uvd_send_msg(rdev, ring, bo, fence); 672 return radeon_uvd_send_msg(rdev, ring, bo, fence);
668} 673}
674
675static void radeon_uvd_idle_work_handler(struct work_struct *work)
676{
677 struct radeon_device *rdev =
678 container_of(work, struct radeon_device, uvd.idle_work.work);
679
680 if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0)
681 radeon_set_uvd_clocks(rdev, 0, 0);
682 else
683 schedule_delayed_work(&rdev->uvd.idle_work,
684 msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
685}
686
687void radeon_uvd_note_usage(struct radeon_device *rdev)
688{
689 bool set_clocks = !cancel_delayed_work_sync(&rdev->uvd.idle_work);
690 set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work,
691 msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
692 if (set_clocks)
693 radeon_set_uvd_clocks(rdev, 53300, 40000);
694}