Skip to content

Commit a48b9b4

Browse files
agd5fairlied
authored andcommitted
drm/radeon/kms/pm: add asic specific callbacks for getting power state (v2)
This also simplifies the code and enables reclocking with multiple heads active by tracking whether the power states are single or multi-head capable. Eventually, we will want to select a power state based on external factors (AC/DC state, user selection, etc.). (v2) Update for evergreen Signed-off-by: Alex Deucher <[email protected]> Signed-off-by: Dave Airlie <[email protected]>
1 parent bae6b56 commit a48b9b4

10 files changed

+413
-246
lines changed

drivers/gpu/drm/radeon/atombios_crtc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
251251
atombios_blank_crtc(crtc, ATOM_DISABLE);
252252
drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
253253
radeon_crtc_load_lut(crtc);
254+
radeon_crtc->enabled = true;
254255
break;
255256
case DRM_MODE_DPMS_STANDBY:
256257
case DRM_MODE_DPMS_SUSPEND:
@@ -260,6 +261,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
260261
if (ASIC_IS_DCE3(rdev))
261262
atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
262263
atombios_enable_crtc(crtc, ATOM_DISABLE);
264+
radeon_crtc->enabled = false;
263265
break;
264266
}
265267

drivers/gpu/drm/radeon/r100.c

Lines changed: 116 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -67,41 +67,133 @@ MODULE_FIRMWARE(FIRMWARE_R520);
6767
* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280
6868
*/
6969

70+
void r100_get_power_state(struct radeon_device *rdev,
71+
enum radeon_pm_action action)
72+
{
73+
int i;
74+
rdev->pm.can_upclock = true;
75+
rdev->pm.can_downclock = true;
76+
77+
switch (action) {
78+
case PM_ACTION_MINIMUM:
79+
rdev->pm.requested_power_state_index = 0;
80+
rdev->pm.can_downclock = false;
81+
break;
82+
case PM_ACTION_DOWNCLOCK:
83+
if (rdev->pm.current_power_state_index == 0) {
84+
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
85+
rdev->pm.can_downclock = false;
86+
} else {
87+
if (rdev->pm.active_crtc_count > 1) {
88+
for (i = 0; i < rdev->pm.num_power_states; i++) {
89+
if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
90+
continue;
91+
else if (i >= rdev->pm.current_power_state_index) {
92+
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
93+
break;
94+
} else {
95+
rdev->pm.requested_power_state_index = i;
96+
break;
97+
}
98+
}
99+
} else
100+
rdev->pm.requested_power_state_index =
101+
rdev->pm.current_power_state_index - 1;
102+
}
103+
break;
104+
case PM_ACTION_UPCLOCK:
105+
if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) {
106+
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
107+
rdev->pm.can_upclock = false;
108+
} else {
109+
if (rdev->pm.active_crtc_count > 1) {
110+
for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) {
111+
if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
112+
continue;
113+
else if (i <= rdev->pm.current_power_state_index) {
114+
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
115+
break;
116+
} else {
117+
rdev->pm.requested_power_state_index = i;
118+
break;
119+
}
120+
}
121+
} else
122+
rdev->pm.requested_power_state_index =
123+
rdev->pm.current_power_state_index + 1;
124+
}
125+
break;
126+
case PM_ACTION_NONE:
127+
default:
128+
DRM_ERROR("Requested mode for not defined action\n");
129+
return;
130+
}
131+
/* only one clock mode per power state */
132+
rdev->pm.requested_clock_mode_index = 0;
133+
134+
DRM_INFO("Requested: e: %d m: %d p: %d\n",
135+
rdev->pm.power_state[rdev->pm.requested_power_state_index].
136+
clock_info[rdev->pm.requested_clock_mode_index].sclk,
137+
rdev->pm.power_state[rdev->pm.requested_power_state_index].
138+
clock_info[rdev->pm.requested_clock_mode_index].mclk,
139+
rdev->pm.power_state[rdev->pm.requested_power_state_index].
140+
non_clock_info.pcie_lanes);
141+
}
142+
70143
void r100_set_power_state(struct radeon_device *rdev)
71144
{
72-
/* if *_clock_mode are the same, *_power_state are as well */
73-
if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode)
145+
u32 sclk, mclk;
146+
147+
if (rdev->pm.current_power_state_index == rdev->pm.requested_power_state_index)
74148
return;
75149

76-
DRM_INFO("Setting: e: %d m: %d p: %d\n",
77-
rdev->pm.requested_clock_mode->sclk,
78-
rdev->pm.requested_clock_mode->mclk,
79-
rdev->pm.requested_power_state->non_clock_info.pcie_lanes);
150+
if (radeon_gui_idle(rdev)) {
80151

81-
/* set pcie lanes */
82-
/* TODO */
152+
sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
153+
clock_info[rdev->pm.requested_clock_mode_index].sclk;
154+
if (sclk > rdev->clock.default_sclk)
155+
sclk = rdev->clock.default_sclk;
83156

84-
/* set voltage */
85-
/* TODO */
157+
mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
158+
clock_info[rdev->pm.requested_clock_mode_index].mclk;
159+
if (mclk > rdev->clock.default_mclk)
160+
mclk = rdev->clock.default_mclk;
161+
/* don't change the mclk with multiple crtcs */
162+
if (rdev->pm.active_crtc_count > 1)
163+
mclk = rdev->clock.default_mclk;
86164

87-
/* set engine clock */
88-
radeon_sync_with_vblank(rdev);
89-
radeon_pm_debug_check_in_vbl(rdev, false);
90-
radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk);
91-
radeon_pm_debug_check_in_vbl(rdev, true);
165+
/* set pcie lanes */
166+
/* TODO */
167+
168+
/* set voltage */
169+
/* TODO */
170+
171+
/* set engine clock */
172+
if (sclk != rdev->pm.current_sclk) {
173+
radeon_sync_with_vblank(rdev);
174+
radeon_pm_debug_check_in_vbl(rdev, false);
175+
radeon_set_engine_clock(rdev, sclk);
176+
radeon_pm_debug_check_in_vbl(rdev, true);
177+
rdev->pm.current_sclk = sclk;
178+
DRM_INFO("Setting: e: %d\n", sclk);
179+
}
92180

93181
#if 0
94-
/* set memory clock */
95-
if (rdev->asic->set_memory_clock) {
96-
radeon_sync_with_vblank(rdev);
97-
radeon_pm_debug_check_in_vbl(rdev, false);
98-
radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk);
99-
radeon_pm_debug_check_in_vbl(rdev, true);
100-
}
182+
/* set memory clock */
183+
if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
184+
radeon_sync_with_vblank(rdev);
185+
radeon_pm_debug_check_in_vbl(rdev, false);
186+
radeon_set_memory_clock(rdev, mclk);
187+
radeon_pm_debug_check_in_vbl(rdev, true);
188+
rdev->pm.current_mclk = mclk;
189+
DRM_INFO("Setting: m: %d\n", mclk);
190+
}
101191
#endif
102192

103-
rdev->pm.current_power_state = rdev->pm.requested_power_state;
104-
rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode;
193+
rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
194+
rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
195+
} else
196+
DRM_INFO("GUI not idle!!!\n");
105197
}
106198

107199
bool r100_gui_idle(struct radeon_device *rdev)

0 commit comments

Comments
 (0)