1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright 2026 Advanced Micro Devices, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 * OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: AMD 24 * 25 */ 26 27 #include <linux/types.h> 28 #include <drm/drm_vblank.h> 29 30 #include "dc.h" 31 #include "amdgpu.h" 32 #include "amdgpu_dm_ism.h" 33 #include "amdgpu_dm_crtc.h" 34 #include "amdgpu_dm_trace.h" 35 #include "amdgpu_dm_kunit_helpers.h" 36 37 38 /** 39 * dm_ism_next_state - Get next state based on current state and event 40 * @current_state: current ISM state 41 * @event: event being processed 42 * @next_state: place to store the next state 43 * 44 * This function defines the idle state management FSM. Invalid transitions 45 * are ignored and will not progress the FSM. 46 */ 47 STATIC_IFN_KUNIT 48 bool dm_ism_next_state(enum amdgpu_dm_ism_state current_state, 49 enum amdgpu_dm_ism_event event, 50 enum amdgpu_dm_ism_state *next_state) 51 { 52 switch (STATE_EVENT(current_state, event)) { 53 case STATE_EVENT(DM_ISM_STATE_FULL_POWER_RUNNING, 54 DM_ISM_EVENT_ENTER_IDLE_REQUESTED): 55 *next_state = DM_ISM_STATE_HYSTERESIS_WAITING; 56 break; 57 case STATE_EVENT(DM_ISM_STATE_FULL_POWER_RUNNING, 58 DM_ISM_EVENT_BEGIN_CURSOR_UPDATE): 59 *next_state = DM_ISM_STATE_FULL_POWER_BUSY; 60 break; 61 62 case STATE_EVENT(DM_ISM_STATE_FULL_POWER_BUSY, 63 DM_ISM_EVENT_ENTER_IDLE_REQUESTED): 64 *next_state = DM_ISM_STATE_HYSTERESIS_BUSY; 65 break; 66 case STATE_EVENT(DM_ISM_STATE_FULL_POWER_BUSY, 67 DM_ISM_EVENT_END_CURSOR_UPDATE): 68 *next_state = DM_ISM_STATE_FULL_POWER_RUNNING; 69 break; 70 71 case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_WAITING, 72 DM_ISM_EVENT_EXIT_IDLE_REQUESTED): 73 *next_state = DM_ISM_STATE_TIMER_ABORTED; 74 break; 75 case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_WAITING, 76 DM_ISM_EVENT_BEGIN_CURSOR_UPDATE): 77 *next_state = DM_ISM_STATE_HYSTERESIS_BUSY; 78 break; 79 case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_WAITING, 80 DM_ISM_EVENT_TIMER_ELAPSED): 81 *next_state = DM_ISM_STATE_OPTIMIZED_IDLE; 82 break; 83 case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_WAITING, 84 DM_ISM_EVENT_IMMEDIATE): 85 *next_state = DM_ISM_STATE_OPTIMIZED_IDLE; 86 break; 87 88 case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_BUSY, 89 DM_ISM_EVENT_EXIT_IDLE_REQUESTED): 90 *next_state = DM_ISM_STATE_FULL_POWER_BUSY; 91 break; 92 case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_BUSY, 93 DM_ISM_EVENT_END_CURSOR_UPDATE): 94 *next_state = DM_ISM_STATE_HYSTERESIS_WAITING; 95 break; 96 97 case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE, 98 DM_ISM_EVENT_EXIT_IDLE_REQUESTED): 99 *next_state = DM_ISM_STATE_FULL_POWER_RUNNING; 100 break; 101 case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE, 102 DM_ISM_EVENT_BEGIN_CURSOR_UPDATE): 103 *next_state = DM_ISM_STATE_HYSTERESIS_BUSY; 104 break; 105 case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE, 106 DM_ISM_EVENT_SSO_TIMER_ELAPSED): 107 case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE, 108 DM_ISM_EVENT_IMMEDIATE): 109 *next_state = DM_ISM_STATE_OPTIMIZED_IDLE_SSO; 110 break; 111 112 case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE_SSO, 113 DM_ISM_EVENT_EXIT_IDLE_REQUESTED): 114 *next_state = DM_ISM_STATE_FULL_POWER_RUNNING; 115 break; 116 case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE_SSO, 117 DM_ISM_EVENT_BEGIN_CURSOR_UPDATE): 118 *next_state = DM_ISM_STATE_HYSTERESIS_BUSY; 119 break; 120 121 case STATE_EVENT(DM_ISM_STATE_TIMER_ABORTED, 122 DM_ISM_EVENT_IMMEDIATE): 123 *next_state = DM_ISM_STATE_FULL_POWER_RUNNING; 124 break; 125 126 default: 127 return false; 128 } 129 return true; 130 } 131 EXPORT_IF_KUNIT(dm_ism_next_state); 132 133 STATIC_IFN_KUNIT 134 uint64_t dm_ism_get_sso_delay(const struct amdgpu_dm_ism *ism, 135 const struct dc_stream_state *stream) 136 { 137 const struct amdgpu_dm_ism_config *config = &ism->config; 138 uint32_t v_total, h_total; 139 uint64_t one_frame_ns, sso_delay_ns; 140 141 if (!stream) 142 return 0; 143 144 if (!config->sso_num_frames) 145 return 0; 146 147 v_total = stream->timing.v_total; 148 h_total = stream->timing.h_total; 149 150 one_frame_ns = div64_u64(v_total * h_total * 10000000ull, 151 stream->timing.pix_clk_100hz); 152 sso_delay_ns = config->sso_num_frames * one_frame_ns; 153 154 return sso_delay_ns; 155 } 156 EXPORT_IF_KUNIT(dm_ism_get_sso_delay); 157 158 /** 159 * dm_ism_get_idle_allow_delay - Calculate hysteresis-based idle allow delay 160 * @ism: ISM instance containing configuration, history, and current state 161 * @stream: display stream used to derive frame timing values for delay 162 * 163 * Calculates the delay before allowing idle optimizations based on recent 164 * idle history and the current stream timing. 165 */ 166 STATIC_IFN_KUNIT 167 uint64_t dm_ism_get_idle_allow_delay(const struct amdgpu_dm_ism *ism, 168 const struct dc_stream_state *stream) 169 { 170 const struct amdgpu_dm_ism_config *config = &ism->config; 171 uint32_t v_total, h_total; 172 uint64_t one_frame_ns, short_idle_ns, old_hist_ns; 173 uint32_t history_size; 174 int pos; 175 uint32_t short_idle_count = 0; 176 uint64_t ret_ns = 0; 177 178 if (!stream) 179 return 0; 180 181 if (!config->filter_num_frames) 182 return 0; 183 if (!config->filter_entry_count) 184 return 0; 185 if (!config->activation_num_delay_frames) 186 return 0; 187 188 v_total = stream->timing.v_total; 189 h_total = stream->timing.h_total; 190 191 one_frame_ns = div64_u64(v_total * h_total * 10000000ull, 192 stream->timing.pix_clk_100hz); 193 194 short_idle_ns = config->filter_num_frames * one_frame_ns; 195 old_hist_ns = config->filter_old_history_threshold * one_frame_ns; 196 197 /* 198 * Look back into the recent history and count how many times we entered 199 * idle power state for a short duration of time 200 */ 201 history_size = min( 202 max(config->filter_history_size, config->filter_entry_count), 203 AMDGPU_DM_IDLE_HIST_LEN); 204 pos = ism->next_record_idx; 205 206 for (int k = 0; k < history_size; k++) { 207 if (pos <= 0 || pos > AMDGPU_DM_IDLE_HIST_LEN) 208 pos = AMDGPU_DM_IDLE_HIST_LEN; 209 pos -= 1; 210 211 if (ism->records[pos].duration_ns <= short_idle_ns) 212 short_idle_count += 1; 213 214 if (short_idle_count >= config->filter_entry_count) 215 break; 216 217 if (old_hist_ns > 0 && 218 ism->last_idle_timestamp_ns - ism->records[pos].timestamp_ns > old_hist_ns) 219 break; 220 } 221 222 if (short_idle_count >= config->filter_entry_count) 223 ret_ns = config->activation_num_delay_frames * one_frame_ns; 224 225 return ret_ns; 226 } 227 EXPORT_IF_KUNIT(dm_ism_get_idle_allow_delay); 228 229 /** 230 * dm_ism_insert_record - Insert a record into the circular history buffer 231 * @ism: ISM instance 232 */ 233 STATIC_IFN_KUNIT 234 void dm_ism_insert_record(struct amdgpu_dm_ism *ism) 235 { 236 struct amdgpu_dm_ism_record *record; 237 238 if (ism->next_record_idx < 0 || 239 ism->next_record_idx >= AMDGPU_DM_IDLE_HIST_LEN) 240 ism->next_record_idx = 0; 241 242 record = &ism->records[ism->next_record_idx]; 243 ism->next_record_idx += 1; 244 245 record->timestamp_ns = ktime_get_ns(); 246 record->duration_ns = 247 record->timestamp_ns - ism->last_idle_timestamp_ns; 248 } 249 EXPORT_IF_KUNIT(dm_ism_insert_record); 250 251 252 STATIC_IFN_KUNIT 253 void dm_ism_set_last_idle_ts(struct amdgpu_dm_ism *ism) 254 { 255 ism->last_idle_timestamp_ns = ktime_get_ns(); 256 } 257 EXPORT_IF_KUNIT(dm_ism_set_last_idle_ts); 258 259 260 STATIC_IFN_KUNIT 261 bool dm_ism_trigger_event(struct amdgpu_dm_ism *ism, 262 enum amdgpu_dm_ism_event event) 263 { 264 enum amdgpu_dm_ism_state next_state; 265 266 bool gotNextState = dm_ism_next_state(ism->current_state, event, 267 &next_state); 268 269 if (gotNextState) { 270 ism->previous_state = ism->current_state; 271 ism->current_state = next_state; 272 } 273 274 return gotNextState; 275 } 276 EXPORT_IF_KUNIT(dm_ism_trigger_event); 277 278 279 static void dm_ism_commit_idle_optimization_state(struct amdgpu_dm_ism *ism, 280 struct dc_stream_state *stream, 281 bool vblank_enabled, 282 bool allow_panel_sso) 283 { 284 struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism); 285 struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev); 286 struct amdgpu_display_manager *dm = &adev->dm; 287 288 trace_amdgpu_dm_ism_commit(dm->active_vblank_irq_count, 289 vblank_enabled, 290 allow_panel_sso); 291 292 /* 293 * If there is an active vblank requestor, or if SSO is being engaged, 294 * then disallow idle optimizations. 295 */ 296 if (vblank_enabled || allow_panel_sso) 297 dc_allow_idle_optimizations(dm->dc, false); 298 299 /* 300 * Control PSR based on vblank requirements from OS 301 * 302 * If panel supports PSR SU/Replay, there's no need to exit self-refresh 303 * when OS is submitting fast atomic commits, as they can allow 304 * self-refresh during vblank periods. 305 */ 306 if (stream && stream->link) { 307 /* 308 * If the OS requires vblank events (or vblank is otherwise enabled), 309 * do not allow static screen optimizations. 310 * 311 * Keep ism->allow_static_screen_optimizations unchanged so the 312 * hysteresis-based decision can be reused once vblank is disabled. 313 */ 314 allow_panel_sso = allow_panel_sso && !vblank_enabled; 315 amdgpu_dm_crtc_set_static_screen_optimze( 316 dm, stream, allow_panel_sso, 317 acrtc->dm_irq_params.allow_sr_entry); 318 } 319 320 /* 321 * Check for any active drm vblank requestors on other CRTCs 322 * (dm->active_vblank_irq_count) before allowing HW-wide idle 323 * optimizations. 324 * 325 * There's no need to have a "balanced" check when disallowing idle 326 * optimizations at the start of this func -- we should disallow 327 * whenever there's *an* active CRTC. 328 */ 329 if (!vblank_enabled && dm->active_vblank_irq_count == 0) { 330 dc_post_update_surfaces_to_stream(dm->dc); 331 dc_allow_idle_optimizations(dm->dc, true); 332 } 333 } 334 335 STATIC_IFN_KUNIT 336 enum amdgpu_dm_ism_event dm_ism_dispatch_next_event( 337 enum amdgpu_dm_ism_state current_state, 338 uint64_t delay_ns, 339 uint64_t sso_delay_ns) 340 { 341 switch (current_state) { 342 case DM_ISM_STATE_HYSTERESIS_WAITING: 343 if (delay_ns == 0) 344 return DM_ISM_EVENT_IMMEDIATE; 345 break; 346 case DM_ISM_STATE_OPTIMIZED_IDLE: 347 if (sso_delay_ns == 0) 348 return DM_ISM_EVENT_IMMEDIATE; 349 break; 350 case DM_ISM_STATE_TIMER_ABORTED: 351 return DM_ISM_EVENT_IMMEDIATE; 352 default: 353 break; 354 } 355 return DM_ISM_NUM_EVENTS; 356 } 357 EXPORT_IF_KUNIT(dm_ism_dispatch_next_event); 358 359 static enum amdgpu_dm_ism_event dm_ism_dispatch_power_state( 360 struct amdgpu_dm_ism *ism, 361 struct dm_crtc_state *acrtc_state) 362 { 363 const struct amdgpu_dm_ism_config *config = &ism->config; 364 uint64_t delay_ns = 0, sso_delay_ns = 0; 365 366 switch (ism->previous_state) { 367 case DM_ISM_STATE_HYSTERESIS_WAITING: 368 /* 369 * Stop the timer if it was set, and we're not running from the 370 * idle allow worker. 371 */ 372 if (ism->current_state != DM_ISM_STATE_OPTIMIZED_IDLE && 373 ism->current_state != DM_ISM_STATE_OPTIMIZED_IDLE_SSO) 374 cancel_delayed_work(&ism->delayed_work); 375 break; 376 case DM_ISM_STATE_OPTIMIZED_IDLE: 377 if (ism->current_state == DM_ISM_STATE_OPTIMIZED_IDLE_SSO) 378 break; 379 /* If idle disallow, cancel SSO work and insert record */ 380 cancel_delayed_work(&ism->sso_delayed_work); 381 dm_ism_insert_record(ism); 382 dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream, 383 true, false); 384 break; 385 case DM_ISM_STATE_OPTIMIZED_IDLE_SSO: 386 /* Disable idle optimization */ 387 dm_ism_insert_record(ism); 388 dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream, 389 true, false); 390 break; 391 default: 392 break; 393 } 394 395 switch (ism->current_state) { 396 case DM_ISM_STATE_HYSTERESIS_WAITING: 397 dm_ism_set_last_idle_ts(ism); 398 delay_ns = dm_ism_get_idle_allow_delay(ism, acrtc_state->stream); 399 /* Schedule worker */ 400 if (delay_ns > 0) 401 mod_delayed_work(system_dfl_wq, &ism->delayed_work, 402 nsecs_to_jiffies(delay_ns)); 403 break; 404 case DM_ISM_STATE_OPTIMIZED_IDLE: 405 sso_delay_ns = dm_ism_get_sso_delay(ism, acrtc_state->stream); 406 if (sso_delay_ns > 0) { 407 /* 408 * If sso_num_frames is less than hysteresis frames, it 409 * indicates that allowing idle here, then disallowing 410 * idle after sso_num_frames has expired, will likely 411 * have a negative power impact. Skip idle allow here, 412 * and let the sso_delayed_work handle it. 413 */ 414 if (config->sso_num_frames >= config->filter_num_frames) 415 dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream, 416 false, false); 417 418 mod_delayed_work(system_dfl_wq, 419 &ism->sso_delayed_work, 420 nsecs_to_jiffies(sso_delay_ns)); 421 } 422 break; 423 case DM_ISM_STATE_OPTIMIZED_IDLE_SSO: 424 /* Enable static screen optimizations. */ 425 dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream, 426 false, true); 427 break; 428 case DM_ISM_STATE_TIMER_ABORTED: 429 dm_ism_insert_record(ism); 430 dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream, 431 true, false); 432 break; 433 default: 434 break; 435 } 436 437 return dm_ism_dispatch_next_event(ism->current_state, delay_ns, sso_delay_ns); 438 } 439 440 static char *dm_ism_events_str[DM_ISM_NUM_EVENTS] = { 441 [DM_ISM_EVENT_IMMEDIATE] = "IMMEDIATE", 442 [DM_ISM_EVENT_ENTER_IDLE_REQUESTED] = "ENTER_IDLE_REQUESTED", 443 [DM_ISM_EVENT_EXIT_IDLE_REQUESTED] = "EXIT_IDLE_REQUESTED", 444 [DM_ISM_EVENT_BEGIN_CURSOR_UPDATE] = "BEGIN_CURSOR_UPDATE", 445 [DM_ISM_EVENT_END_CURSOR_UPDATE] = "END_CURSOR_UPDATE", 446 [DM_ISM_EVENT_TIMER_ELAPSED] = "TIMER_ELAPSED", 447 [DM_ISM_EVENT_SSO_TIMER_ELAPSED] = "SSO_TIMER_ELAPSED", 448 }; 449 450 static char *dm_ism_states_str[DM_ISM_NUM_STATES] = { 451 [DM_ISM_STATE_FULL_POWER_RUNNING] = "FULL_POWER_RUNNING", 452 [DM_ISM_STATE_FULL_POWER_BUSY] = "FULL_POWER_BUSY", 453 [DM_ISM_STATE_HYSTERESIS_WAITING] = "HYSTERESIS_WAITING", 454 [DM_ISM_STATE_HYSTERESIS_BUSY] = "HYSTERESIS_BUSY", 455 [DM_ISM_STATE_OPTIMIZED_IDLE] = "OPTIMIZED_IDLE", 456 [DM_ISM_STATE_OPTIMIZED_IDLE_SSO] = "OPTIMIZED_IDLE_SSO", 457 [DM_ISM_STATE_TIMER_ABORTED] = "TIMER_ABORTED", 458 }; 459 460 461 void amdgpu_dm_ism_commit_event(struct amdgpu_dm_ism *ism, 462 enum amdgpu_dm_ism_event event) 463 { 464 enum amdgpu_dm_ism_event next_event = event; 465 struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism); 466 struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev); 467 struct amdgpu_display_manager *dm = &adev->dm; 468 struct dm_crtc_state *acrtc_state = to_dm_crtc_state(acrtc->base.state); 469 470 /* ISM transitions must be called with dc_lock held */ 471 lockdep_assert_held(&dm->dc_lock); 472 473 /* ISM should not run after dc is destroyed */ 474 ASSERT(dm->dc); 475 476 if (!acrtc_state) { 477 trace_amdgpu_dm_ism_event(acrtc->crtc_id, "NO_STATE", 478 "NO_STATE", "N/A"); 479 return; 480 } 481 482 do { 483 bool transition = dm_ism_trigger_event(ism, event); 484 485 next_event = DM_ISM_NUM_EVENTS; 486 if (transition) { 487 trace_amdgpu_dm_ism_event( 488 acrtc->crtc_id, 489 dm_ism_states_str[ism->previous_state], 490 dm_ism_states_str[ism->current_state], 491 dm_ism_events_str[event]); 492 next_event = dm_ism_dispatch_power_state(ism, acrtc_state); 493 } else { 494 trace_amdgpu_dm_ism_event( 495 acrtc->crtc_id, 496 dm_ism_states_str[ism->current_state], 497 dm_ism_states_str[ism->current_state], 498 dm_ism_events_str[event]); 499 } 500 501 event = next_event; 502 503 } while (next_event < DM_ISM_NUM_EVENTS); 504 } 505 506 507 static void dm_ism_delayed_work_func(struct work_struct *work) 508 { 509 struct amdgpu_dm_ism *ism = 510 container_of(work, struct amdgpu_dm_ism, delayed_work.work); 511 struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism); 512 struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev); 513 struct amdgpu_display_manager *dm = &adev->dm; 514 515 guard(mutex)(&dm->dc_lock); 516 517 amdgpu_dm_ism_commit_event(ism, DM_ISM_EVENT_TIMER_ELAPSED); 518 } 519 520 static void dm_ism_sso_delayed_work_func(struct work_struct *work) 521 { 522 struct amdgpu_dm_ism *ism = 523 container_of(work, struct amdgpu_dm_ism, sso_delayed_work.work); 524 struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism); 525 struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev); 526 struct amdgpu_display_manager *dm = &adev->dm; 527 528 guard(mutex)(&dm->dc_lock); 529 530 amdgpu_dm_ism_commit_event(ism, DM_ISM_EVENT_SSO_TIMER_ELAPSED); 531 } 532 533 /** 534 * amdgpu_dm_ism_disable - Quiesce ISM workers 535 * 536 * @dm: The amdgpu display manager 537 * 538 * Cancels and disables any pending or in-flight ISM delayed work and waits 539 * for in-progress work to finish. After this returns, no ISM worker can run 540 * and subsequent mod_delayed_work() calls become no-ops via 541 * clear_pending_if_disabled(). 542 * 543 * Must NOT be called with dc_lock held: the workers themselves take dc_lock, 544 * so a synchronous wait under dc_lock would deadlock. 545 * 546 * The caller is responsible for driving the FSM back to FULL_POWER_RUNNING 547 * (under dc_lock) by calling amdgpu_dm_ism_force_full_power(). 548 */ 549 void amdgpu_dm_ism_disable(struct amdgpu_display_manager *dm) 550 { 551 struct drm_crtc *crtc; 552 struct amdgpu_crtc *acrtc; 553 struct amdgpu_dm_ism *ism; 554 555 /* 556 * Caller must NOT hold dc_lock: the ISM delayed work handlers 557 * acquire dc_lock themselves, so waiting for them via 558 * disable_delayed_work_sync() while holding dc_lock would 559 * self-deadlock against an in-flight worker. 560 */ 561 lockdep_assert_not_held(&dm->dc_lock); 562 563 drm_for_each_crtc(crtc, dm->ddev) { 564 acrtc = to_amdgpu_crtc(crtc); 565 ism = &acrtc->ism; 566 567 disable_delayed_work_sync(&ism->delayed_work); 568 disable_delayed_work_sync(&ism->sso_delayed_work); 569 } 570 } 571 572 /** 573 * amdgpu_dm_ism_force_full_power - Force every CRTC's ISM FSM to FULL_POWER 574 * 575 * @dm: The amdgpu display manager 576 * 577 * Sends DM_ISM_EVENT_EXIT_IDLE_REQUESTED to every CRTC's ISM, leaving each 578 * FSM in FULL_POWER_RUNNING. Intended to be paired with 579 * amdgpu_dm_ism_disable(): callers should first quiesce workers (without 580 * dc_lock), then take dc_lock and call this helper. 581 * 582 * Must be called with dc_lock held. 583 */ 584 void amdgpu_dm_ism_force_full_power(struct amdgpu_display_manager *dm) 585 { 586 struct drm_crtc *crtc; 587 struct amdgpu_crtc *acrtc; 588 589 /* 590 * Caller must hold dc_lock: commit_event() drives the FSM and 591 * may touch dc state via dc_allow_idle_optimizations() etc. 592 */ 593 lockdep_assert_held(&dm->dc_lock); 594 595 drm_for_each_crtc(crtc, dm->ddev) { 596 acrtc = to_amdgpu_crtc(crtc); 597 598 /* 599 * When disabled, leave in FULL_POWER_RUNNING state. 600 * EXIT_IDLE will not queue any work. 601 */ 602 amdgpu_dm_ism_commit_event(&acrtc->ism, 603 DM_ISM_EVENT_EXIT_IDLE_REQUESTED); 604 } 605 } 606 607 /** 608 * amdgpu_dm_ism_enable - enable the ISM 609 * 610 * @dm: The amdgpu display manager 611 * 612 * Re-enable the idle state manager by enabling work that was disabled by 613 * amdgpu_dm_ism_disable. 614 */ 615 void amdgpu_dm_ism_enable(struct amdgpu_display_manager *dm) 616 { 617 struct drm_crtc *crtc; 618 struct amdgpu_crtc *acrtc; 619 struct amdgpu_dm_ism *ism; 620 621 drm_for_each_crtc(crtc, dm->ddev) { 622 acrtc = to_amdgpu_crtc(crtc); 623 ism = &acrtc->ism; 624 625 enable_delayed_work(&ism->delayed_work); 626 enable_delayed_work(&ism->sso_delayed_work); 627 } 628 } 629 630 void amdgpu_dm_ism_init(struct amdgpu_dm_ism *ism, 631 struct amdgpu_dm_ism_config *config) 632 { 633 ism->config = *config; 634 635 ism->current_state = DM_ISM_STATE_FULL_POWER_RUNNING; 636 ism->previous_state = DM_ISM_STATE_FULL_POWER_RUNNING; 637 ism->next_record_idx = 0; 638 ism->last_idle_timestamp_ns = 0; 639 640 INIT_DELAYED_WORK(&ism->delayed_work, dm_ism_delayed_work_func); 641 INIT_DELAYED_WORK(&ism->sso_delayed_work, dm_ism_sso_delayed_work_func); 642 } 643 EXPORT_IF_KUNIT(amdgpu_dm_ism_init); 644 645 646 void amdgpu_dm_ism_fini(struct amdgpu_dm_ism *ism) 647 { 648 cancel_delayed_work_sync(&ism->sso_delayed_work); 649 cancel_delayed_work_sync(&ism->delayed_work); 650 } 651 EXPORT_IF_KUNIT(amdgpu_dm_ism_fini); 652