Rev 1404 | Rev 1963 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1404 | Rev 1430 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Permission is hereby granted, free of charge, to any person obtaining a |
2 | * Permission is hereby granted, free of charge, to any person obtaining a |
3 | * copy of this software and associated documentation files (the "Software"), |
3 | * copy of this software and associated documentation files (the "Software"), |
4 | * to deal in the Software without restriction, including without limitation |
4 | * to deal in the Software without restriction, including without limitation |
5 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
5 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
6 | * and/or sell copies of the Software, and to permit persons to whom the |
6 | * and/or sell copies of the Software, and to permit persons to whom the |
7 | * Software is furnished to do so, subject to the following conditions: |
7 | * Software is furnished to do so, subject to the following conditions: |
8 | * |
8 | * |
9 | * The above copyright notice and this permission notice shall be included in |
9 | * The above copyright notice and this permission notice shall be included in |
10 | * all copies or substantial portions of the Software. |
10 | * all copies or substantial portions of the Software. |
11 | * |
11 | * |
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
15 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
15 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
16 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
16 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
17 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
17 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
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 | */ |
22 | */ |
22 | #include "drmP.h" |
23 | #include "drmP.h" |
23 | #include "radeon.h" |
24 | #include "radeon.h" |
- | 25 | #include "avivod.h" |
|
- | 26 | ||
- | 27 | #define RADEON_IDLE_LOOP_MS 100 |
|
- | 28 | #define RADEON_RECLOCK_DELAY_MS 200 |
|
- | 29 | #define RADEON_WAIT_VBLANK_TIMEOUT 200 |
|
- | 30 | ||
- | 31 | static void radeon_pm_set_clocks_locked(struct radeon_device *rdev); |
|
- | 32 | static void radeon_pm_set_clocks(struct radeon_device *rdev); |
|
24 | 33 | static void radeon_pm_idle_work_handler(struct work_struct *work); |
|
- | 34 | static int radeon_debugfs_pm_init(struct radeon_device *rdev); |
|
- | 35 | ||
- | 36 | static const char *pm_state_names[4] = { |
|
- | 37 | "PM_STATE_DISABLED", |
|
- | 38 | "PM_STATE_MINIMUM", |
|
- | 39 | "PM_STATE_PAUSED", |
|
- | 40 | "PM_STATE_ACTIVE" |
|
- | 41 | }; |
|
- | 42 | ||
- | 43 | static const char *pm_state_types[5] = { |
|
- | 44 | "Default", |
|
- | 45 | "Powersave", |
|
- | 46 | "Battery", |
|
- | 47 | "Balanced", |
|
- | 48 | "Performance", |
|
- | 49 | }; |
|
- | 50 | ||
- | 51 | static void radeon_print_power_mode_info(struct radeon_device *rdev) |
|
- | 52 | { |
|
- | 53 | int i, j; |
|
- | 54 | bool is_default; |
|
- | 55 | ||
- | 56 | DRM_INFO("%d Power State(s)\n", rdev->pm.num_power_states); |
|
- | 57 | for (i = 0; i < rdev->pm.num_power_states; i++) { |
|
- | 58 | if (rdev->pm.default_power_state == &rdev->pm.power_state[i]) |
|
- | 59 | is_default = true; |
|
- | 60 | else |
|
- | 61 | is_default = false; |
|
- | 62 | DRM_INFO("State %d %s %s\n", i, |
|
- | 63 | pm_state_types[rdev->pm.power_state[i].type], |
|
- | 64 | is_default ? "(default)" : ""); |
|
- | 65 | if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) |
|
- | 66 | DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].non_clock_info.pcie_lanes); |
|
- | 67 | DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes); |
|
- | 68 | for (j = 0; j < rdev->pm.power_state[i].num_clock_modes; j++) { |
|
- | 69 | if (rdev->flags & RADEON_IS_IGP) |
|
- | 70 | DRM_INFO("\t\t%d engine: %d\n", |
|
- | 71 | j, |
|
- | 72 | rdev->pm.power_state[i].clock_info[j].sclk * 10); |
|
- | 73 | else |
|
- | 74 | DRM_INFO("\t\t%d engine/memory: %d/%d\n", |
|
- | 75 | j, |
|
- | 76 | rdev->pm.power_state[i].clock_info[j].sclk * 10, |
|
- | 77 | rdev->pm.power_state[i].clock_info[j].mclk * 10); |
|
- | 78 | } |
|
- | 79 | } |
|
- | 80 | } |
|
- | 81 | ||
- | 82 | static struct radeon_power_state * radeon_pick_power_state(struct radeon_device *rdev, |
|
- | 83 | enum radeon_pm_state_type type) |
|
- | 84 | { |
|
- | 85 | int i, j; |
|
- | 86 | enum radeon_pm_state_type wanted_types[2]; |
|
- | 87 | int wanted_count; |
|
- | 88 | ||
- | 89 | switch (type) { |
|
- | 90 | case POWER_STATE_TYPE_DEFAULT: |
|
- | 91 | default: |
|
- | 92 | return rdev->pm.default_power_state; |
|
- | 93 | case POWER_STATE_TYPE_POWERSAVE: |
|
- | 94 | if (rdev->flags & RADEON_IS_MOBILITY) { |
|
- | 95 | wanted_types[0] = POWER_STATE_TYPE_POWERSAVE; |
|
- | 96 | wanted_types[1] = POWER_STATE_TYPE_BATTERY; |
|
- | 97 | wanted_count = 2; |
|
- | 98 | } else { |
|
- | 99 | wanted_types[0] = POWER_STATE_TYPE_PERFORMANCE; |
|
- | 100 | wanted_count = 1; |
|
- | 101 | } |
|
- | 102 | break; |
|
- | 103 | case POWER_STATE_TYPE_BATTERY: |
|
- | 104 | if (rdev->flags & RADEON_IS_MOBILITY) { |
|
- | 105 | wanted_types[0] = POWER_STATE_TYPE_BATTERY; |
|
- | 106 | wanted_types[1] = POWER_STATE_TYPE_POWERSAVE; |
|
- | 107 | wanted_count = 2; |
|
- | 108 | } else { |
|
- | 109 | wanted_types[0] = POWER_STATE_TYPE_PERFORMANCE; |
|
- | 110 | wanted_count = 1; |
|
- | 111 | } |
|
- | 112 | break; |
|
- | 113 | case POWER_STATE_TYPE_BALANCED: |
|
- | 114 | case POWER_STATE_TYPE_PERFORMANCE: |
|
- | 115 | wanted_types[0] = type; |
|
- | 116 | wanted_count = 1; |
|
- | 117 | break; |
|
- | 118 | } |
|
- | 119 | ||
- | 120 | for (i = 0; i < wanted_count; i++) { |
|
- | 121 | for (j = 0; j < rdev->pm.num_power_states; j++) { |
|
- | 122 | if (rdev->pm.power_state[j].type == wanted_types[i]) |
|
- | 123 | return &rdev->pm.power_state[j]; |
|
- | 124 | } |
|
- | 125 | } |
|
- | 126 | ||
- | 127 | return rdev->pm.default_power_state; |
|
- | 128 | } |
|
- | 129 | ||
- | 130 | static struct radeon_pm_clock_info * radeon_pick_clock_mode(struct radeon_device *rdev, |
|
- | 131 | struct radeon_power_state *power_state, |
|
- | 132 | enum radeon_pm_clock_mode_type type) |
|
- | 133 | { |
|
- | 134 | switch (type) { |
|
- | 135 | case POWER_MODE_TYPE_DEFAULT: |
|
- | 136 | default: |
|
- | 137 | return power_state->default_clock_mode; |
|
- | 138 | case POWER_MODE_TYPE_LOW: |
|
- | 139 | return &power_state->clock_info[0]; |
|
- | 140 | case POWER_MODE_TYPE_MID: |
|
- | 141 | if (power_state->num_clock_modes > 2) |
|
- | 142 | return &power_state->clock_info[1]; |
|
- | 143 | else |
|
- | 144 | return &power_state->clock_info[0]; |
|
- | 145 | break; |
|
- | 146 | case POWER_MODE_TYPE_HIGH: |
|
- | 147 | return &power_state->clock_info[power_state->num_clock_modes - 1]; |
|
- | 148 | } |
|
- | 149 | ||
- | 150 | } |
|
- | 151 | ||
- | 152 | static void radeon_get_power_state(struct radeon_device *rdev, |
|
- | 153 | enum radeon_pm_action action) |
|
- | 154 | { |
|
- | 155 | switch (action) { |
|
- | 156 | case PM_ACTION_MINIMUM: |
|
- | 157 | rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_BATTERY); |
|
- | 158 | rdev->pm.requested_clock_mode = |
|
- | 159 | radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_LOW); |
|
- | 160 | break; |
|
- | 161 | case PM_ACTION_DOWNCLOCK: |
|
- | 162 | rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_POWERSAVE); |
|
- | 163 | rdev->pm.requested_clock_mode = |
|
- | 164 | radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_MID); |
|
- | 165 | break; |
|
- | 166 | case PM_ACTION_UPCLOCK: |
|
- | 167 | rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_DEFAULT); |
|
- | 168 | rdev->pm.requested_clock_mode = |
|
- | 169 | radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_HIGH); |
|
- | 170 | break; |
|
- | 171 | case PM_ACTION_NONE: |
|
- | 172 | default: |
|
- | 173 | DRM_ERROR("Requested mode for not defined action\n"); |
|
- | 174 | return; |
|
- | 175 | } |
|
- | 176 | DRM_INFO("Requested: e: %d m: %d p: %d\n", |
|
- | 177 | rdev->pm.requested_clock_mode->sclk, |
|
- | 178 | rdev->pm.requested_clock_mode->mclk, |
|
- | 179 | rdev->pm.requested_power_state->non_clock_info.pcie_lanes); |
|
- | 180 | } |
|
- | 181 | ||
- | 182 | static void radeon_set_power_state(struct radeon_device *rdev) |
|
- | 183 | { |
|
- | 184 | /* if *_clock_mode are the same, *_power_state are as well */ |
|
- | 185 | if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) |
|
- | 186 | return; |
|
- | 187 | ||
- | 188 | DRM_INFO("Setting: e: %d m: %d p: %d\n", |
|
- | 189 | rdev->pm.requested_clock_mode->sclk, |
|
- | 190 | rdev->pm.requested_clock_mode->mclk, |
|
- | 191 | rdev->pm.requested_power_state->non_clock_info.pcie_lanes); |
|
- | 192 | /* set pcie lanes */ |
|
- | 193 | /* set voltage */ |
|
- | 194 | /* set engine clock */ |
|
- | 195 | radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); |
|
- | 196 | /* set memory clock */ |
|
- | 197 | ||
- | 198 | rdev->pm.current_power_state = rdev->pm.requested_power_state; |
|
- | 199 | rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; |
|
25 | int radeon_debugfs_pm_init(struct radeon_device *rdev); |
200 | } |
26 | 201 | ||
27 | int radeon_pm_init(struct radeon_device *rdev) |
202 | int radeon_pm_init(struct radeon_device *rdev) |
28 | { |
203 | { |
- | 204 | rdev->pm.state = PM_STATE_DISABLED; |
|
- | 205 | rdev->pm.planned_action = PM_ACTION_NONE; |
|
- | 206 | rdev->pm.downclocked = false; |
|
- | 207 | ||
- | 208 | if (rdev->bios) { |
|
- | 209 | if (rdev->is_atom_bios) |
|
- | 210 | radeon_atombios_get_power_modes(rdev); |
|
- | 211 | else |
|
- | 212 | radeon_combios_get_power_modes(rdev); |
|
- | 213 | radeon_print_power_mode_info(rdev); |
|
- | 214 | } |
|
- | 215 | ||
29 | if (radeon_debugfs_pm_init(rdev)) { |
216 | if (radeon_debugfs_pm_init(rdev)) { |
30 | DRM_ERROR("Failed to register debugfs file for PM!\n"); |
217 | DRM_ERROR("Failed to register debugfs file for PM!\n"); |
31 | } |
218 | } |
- | 219 | ||
- | 220 | // INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler); |
|
- | 221 | ||
- | 222 | if (radeon_dynpm != -1 && radeon_dynpm) { |
|
- | 223 | rdev->pm.state = PM_STATE_PAUSED; |
|
- | 224 | DRM_INFO("radeon: dynamic power management enabled\n"); |
|
- | 225 | } |
|
- | 226 | ||
- | 227 | DRM_INFO("radeon: power management initialized\n"); |
|
32 | 228 | ||
33 | return 0; |
229 | return 0; |
34 | } |
230 | } |
- | 231 | ||
- | 232 | void radeon_pm_compute_clocks(struct radeon_device *rdev) |
|
- | 233 | { |
|
- | 234 | struct drm_device *ddev = rdev->ddev; |
|
- | 235 | struct drm_connector *connector; |
|
- | 236 | struct radeon_crtc *radeon_crtc; |
|
- | 237 | int count = 0; |
|
- | 238 | ||
- | 239 | if (rdev->pm.state == PM_STATE_DISABLED) |
|
- | 240 | return; |
|
- | 241 | ||
- | 242 | mutex_lock(&rdev->pm.mutex); |
|
- | 243 | ||
- | 244 | rdev->pm.active_crtcs = 0; |
|
- | 245 | list_for_each_entry(connector, |
|
- | 246 | &ddev->mode_config.connector_list, head) { |
|
- | 247 | if (connector->encoder && |
|
- | 248 | connector->dpms != DRM_MODE_DPMS_OFF) { |
|
- | 249 | radeon_crtc = to_radeon_crtc(connector->encoder->crtc); |
|
- | 250 | rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id); |
|
- | 251 | ++count; |
|
- | 252 | } |
|
- | 253 | } |
|
- | 254 | ||
- | 255 | if (count > 1) { |
|
- | 256 | if (rdev->pm.state == PM_STATE_ACTIVE) { |
|
- | 257 | ||
- | 258 | rdev->pm.state = PM_STATE_PAUSED; |
|
- | 259 | rdev->pm.planned_action = PM_ACTION_UPCLOCK; |
|
- | 260 | if (rdev->pm.downclocked) |
|
- | 261 | radeon_pm_set_clocks(rdev); |
|
- | 262 | ||
- | 263 | DRM_DEBUG("radeon: dynamic power management deactivated\n"); |
|
- | 264 | } |
|
- | 265 | } else if (count == 1) { |
|
- | 266 | /* TODO: Increase clocks if needed for current mode */ |
|
- | 267 | ||
- | 268 | if (rdev->pm.state == PM_STATE_MINIMUM) { |
|
- | 269 | rdev->pm.state = PM_STATE_ACTIVE; |
|
- | 270 | rdev->pm.planned_action = PM_ACTION_UPCLOCK; |
|
- | 271 | radeon_pm_set_clocks(rdev); |
|
- | 272 | } |
|
- | 273 | else if (rdev->pm.state == PM_STATE_PAUSED) { |
|
- | 274 | rdev->pm.state = PM_STATE_ACTIVE; |
|
- | 275 | DRM_DEBUG("radeon: dynamic power management activated\n"); |
|
- | 276 | } |
|
- | 277 | } |
|
- | 278 | else { /* count == 0 */ |
|
- | 279 | if (rdev->pm.state != PM_STATE_MINIMUM) { |
|
- | 280 | rdev->pm.state = PM_STATE_MINIMUM; |
|
- | 281 | rdev->pm.planned_action = PM_ACTION_MINIMUM; |
|
- | 282 | radeon_pm_set_clocks(rdev); |
|
- | 283 | } |
|
- | 284 | } |
|
- | 285 | ||
- | 286 | mutex_unlock(&rdev->pm.mutex); |
|
- | 287 | } |
|
- | 288 | ||
- | 289 | static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) |
|
- | 290 | { |
|
- | 291 | u32 stat_crtc1 = 0, stat_crtc2 = 0; |
|
- | 292 | bool in_vbl = true; |
|
- | 293 | ||
- | 294 | if (ASIC_IS_AVIVO(rdev)) { |
|
- | 295 | if (rdev->pm.active_crtcs & (1 << 0)) { |
|
- | 296 | stat_crtc1 = RREG32(D1CRTC_STATUS); |
|
- | 297 | if (!(stat_crtc1 & 1)) |
|
- | 298 | in_vbl = false; |
|
- | 299 | } |
|
- | 300 | if (rdev->pm.active_crtcs & (1 << 1)) { |
|
- | 301 | stat_crtc2 = RREG32(D2CRTC_STATUS); |
|
- | 302 | if (!(stat_crtc2 & 1)) |
|
- | 303 | in_vbl = false; |
|
- | 304 | } |
|
- | 305 | } |
|
- | 306 | if (in_vbl == false) |
|
- | 307 | DRM_INFO("not in vbl for pm change %08x %08x at %s\n", stat_crtc1, |
|
- | 308 | stat_crtc2, finish ? "exit" : "entry"); |
|
- | 309 | return in_vbl; |
|
- | 310 | } |
|
- | 311 | static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) |
|
- | 312 | { |
|
- | 313 | /*radeon_fence_wait_last(rdev);*/ |
|
- | 314 | switch (rdev->pm.planned_action) { |
|
- | 315 | case PM_ACTION_UPCLOCK: |
|
- | 316 | rdev->pm.downclocked = false; |
|
- | 317 | break; |
|
- | 318 | case PM_ACTION_DOWNCLOCK: |
|
- | 319 | rdev->pm.downclocked = true; |
|
- | 320 | break; |
|
- | 321 | case PM_ACTION_MINIMUM: |
|
- | 322 | break; |
|
- | 323 | case PM_ACTION_NONE: |
|
- | 324 | DRM_ERROR("%s: PM_ACTION_NONE\n", __func__); |
|
- | 325 | break; |
|
- | 326 | } |
|
- | 327 | ||
- | 328 | /* check if we are in vblank */ |
|
- | 329 | radeon_pm_debug_check_in_vbl(rdev, false); |
|
- | 330 | radeon_set_power_state(rdev); |
|
- | 331 | radeon_pm_debug_check_in_vbl(rdev, true); |
|
- | 332 | rdev->pm.planned_action = PM_ACTION_NONE; |
|
- | 333 | } |
|
- | 334 | ||
- | 335 | static void radeon_pm_set_clocks(struct radeon_device *rdev) |
|
- | 336 | { |
|
- | 337 | radeon_get_power_state(rdev, rdev->pm.planned_action); |
|
- | 338 | mutex_lock(&rdev->cp.mutex); |
|
- | 339 | ||
- | 340 | if (rdev->pm.active_crtcs & (1 << 0)) { |
|
- | 341 | rdev->pm.req_vblank |= (1 << 0); |
|
- | 342 | // drm_vblank_get(rdev->ddev, 0); |
|
- | 343 | } |
|
- | 344 | if (rdev->pm.active_crtcs & (1 << 1)) { |
|
- | 345 | rdev->pm.req_vblank |= (1 << 1); |
|
- | 346 | // drm_vblank_get(rdev->ddev, 1); |
|
- | 347 | } |
|
- | 348 | if (rdev->pm.active_crtcs) |
|
- | 349 | // wait_event_interruptible_timeout( |
|
- | 350 | // rdev->irq.vblank_queue, 0, |
|
- | 351 | // msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); |
|
- | 352 | if (rdev->pm.req_vblank & (1 << 0)) { |
|
- | 353 | rdev->pm.req_vblank &= ~(1 << 0); |
|
- | 354 | // drm_vblank_put(rdev->ddev, 0); |
|
- | 355 | } |
|
- | 356 | if (rdev->pm.req_vblank & (1 << 1)) { |
|
- | 357 | rdev->pm.req_vblank &= ~(1 << 1); |
|
- | 358 | // drm_vblank_put(rdev->ddev, 1); |
|
- | 359 | } |
|
- | 360 | ||
- | 361 | radeon_pm_set_clocks_locked(rdev); |
|
- | 362 | mutex_unlock(&rdev->cp.mutex); |
|
- | 363 | } |
|
- | 364 | ||
- | 365 | #if 0 |
|
- | 366 | static void radeon_pm_idle_work_handler(struct work_struct *work) |
|
- | 367 | { |
|
- | 368 | struct radeon_device *rdev; |
|
- | 369 | rdev = container_of(work, struct radeon_device, |
|
- | 370 | pm.idle_work.work); |
|
- | 371 | ||
- | 372 | mutex_lock(&rdev->pm.mutex); |
|
- | 373 | if (rdev->pm.state == PM_STATE_ACTIVE) { |
|
- | 374 | unsigned long irq_flags; |
|
- | 375 | int not_processed = 0; |
|
- | 376 | ||
- | 377 | read_lock_irqsave(&rdev->fence_drv.lock, irq_flags); |
|
- | 378 | if (!list_empty(&rdev->fence_drv.emited)) { |
|
- | 379 | struct list_head *ptr; |
|
- | 380 | list_for_each(ptr, &rdev->fence_drv.emited) { |
|
- | 381 | /* count up to 3, that's enought info */ |
|
- | 382 | if (++not_processed >= 3) |
|
- | 383 | break; |
|
- | 384 | } |
|
- | 385 | } |
|
- | 386 | read_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); |
|
- | 387 | ||
- | 388 | if (not_processed >= 3) { /* should upclock */ |
|
- | 389 | if (rdev->pm.planned_action == PM_ACTION_DOWNCLOCK) { |
|
- | 390 | rdev->pm.planned_action = PM_ACTION_NONE; |
|
- | 391 | } else if (rdev->pm.planned_action == PM_ACTION_NONE && |
|
- | 392 | rdev->pm.downclocked) { |
|
- | 393 | rdev->pm.planned_action = |
|
- | 394 | PM_ACTION_UPCLOCK; |
|
- | 395 | rdev->pm.action_timeout = jiffies + |
|
- | 396 | msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS); |
|
- | 397 | } |
|
- | 398 | } else if (not_processed == 0) { /* should downclock */ |
|
- | 399 | if (rdev->pm.planned_action == PM_ACTION_UPCLOCK) { |
|
- | 400 | rdev->pm.planned_action = PM_ACTION_NONE; |
|
- | 401 | } else if (rdev->pm.planned_action == PM_ACTION_NONE && |
|
- | 402 | !rdev->pm.downclocked) { |
|
- | 403 | rdev->pm.planned_action = |
|
- | 404 | PM_ACTION_DOWNCLOCK; |
|
- | 405 | rdev->pm.action_timeout = jiffies + |
|
- | 406 | msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS); |
|
- | 407 | } |
|
- | 408 | } |
|
- | 409 | ||
- | 410 | if (rdev->pm.planned_action != PM_ACTION_NONE && |
|
- | 411 | jiffies > rdev->pm.action_timeout) { |
|
- | 412 | radeon_pm_set_clocks(rdev); |
|
- | 413 | } |
|
- | 414 | } |
|
- | 415 | mutex_unlock(&rdev->pm.mutex); |
|
- | 416 | ||
- | 417 | queue_delayed_work(rdev->wq, &rdev->pm.idle_work, |
|
- | 418 | msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); |
|
- | 419 | } |
|
- | 420 | #endif |
|
35 | 421 | ||
36 | /* |
422 | /* |
37 | * Debugfs info |
423 | * Debugfs info |
38 | */ |
424 | */ |
39 | #if defined(CONFIG_DEBUG_FS) |
425 | #if defined(CONFIG_DEBUG_FS) |
40 | 426 | ||
41 | static int radeon_debugfs_pm_info(struct seq_file *m, void *data) |
427 | static int radeon_debugfs_pm_info(struct seq_file *m, void *data) |
42 | { |
428 | { |
43 | struct drm_info_node *node = (struct drm_info_node *) m->private; |
429 | struct drm_info_node *node = (struct drm_info_node *) m->private; |
44 | struct drm_device *dev = node->minor->dev; |
430 | struct drm_device *dev = node->minor->dev; |
45 | struct radeon_device *rdev = dev->dev_private; |
431 | struct radeon_device *rdev = dev->dev_private; |
- | 432 | ||
46 | 433 | seq_printf(m, "state: %s\n", pm_state_names[rdev->pm.state]); |
|
47 | seq_printf(m, "default engine clock: %u0 kHz\n", rdev->clock.default_sclk); |
434 | seq_printf(m, "default engine clock: %u0 kHz\n", rdev->clock.default_sclk); |
48 | seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); |
435 | seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); |
49 | seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk); |
436 | seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk); |
50 | if (rdev->asic->get_memory_clock) |
437 | if (rdev->asic->get_memory_clock) |
51 | seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev)); |
438 | seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev)); |
- | 439 | if (rdev->asic->get_pcie_lanes) |
|
- | 440 | seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev)); |
|
52 | 441 | ||
53 | return 0; |
442 | return 0; |
54 | } |
443 | } |
55 | 444 | ||
56 | static struct drm_info_list radeon_pm_info_list[] = { |
445 | static struct drm_info_list radeon_pm_info_list[] = { |
57 | {"radeon_pm_info", radeon_debugfs_pm_info, 0, NULL}, |
446 | {"radeon_pm_info", radeon_debugfs_pm_info, 0, NULL}, |
58 | }; |
447 | }; |
59 | #endif |
448 | #endif |
60 | 449 | ||
61 | int radeon_debugfs_pm_init(struct radeon_device *rdev) |
450 | static int radeon_debugfs_pm_init(struct radeon_device *rdev) |
62 | { |
451 | { |
63 | #if defined(CONFIG_DEBUG_FS) |
452 | #if defined(CONFIG_DEBUG_FS) |
64 | return radeon_debugfs_add_files(rdev, radeon_pm_info_list, ARRAY_SIZE(radeon_pm_info_list)); |
453 | return radeon_debugfs_add_files(rdev, radeon_pm_info_list, ARRAY_SIZE(radeon_pm_info_list)); |
65 | #else |
454 | #else |
66 | return 0; |
455 | return 0; |
67 | #endif |
456 | #endif |
68 | } |
457 | }><>><>><>><>><>><>><>><>><>><>><>>>>> |