Rev 1986 | Rev 5078 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1986 | Rev 2997 | ||
---|---|---|---|
Line 18... | Line 18... | ||
18 | * OTHER DEALINGS IN THE SOFTWARE. |
18 | * OTHER DEALINGS IN THE SOFTWARE. |
19 | * |
19 | * |
20 | * Authors: Rafał Miłecki |
20 | * Authors: Rafał Miłecki |
21 | * Alex Deucher |
21 | * Alex Deucher |
22 | */ |
22 | */ |
23 | #include "drmP.h" |
23 | #include |
24 | #include "radeon.h" |
24 | #include "radeon.h" |
25 | #include "avivod.h" |
25 | #include "avivod.h" |
26 | #include "atom.h" |
26 | #include "atom.h" |
Line 27... | Line -... | ||
27 | - | ||
Line 28... | Line 27... | ||
28 | #define DRM_DEBUG_DRIVER(fmt, args...) |
27 | |
29 | 28 | ||
30 | #define RADEON_IDLE_LOOP_MS 100 |
29 | #define RADEON_IDLE_LOOP_MS 100 |
31 | #define RADEON_RECLOCK_DELAY_MS 200 |
- | |
Line 32... | Line 30... | ||
32 | #define RADEON_WAIT_VBLANK_TIMEOUT 200 |
30 | #define RADEON_RECLOCK_DELAY_MS 200 |
33 | #define RADEON_WAIT_IDLE_TIMEOUT 200 |
31 | #define RADEON_WAIT_VBLANK_TIMEOUT 200 |
34 | 32 | ||
35 | static const char *radeon_pm_state_type_name[5] = { |
33 | static const char *radeon_pm_state_type_name[5] = { |
36 | "Default", |
34 | "", |
37 | "Powersave", |
35 | "Powersave", |
38 | "Battery", |
36 | "Battery", |
Line 45... | Line 43... | ||
45 | static bool radeon_pm_in_vbl(struct radeon_device *rdev); |
43 | static bool radeon_pm_in_vbl(struct radeon_device *rdev); |
46 | static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); |
44 | static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); |
47 | static void radeon_pm_update_profile(struct radeon_device *rdev); |
45 | static void radeon_pm_update_profile(struct radeon_device *rdev); |
48 | static void radeon_pm_set_clocks(struct radeon_device *rdev); |
46 | static void radeon_pm_set_clocks(struct radeon_device *rdev); |
Line 49... | Line -... | ||
49 | - | ||
50 | static inline int power_supply_is_system_supplied(void) { return -ENOSYS; } |
- | |
51 | - | ||
52 | #define ACPI_AC_CLASS "ac_adapter" |
- | |
53 | - | ||
54 | #ifdef CONFIG_ACPI |
47 | |
55 | static int radeon_acpi_event(struct notifier_block *nb, |
48 | int radeon_pm_get_type_index(struct radeon_device *rdev, |
56 | unsigned long val, |
49 | enum radeon_pm_state_type ps_type, |
57 | void *data) |
50 | int instance) |
58 | { |
51 | { |
59 | struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb); |
52 | int i; |
Line 60... | Line 53... | ||
60 | struct acpi_bus_event *entry = (struct acpi_bus_event *)data; |
53 | int found_instance = -1; |
61 | 54 | ||
- | 55 | for (i = 0; i < rdev->pm.num_power_states; i++) { |
|
62 | if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { |
56 | if (rdev->pm.power_state[i].type == ps_type) { |
- | 57 | found_instance++; |
|
63 | if (power_supply_is_system_supplied() > 0) |
58 | if (found_instance == instance) |
- | 59 | return i; |
|
64 | DRM_DEBUG_DRIVER("pm: AC\n"); |
60 | } |
- | 61 | } |
|
- | 62 | /* return default if no match */ |
|
Line -... | Line 63... | ||
- | 63 | return rdev->pm.default_power_state_index; |
|
- | 64 | } |
|
65 | else |
65 | |
66 | DRM_DEBUG_DRIVER("pm: DC\n"); |
66 | void radeon_pm_acpi_event_handler(struct radeon_device *rdev) |
67 | 67 | { |
|
68 | if (rdev->pm.pm_method == PM_METHOD_PROFILE) { |
68 | if (rdev->pm.pm_method == PM_METHOD_PROFILE) { |
69 | if (rdev->pm.profile == PM_PROFILE_AUTO) { |
69 | if (rdev->pm.profile == PM_PROFILE_AUTO) { |
70 | mutex_lock(&rdev->pm.mutex); |
70 | mutex_lock(&rdev->pm.mutex); |
71 | radeon_pm_update_profile(rdev); |
71 | radeon_pm_update_profile(rdev); |
72 | radeon_pm_set_clocks(rdev); |
72 | radeon_pm_set_clocks(rdev); |
73 | mutex_unlock(&rdev->pm.mutex); |
- | |
74 | } |
- | |
75 | } |
- | |
76 | } |
73 | mutex_unlock(&rdev->pm.mutex); |
77 | - | ||
Line 78... | Line 74... | ||
78 | return NOTIFY_OK; |
74 | } |
79 | } |
75 | } |
80 | #endif |
76 | } |
81 | 77 | ||
Line 138... | Line 134... | ||
138 | if (list_empty(&rdev->gem.objects)) |
134 | if (list_empty(&rdev->gem.objects)) |
139 | return; |
135 | return; |
Line 140... | Line 136... | ||
140 | 136 | ||
Line -... | Line 137... | ||
- | 137 | } |
|
- | 138 | ||
- | 139 | static void radeon_sync_with_vblank(struct radeon_device *rdev) |
|
- | 140 | { |
|
- | 141 | if (rdev->pm.active_crtcs) { |
|
- | 142 | rdev->pm.vblank_sync = false; |
|
- | 143 | // wait_event_timeout( |
|
- | 144 | // rdev->irq.vblank_queue, rdev->pm.vblank_sync, |
|
- | 145 | // msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); |
|
Line 141... | Line 146... | ||
141 | } |
146 | } |
142 | 147 | } |
|
143 | 148 | ||
144 | static void radeon_set_power_state(struct radeon_device *rdev) |
149 | static void radeon_set_power_state(struct radeon_device *rdev) |
Line 154... | Line 159... | ||
154 | sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
159 | sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
155 | clock_info[rdev->pm.requested_clock_mode_index].sclk; |
160 | clock_info[rdev->pm.requested_clock_mode_index].sclk; |
156 | if (sclk > rdev->pm.default_sclk) |
161 | if (sclk > rdev->pm.default_sclk) |
157 | sclk = rdev->pm.default_sclk; |
162 | sclk = rdev->pm.default_sclk; |
Line -... | Line 163... | ||
- | 163 | ||
- | 164 | /* starting with BTC, there is one state that is used for both |
|
- | 165 | * MH and SH. Difference is that we always use the high clock index for |
|
- | 166 | * mclk. |
|
- | 167 | */ |
|
- | 168 | if ((rdev->pm.pm_method == PM_METHOD_PROFILE) && |
|
- | 169 | (rdev->family >= CHIP_BARTS) && |
|
- | 170 | rdev->pm.active_crtc_count && |
|
- | 171 | ((rdev->pm.profile_index == PM_PROFILE_MID_MH_IDX) || |
|
- | 172 | (rdev->pm.profile_index == PM_PROFILE_LOW_MH_IDX))) |
|
- | 173 | mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
|
- | 174 | clock_info[rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx].mclk; |
|
158 | 175 | else |
|
159 | mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
176 | mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
- | 177 | clock_info[rdev->pm.requested_clock_mode_index].mclk; |
|
160 | clock_info[rdev->pm.requested_clock_mode_index].mclk; |
178 | |
161 | if (mclk > rdev->pm.default_mclk) |
179 | if (mclk > rdev->pm.default_mclk) |
Line 162... | Line 180... | ||
162 | mclk = rdev->pm.default_mclk; |
180 | mclk = rdev->pm.default_mclk; |
163 | 181 | ||
164 | /* upvolt before raising clocks, downvolt after lowering clocks */ |
182 | /* upvolt before raising clocks, downvolt after lowering clocks */ |
Line 165... | Line 183... | ||
165 | if (sclk < rdev->pm.current_sclk) |
183 | if (sclk < rdev->pm.current_sclk) |
Line 166... | Line 184... | ||
166 | misc_after = true; |
184 | misc_after = true; |
167 | 185 | ||
168 | // radeon_sync_with_vblank(rdev); |
186 | radeon_sync_with_vblank(rdev); |
169 | 187 | ||
Line 186... | Line 204... | ||
186 | rdev->pm.current_sclk = sclk; |
204 | rdev->pm.current_sclk = sclk; |
187 | DRM_DEBUG_DRIVER("Setting: e: %d\n", sclk); |
205 | DRM_DEBUG_DRIVER("Setting: e: %d\n", sclk); |
188 | } |
206 | } |
Line 189... | Line 207... | ||
189 | 207 | ||
190 | /* set memory clock */ |
208 | /* set memory clock */ |
191 | if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { |
209 | if (rdev->asic->pm.set_memory_clock && (mclk != rdev->pm.current_mclk)) { |
192 | radeon_pm_debug_check_in_vbl(rdev, false); |
210 | radeon_pm_debug_check_in_vbl(rdev, false); |
193 | radeon_set_memory_clock(rdev, mclk); |
211 | radeon_set_memory_clock(rdev, mclk); |
194 | radeon_pm_debug_check_in_vbl(rdev, true); |
212 | radeon_pm_debug_check_in_vbl(rdev, true); |
195 | rdev->pm.current_mclk = mclk; |
213 | rdev->pm.current_mclk = mclk; |
Line 216... | Line 234... | ||
216 | if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && |
234 | if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && |
217 | (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) |
235 | (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) |
218 | return; |
236 | return; |
Line 219... | Line 237... | ||
219 | 237 | ||
220 | mutex_lock(&rdev->ddev->struct_mutex); |
238 | mutex_lock(&rdev->ddev->struct_mutex); |
221 | mutex_lock(&rdev->vram_mutex); |
239 | // down_write(&rdev->pm.mclk_lock); |
Line 222... | Line -... | ||
222 | mutex_lock(&rdev->cp.mutex); |
- | |
223 | - | ||
224 | /* gui idle int has issues on older chips it seems */ |
- | |
225 | if (rdev->family >= CHIP_R600) { |
240 | mutex_lock(&rdev->ring_lock); |
226 | if (rdev->irq.installed) { |
241 | |
227 | /* wait for GPU idle */ |
242 | /* wait for the rings to drain */ |
228 | rdev->pm.gui_idle = false; |
- | |
229 | rdev->irq.gui_idle = true; |
- | |
230 | } |
243 | for (i = 0; i < RADEON_NUM_RINGS; i++) { |
231 | } else { |
- | |
232 | if (rdev->cp.ready) { |
- | |
233 | // struct radeon_fence *fence; |
- | |
234 | // radeon_ring_alloc(rdev, 64); |
- | |
235 | // radeon_fence_create(rdev, &fence); |
- | |
236 | // radeon_fence_emit(rdev, fence); |
244 | struct radeon_ring *ring = &rdev->ring[i]; |
237 | // radeon_ring_commit(rdev); |
- | |
238 | // radeon_fence_wait(fence, false); |
- | |
239 | // radeon_fence_unref(&fence); |
245 | if (ring->ready) |
- | 246 | radeon_fence_wait_empty_locked(rdev, i); |
|
240 | } |
247 | } |
Line 241... | Line 248... | ||
241 | } |
248 | |
242 | radeon_unmap_vram_bos(rdev); |
249 | radeon_unmap_vram_bos(rdev); |
243 | 250 | ||
Line 266... | Line 273... | ||
266 | if (rdev->pm.active_crtc_count) |
273 | if (rdev->pm.active_crtc_count) |
267 | radeon_bandwidth_update(rdev); |
274 | radeon_bandwidth_update(rdev); |
Line 268... | Line 275... | ||
268 | 275 | ||
Line 269... | Line 276... | ||
269 | rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; |
276 | rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; |
270 | 277 | ||
271 | mutex_unlock(&rdev->cp.mutex); |
278 | mutex_unlock(&rdev->ring_lock); |
272 | mutex_unlock(&rdev->vram_mutex); |
279 | // up_write(&rdev->pm.mclk_lock); |
Line 273... | Line 280... | ||
273 | mutex_unlock(&rdev->ddev->struct_mutex); |
280 | mutex_unlock(&rdev->ddev->struct_mutex); |
274 | } |
281 | } |
Line 292... | Line 299... | ||
292 | DRM_DEBUG_DRIVER("\tSingle display only\n"); |
299 | DRM_DEBUG_DRIVER("\tSingle display only\n"); |
293 | DRM_DEBUG_DRIVER("\t%d Clock Mode(s)\n", power_state->num_clock_modes); |
300 | DRM_DEBUG_DRIVER("\t%d Clock Mode(s)\n", power_state->num_clock_modes); |
294 | for (j = 0; j < power_state->num_clock_modes; j++) { |
301 | for (j = 0; j < power_state->num_clock_modes; j++) { |
295 | clock_info = &(power_state->clock_info[j]); |
302 | clock_info = &(power_state->clock_info[j]); |
296 | if (rdev->flags & RADEON_IS_IGP) |
303 | if (rdev->flags & RADEON_IS_IGP) |
297 | DRM_DEBUG_DRIVER("\t\t%d e: %d%s\n", |
304 | DRM_DEBUG_DRIVER("\t\t%d e: %d\n", |
298 | j, |
305 | j, |
299 | clock_info->sclk * 10, |
306 | clock_info->sclk * 10); |
300 | clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : ""); |
- | |
301 | else |
307 | else |
302 | DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d%s\n", |
308 | DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d\n", |
303 | j, |
309 | j, |
304 | clock_info->sclk * 10, |
310 | clock_info->sclk * 10, |
305 | clock_info->mclk * 10, |
311 | clock_info->mclk * 10, |
306 | clock_info->voltage.voltage, |
312 | clock_info->voltage.voltage); |
307 | clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : ""); |
- | |
308 | } |
313 | } |
309 | } |
314 | } |
310 | } |
315 | } |
Line 311... | Line 316... | ||
311 | 316 | ||
312 | static ssize_t radeon_get_pm_profile(struct device *dev, |
317 | static ssize_t radeon_get_pm_profile(struct device *dev, |
313 | struct device_attribute *attr, |
318 | struct device_attribute *attr, |
314 | char *buf) |
319 | char *buf) |
- | 320 | { |
|
- | 321 | struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); |
|
- | 322 | struct radeon_device *rdev = ddev->dev_private; |
|
Line 315... | Line 323... | ||
315 | { |
323 | int cp = rdev->pm.profile; |
- | 324 | ||
- | 325 | return snprintf(buf, PAGE_SIZE, "%s\n", |
|
- | 326 | (cp == PM_PROFILE_AUTO) ? "auto" : |
|
- | 327 | (cp == PM_PROFILE_LOW) ? "low" : |
|
316 | 328 | (cp == PM_PROFILE_MID) ? "mid" : |
|
Line 317... | Line 329... | ||
317 | return snprintf(buf, PAGE_SIZE, "%s\n", "default"); |
329 | (cp == PM_PROFILE_HIGH) ? "high" : "default"); |
318 | } |
330 | } |
319 | 331 | ||
Line 324... | Line 336... | ||
324 | { |
336 | { |
325 | struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); |
337 | struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); |
326 | struct radeon_device *rdev = ddev->dev_private; |
338 | struct radeon_device *rdev = ddev->dev_private; |
Line 327... | Line 339... | ||
327 | 339 | ||
328 | mutex_lock(&rdev->pm.mutex); |
- | |
- | 340 | mutex_lock(&rdev->pm.mutex); |
|
- | 341 | if (rdev->pm.pm_method == PM_METHOD_PROFILE) { |
|
329 | 342 | if (strncmp("default", buf, strlen("default")) == 0) |
|
- | 343 | rdev->pm.profile = PM_PROFILE_DEFAULT; |
|
- | 344 | else if (strncmp("auto", buf, strlen("auto")) == 0) |
|
- | 345 | rdev->pm.profile = PM_PROFILE_AUTO; |
|
- | 346 | else if (strncmp("low", buf, strlen("low")) == 0) |
|
- | 347 | rdev->pm.profile = PM_PROFILE_LOW; |
|
- | 348 | else if (strncmp("mid", buf, strlen("mid")) == 0) |
|
- | 349 | rdev->pm.profile = PM_PROFILE_MID; |
|
- | 350 | else if (strncmp("high", buf, strlen("high")) == 0) |
|
- | 351 | rdev->pm.profile = PM_PROFILE_HIGH; |
|
- | 352 | else { |
|
- | 353 | count = -EINVAL; |
|
330 | rdev->pm.profile = PM_PROFILE_DEFAULT; |
354 | goto fail; |
331 | 355 | } |
|
332 | radeon_pm_update_profile(rdev); |
356 | radeon_pm_update_profile(rdev); |
- | 357 | radeon_pm_set_clocks(rdev); |
|
- | 358 | } else |
|
- | 359 | count = -EINVAL; |
|
333 | radeon_pm_set_clocks(rdev); |
360 | |
334 | fail: |
361 | fail: |
Line 335... | Line 362... | ||
335 | mutex_unlock(&rdev->pm.mutex); |
362 | mutex_unlock(&rdev->pm.mutex); |
336 | 363 | ||
Line 371... | Line 398... | ||
371 | rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; |
398 | rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; |
372 | rdev->pm.pm_method = PM_METHOD_PROFILE; |
399 | rdev->pm.pm_method = PM_METHOD_PROFILE; |
373 | mutex_unlock(&rdev->pm.mutex); |
400 | mutex_unlock(&rdev->pm.mutex); |
374 | // cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); |
401 | // cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); |
375 | } else { |
402 | } else { |
376 | DRM_ERROR("invalid power method!\n"); |
403 | count = -EINVAL; |
377 | goto fail; |
404 | goto fail; |
378 | } |
405 | } |
379 | radeon_pm_compute_clocks(rdev); |
406 | radeon_pm_compute_clocks(rdev); |
380 | fail: |
407 | fail: |
381 | return count; |
408 | return count; |
382 | } |
409 | } |
Line -... | Line 410... | ||
- | 410 | ||
- | 411 | //static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); |
|
- | 412 | //static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); |
|
383 | 413 | ||
384 | static ssize_t radeon_hwmon_show_temp(struct device *dev, |
414 | static ssize_t radeon_hwmon_show_temp(struct device *dev, |
385 | struct device_attribute *attr, |
415 | struct device_attribute *attr, |
386 | char *buf) |
416 | char *buf) |
387 | { |
417 | { |
388 | struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); |
418 | struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); |
389 | struct radeon_device *rdev = ddev->dev_private; |
419 | struct radeon_device *rdev = ddev->dev_private; |
Line 390... | Line 420... | ||
390 | u32 temp; |
420 | int temp; |
391 | 421 | ||
392 | switch (rdev->pm.int_thermal_type) { |
422 | switch (rdev->pm.int_thermal_type) { |
393 | case THERMAL_TYPE_RV6XX: |
423 | case THERMAL_TYPE_RV6XX: |
Line 398... | Line 428... | ||
398 | break; |
428 | break; |
399 | case THERMAL_TYPE_EVERGREEN: |
429 | case THERMAL_TYPE_EVERGREEN: |
400 | case THERMAL_TYPE_NI: |
430 | case THERMAL_TYPE_NI: |
401 | temp = evergreen_get_temp(rdev); |
431 | temp = evergreen_get_temp(rdev); |
402 | break; |
432 | break; |
- | 433 | case THERMAL_TYPE_SUMO: |
|
- | 434 | temp = sumo_get_temp(rdev); |
|
- | 435 | break; |
|
- | 436 | case THERMAL_TYPE_SI: |
|
- | 437 | temp = si_get_temp(rdev); |
|
- | 438 | break; |
|
403 | default: |
439 | default: |
404 | temp = 0; |
440 | temp = 0; |
405 | break; |
441 | break; |
406 | } |
442 | } |