Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce3537d5 authored by Alex Deucher's avatar Alex Deucher
Browse files

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
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -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;
+7 −4
Original line number Diff line number Diff line
@@ -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;
+30 −0
Original line number Diff line number Diff line
@@ -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 */
	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);
+16 −7
Original line number Diff line number Diff line
@@ -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);
		}