Commit 55b51c88 authored by Christian König's avatar Christian König Committed by Alex Deucher

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: default avatarChristian König <christian.koenig@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 4ed10835
...@@ -1143,6 +1143,7 @@ struct radeon_uvd { ...@@ -1143,6 +1143,7 @@ struct radeon_uvd {
uint64_t gpu_addr; uint64_t gpu_addr;
atomic_t handles[RADEON_MAX_UVD_HANDLES]; atomic_t handles[RADEON_MAX_UVD_HANDLES];
struct drm_file *filp[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); int radeon_uvd_init(struct radeon_device *rdev);
...@@ -1157,6 +1158,7 @@ void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo); ...@@ -1157,6 +1158,7 @@ void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo);
void radeon_uvd_free_handles(struct radeon_device *rdev, void radeon_uvd_free_handles(struct radeon_device *rdev,
struct drm_file *filp); struct drm_file *filp);
int radeon_uvd_cs_parse(struct radeon_cs_parser *parser); int radeon_uvd_cs_parse(struct radeon_cs_parser *parser);
void radeon_uvd_note_usage(struct radeon_device *rdev);
struct r600_audio { struct r600_audio {
int channels; int channels;
......
...@@ -549,6 +549,10 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) ...@@ -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); r = radeon_cs_handle_lockup(rdev, r);
return r; return r;
} }
if (parser.ring == R600_RING_TYPE_UVD_INDEX)
radeon_uvd_note_usage(rdev);
r = radeon_cs_ib_chunk(rdev, &parser); r = radeon_cs_ib_chunk(rdev, &parser);
if (r) { if (r) {
goto out; goto out;
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
#include "radeon.h" #include "radeon.h"
#include "r600d.h" #include "r600d.h"
/* 1 second timeout */
#define UVD_IDLE_TIMEOUT_MS 1000
/* Firmware Names */ /* Firmware Names */
#define FIRMWARE_RV710 "radeon/RV710_uvd.bin" #define FIRMWARE_RV710 "radeon/RV710_uvd.bin"
#define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin" #define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin"
...@@ -47,6 +50,8 @@ MODULE_FIRMWARE(FIRMWARE_CYPRESS); ...@@ -47,6 +50,8 @@ MODULE_FIRMWARE(FIRMWARE_CYPRESS);
MODULE_FIRMWARE(FIRMWARE_SUMO); MODULE_FIRMWARE(FIRMWARE_SUMO);
MODULE_FIRMWARE(FIRMWARE_TAHITI); MODULE_FIRMWARE(FIRMWARE_TAHITI);
static void radeon_uvd_idle_work_handler(struct work_struct *work);
int radeon_uvd_init(struct radeon_device *rdev) int radeon_uvd_init(struct radeon_device *rdev)
{ {
struct platform_device *pdev; struct platform_device *pdev;
...@@ -54,6 +59,8 @@ int radeon_uvd_init(struct radeon_device *rdev) ...@@ -54,6 +59,8 @@ int radeon_uvd_init(struct radeon_device *rdev)
const char *fw_name; const char *fw_name;
int i, r; 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); pdev = platform_device_register_simple("radeon_uvd", 0, NULL, 0);
r = IS_ERR(pdev); r = IS_ERR(pdev);
if (r) { if (r) {
...@@ -188,8 +195,6 @@ int radeon_uvd_resume(struct radeon_device *rdev) ...@@ -188,8 +195,6 @@ int radeon_uvd_resume(struct radeon_device *rdev)
radeon_bo_unreserve(rdev->uvd.vcpu_bo); radeon_bo_unreserve(rdev->uvd.vcpu_bo);
radeon_set_uvd_clocks(rdev, 53300, 40000);
return 0; return 0;
} }
...@@ -666,3 +671,24 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, ...@@ -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); 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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment