Commit d7311171 authored by Alex Deucher's avatar Alex Deucher Committed by Dave Airlie
Browse files

drm/radeon/kms/pm: add support for no display power states



The lowest power states often cause display problems, so only enable
them when all displays are off.

Signed-off-by: default avatarAlex Deucher <alexdeucher@gmail.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent ca2af923
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -245,13 +245,15 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)

	switch (mode) {
	case DRM_MODE_DPMS_ON:
		radeon_crtc->enabled = true;
		/* adjust pm to dpms changes BEFORE enabling crtcs */
		radeon_pm_compute_clocks(rdev);
		atombios_enable_crtc(crtc, ATOM_ENABLE);
		if (ASIC_IS_DCE3(rdev))
			atombios_enable_crtc_memreq(crtc, ATOM_ENABLE);
		atombios_blank_crtc(crtc, ATOM_DISABLE);
		drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
		radeon_crtc_load_lut(crtc);
		radeon_crtc->enabled = true;
		break;
	case DRM_MODE_DPMS_STANDBY:
	case DRM_MODE_DPMS_SUSPEND:
@@ -262,11 +264,10 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
			atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
		atombios_enable_crtc(crtc, ATOM_DISABLE);
		radeon_crtc->enabled = false;
		/* adjust pm to dpms changes AFTER disabling crtcs */
		radeon_pm_compute_clocks(rdev);
		break;
	}

	/* adjust pm to dpms change */
	radeon_pm_compute_clocks(rdev);
}

static void
+9 −3
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ void r100_get_power_state(struct radeon_device *rdev,
		} else {
			if (rdev->pm.active_crtc_count > 1) {
				for (i = 0; i < rdev->pm.num_power_states; i++) {
					if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
					if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
						continue;
					else if (i >= rdev->pm.current_power_state_index) {
						rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
@@ -101,6 +101,12 @@ void r100_get_power_state(struct radeon_device *rdev,
				rdev->pm.requested_power_state_index =
					rdev->pm.current_power_state_index - 1;
		}
		/* don't use the power state if crtcs are active and no display flag is set */
		if ((rdev->pm.active_crtc_count > 0) &&
		    (rdev->pm.power_state[rdev->pm.requested_power_state_index].clock_info[0].flags &
		     RADEON_PM_MODE_NO_DISPLAY)) {
			rdev->pm.requested_power_state_index++;
		}
		break;
	case PM_ACTION_UPCLOCK:
		if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) {
@@ -109,7 +115,7 @@ void r100_get_power_state(struct radeon_device *rdev,
		} else {
			if (rdev->pm.active_crtc_count > 1) {
				for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) {
					if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
					if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
						continue;
					else if (i <= rdev->pm.current_power_state_index) {
						rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
@@ -215,7 +221,7 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch)
		rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
		rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
	} else
		DRM_INFO("GUI not idle!!!\n");
		DRM_INFO("pm: GUI not idle!!!\n");
}

void r100_pm_misc(struct radeon_device *rdev)
+17 −3
Original line number Diff line number Diff line
@@ -120,7 +120,7 @@ void r600_get_power_state(struct radeon_device *rdev,
			} else {
				if (rdev->pm.active_crtc_count > 1) {
					for (i = 0; i < rdev->pm.num_power_states; i++) {
						if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
						if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
							continue;
						else if (i >= rdev->pm.current_power_state_index) {
							rdev->pm.requested_power_state_index =
@@ -136,6 +136,13 @@ void r600_get_power_state(struct radeon_device *rdev,
						rdev->pm.current_power_state_index - 1;
			}
			rdev->pm.requested_clock_mode_index = 0;
			/* don't use the power state if crtcs are active and no display flag is set */
			if ((rdev->pm.active_crtc_count > 0) &&
			    (rdev->pm.power_state[rdev->pm.requested_power_state_index].
			     clock_info[rdev->pm.requested_clock_mode_index].flags &
			     RADEON_PM_MODE_NO_DISPLAY)) {
				rdev->pm.requested_power_state_index++;
			}
			break;
		case PM_ACTION_UPCLOCK:
			if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) {
@@ -144,7 +151,7 @@ void r600_get_power_state(struct radeon_device *rdev,
			} else {
				if (rdev->pm.active_crtc_count > 1) {
					for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) {
						if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
						if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
							continue;
						else if (i <= rdev->pm.current_power_state_index) {
							rdev->pm.requested_power_state_index =
@@ -179,7 +186,7 @@ void r600_get_power_state(struct radeon_device *rdev,
			rdev->pm.requested_power_state_index = -1;
			/* start at 1 as we don't want the default mode */
			for (i = 1; i < rdev->pm.num_power_states; i++) {
				if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
				if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
					continue;
				else if ((rdev->pm.power_state[i].type == POWER_STATE_TYPE_PERFORMANCE) ||
					 (rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY)) {
@@ -210,6 +217,13 @@ void r600_get_power_state(struct radeon_device *rdev,
				rdev->pm.requested_clock_mode_index = 0;
				rdev->pm.can_downclock = false;
			}
			/* don't use the power state if crtcs are active and no display flag is set */
			if ((rdev->pm.active_crtc_count > 0) &&
			    (rdev->pm.power_state[rdev->pm.requested_power_state_index].
			     clock_info[rdev->pm.requested_clock_mode_index].flags &
			     RADEON_PM_MODE_NO_DISPLAY)) {
				rdev->pm.requested_clock_mode_index++;
			}
			break;
		case PM_ACTION_UPCLOCK:
			if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) {
+5 −2
Original line number Diff line number Diff line
@@ -658,6 +658,9 @@ struct radeon_voltage {
	u32 voltage;
};

/* clock mode flags */
#define RADEON_PM_MODE_NO_DISPLAY          (1 << 0)

struct radeon_pm_clock_info {
	/* memory clock */
	u32 mclk;
@@ -665,12 +668,12 @@ struct radeon_pm_clock_info {
	u32 sclk;
	/* voltage info */
	struct radeon_voltage voltage;
	/* standardized clock flags - not sure we'll need these */
	/* standardized clock flags */
	u32 flags;
};

/* state flags */
#define RADEON_PM_SINGLE_DISPLAY_ONLY (1 << 0)
#define RADEON_PM_STATE_SINGLE_DISPLAY_ONLY (1 << 0)

struct radeon_power_state {
	enum radeon_pm_state_type type;
+26 −11
Original line number Diff line number Diff line
@@ -1549,7 +1549,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
						rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
							power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex;
					}
					rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY;
					rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
					rdev->pm.power_state[state_index].misc = misc;
					/* order matters! */
					if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
@@ -1568,7 +1568,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
						rdev->pm.power_state[state_index].type =
							POWER_STATE_TYPE_PERFORMANCE;
						rdev->pm.power_state[state_index].flags &=
							~RADEON_PM_SINGLE_DISPLAY_ONLY;
							~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
					}
					if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
						rdev->pm.power_state[state_index].type =
@@ -1577,7 +1577,10 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
						rdev->pm.power_state[state_index].default_clock_mode =
							&rdev->pm.power_state[state_index].clock_info[0];
						rdev->pm.power_state[state_index].flags &=
							~RADEON_PM_SINGLE_DISPLAY_ONLY;
							~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
					} else if (state_index == 0) {
						rdev->pm.power_state[state_index].clock_info[0].flags |=
							RADEON_PM_MODE_NO_DISPLAY;
					}
					state_index++;
					break;
@@ -1613,7 +1616,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
						rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
							power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex;
					}
					rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY;
					rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
					rdev->pm.power_state[state_index].misc = misc;
					rdev->pm.power_state[state_index].misc2 = misc2;
					/* order matters! */
@@ -1633,14 +1636,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
						rdev->pm.power_state[state_index].type =
							POWER_STATE_TYPE_PERFORMANCE;
						rdev->pm.power_state[state_index].flags &=
							~RADEON_PM_SINGLE_DISPLAY_ONLY;
							~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
					}
					if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
						rdev->pm.power_state[state_index].type =
							POWER_STATE_TYPE_BALANCED;
					if (misc2 & ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT)
						rdev->pm.power_state[state_index].flags &=
							~RADEON_PM_SINGLE_DISPLAY_ONLY;
							~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
					if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
						rdev->pm.power_state[state_index].type =
							POWER_STATE_TYPE_DEFAULT;
@@ -1648,7 +1651,10 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
						rdev->pm.power_state[state_index].default_clock_mode =
							&rdev->pm.power_state[state_index].clock_info[0];
						rdev->pm.power_state[state_index].flags &=
							~RADEON_PM_SINGLE_DISPLAY_ONLY;
							~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
					} else if (state_index == 0) {
						rdev->pm.power_state[state_index].clock_info[0].flags |=
							RADEON_PM_MODE_NO_DISPLAY;
					}
					state_index++;
					break;
@@ -1690,7 +1696,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
							power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex;
						}
					}
					rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY;
					rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
					rdev->pm.power_state[state_index].misc = misc;
					rdev->pm.power_state[state_index].misc2 = misc2;
					/* order matters! */
@@ -1710,7 +1716,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
						rdev->pm.power_state[state_index].type =
							POWER_STATE_TYPE_PERFORMANCE;
						rdev->pm.power_state[state_index].flags &=
							~RADEON_PM_SINGLE_DISPLAY_ONLY;
							~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
					}
					if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
						rdev->pm.power_state[state_index].type =
@@ -1721,6 +1727,9 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
						rdev->pm.default_power_state_index = state_index;
						rdev->pm.power_state[state_index].default_clock_mode =
							&rdev->pm.power_state[state_index].clock_info[0];
					} else if (state_index == 0) {
						rdev->pm.power_state[state_index].clock_info[0].flags |=
							RADEON_PM_MODE_NO_DISPLAY;
					}
					state_index++;
					break;
@@ -1734,7 +1743,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
				rdev->pm.power_state[state_index - 1].default_clock_mode =
					&rdev->pm.power_state[state_index - 1].clock_info[0];
				rdev->pm.power_state[state_index].flags &=
					~RADEON_PM_SINGLE_DISPLAY_ONLY;
					~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
				rdev->pm.power_state[state_index].misc = 0;
				rdev->pm.power_state[state_index].misc2 = 0;
			}
@@ -1881,7 +1890,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
					rdev->pm.power_state[state_index].flags = 0;
					if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
						rdev->pm.power_state[state_index].flags |=
							RADEON_PM_SINGLE_DISPLAY_ONLY;
							RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
					if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) {
						rdev->pm.power_state[state_index].type =
							POWER_STATE_TYPE_DEFAULT;
@@ -1892,6 +1901,12 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
					state_index++;
				}
			}
			/* if multiple clock modes, mark the lowest as no display */
			for (i = 0; i < state_index; i++) {
				if (rdev->pm.power_state[i].num_clock_modes > 1)
					rdev->pm.power_state[i].clock_info[0].flags |=
						RADEON_PM_MODE_NO_DISPLAY;
			}
			/* first mode is usually default */
			if (rdev->pm.default_power_state_index == -1) {
				rdev->pm.power_state[0].type =
Loading