Commit ce3537d5 authored by Alex Deucher's avatar Alex Deucher

drm/radeon/dpm: use multiple UVD power states (v3)

Use the UVD handle information to determine which
which power states to select when using UVD.  For
example, decoding a single SD stream requires much
lower clocks than multiple HD streams.

v2: switch to a cleaner dpm/uvd interface
v3: change the uvd power state while streams
are active if need be
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 85a129ca
...@@ -1360,11 +1360,14 @@ struct radeon_dpm { ...@@ -1360,11 +1360,14 @@ struct radeon_dpm {
struct radeon_dpm_thermal thermal; struct radeon_dpm_thermal thermal;
/* forced levels */ /* forced levels */
enum radeon_dpm_forced_level forced_level; enum radeon_dpm_forced_level forced_level;
/* track UVD streams */
unsigned sd;
unsigned hd;
}; };
void radeon_dpm_enable_power_state(struct radeon_device *rdev, void radeon_dpm_enable_power_state(struct radeon_device *rdev,
enum radeon_pm_state_type dpm_state); enum radeon_pm_state_type dpm_state);
void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable);
struct radeon_pm { struct radeon_pm {
struct mutex mutex; struct mutex mutex;
......
...@@ -383,6 +383,10 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev, ...@@ -383,6 +383,10 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,
DRM_ERROR("Invalid command stream !\n"); DRM_ERROR("Invalid command stream !\n");
return r; return r;
} }
if (parser->ring == R600_RING_TYPE_UVD_INDEX)
radeon_uvd_note_usage(rdev);
radeon_cs_sync_rings(parser); radeon_cs_sync_rings(parser);
r = radeon_ib_schedule(rdev, &parser->ib, NULL); r = radeon_ib_schedule(rdev, &parser->ib, NULL);
if (r) { if (r) {
...@@ -474,6 +478,9 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, ...@@ -474,6 +478,9 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
return r; return r;
} }
if (parser->ring == R600_RING_TYPE_UVD_INDEX)
radeon_uvd_note_usage(rdev);
mutex_lock(&rdev->vm_manager.lock); mutex_lock(&rdev->vm_manager.lock);
mutex_lock(&vm->mutex); mutex_lock(&vm->mutex);
r = radeon_vm_alloc_pt(rdev, vm); r = radeon_vm_alloc_pt(rdev, vm);
...@@ -552,10 +559,6 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) ...@@ -552,10 +559,6 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
return r; return r;
} }
/* XXX pick SD/HD/MVC */
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;
......
...@@ -729,6 +729,8 @@ static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev, ...@@ -729,6 +729,8 @@ static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
/* use a fallback state if we didn't match */ /* use a fallback state if we didn't match */
switch (dpm_state) { switch (dpm_state) {
case POWER_STATE_TYPE_INTERNAL_UVD_SD: case POWER_STATE_TYPE_INTERNAL_UVD_SD:
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
goto restart_search;
case POWER_STATE_TYPE_INTERNAL_UVD_HD: case POWER_STATE_TYPE_INTERNAL_UVD_HD:
case POWER_STATE_TYPE_INTERNAL_UVD_HD2: case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
case POWER_STATE_TYPE_INTERNAL_UVD_MVC: case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
...@@ -884,6 +886,34 @@ void radeon_dpm_enable_power_state(struct radeon_device *rdev, ...@@ -884,6 +886,34 @@ void radeon_dpm_enable_power_state(struct radeon_device *rdev,
radeon_pm_compute_clocks(rdev); radeon_pm_compute_clocks(rdev);
} }
void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)
{
enum radeon_pm_state_type dpm_state;
if (enable) {
mutex_lock(&rdev->pm.mutex);
rdev->pm.dpm.uvd_active = true;
if ((rdev->pm.dpm.sd == 1) && (rdev->pm.dpm.hd == 0))
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_SD;
else if ((rdev->pm.dpm.sd == 2) && (rdev->pm.dpm.hd == 0))
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 1))
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 2))
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD2;
else
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD;
rdev->pm.dpm.state = dpm_state;
mutex_unlock(&rdev->pm.mutex);
} else {
mutex_lock(&rdev->pm.mutex);
rdev->pm.dpm.uvd_active = false;
mutex_unlock(&rdev->pm.mutex);
}
radeon_pm_compute_clocks(rdev);
}
static void radeon_pm_suspend_old(struct radeon_device *rdev) static void radeon_pm_suspend_old(struct radeon_device *rdev)
{ {
mutex_lock(&rdev->pm.mutex); mutex_lock(&rdev->pm.mutex);
......
...@@ -775,10 +775,7 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work) ...@@ -775,10 +775,7 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work)
if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0) { if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0) {
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
mutex_lock(&rdev->pm.mutex); radeon_dpm_enable_uvd(rdev, false);
rdev->pm.dpm.uvd_active = false;
mutex_unlock(&rdev->pm.mutex);
radeon_pm_compute_clocks(rdev);
} else { } else {
radeon_set_uvd_clocks(rdev, 0, 0); radeon_set_uvd_clocks(rdev, 0, 0);
} }
...@@ -790,13 +787,25 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work) ...@@ -790,13 +787,25 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work)
void radeon_uvd_note_usage(struct radeon_device *rdev) void radeon_uvd_note_usage(struct radeon_device *rdev)
{ {
bool streams_changed = false;
bool set_clocks = !cancel_delayed_work_sync(&rdev->uvd.idle_work); bool set_clocks = !cancel_delayed_work_sync(&rdev->uvd.idle_work);
set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work, set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work,
msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS)); msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
if (set_clocks) {
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
unsigned hd = 0, sd = 0;
radeon_uvd_count_handles(rdev, &sd, &hd);
if ((rdev->pm.dpm.sd != sd) ||
(rdev->pm.dpm.hd != hd)) {
rdev->pm.dpm.sd = sd;
rdev->pm.dpm.hd = hd;
streams_changed = true;
}
}
if (set_clocks || streams_changed) {
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
/* XXX pick SD/HD/MVC */ radeon_dpm_enable_uvd(rdev, true);
radeon_dpm_enable_power_state(rdev, POWER_STATE_TYPE_INTERNAL_UVD);
} else { } else {
radeon_set_uvd_clocks(rdev, 53300, 40000); 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