[PATCH 2/2] drm/radeon: raise UVD clocks only on demand

Christian König deathsimple at vodafone.de
Thu Apr 18 06:25:59 PDT 2013


From: Christian König <christian.koenig at amd.com>

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 at amd.com>
---
 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 18904fb..deafb54 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 c740707..7e265a5 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 15580fb..0312a7f 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);
+}
-- 
1.7.10.4



More information about the dri-devel mailing list