drm/radeon/kms: enable UVD as needed (v9)
authorAlex Deucher <alexander.deucher@amd.com>
Fri, 21 Jun 2013 19:12:57 +0000 (15:12 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 27 Jun 2013 23:15:49 +0000 (19:15 -0400)
When using UVD, the driver must switch to a special UVD power
state.  In the CS ioctl, switch to the power state and schedule
work to change the power state back, when the work comes up,
check if uvd is still busy and if not, switch back to the user
state, otherwise, reschedule the work.

Note:  We really need some better way to decide when to
switch out of the uvd power state.  Switching power states
while playback is active make uvd angry.

V2: fix locking.

V3: switch from timer to delayed work

V4: check fence driver for UVD jobs, reduce timeout to
    1 second and rearm timeout on activity

v5: rebase on new dpm tree

v6: rebase on interim uvd on demand changes

v7: fix UVD when DPM is disabled

v8: unify non-DPM and DPM UVD handling

v9: remove leftover idle work struct

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Christian König <deathsimple@vodafone.de>
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 5d4731b66e7d50354ee0e40f5b9cc62294ad6f36..84c459d447e820d243b7c1cc136d9ebd7617458d 100644 (file)
@@ -1241,6 +1241,7 @@ struct radeon_dpm {
        int                     current_active_crtc_count;
        /* special states active */
        bool                    thermal_active;
+       bool                    uvd_active;
        /* thermal handling */
        struct radeon_dpm_thermal thermal;
 };
index 7e265a58141f48aece454063599f416835f24f99..4f6b22b799ba36e684434f2ba06388a3c52ad9cf 100644 (file)
@@ -550,6 +550,7 @@ 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);
 
index 2998e75423a03eee69d3310c29416da030ec4e20..a97af88a81de365c35a87a3628305d0bb982cdf3 100644 (file)
@@ -696,7 +696,8 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 
        if (rdev->pm.dpm.user_state != rdev->pm.dpm.state) {
                /* add other state override checks here */
-               if (!rdev->pm.dpm.thermal_active)
+               if ((!rdev->pm.dpm.thermal_active) &&
+                   (!rdev->pm.dpm.uvd_active))
                        rdev->pm.dpm.state = rdev->pm.dpm.user_state;
        }
        dpm_state = rdev->pm.dpm.state;
@@ -766,8 +767,16 @@ void radeon_dpm_enable_power_state(struct radeon_device *rdev,
        case POWER_STATE_TYPE_INTERNAL_THERMAL:
                rdev->pm.dpm.thermal_active = true;
                break;
+       case POWER_STATE_TYPE_INTERNAL_UVD:
+       case POWER_STATE_TYPE_INTERNAL_UVD_SD:
+       case POWER_STATE_TYPE_INTERNAL_UVD_HD:
+       case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
+       case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
+               rdev->pm.dpm.uvd_active = true;
+               break;
        default:
                rdev->pm.dpm.thermal_active = false;
+               rdev->pm.dpm.uvd_active = false;
                break;
        }
        rdev->pm.dpm.state = dpm_state;
@@ -1220,6 +1229,7 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
        radeon_dpm_change_power_state_locked(rdev);
 
        mutex_unlock(&rdev->pm.mutex);
+
 }
 
 void radeon_pm_compute_clocks(struct radeon_device *rdev)
index fdc77d1eaac8276ff08cc950b6f38db7f58aa56a..ce5a10c8d3382c3a7abf55b22701539c4ee83e22 100644 (file)
@@ -699,11 +699,19 @@ 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
+       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);
+               } else {
+                       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)
@@ -711,8 +719,14 @@ 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);
+       if (set_clocks) {
+               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);
+               } else {
+                       radeon_set_uvd_clocks(rdev, 53300, 40000);
+               }
+       }
 }
 
 static unsigned radeon_uvd_calc_upll_post_div(unsigned vco_freq,