diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2013-08-23 19:56:26 +0400 |
---|---|---|
committer | Christian König <christian.koenig@amd.com> | 2014-02-18 19:11:41 +0400 |
commit | 03afe6f6480f2544d6cd18866556f1f76bb05f14 (patch) | |
tree | 3a3d690eebc5a34439fe9d8b4e961bd26a3bf08a /drivers/gpu/drm | |
parent | 4233290519c779e44a01816cf825f6df067a0886 (diff) | |
download | linux-03afe6f6480f2544d6cd18866556f1f76bb05f14.tar.xz |
drm/radeon/dpm: enable dynamic vce state switching v2
enable vce states when vce is active. When vce is active,
it adjusts the currently selected state (performance, battery,
uvd, etc.)
v2: add code comments
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Christian König <christian.koenig@amd.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_cs.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_vce.c | 62 |
4 files changed, 85 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 693a8fccd94d..540624e7491c 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1518,6 +1518,7 @@ struct radeon_dpm { }; void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable); +void radeon_dpm_enable_vce(struct radeon_device *rdev, bool enable); struct radeon_pm { struct mutex mutex; @@ -1638,6 +1639,7 @@ struct radeon_vce { unsigned fb_version; atomic_t handles[RADEON_MAX_VCE_HANDLES]; struct drm_file *filp[RADEON_MAX_VCE_HANDLES]; + struct delayed_work idle_work; }; int radeon_vce_init(struct radeon_device *rdev); @@ -1649,6 +1651,7 @@ int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, uint32_t handle, struct radeon_fence **fence); void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp); +void radeon_vce_note_usage(struct radeon_device *rdev); int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi); int radeon_vce_cs_parse(struct radeon_cs_parser *p); bool radeon_vce_semaphore_emit(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 701ee7981b5c..f28a8d82fa19 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -347,6 +347,9 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev, if (parser->ring == R600_RING_TYPE_UVD_INDEX) radeon_uvd_note_usage(rdev); + else if ((parser->ring == TN_RING_TYPE_VCE1_INDEX) || + (parser->ring == TN_RING_TYPE_VCE2_INDEX)) + radeon_vce_note_usage(rdev); radeon_cs_sync_rings(parser); r = radeon_ib_schedule(rdev, &parser->ib, NULL); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index a4687e7b45f8..4ad9af9fc517 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -968,6 +968,23 @@ void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable) } } +void radeon_dpm_enable_vce(struct radeon_device *rdev, bool enable) +{ + if (enable) { + mutex_lock(&rdev->pm.mutex); + rdev->pm.dpm.vce_active = true; + /* XXX select vce level based on ring/task */ + rdev->pm.dpm.vce_level = RADEON_VCE_LEVEL_AC_ALL; + mutex_unlock(&rdev->pm.mutex); + } else { + mutex_lock(&rdev->pm.mutex); + rdev->pm.dpm.vce_active = false; + mutex_unlock(&rdev->pm.mutex); + } + + radeon_pm_compute_clocks(rdev); +} + static void radeon_pm_suspend_old(struct radeon_device *rdev) { mutex_lock(&rdev->pm.mutex); diff --git a/drivers/gpu/drm/radeon/radeon_vce.c b/drivers/gpu/drm/radeon/radeon_vce.c index f46563b60921..d130432e313a 100644 --- a/drivers/gpu/drm/radeon/radeon_vce.c +++ b/drivers/gpu/drm/radeon/radeon_vce.c @@ -34,11 +34,16 @@ #include "radeon_asic.h" #include "sid.h" +/* 1 second timeout */ +#define VCE_IDLE_TIMEOUT_MS 1000 + /* Firmware Names */ #define FIRMWARE_BONAIRE "radeon/BONAIRE_vce.bin" MODULE_FIRMWARE(FIRMWARE_BONAIRE); +static void radeon_vce_idle_work_handler(struct work_struct *work); + /** * radeon_vce_init - allocate memory, load vce firmware * @@ -55,6 +60,8 @@ int radeon_vce_init(struct radeon_device *rdev) uint8_t start, mid, end; int i, r; + INIT_DELAYED_WORK(&rdev->vce.idle_work, radeon_vce_idle_work_handler); + switch (rdev->family) { case CHIP_BONAIRE: case CHIP_KAVERI: @@ -220,6 +227,59 @@ int radeon_vce_resume(struct radeon_device *rdev) } /** + * radeon_vce_idle_work_handler - power off VCE + * + * @work: pointer to work structure + * + * power of VCE when it's not used any more + */ +static void radeon_vce_idle_work_handler(struct work_struct *work) +{ + struct radeon_device *rdev = + container_of(work, struct radeon_device, vce.idle_work.work); + + if ((radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE1_INDEX) == 0) && + (radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE2_INDEX) == 0)) { + if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { + radeon_dpm_enable_vce(rdev, false); + } else { + radeon_set_vce_clocks(rdev, 0, 0); + } + } else { + schedule_delayed_work(&rdev->vce.idle_work, + msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); + } +} + +/** + * radeon_vce_note_usage - power up VCE + * + * @rdev: radeon_device pointer + * + * Make sure VCE is powerd up when we want to use it + */ +void radeon_vce_note_usage(struct radeon_device *rdev) +{ + bool streams_changed = false; + bool set_clocks = !cancel_delayed_work_sync(&rdev->vce.idle_work); + set_clocks &= schedule_delayed_work(&rdev->vce.idle_work, + msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); + + if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { + /* XXX figure out if the streams changed */ + streams_changed = false; + } + + if (set_clocks || streams_changed) { + if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { + radeon_dpm_enable_vce(rdev, true); + } else { + radeon_set_vce_clocks(rdev, 53300, 40000); + } + } +} + +/** * radeon_vce_free_handles - free still open VCE handles * * @rdev: radeon_device pointer @@ -235,6 +295,8 @@ void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp) if (!handle || rdev->vce.filp[i] != filp) continue; + radeon_vce_note_usage(rdev); + r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX, handle, NULL); if (r) |