drm/radeon/dpm: use multiple UVD power states (v3)
authorAlex Deucher <alexander.deucher@amd.com>
Wed, 24 Jul 2013 16:12:49 +0000 (12:12 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 30 Aug 2013 20:29:59 +0000 (16:29 -0400)
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: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_uvd.c

index fc8d03be933c65392dc9e9c33e839d6bfa3a8fd8..a276f0267433285bfa6851d286d47fe8c5736fe1 100644 (file)
@@ -1360,11 +1360,14 @@ struct radeon_dpm {
        struct radeon_dpm_thermal thermal;
        /* forced levels */
        enum radeon_dpm_forced_level forced_level;
+       /* track UVD streams */
+       unsigned sd;
+       unsigned hd;
 };
 
 void radeon_dpm_enable_power_state(struct radeon_device *rdev,
                                    enum radeon_pm_state_type dpm_state);
-
+void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable);
 
 struct radeon_pm {
        struct mutex            mutex;
index 13a130fb3517abf56b2cface0641899890a9ec3f..5384fa42c16e4b458e8fe613fc0e6d77747f6d88 100644 (file)
@@ -383,6 +383,10 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,
                DRM_ERROR("Invalid command stream !\n");
                return r;
        }
+
+       if (parser->ring == R600_RING_TYPE_UVD_INDEX)
+               radeon_uvd_note_usage(rdev);
+
        radeon_cs_sync_rings(parser);
        r = radeon_ib_schedule(rdev, &parser->ib, NULL);
        if (r) {
@@ -474,6 +478,9 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
                return r;
        }
 
+       if (parser->ring == R600_RING_TYPE_UVD_INDEX)
+               radeon_uvd_note_usage(rdev);
+
        mutex_lock(&rdev->vm_manager.lock);
        mutex_lock(&vm->mutex);
        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)
                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);
        if (r) {
                goto out;
index c557850cd3450a5b0f363f24315d3051cb96cf3c..59d7a0c865892c7523f81b7660b51a1695424b6a 100644 (file)
@@ -729,6 +729,8 @@ restart_search:
        /* use a fallback state if we didn't match */
        switch (dpm_state) {
        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_HD2:
        case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
@@ -884,6 +886,34 @@ void radeon_dpm_enable_power_state(struct radeon_device *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)
 {
        mutex_lock(&rdev->pm.mutex);
index 2a4cff1acf0220c29b39ad33e0af8ec87c4e51a3..1a01bbff9bfa4f5c9ca1d354cd99abae981a36ce 100644 (file)
@@ -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 ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
-                       mutex_lock(&rdev->pm.mutex);
-                       rdev->pm.dpm.uvd_active = false;
-                       mutex_unlock(&rdev->pm.mutex);
-                       radeon_pm_compute_clocks(rdev);
+                       radeon_dpm_enable_uvd(rdev, false);
                } else {
                        radeon_set_uvd_clocks(rdev, 0, 0);
                }
@@ -790,13 +787,25 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work)
 
 void radeon_uvd_note_usage(struct radeon_device *rdev)
 {
+       bool streams_changed = false;
        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) {
+
+       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) {
-                       /* XXX pick SD/HD/MVC */
-                       radeon_dpm_enable_power_state(rdev, POWER_STATE_TYPE_INTERNAL_UVD);
+                       radeon_dpm_enable_uvd(rdev, true);
                } else {
                        radeon_set_uvd_clocks(rdev, 53300, 40000);
                }