diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2010-04-22 14:03:55 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-05-18 04:20:58 -0400 |
commit | a48b9b4edb8bb87deb13b9f088a595cf71457b69 (patch) | |
tree | 2cfe4156f911042a6c3943ee98503d452941dd92 /drivers/gpu/drm/radeon/r600.c | |
parent | bae6b5627387a950a8faf366d6027bd0a7a93078 (diff) |
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 <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/r600.c')
-rw-r--r-- | drivers/gpu/drm/radeon/r600.c | 217 |
1 files changed, 191 insertions, 26 deletions
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c2d1946535ab..cc2797949ee5 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c | |||
@@ -92,41 +92,206 @@ void r600_gpu_init(struct radeon_device *rdev); | |||
92 | void r600_fini(struct radeon_device *rdev); | 92 | void r600_fini(struct radeon_device *rdev); |
93 | void r600_irq_disable(struct radeon_device *rdev); | 93 | void r600_irq_disable(struct radeon_device *rdev); |
94 | 94 | ||
95 | void r600_set_power_state(struct radeon_device *rdev) | 95 | void r600_get_power_state(struct radeon_device *rdev, |
96 | enum radeon_pm_action action) | ||
96 | { | 97 | { |
97 | /* if *_clock_mode are the same, *_power_state are as well */ | 98 | int i; |
98 | if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) | 99 | |
99 | return; | 100 | rdev->pm.can_upclock = true; |
101 | rdev->pm.can_downclock = true; | ||
102 | |||
103 | /* power state array is low to high, default is first */ | ||
104 | if ((rdev->flags & RADEON_IS_IGP) || (rdev->family == CHIP_R600)) { | ||
105 | int min_power_state_index = 0; | ||
106 | |||
107 | if (rdev->pm.num_power_states > 2) | ||
108 | min_power_state_index = 1; | ||
109 | |||
110 | switch (action) { | ||
111 | case PM_ACTION_MINIMUM: | ||
112 | rdev->pm.requested_power_state_index = min_power_state_index; | ||
113 | rdev->pm.requested_clock_mode_index = 0; | ||
114 | rdev->pm.can_downclock = false; | ||
115 | break; | ||
116 | case PM_ACTION_DOWNCLOCK: | ||
117 | if (rdev->pm.current_power_state_index == min_power_state_index) { | ||
118 | rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; | ||
119 | rdev->pm.can_downclock = false; | ||
120 | } else { | ||
121 | if (rdev->pm.active_crtc_count > 1) { | ||
122 | for (i = 0; i < rdev->pm.num_power_states; i++) { | ||
123 | if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) | ||
124 | continue; | ||
125 | else if (i >= rdev->pm.current_power_state_index) { | ||
126 | rdev->pm.requested_power_state_index = | ||
127 | rdev->pm.current_power_state_index; | ||
128 | break; | ||
129 | } else { | ||
130 | rdev->pm.requested_power_state_index = i; | ||
131 | break; | ||
132 | } | ||
133 | } | ||
134 | } else | ||
135 | rdev->pm.requested_power_state_index = | ||
136 | rdev->pm.current_power_state_index - 1; | ||
137 | } | ||
138 | rdev->pm.requested_clock_mode_index = 0; | ||
139 | break; | ||
140 | case PM_ACTION_UPCLOCK: | ||
141 | if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { | ||
142 | rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; | ||
143 | rdev->pm.can_upclock = false; | ||
144 | } else { | ||
145 | if (rdev->pm.active_crtc_count > 1) { | ||
146 | for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { | ||
147 | if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) | ||
148 | continue; | ||
149 | else if (i <= rdev->pm.current_power_state_index) { | ||
150 | rdev->pm.requested_power_state_index = | ||
151 | rdev->pm.current_power_state_index; | ||
152 | break; | ||
153 | } else { | ||
154 | rdev->pm.requested_power_state_index = i; | ||
155 | break; | ||
156 | } | ||
157 | } | ||
158 | } else | ||
159 | rdev->pm.requested_power_state_index = | ||
160 | rdev->pm.current_power_state_index + 1; | ||
161 | } | ||
162 | rdev->pm.requested_clock_mode_index = 0; | ||
163 | break; | ||
164 | case PM_ACTION_NONE: | ||
165 | default: | ||
166 | DRM_ERROR("Requested mode for not defined action\n"); | ||
167 | return; | ||
168 | } | ||
169 | } else { | ||
170 | /* XXX select a power state based on AC/DC, single/dualhead, etc. */ | ||
171 | /* for now just select the first power state and switch between clock modes */ | ||
172 | /* power state array is low to high, default is first (0) */ | ||
173 | if (rdev->pm.active_crtc_count > 1) { | ||
174 | rdev->pm.requested_power_state_index = -1; | ||
175 | /* start at 1 as we don't want the default mode */ | ||
176 | for (i = 1; i < rdev->pm.num_power_states; i++) { | ||
177 | if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) | ||
178 | continue; | ||
179 | else if ((rdev->pm.power_state[i].type == POWER_STATE_TYPE_PERFORMANCE) || | ||
180 | (rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY)) { | ||
181 | rdev->pm.requested_power_state_index = i; | ||
182 | break; | ||
183 | } | ||
184 | } | ||
185 | /* if nothing selected, grab the default state. */ | ||
186 | if (rdev->pm.requested_power_state_index == -1) | ||
187 | rdev->pm.requested_power_state_index = 0; | ||
188 | } else | ||
189 | rdev->pm.requested_power_state_index = 1; | ||
190 | |||
191 | switch (action) { | ||
192 | case PM_ACTION_MINIMUM: | ||
193 | rdev->pm.requested_clock_mode_index = 0; | ||
194 | rdev->pm.can_downclock = false; | ||
195 | break; | ||
196 | case PM_ACTION_DOWNCLOCK: | ||
197 | if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { | ||
198 | if (rdev->pm.current_clock_mode_index == 0) { | ||
199 | rdev->pm.requested_clock_mode_index = 0; | ||
200 | rdev->pm.can_downclock = false; | ||
201 | } else | ||
202 | rdev->pm.requested_clock_mode_index = | ||
203 | rdev->pm.current_clock_mode_index - 1; | ||
204 | } else { | ||
205 | rdev->pm.requested_clock_mode_index = 0; | ||
206 | rdev->pm.can_downclock = false; | ||
207 | } | ||
208 | break; | ||
209 | case PM_ACTION_UPCLOCK: | ||
210 | if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { | ||
211 | if (rdev->pm.current_clock_mode_index == | ||
212 | (rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1)) { | ||
213 | rdev->pm.requested_clock_mode_index = rdev->pm.current_clock_mode_index; | ||
214 | rdev->pm.can_upclock = false; | ||
215 | } else | ||
216 | rdev->pm.requested_clock_mode_index = | ||
217 | rdev->pm.current_clock_mode_index + 1; | ||
218 | } else { | ||
219 | rdev->pm.requested_clock_mode_index = | ||
220 | rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1; | ||
221 | rdev->pm.can_upclock = false; | ||
222 | } | ||
223 | break; | ||
224 | case PM_ACTION_NONE: | ||
225 | default: | ||
226 | DRM_ERROR("Requested mode for not defined action\n"); | ||
227 | return; | ||
228 | } | ||
229 | } | ||
100 | 230 | ||
101 | DRM_INFO("Setting: e: %d m: %d p: %d\n", | 231 | DRM_INFO("Requested: e: %d m: %d p: %d\n", |
102 | rdev->pm.requested_clock_mode->sclk, | 232 | rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
103 | rdev->pm.requested_clock_mode->mclk, | 233 | clock_info[rdev->pm.requested_clock_mode_index].sclk, |
104 | rdev->pm.requested_power_state->non_clock_info.pcie_lanes); | 234 | rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
235 | clock_info[rdev->pm.requested_clock_mode_index].mclk, | ||
236 | rdev->pm.power_state[rdev->pm.requested_power_state_index]. | ||
237 | non_clock_info.pcie_lanes); | ||
238 | } | ||
105 | 239 | ||
106 | /* set pcie lanes */ | 240 | void r600_set_power_state(struct radeon_device *rdev) |
107 | /* TODO */ | 241 | { |
242 | u32 sclk, mclk; | ||
108 | 243 | ||
109 | /* set voltage */ | 244 | if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && |
110 | /* TODO */ | 245 | (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) |
246 | return; | ||
111 | 247 | ||
112 | /* set engine clock */ | 248 | if (radeon_gui_idle(rdev)) { |
113 | radeon_sync_with_vblank(rdev); | 249 | |
114 | radeon_pm_debug_check_in_vbl(rdev, false); | 250 | sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
115 | radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); | 251 | clock_info[rdev->pm.requested_clock_mode_index].sclk; |
116 | radeon_pm_debug_check_in_vbl(rdev, true); | 252 | if (sclk > rdev->clock.default_sclk) |
253 | sclk = rdev->clock.default_sclk; | ||
254 | |||
255 | mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. | ||
256 | clock_info[rdev->pm.requested_clock_mode_index].mclk; | ||
257 | if (mclk > rdev->clock.default_mclk) | ||
258 | mclk = rdev->clock.default_mclk; | ||
259 | /* don't change the mclk with multiple crtcs */ | ||
260 | if (rdev->pm.active_crtc_count > 1) | ||
261 | mclk = rdev->clock.default_mclk; | ||
262 | |||
263 | /* set pcie lanes */ | ||
264 | /* TODO */ | ||
265 | |||
266 | /* set voltage */ | ||
267 | /* TODO */ | ||
268 | |||
269 | /* set engine clock */ | ||
270 | if (sclk != rdev->pm.current_sclk) { | ||
271 | radeon_sync_with_vblank(rdev); | ||
272 | radeon_pm_debug_check_in_vbl(rdev, false); | ||
273 | radeon_set_engine_clock(rdev, sclk); | ||
274 | radeon_pm_debug_check_in_vbl(rdev, true); | ||
275 | rdev->pm.current_sclk = sclk; | ||
276 | DRM_INFO("Setting: e: %d\n", sclk); | ||
277 | } | ||
117 | 278 | ||
118 | #if 0 | 279 | #if 0 |
119 | /* set memory clock */ | 280 | /* set memory clock */ |
120 | if (rdev->asic->set_memory_clock) { | 281 | if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { |
121 | radeon_sync_with_vblank(rdev); | 282 | radeon_sync_with_vblank(rdev); |
122 | radeon_pm_debug_check_in_vbl(rdev, false); | 283 | radeon_pm_debug_check_in_vbl(rdev, false); |
123 | radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk); | 284 | radeon_set_memory_clock(rdev, mclk); |
124 | radeon_pm_debug_check_in_vbl(rdev, true); | 285 | radeon_pm_debug_check_in_vbl(rdev, true); |
125 | } | 286 | rdev->pm.current_mclk = mclk; |
287 | DRM_INFO("Setting: m: %d\n", mclk); | ||
288 | } | ||
126 | #endif | 289 | #endif |
127 | 290 | ||
128 | rdev->pm.current_power_state = rdev->pm.requested_power_state; | 291 | rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; |
129 | rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; | 292 | rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; |
293 | } else | ||
294 | DRM_INFO("GUI not idle!!!\n"); | ||
130 | } | 295 | } |
131 | 296 | ||
132 | bool r600_gui_idle(struct radeon_device *rdev) | 297 | bool r600_gui_idle(struct radeon_device *rdev) |