diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2013-08-23 11:56:26 -0400 |
---|---|---|
committer | Christian König <christian.koenig@amd.com> | 2014-02-18 10:11:41 -0500 |
commit | 03afe6f6480f2544d6cd18866556f1f76bb05f14 (patch) | |
tree | 3a3d690eebc5a34439fe9d8b4e961bd26a3bf08a /drivers/gpu/drm/radeon | |
parent | 4233290519c779e44a01816cf825f6df067a0886 (diff) |
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/radeon')
-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 { | |||
1518 | }; | 1518 | }; |
1519 | 1519 | ||
1520 | void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable); | 1520 | void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable); |
1521 | void radeon_dpm_enable_vce(struct radeon_device *rdev, bool enable); | ||
1521 | 1522 | ||
1522 | struct radeon_pm { | 1523 | struct radeon_pm { |
1523 | struct mutex mutex; | 1524 | struct mutex mutex; |
@@ -1638,6 +1639,7 @@ struct radeon_vce { | |||
1638 | unsigned fb_version; | 1639 | unsigned fb_version; |
1639 | atomic_t handles[RADEON_MAX_VCE_HANDLES]; | 1640 | atomic_t handles[RADEON_MAX_VCE_HANDLES]; |
1640 | struct drm_file *filp[RADEON_MAX_VCE_HANDLES]; | 1641 | struct drm_file *filp[RADEON_MAX_VCE_HANDLES]; |
1642 | struct delayed_work idle_work; | ||
1641 | }; | 1643 | }; |
1642 | 1644 | ||
1643 | int radeon_vce_init(struct radeon_device *rdev); | 1645 | int radeon_vce_init(struct radeon_device *rdev); |
@@ -1649,6 +1651,7 @@ int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, | |||
1649 | int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, | 1651 | int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, |
1650 | uint32_t handle, struct radeon_fence **fence); | 1652 | uint32_t handle, struct radeon_fence **fence); |
1651 | void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp); | 1653 | void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp); |
1654 | void radeon_vce_note_usage(struct radeon_device *rdev); | ||
1652 | int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi); | 1655 | int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi); |
1653 | int radeon_vce_cs_parse(struct radeon_cs_parser *p); | 1656 | int radeon_vce_cs_parse(struct radeon_cs_parser *p); |
1654 | bool radeon_vce_semaphore_emit(struct radeon_device *rdev, | 1657 | 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, | |||
347 | 347 | ||
348 | if (parser->ring == R600_RING_TYPE_UVD_INDEX) | 348 | if (parser->ring == R600_RING_TYPE_UVD_INDEX) |
349 | radeon_uvd_note_usage(rdev); | 349 | radeon_uvd_note_usage(rdev); |
350 | else if ((parser->ring == TN_RING_TYPE_VCE1_INDEX) || | ||
351 | (parser->ring == TN_RING_TYPE_VCE2_INDEX)) | ||
352 | radeon_vce_note_usage(rdev); | ||
350 | 353 | ||
351 | radeon_cs_sync_rings(parser); | 354 | radeon_cs_sync_rings(parser); |
352 | r = radeon_ib_schedule(rdev, &parser->ib, NULL); | 355 | 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) | |||
968 | } | 968 | } |
969 | } | 969 | } |
970 | 970 | ||
971 | void radeon_dpm_enable_vce(struct radeon_device *rdev, bool enable) | ||
972 | { | ||
973 | if (enable) { | ||
974 | mutex_lock(&rdev->pm.mutex); | ||
975 | rdev->pm.dpm.vce_active = true; | ||
976 | /* XXX select vce level based on ring/task */ | ||
977 | rdev->pm.dpm.vce_level = RADEON_VCE_LEVEL_AC_ALL; | ||
978 | mutex_unlock(&rdev->pm.mutex); | ||
979 | } else { | ||
980 | mutex_lock(&rdev->pm.mutex); | ||
981 | rdev->pm.dpm.vce_active = false; | ||
982 | mutex_unlock(&rdev->pm.mutex); | ||
983 | } | ||
984 | |||
985 | radeon_pm_compute_clocks(rdev); | ||
986 | } | ||
987 | |||
971 | static void radeon_pm_suspend_old(struct radeon_device *rdev) | 988 | static void radeon_pm_suspend_old(struct radeon_device *rdev) |
972 | { | 989 | { |
973 | mutex_lock(&rdev->pm.mutex); | 990 | 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 @@ | |||
34 | #include "radeon_asic.h" | 34 | #include "radeon_asic.h" |
35 | #include "sid.h" | 35 | #include "sid.h" |
36 | 36 | ||
37 | /* 1 second timeout */ | ||
38 | #define VCE_IDLE_TIMEOUT_MS 1000 | ||
39 | |||
37 | /* Firmware Names */ | 40 | /* Firmware Names */ |
38 | #define FIRMWARE_BONAIRE "radeon/BONAIRE_vce.bin" | 41 | #define FIRMWARE_BONAIRE "radeon/BONAIRE_vce.bin" |
39 | 42 | ||
40 | MODULE_FIRMWARE(FIRMWARE_BONAIRE); | 43 | MODULE_FIRMWARE(FIRMWARE_BONAIRE); |
41 | 44 | ||
45 | static void radeon_vce_idle_work_handler(struct work_struct *work); | ||
46 | |||
42 | /** | 47 | /** |
43 | * radeon_vce_init - allocate memory, load vce firmware | 48 | * radeon_vce_init - allocate memory, load vce firmware |
44 | * | 49 | * |
@@ -55,6 +60,8 @@ int radeon_vce_init(struct radeon_device *rdev) | |||
55 | uint8_t start, mid, end; | 60 | uint8_t start, mid, end; |
56 | int i, r; | 61 | int i, r; |
57 | 62 | ||
63 | INIT_DELAYED_WORK(&rdev->vce.idle_work, radeon_vce_idle_work_handler); | ||
64 | |||
58 | switch (rdev->family) { | 65 | switch (rdev->family) { |
59 | case CHIP_BONAIRE: | 66 | case CHIP_BONAIRE: |
60 | case CHIP_KAVERI: | 67 | case CHIP_KAVERI: |
@@ -220,6 +227,59 @@ int radeon_vce_resume(struct radeon_device *rdev) | |||
220 | } | 227 | } |
221 | 228 | ||
222 | /** | 229 | /** |
230 | * radeon_vce_idle_work_handler - power off VCE | ||
231 | * | ||
232 | * @work: pointer to work structure | ||
233 | * | ||
234 | * power of VCE when it's not used any more | ||
235 | */ | ||
236 | static void radeon_vce_idle_work_handler(struct work_struct *work) | ||
237 | { | ||
238 | struct radeon_device *rdev = | ||
239 | container_of(work, struct radeon_device, vce.idle_work.work); | ||
240 | |||
241 | if ((radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE1_INDEX) == 0) && | ||
242 | (radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE2_INDEX) == 0)) { | ||
243 | if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { | ||
244 | radeon_dpm_enable_vce(rdev, false); | ||
245 | } else { | ||
246 | radeon_set_vce_clocks(rdev, 0, 0); | ||
247 | } | ||
248 | } else { | ||
249 | schedule_delayed_work(&rdev->vce.idle_work, | ||
250 | msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * radeon_vce_note_usage - power up VCE | ||
256 | * | ||
257 | * @rdev: radeon_device pointer | ||
258 | * | ||
259 | * Make sure VCE is powerd up when we want to use it | ||
260 | */ | ||
261 | void radeon_vce_note_usage(struct radeon_device *rdev) | ||
262 | { | ||
263 | bool streams_changed = false; | ||
264 | bool set_clocks = !cancel_delayed_work_sync(&rdev->vce.idle_work); | ||
265 | set_clocks &= schedule_delayed_work(&rdev->vce.idle_work, | ||
266 | msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); | ||
267 | |||
268 | if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { | ||
269 | /* XXX figure out if the streams changed */ | ||
270 | streams_changed = false; | ||
271 | } | ||
272 | |||
273 | if (set_clocks || streams_changed) { | ||
274 | if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { | ||
275 | radeon_dpm_enable_vce(rdev, true); | ||
276 | } else { | ||
277 | radeon_set_vce_clocks(rdev, 53300, 40000); | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | |||
282 | /** | ||
223 | * radeon_vce_free_handles - free still open VCE handles | 283 | * radeon_vce_free_handles - free still open VCE handles |
224 | * | 284 | * |
225 | * @rdev: radeon_device pointer | 285 | * @rdev: radeon_device pointer |
@@ -235,6 +295,8 @@ void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp) | |||
235 | if (!handle || rdev->vce.filp[i] != filp) | 295 | if (!handle || rdev->vce.filp[i] != filp) |
236 | continue; | 296 | continue; |
237 | 297 | ||
298 | radeon_vce_note_usage(rdev); | ||
299 | |||
238 | r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX, | 300 | r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX, |
239 | handle, NULL); | 301 | handle, NULL); |
240 | if (r) | 302 | if (r) |