diff options
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) |