xref: /linux/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c (revision bb3ab95ac78671b128314b3515aa007439b7b58d)
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