Skip to content

Commit

Permalink
drm/radeon/kms/pm: add support for no display power states
Browse files Browse the repository at this point in the history
The lowest power states often cause display problems, so only enable
them when all displays are off.

Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Alex Deucher authored and Dave Airlie committed May 18, 2010
1 parent ca2af92 commit d731117
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 40 deletions.
9 changes: 5 additions & 4 deletions drivers/gpu/drm/radeon/atombios_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand Down
12 changes: 9 additions & 3 deletions drivers/gpu/drm/radeon/r100.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)) {
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
20 changes: 17 additions & 3 deletions drivers/gpu/drm/radeon/r600.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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)) {
Expand All @@ -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 =
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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) {
Expand Down
7 changes: 5 additions & 2 deletions drivers/gpu/drm/radeon/radeon.h
Original file line number Diff line number Diff line change
Expand Up @@ -658,19 +658,22 @@ 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;
/* engine clock */
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;
Expand Down
37 changes: 26 additions & 11 deletions drivers/gpu/drm/radeon/radeon_atombios.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 =
Expand All @@ -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;
Expand Down Expand Up @@ -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! */
Expand All @@ -1633,22 +1636,25 @@ 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;
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];
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;
Expand Down Expand Up @@ -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! */
Expand All @@ -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 =
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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 =
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/radeon/radeon_combios.c
Original file line number Diff line number Diff line change
Expand Up @@ -2437,7 +2437,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
if (rev > 6)
rdev->pm.power_state[state_index].pcie_lanes =
RBIOS8(offset + 0x5 + 0x10);
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;
state_index++;
} else {
/* XXX figure out some good default low power mode for mobility cards w/out power tables */
Expand Down
9 changes: 5 additions & 4 deletions drivers/gpu/drm/radeon/radeon_legacy_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,9 @@ void radeon_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);
if (radeon_crtc->crtc_id)
WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~(RADEON_CRTC2_EN | mask));
else {
Expand All @@ -323,7 +326,6 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
}
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:
Expand All @@ -337,11 +339,10 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask);
}
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);
}

int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
Expand Down
Loading

0 comments on commit d731117

Please sign in to comment.