xref: /linux/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c (revision 40288c9206c17eb66a603262e06a58d300d0f279)
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2024 Advanced Micro Devices, Inc.
4 
5 #include "dm_services.h"
6 #include "dm_helpers.h"
7 #include "core_types.h"
8 #include "resource.h"
9 #include "dccg.h"
10 #include "dce/dce_hwseq.h"
11 #include "reg_helper.h"
12 #include "abm.h"
13 #include "hubp.h"
14 #include "dchubbub.h"
15 #include "timing_generator.h"
16 #include "opp.h"
17 #include "ipp.h"
18 #include "mpc.h"
19 #include "mcif_wb.h"
20 #include "dc_dmub_srv.h"
21 #include "link_hwss.h"
22 #include "dpcd_defs.h"
23 #include "clk_mgr.h"
24 #include "dsc.h"
25 #include "link_service.h"
26 
27 #include "dce/dmub_hw_lock_mgr.h"
28 #include "dcn10/dcn10_cm_common.h"
29 #include "dcn20/dcn20_optc.h"
30 #include "dcn30/dcn30_cm_common.h"
31 #include "dce110/dce110_hwseq.h"
32 #include "dcn32/dcn32_hwseq.h"
33 #include "dcn401/dcn401_hwseq.h"
34 #include "dcn50/dcn50_hwseq.h"
35 #include "dcn60_hwseq.h"
36 #include "dcn401/dcn401_resource.h"
37 #include "dcn60/dcn60_resource.h"
38 #include "dc_state_priv.h"
39 #include "link_enc_cfg.h"
40 #include "dio/dcn10/dcn10_dio.h"
41 
42 #define DC_LOGGER_INIT(logger)
43 
44 #define CTX \
45 	hws->ctx
46 #define REG(reg)\
47 	hws->regs->reg
48 #define DC_LOGGER \
49 	dc->ctx->logger
50 
51 #undef FN
52 #define FN(reg_name, field_name) \
53 	hws->shifts->field_name, hws->masks->field_name
54 
dcn60_build_audio_output(struct dc_state * state,const struct pipe_ctx * pipe_ctx,struct audio_output * audio_output)55 static void dcn60_build_audio_output(
56 	struct dc_state *state,
57 	const struct pipe_ctx *pipe_ctx,
58 	struct audio_output *audio_output)
59 {
60 	const struct dc_stream_state *stream = pipe_ctx->stream;
61 	audio_output->engine_id = pipe_ctx->stream_res.stream_enc->id;
62 
63 	audio_output->signal = pipe_ctx->stream->signal;
64 
65 	/* audio_crtc_info  */
66 
67 	audio_output->crtc_info.h_total =
68 		stream->timing.h_total;
69 
70 	/*
71 	 * Audio packets are sent during actual CRTC blank physical signal, we
72 	 * need to specify actual active signal portion
73 	 */
74 	audio_output->crtc_info.h_active =
75 			stream->timing.h_addressable
76 			+ stream->timing.h_border_left
77 			+ stream->timing.h_border_right;
78 
79 	audio_output->crtc_info.v_active =
80 			stream->timing.v_addressable
81 			+ stream->timing.v_border_top
82 			+ stream->timing.v_border_bottom;
83 
84 	audio_output->crtc_info.pixel_repetition = 1;
85 
86 	audio_output->crtc_info.interlaced =
87 			(stream->timing.flags.INTERLACE != 0);
88 
89 	audio_output->crtc_info.refresh_rate =
90 		(uint16_t)((stream->timing.pix_clk_100hz*100)/
91 		(stream->timing.h_total*stream->timing.v_total));
92 
93 	audio_output->crtc_info.color_depth =
94 		stream->timing.display_color_depth;
95 
96 	audio_output->crtc_info.requested_pixel_clock_100Hz =
97 			pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz;
98 
99 	audio_output->crtc_info.calculated_pixel_clock_100Hz =
100 			pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz;
101 
102 	audio_output->crtc_info.pixel_encoding =
103 		stream->timing.pixel_encoding;
104 
105 	audio_output->crtc_info.dsc_bits_per_pixel =
106 			stream->timing.dsc_cfg.bits_per_pixel;
107 
108 	audio_output->crtc_info.dsc_num_slices =
109 			stream->timing.dsc_cfg.num_slices_h;
110 
111 /*for HDMI, audio ACR is with deep color ratio factor*/
112 	if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) &&
113 		audio_output->crtc_info.requested_pixel_clock_100Hz ==
114 				(stream->timing.pix_clk_100hz)) {
115 		if (pipe_ctx->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420) {
116 			audio_output->crtc_info.requested_pixel_clock_100Hz =
117 					audio_output->crtc_info.requested_pixel_clock_100Hz/2;
118 			audio_output->crtc_info.calculated_pixel_clock_100Hz =
119 					pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz/2;
120 
121 		}
122 	}
123 	if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_FRL) {
124 		switch (pipe_ctx->stream->link->frl_link_settings.frl_link_rate) {
125 		case HDMI_FRL_LINK_RATE_3GBPS:
126 			audio_output->crtc_info.frl_character_clock_kHz = 166667;
127 			break;
128 		case HDMI_FRL_LINK_RATE_6GBPS:
129 		case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
130 			audio_output->crtc_info.frl_character_clock_kHz = 333333;
131 			break;
132 		case HDMI_FRL_LINK_RATE_8GBPS:
133 			audio_output->crtc_info.frl_character_clock_kHz = 444444;
134 			break;
135 		case HDMI_FRL_LINK_RATE_10GBPS:
136 			audio_output->crtc_info.frl_character_clock_kHz = 555555;
137 			break;
138 		case HDMI_FRL_LINK_RATE_12GBPS:
139 			audio_output->crtc_info.frl_character_clock_kHz = 666667;
140 			break;
141 		case HDMI_FRL_LINK_RATE_16GBPS:
142 			audio_output->crtc_info.frl_character_clock_kHz = 888889;
143 			break;
144 		case HDMI_FRL_LINK_RATE_20GBPS:
145 		default:
146 			audio_output->crtc_info.frl_character_clock_kHz = 1111111;
147 			break;
148 	}
149 	} else
150 			audio_output->crtc_info.frl_character_clock_kHz = 0;
151 
152 	if (state->clk_mgr &&
153 		(pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
154 			pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_FRL ||
155 			pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)) {
156 		audio_output->pll_info.audio_dto_source_clock_in_khz =
157 				state->clk_mgr->funcs->get_dp_ref_clk_frequency(
158 						state->clk_mgr);
159 	}
160 
161 	audio_output->pll_info.dto_source =
162 		translate_to_dto_source(
163 			pipe_ctx->stream_res.tg->inst + 1);
164 
165 	/* TODO hard code to enable for now. Need get from stream */
166 	audio_output->pll_info.ss_enabled = true;
167 
168 	audio_output->pll_info.ss_percentage =
169 			pipe_ctx->pll_settings.ss_percentage;
170 
171 	if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
172 		populate_audio_dp_link_info(pipe_ctx, &audio_output->dp_link_info);
173 	}
174 }
175 
dcn60_apply_single_controller_ctx_to_hw(struct pipe_ctx * pipe_ctx,struct dc_state * context,struct dc * dc)176 enum dc_status dcn60_apply_single_controller_ctx_to_hw(
177 		struct pipe_ctx *pipe_ctx,
178 		struct dc_state *context,
179 		struct dc *dc)
180 {
181 	struct dc_stream_state *stream = pipe_ctx->stream;
182 	struct dc_link *link = stream->link;
183 	struct drr_params params = {0};
184 	unsigned int event_triggers = 0;
185 	struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
186 	struct dce_hwseq *hws = dc->hwseq;
187 	const struct link_hwss *link_hwss = get_link_hwss(
188 			link, &pipe_ctx->link_res);
189 
190 	if (hws->funcs.disable_stream_gating) {
191 		hws->funcs.disable_stream_gating(dc, pipe_ctx);
192 	}
193 
194 	if (pipe_ctx->stream_res.audio != NULL) {
195 		struct audio_output audio_output = {0};
196 
197 		dcn60_build_audio_output(context, pipe_ctx, &audio_output);
198 
199 		link_hwss->setup_audio_output(pipe_ctx, &audio_output,
200 				pipe_ctx->stream_res.audio->inst);
201 
202 		pipe_ctx->stream_res.audio->funcs->az_configure(
203 				pipe_ctx->stream_res.audio,
204 				pipe_ctx->stream->signal,
205 				&audio_output.crtc_info,
206 				&pipe_ctx->stream->audio_info,
207 				&audio_output.dp_link_info);
208 
209 		if (dc->config.disable_hbr_audio_dp2)
210 			if (pipe_ctx->stream_res.audio->funcs->az_disable_hbr_audio &&
211 					dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))
212 				pipe_ctx->stream_res.audio->funcs->az_disable_hbr_audio(pipe_ctx->stream_res.audio);
213 	}
214 
215 	/* make sure no pipes syncd to the pipe being enabled */
216 	if (!pipe_ctx->stream->apply_seamless_boot_optimization && dc->config.use_pipe_ctx_sync_logic)
217 		check_syncd_pipes_for_disabled_master_pipe(dc, context, pipe_ctx->pipe_idx);
218 
219 	pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
220 		pipe_ctx->stream_res.opp,
221 		&stream->bit_depth_params,
222 		&stream->clamping);
223 
224 	pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
225 			pipe_ctx->stream_res.opp,
226 			COLOR_SPACE_YCBCR601,
227 			stream->timing.display_color_depth,
228 			stream->signal);
229 
230 	while (odm_pipe) {
231 		odm_pipe->stream_res.opp->funcs->opp_set_dyn_expansion(
232 				odm_pipe->stream_res.opp,
233 				COLOR_SPACE_YCBCR601,
234 				stream->timing.display_color_depth,
235 				stream->signal);
236 
237 		odm_pipe->stream_res.opp->funcs->opp_program_fmt(
238 				odm_pipe->stream_res.opp,
239 				&stream->bit_depth_params,
240 				&stream->clamping);
241 		odm_pipe = odm_pipe->next_odm_pipe;
242 	}
243 
244 	/* DCN3.1 FPGA Workaround
245 	 * Need to enable HPO DP Stream Encoder before setting OTG master enable.
246 	 * To do so, move calling function enable_stream_timing to only be done AFTER calling
247 	 * function core_link_enable_stream
248 	 */
249 	if (!(hws->wa.dp_hpo_and_otg_sequence && dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)))
250 		/*  */
251 		/* Do not touch stream timing on seamless boot optimization. */
252 		if (!pipe_ctx->stream->apply_seamless_boot_optimization)
253 			hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
254 
255 	if (hws->funcs.setup_vupdate_interrupt)
256 		hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
257 
258 	params.vertical_total_min = stream->adjust.v_total_min;
259 	params.vertical_total_max = stream->adjust.v_total_max;
260 	set_drr_and_clear_adjust_pending(pipe_ctx, stream, &params);
261 
262 	// DRR should set trigger event to monitor surface update event
263 	if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
264 		event_triggers = 0x80;
265 	/* Event triggers and num frames initialized for DRR, but can be
266 	 * later updated for PSR use. Note DRR trigger events are generated
267 	 * regardless of whether num frames met.
268 	 */
269 	if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
270 		pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
271 				pipe_ctx->stream_res.tg, event_triggers, 2);
272 
273 	if (!dc_is_virtual_signal(pipe_ctx->stream->signal)
274 		&& !dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
275 		pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg(
276 			pipe_ctx->stream_res.stream_enc,
277 			pipe_ctx->stream_res.tg->inst);
278 
279 	if (dc_is_dp_signal(pipe_ctx->stream->signal))
280 		dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
281 
282 	/* Temporary workaround to perform DSC programming ahead of stream enablement
283 	 * for smartmux/SPRS
284 	 * TODO: Remove SmartMux/SPRS checks once movement of DSC programming is generalized
285 	 */
286 	if (pipe_ctx->stream->timing.flags.DSC) {
287 		if ((pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
288 			((link->dc->config.smart_mux_version && link->dc->is_switch_in_progress_dest)
289 			|| link->is_dds || link->skip_implict_edp_power_control)) &&
290 			(dc_is_dp_signal(pipe_ctx->stream->signal) ||
291 			dc_is_virtual_signal(pipe_ctx->stream->signal)))
292 			dc->link_srv->set_dsc_enable(pipe_ctx, true);
293 	}
294 	if (!stream->dpms_off)
295 		dc->link_srv->set_dpms_on(context, pipe_ctx);
296 
297 	/* DCN3.1 FPGA Workaround
298 	 * Need to enable HPO DP Stream Encoder before setting OTG master enable.
299 	 * To do so, move calling function enable_stream_timing to only be done AFTER calling
300 	 * function core_link_enable_stream
301 	 */
302 	if (hws->wa.dp_hpo_and_otg_sequence && dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
303 		if (!pipe_ctx->stream->apply_seamless_boot_optimization)
304 			hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
305 	}
306 
307 	pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != NULL;
308 
309 	/* Phantom and main stream share the same link (because the stream
310 	 * is constructed with the same sink). Make sure not to override
311 	 * and link programming on the main.
312 	 */
313 	if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) {
314 		pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false;
315 		pipe_ctx->stream->link->replay_settings.replay_feature_enabled = false;
316 	}
317 	return DC_OK;
318 }
319 
dcn60_setup_audio_dto(struct dc * dc,struct dc_state * context)320 static void dcn60_setup_audio_dto(
321 		struct dc *dc,
322 		struct dc_state *context)
323 {
324 	unsigned int i;
325 
326 	/* program audio wall clock. use HDMI as clock source if HDMI
327 	 * audio active. Otherwise, use DP as clock source
328 	 * first, loop to find any HDMI audio, if not, loop find DP audio
329 	 */
330 	/* Setup audio rate clock source */
331 	/* Issue:
332 	* Audio lag happened on DP monitor when unplug a HDMI monitor
333 	*
334 	* Cause:
335 	* In case of DP and HDMI connected or HDMI only, DCCG_AUDIO_DTO_SEL
336 	* is set to either dto0 or dto1, audio should work fine.
337 	* In case of DP connected only, DCCG_AUDIO_DTO_SEL should be dto1,
338 	* set to dto0 will cause audio lag.
339 	*
340 	* Solution:
341 	* Not optimized audio wall dto setup. When mode set, iterate pipe_ctx,
342 	* find first available pipe with audio, setup audio wall DTO per topology
343 	* instead of per pipe.
344 	*/
345 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
346 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
347 
348 		if (pipe_ctx->stream == NULL)
349 			continue;
350 
351 		if (pipe_ctx->top_pipe)
352 			continue;
353 		if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_TYPE_A &&
354 			pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_FRL)
355 			continue;
356 		if (pipe_ctx->stream_res.audio != NULL) {
357 			struct audio_output audio_output;
358 
359 			dcn60_build_audio_output(context, pipe_ctx, &audio_output);
360 
361 			if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->set_audio_dtbclk_dto) {
362 				struct dtbclk_dto_params dto_params = {0};
363 				dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
364 
365 				if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_FRL) {
366 					/* For DCN3.1, audio to HPO FRL encoder is using audio DTBCLK DTO */
367 					/* set audio DTBCLK DTO to 24MHz */
368 					dto_params.req_audio_dtbclk_khz = 24000;
369 					dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
370 						dc->res_pool->dccg,
371 						&dto_params);
372 				} else {
373 					/* Audio DTBCLK params default to disabled */
374 					dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
375 						dc->res_pool->dccg,
376 						&dto_params);
377 
378 					pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
379 						pipe_ctx->stream_res.audio,
380 						pipe_ctx->stream->signal,
381 						&audio_output.crtc_info,
382 						&audio_output.pll_info);
383 				}
384 			} else
385 				pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
386 					pipe_ctx->stream_res.audio,
387 					pipe_ctx->stream->signal,
388 					&audio_output.crtc_info,
389 					&audio_output.pll_info);
390 			break;
391 		}
392 	}
393 
394 	/* no HDMI audio is found, try DP audio */
395 	if (i == dc->res_pool->pipe_count) {
396 		for (i = 0; i < dc->res_pool->pipe_count; i++) {
397 			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
398 
399 			if (pipe_ctx->stream == NULL)
400 				continue;
401 
402 			if (pipe_ctx->top_pipe)
403 				continue;
404 
405 			if (!dc_is_dp_signal(pipe_ctx->stream->signal))
406 				continue;
407 
408 			if (pipe_ctx->stream_res.audio != NULL) {
409 				struct audio_output audio_output = {0};
410 
411 				dcn60_build_audio_output(context, pipe_ctx, &audio_output);
412 
413 				/* Audio to HPO DP encoder is using audio DTBCLK DTO */
414 				if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->set_audio_dtbclk_dto) {
415 					struct dtbclk_dto_params dto_params = {0};
416 					dto_params.ref_dtbclk_khz =
417 							dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
418 
419 					if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
420 						/* set audio DTBCLK DTO to 24MHz */
421 						dto_params.req_audio_dtbclk_khz = 24000;
422 						dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
423 							dc->res_pool->dccg,
424 							&dto_params);
425 					} else {
426 						/* Audio DTBCLK params default to disabled */
427 						dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
428 							dc->res_pool->dccg,
429 							&dto_params);
430 
431 						pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
432 							pipe_ctx->stream_res.audio,
433 							pipe_ctx->stream->signal,
434 							&audio_output.crtc_info,
435 							&audio_output.pll_info);
436 					}
437 				} else {
438 					pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
439 						pipe_ctx->stream_res.audio,
440 						pipe_ctx->stream->signal,
441 						&audio_output.crtc_info,
442 						&audio_output.pll_info);
443 				}
444 				break;
445 			}
446 		}
447 	}
448 }
449 
dcn60_apply_ctx_to_hw(struct dc * dc,struct dc_state * context)450 enum dc_status dcn60_apply_ctx_to_hw(
451 		struct dc *dc,
452 		struct dc_state *context)
453 {
454 	struct dce_hwseq *hws = dc->hwseq;
455 	struct dc_bios *dcb = dc->ctx->dc_bios;
456 	enum dc_status status;
457 	uint8_t i;
458 	bool was_hpo_acquired = resource_is_hpo_acquired(dc->current_state);
459 	bool is_hpo_acquired = resource_is_hpo_acquired(context);
460 
461 	/* reset syncd pipes from disabled pipes */
462 	if (dc->config.use_pipe_ctx_sync_logic)
463 		reset_syncd_pipes_from_disabled_pipes(dc, context);
464 
465 	/* Reset old context */
466 	/* look up the targets that have been removed since last commit */
467 	hws->funcs.reset_hw_ctx_wrap(dc, context);
468 
469 	/* Skip applying if no targets */
470 	if (context->stream_count <= 0)
471 		return DC_OK;
472 
473 	/* Apply new context */
474 	dcb->funcs->set_scratch_critical_state(dcb, true);
475 
476 	/* below is for real asic only */
477 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
478 		struct pipe_ctx *pipe_ctx_old =
479 					&dc->current_state->res_ctx.pipe_ctx[i];
480 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
481 
482 		if (pipe_ctx->stream == NULL || pipe_ctx->top_pipe)
483 			continue;
484 
485 		if (pipe_ctx->stream == pipe_ctx_old->stream) {
486 			if (pipe_ctx_old->clock_source != pipe_ctx->clock_source)
487 				dce_crtc_switch_to_clk_src(dc->hwseq,
488 						pipe_ctx->clock_source, i);
489 			continue;
490 		}
491 
492 		hws->funcs.enable_display_power_gating(
493 				dc, i, dc->ctx->dc_bios,
494 				PIPE_GATING_CONTROL_DISABLE);
495 	}
496 
497 	dcn60_setup_audio_dto(dc, context);
498 
499 	if (dc->hwseq->funcs.setup_hpo_hw_control && was_hpo_acquired != is_hpo_acquired) {
500 		dc->hwseq->funcs.setup_hpo_hw_control(dc->hwseq, is_hpo_acquired);
501 	}
502 
503 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
504 		struct pipe_ctx *pipe_ctx_old =
505 					&dc->current_state->res_ctx.pipe_ctx[i];
506 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
507 
508 		if (pipe_ctx->stream == NULL)
509 			continue;
510 
511 		if (pipe_ctx->stream == pipe_ctx_old->stream &&
512 			pipe_ctx->stream->link->link_state_valid) {
513 			continue;
514 		}
515 
516 		if (pipe_ctx_old->stream && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
517 			continue;
518 
519 		if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe)
520 			continue;
521 
522 		status = dcn60_apply_single_controller_ctx_to_hw(
523 				pipe_ctx,
524 				context,
525 				dc);
526 
527 		if (DC_OK != status)
528 			return status;
529 
530 #ifdef CONFIG_DRM_AMD_DC_FP
531 		if (hws->funcs.resync_fifo_dccg_dio)
532 			hws->funcs.resync_fifo_dccg_dio(hws, dc, context, i);
533 #endif
534 	}
535 
536 	dcb->funcs->set_scratch_critical_state(dcb, false);
537 
538 	return DC_OK;
539 }
540 
dcn60_init_hw(struct dc * dc)541 void dcn60_init_hw(struct dc *dc)
542 {
543 	struct abm **abms = dc->res_pool->multiple_abms;
544 	struct dce_hwseq *hws = dc->hwseq;
545 	struct dc_bios *dcb = dc->ctx->dc_bios;
546 	struct resource_pool *res_pool = dc->res_pool;
547 	unsigned int i;
548 	unsigned int edp_num;
549 	uint32_t backlight = MAX_BACKLIGHT_LEVEL;
550 	uint32_t user_level = MAX_BACKLIGHT_LEVEL;
551 
552 	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) {
553 		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
554 
555 		// mark dcmode limits present if any clock has distinct AC and DC values from SMU
556 		dc->caps.dcmode_power_limits_present = dc->clk_mgr->funcs->is_dc_mode_present &&
557 			dc->clk_mgr->funcs->is_dc_mode_present(dc->clk_mgr);
558 	}
559 
560 	// Initialize the dccg
561 	if (res_pool->dccg->funcs->dccg_init)
562 		res_pool->dccg->funcs->dccg_init(res_pool->dccg);
563 
564 	// Set default OPTC memory power states
565 	if (dc->debug.enable_mem_low_power.bits.optc) {
566 		// Shutdown when unassigned and light sleep in VBLANK
567 		REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
568 	}
569 
570 	if (dc->debug.enable_mem_low_power.bits.vga) {
571 		// Power down VGA memory
572 		REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
573 	}
574 
575 	for (i = 0; i < (unsigned int)dc->res_pool->res_cap->num_dsc; i++) {
576 		struct display_stream_compressor *dsc = dc->res_pool->dscs[i];
577 
578 		if (dsc->funcs->set_fgcg)
579 			dsc->funcs->set_fgcg(dsc, dc->ctx->dc->debug.enable_fine_grain_clock_gating.bits.dsc);
580 	}
581 
582 	if (dc->ctx->dc_bios->fw_info_valid) {
583 		res_pool->ref_clocks.xtalin_clock_inKhz =
584 			dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
585 
586 		if (res_pool->hubbub) {
587 			(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
588 				dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
589 				&res_pool->ref_clocks.dccg_ref_clock_inKhz);
590 
591 			(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
592 				res_pool->ref_clocks.dccg_ref_clock_inKhz,
593 				&res_pool->ref_clocks.dchub_ref_clock_inKhz);
594 		} else {
595 			// Not all ASICs have DCCG sw component
596 			res_pool->ref_clocks.dccg_ref_clock_inKhz =
597 				res_pool->ref_clocks.xtalin_clock_inKhz;
598 			res_pool->ref_clocks.dchub_ref_clock_inKhz =
599 				res_pool->ref_clocks.xtalin_clock_inKhz;
600 		}
601 	} else
602 		ASSERT_CRITICAL(false);
603 
604 	for (i = 0; i < dc->link_count; i++) {
605 		/* Power up AND update implementation according to the
606 		 * required signal (which may be different from the
607 		 * default signal on connector).
608 		 */
609 		struct dc_link *link = dc->links[i];
610 
611 		link->link_enc->funcs->hw_init(link->link_enc);
612 
613 		/* Check for enabled DIG to identify enabled display */
614 		if (link->link_enc->funcs->is_dig_enabled &&
615 			link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
616 			link->link_status.link_active = true;
617 			link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
618 			if (link->link_enc->funcs->fec_is_active &&
619 				link->link_enc->funcs->fec_is_active(link->link_enc))
620 				link->fec_state = dc_link_fec_enabled;
621 		}
622 	}
623 
624 	/* we want to turn off all dp displays before doing detection */
625 	dc->link_srv->blank_all_dp_displays(dc);
626 
627 	/* If taking control over from VBIOS, we may want to optimize our first
628 	 * mode set, so we need to skip powering down pipes until we know which
629 	 * pipes we want to use.
630 	 * Otherwise, if taking control is not possible, we need to power
631 	 * everything down.
632 	 */
633 	if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
634 		/* Disable boot optimizations means power down everything including PHY, DIG,
635 		 * and OTG (i.e. the boot is not optimized because we do a full power down).
636 		 */
637 		if (dc->hwss.enable_accelerated_mode && dc->debug.disable_boot_optimizations)
638 			dc->hwss.enable_accelerated_mode(dc, dc->current_state);
639 		else
640 			hws->funcs.init_pipes(dc, dc->current_state);
641 
642 		if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
643 			dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
644 				!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
645 
646 		if (dc->clk_mgr && dc->clk_mgr->funcs)
647 			dcn401_initialize_min_clocks(dc);
648 
649 		/* On HW init, allow idle optimizations after pipes have been turned off.
650 		 *
651 		 * In certain D3 cases (i.e. BOCO / BOMACO) it's possible that hardware state
652 		 * is reset (i.e. not in idle at the time hw init is called), but software state
653 		 * still has idle_optimizations = true, so we must disable idle optimizations first
654 		 * (i.e. set false), then re-enable (set true).
655 		 */
656 		dc_allow_idle_optimizations(dc, false);
657 		dc_allow_idle_optimizations(dc, true);
658 	}
659 
660 	/* In headless boot cases, DIG may be turned
661 	 * on which causes HW/SW discrepancies.
662 	 * To avoid this, power down hardware on boot
663 	 * if DIG is turned on and seamless boot not enabled
664 	 */
665 	if (!dc->config.seamless_boot_edp_requested) {
666 		struct dc_link *edp_links[MAX_NUM_EDP];
667 		struct dc_link *edp_link;
668 
669 		dc_get_edp_links(dc, edp_links, &edp_num);
670 		if (edp_num) {
671 			for (i = 0; i < edp_num; i++) {
672 				edp_link = edp_links[i];
673 				if (edp_link->link_enc->funcs->is_dig_enabled &&
674 					edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
675 					dc->hwss.edp_backlight_control &&
676 					hws->funcs.power_down &&
677 					dc->hwss.edp_power_control) {
678 					dc->hwss.edp_backlight_control(edp_link, false);
679 					hws->funcs.power_down(dc);
680 					dc->hwss.edp_power_control(edp_link, false);
681 				}
682 			}
683 		} else {
684 			for (i = 0; i < dc->link_count; i++) {
685 				struct dc_link *link = dc->links[i];
686 
687 				if (link->link_enc->funcs->is_dig_enabled &&
688 					link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
689 					hws->funcs.power_down) {
690 					hws->funcs.power_down(dc);
691 					break;
692 				}
693 
694 			}
695 		}
696 	}
697 
698 	for (i = 0; i < res_pool->audio_count; i++) {
699 		struct audio *audio = res_pool->audios[i];
700 
701 		audio->funcs->hw_init(audio);
702 	}
703 
704 	for (i = 0; i < dc->link_count; i++) {
705 		struct dc_link *link = dc->links[i];
706 
707 		if (link->panel_cntl) {
708 			backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
709 			user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL;
710 		}
711 
712 		if (link->force_to_use_aux) {
713 			//Setup corresponding HDCP XFER DEST interrupt to go to DMUCB
714 			dc_dmub_srv_ihc_set_dig_hdcp_interrupt_dest(
715 				dc->ctx->dmub_srv,
716 				link->eng_id,
717 				true);
718 		}
719 
720 	}
721 
722 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
723 		if (abms[i] != NULL && abms[i]->funcs != NULL)
724 			abms[i]->funcs->abm_init(abms[i], backlight, user_level);
725 	}
726 
727 	/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
728 	if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl)
729 		dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false);
730 
731 	if (!dc->debug.disable_clock_gate) {
732 		/* enable all DCN clock gating */
733 		if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->allow_clock_gating)
734 			dc->res_pool->dccg->funcs->allow_clock_gating(dc->res_pool->dccg, true);
735 
736 		REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
737 	}
738 
739 	dcn401_setup_hpo_hw_control(hws, true);
740 
741 	if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
742 		dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
743 
744 	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges)
745 		dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
746 
747 	if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
748 		dc->res_pool->hubbub->funcs->force_pstate_change_control(
749 			dc->res_pool->hubbub, false, false);
750 
751 	if (dc->res_pool->hubbub->funcs->init_crb)
752 		dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
753 
754 	if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0)
755 		dc->res_pool->hubbub->funcs->set_request_limit(dc->res_pool->hubbub, dc->ctx->dc_bios->vram_info.num_chans, dc->config.sdpif_request_limit_words_per_umc);
756 
757 	// Get DMCUB capabilities
758 	if (dc->ctx->dmub_srv) {
759 		dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv);
760 		dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
761 		dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0;
762 		dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
763 		dc->debug.fams2_config.bits.enable &=
764 			dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; // sw & fw fams versions must match for support
765 		if (dc->res_pool->funcs->update_bw_bounding_box) {
766 			/* For DCN6 re-update unconditionally to propagate Alt-Ch address info into DML */
767 			if (dc->clk_mgr)
768 				dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params);
769 		}
770 	}
771 }
772 
dcn60_set_cursor_attribute(struct pipe_ctx * pipe_ctx)773 void dcn60_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
774 {
775 	struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
776 
777 	attributes->force_cursor_to_disp_pref = pipe_ctx->hubp_regs.dlg_regs.force_cursor_to_disp_pref;
778 	pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
779 			pipe_ctx->plane_res.hubp, attributes);
780 	pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes(
781 		pipe_ctx->plane_res.dpp, attributes);
782 }
783 
dcn60_update_cursor_offload_pipe(struct dc * dc,const struct pipe_ctx * pipe)784 void dcn60_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe)
785 {
786 	volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
787 	const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
788 	const struct hubp *hubp = pipe->plane_res.hubp;
789 	const struct dpp *dpp = pipe->plane_res.dpp;
790 	volatile struct dmub_cursor_offload_pipe_data_dcn60_v1 *p;
791 	uint32_t stream_idx, write_idx, payload_idx;
792 
793 	if (!top_pipe || !hubp || !dpp)
794 		return;
795 
796 	stream_idx = top_pipe->pipe_idx;
797 	write_idx = cs->offload_streams[stream_idx].write_idx + 1; /*  new payload (+1) */
798 	payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
799 
800 	p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe->pipe_idx].dcn60;
801 
802 	p->CURSOR0_0_CURSOR_SURFACE_ADDRESS = hubp->att.SURFACE_ADDR;
803 	p->CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH = hubp->att.SURFACE_ADDR_HIGH;
804 	p->CURSOR0_0_CURSOR_SIZE__CURSOR_WIDTH = hubp->att.size.bits.width;
805 	p->CURSOR0_0_CURSOR_SIZE__CURSOR_HEIGHT = hubp->att.size.bits.height;
806 	p->CURSOR0_0_CURSOR_POSITION__CURSOR_X_POSITION = hubp->pos.position.bits.x_pos;
807 	p->CURSOR0_0_CURSOR_POSITION__CURSOR_Y_POSITION = hubp->pos.position.bits.y_pos;
808 	p->CURSOR0_0_CURSOR_HOT_SPOT__CURSOR_HOT_SPOT_X = hubp->pos.hot_spot.bits.x_hot;
809 	p->CURSOR0_0_CURSOR_HOT_SPOT__CURSOR_HOT_SPOT_Y = hubp->pos.hot_spot.bits.y_hot;
810 	p->CURSOR0_0_CURSOR_DST_OFFSET__CURSOR_DST_X_OFFSET = hubp->pos.dst_offset.bits.dst_x_offset;
811 	p->CURSOR0_0_CURSOR_CONTROL__CURSOR_ENABLE = hubp->pos.cur_ctl.bits.cur_enable;
812 	p->CURSOR0_0_CURSOR_CONTROL__CURSOR_MODE = hubp->att.cur_ctl.bits.mode;
813 	p->CURSOR0_0_CURSOR_CONTROL__CURSOR_2X_MAGNIFY = hubp->pos.cur_ctl.bits.cur_2x_magnify;
814 	p->CURSOR0_0_CURSOR_CONTROL__CURSOR_PITCH = hubp->att.cur_ctl.bits.pitch;
815 	p->CURSOR0_0_CURSOR_CONTROL__CURSOR_LINES_PER_CHUNK = hubp->att.cur_ctl.bits.line_per_chunk;
816 
817 	p->CM_CUR0_CURSOR0_CONTROL__CUR0_ENABLE = dpp->att.cur0_ctl.bits.cur0_enable;
818 	p->CM_CUR0_CURSOR0_CONTROL__CUR0_MODE = dpp->att.cur0_ctl.bits.mode;
819 	p->CM_CUR0_CURSOR0_CONTROL__CUR0_EXPANSION_MODE = dpp->att.cur0_ctl.bits.expansion_mode;
820 	p->CM_CUR0_CURSOR0_CONTROL__CUR0_ROM_EN = dpp->att.cur0_ctl.bits.cur0_rom_en;
821 	p->CM_CUR0_CURSOR0_COLOR0__CUR0_COLOR0 = 0x000000;
822 	p->CM_CUR0_CURSOR0_COLOR1__CUR0_COLOR1 = 0xFFFFFF;
823 
824 	p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_G_Y__CUR0_FP_BIAS_G_Y =
825 		dpp->att.fp_scale_bias_g_y.bits.fp_bias_g_y;
826 	p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_G_Y__CUR0_FP_SCALE_G_Y =
827 		dpp->att.fp_scale_bias_g_y.bits.fp_scale_g_y;
828 	p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_RB_CRCB__CUR0_FP_BIAS_RB_CRCB =
829 		dpp->att.fp_scale_bias_rb_crcb.bits.fp_bias_rb_crcb;
830 	p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_RB_CRCB__CUR0_FP_SCALE_RB_CRCB =
831 		dpp->att.fp_scale_bias_rb_crcb.bits.fp_scale_rb_crcb;
832 
833 	p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_DST_Y_OFFSET = hubp->att.settings.bits.dst_y_offset;
834 	p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_CHUNK_HDL_ADJUST = hubp->att.settings.bits.chunk_hdl_adjust;
835 	p->HUBPREQ0_CURSOR_SETTINGS__FORCE_CURSOR_TO_DISP_PREF = hubp->att.settings.bits.force_cursor_to_disp_pref;
836 
837 	cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe->pipe_idx);
838 }
839 
840 /**
841  * dcn60_get_ref_tg_for_hubbub_probe - Resolve the OTG master for hubbub probing.
842  * @context: committed dc state to resolve streams from
843  *
844  * All probe types gate their measurement window to frame edges of the OTG
845  * master of stream 0. Returns NULL when no active stream is present.
846  */
dcn60_get_ref_tg_for_hubbub_probe(struct dc_state * context)847 static struct timing_generator *dcn60_get_ref_tg_for_hubbub_probe(
848 		struct dc_state *context)
849 {
850 	struct pipe_ctx *otg_pipe;
851 
852 	if (!context || !context->stream_count)
853 		return NULL;
854 
855 	otg_pipe = resource_get_otg_master_for_stream(&context->res_ctx,
856 			context->streams[0]);
857 	if (!otg_pipe)
858 		return NULL;
859 
860 	return otg_pipe->stream_res.tg;
861 }
862 
863 /**
864  * dcn60_build_hubbub_perfmon_sequence - Build the hubbub perfmon BLS sequence.
865  * @dc:             DC structure
866  * @context:        Committed dc state to resolve streams from
867  * @probe:          Probe state to build sequence for
868  * @status:         Perfmon status to update with probe results
869  * @block_sequence: Block sequence to append steps to
870  * @num_steps:      Number of steps in the block sequence
871  *
872  * Appends BLS steps for the given probe into @block_sequence. No steps are
873  * added when the probe type is unsupported or prerequisites are not met.
874  */
dcn60_build_hubbub_perfmon_sequence(struct dc * dc,struct dc_state * context,const struct dc_probe_state * probe,struct dc_probe_status * status,struct block_sequence * block_sequence,unsigned int * num_steps)875 static void dcn60_build_hubbub_perfmon_sequence(
876 		struct dc *dc,
877 		struct dc_state *context,
878 		const struct dc_probe_state *probe,
879 		struct dc_probe_status *status,
880 		struct block_sequence *block_sequence,
881 		unsigned int *num_steps)
882 {
883 	struct hubbub *hubbub = dc->res_pool->hubbub;
884 	uint32_t refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
885 	struct timing_generator *ref_tg = dcn60_get_ref_tg_for_hubbub_probe(context);
886 	struct block_sequence_state seq_state = { .steps = block_sequence, .num_steps = num_steps };
887 	uint32_t duration_ns = 0;
888 
889 	if (!hubbub || !hubbub->funcs || !hubbub->funcs->perfmon.reset)
890 		return;
891 
892 	status->type = probe->type;
893 
894 	if (probe->target_state == DC_PROBE_NOT_MEASURING) {
895 		hwss_add_hubbub_perfmon_reset(&seq_state, hubbub);
896 		return;
897 	}
898 
899 	if (probe->target_state != DC_PROBE_MEASURED || !ref_tg)
900 		return;
901 
902 	/* Peak BW needs a single timing group. The out-of-order counter spans one
903 	 * prefetch window, which is meaningless when streams in separate timing
904 	 * groups have non-overlapping prefetch windows. */
905 	if (probe->type == DC_PROBE_PEAK_MEM_BW) {
906 		int group_size = context->stream_status[0].timing_sync_info.group_size;
907 
908 		if (group_size != context->stream_count)
909 			return;
910 	}
911 
912 	switch (probe->type) {
913 	case DC_PROBE_PEAK_MEM_BW:
914 		/* Start at the vblank edge and stop at the next vactive so the counter
915 		 * spans exactly one prefetch window, capturing prefetch traffic only. */
916 		if (!hubbub->funcs->perfmon.arm_measuring_out_of_order_bandwidth ||
917 				!hubbub->funcs->perfmon.start_measuring_out_of_order_bandwidth ||
918 				!hubbub->funcs->perfmon.get_out_of_order_bandwidth_mbps)
919 			return;
920 
921 		hwss_add_hubbub_perfmon_reset(&seq_state, hubbub);
922 		hwss_add_hubbub_perfmon_arm_out_of_order_bw(&seq_state, hubbub);
923 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
924 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
925 		hwss_add_hubbub_perfmon_start_out_of_order_bw(&seq_state, hubbub);
926 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
927 		hwss_add_hubbub_perfmon_get_out_of_order_bw(&seq_state, hubbub,
928 				refclk_mhz, &status->u.bandwidth_mbps, &duration_ns);
929 		break;
930 
931 	case DC_PROBE_AVG_MEM_BW:
932 		/* In-order counter accumulates over a full frame, so no timing group
933 		 * restriction applies (unlike the prefetch-windowed peak BW above). */
934 		if (!hubbub->funcs->perfmon.start_measuring_in_order_bandwidth ||
935 				!hubbub->funcs->perfmon.get_in_order_bandwidth_mbps)
936 			return;
937 
938 		hwss_add_hubbub_perfmon_reset(&seq_state, hubbub);
939 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
940 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
941 		hwss_add_hubbub_perfmon_start_in_order_bw(&seq_state, hubbub);
942 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
943 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
944 		hwss_add_hubbub_perfmon_get_in_order_bw(&seq_state, hubbub,
945 				refclk_mhz, 0, &status->u.bandwidth_mbps, &duration_ns);
946 		break;
947 
948 	case DC_PROBE_MEM_LATENCY:
949 		if (!hubbub->funcs->perfmon.start_measuring_memory_latencies ||
950 				!hubbub->funcs->perfmon.get_memory_latencies_ns)
951 			return;
952 
953 		hwss_add_hubbub_perfmon_reset(&seq_state, hubbub);
954 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
955 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
956 		hwss_add_hubbub_perfmon_start_memory_latencies(&seq_state, hubbub);
957 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
958 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
959 		hwss_add_hubbub_perfmon_get_memory_latencies(&seq_state, hubbub,
960 				refclk_mhz, &status->u.latency);
961 		break;
962 
963 	case DC_PROBE_URGENT_ASSERTION_COUNT:
964 		if (!hubbub->funcs->perfmon.start_measuring_urgent_assertion_count ||
965 				!hubbub->funcs->perfmon.get_urgent_assertion_count)
966 			return;
967 
968 		hwss_add_hubbub_perfmon_reset(&seq_state, hubbub);
969 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
970 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
971 		hwss_add_hubbub_perfmon_start_urgent_assertion_count(&seq_state, hubbub);
972 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
973 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
974 		hwss_add_hubbub_perfmon_get_urgent_assertion_count(&seq_state, hubbub,
975 				refclk_mhz, &status->u.urgent_assertion_count);
976 		break;
977 
978 	case DC_PROBE_PREFETCH_DATA_SIZE:
979 		if (!hubbub->funcs->perfmon.start_measuring_prefetch_data_size ||
980 				!hubbub->funcs->perfmon.get_prefetch_data_size)
981 			return;
982 
983 		hwss_add_hubbub_perfmon_reset(&seq_state, hubbub);
984 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
985 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
986 		hwss_add_hubbub_perfmon_start_prefetch_data_size(&seq_state, hubbub);
987 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
988 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
989 		hwss_add_hubbub_perfmon_get_prefetch_data_size(&seq_state, hubbub,
990 				&status->u.prefetch_data_size);
991 		break;
992 
993 	case DC_PROBE_URGENT_RAMP_LATENCY:
994 		/* Requires caller-supplied window params not available in probe model. */
995 		return;
996 
997 	default:
998 		return;
999 	}
1000 }
1001 
1002 /**
1003  * dcn60_update_probe_status - Set the valid flag on a latched probe result.
1004  * @status: result sink whose u was written by the GET BLS step during execute
1005  * @probe: current probe state used to determine measurement type and validity
1006  */
dcn60_update_probe_status(struct dc_probe_status * status)1007 static void dcn60_update_probe_status(struct dc_probe_status *status)
1008 {
1009 	switch (status->type) {
1010 	case DC_PROBE_PEAK_MEM_BW:
1011 	case DC_PROBE_AVG_MEM_BW:
1012 		/* Zero bandwidth means the counter did not fire — treat as invalid. */
1013 		status->valid = (status->u.bandwidth_mbps != 0);
1014 		break;
1015 	case DC_PROBE_MEM_LATENCY:
1016 	case DC_PROBE_URGENT_ASSERTION_COUNT:
1017 	case DC_PROBE_PREFETCH_DATA_SIZE:
1018 		status->valid = true;
1019 		break;
1020 	default:
1021 		status->valid = false;
1022 		break;
1023 	}
1024 }
1025 
1026 /**
1027  * is_probe_measurement_type_for_hubbub - Returns true if the probe type is
1028  * served by the hubbub perfmon block on DCN60.
1029  * @type: the probe measurement type to classify
1030  */
is_probe_measurement_type_for_hubbub(enum dc_probe_type type)1031 static bool is_probe_measurement_type_for_hubbub(enum dc_probe_type type)
1032 {
1033 	switch (type) {
1034 	case DC_PROBE_PEAK_MEM_BW:
1035 	case DC_PROBE_AVG_MEM_BW:
1036 	case DC_PROBE_MEM_LATENCY:
1037 	case DC_PROBE_URGENT_ASSERTION_COUNT:
1038 	case DC_PROBE_PREFETCH_DATA_SIZE:
1039 	case DC_PROBE_URGENT_RAMP_LATENCY:
1040 		return true;
1041 	default:
1042 		return false;
1043 	}
1044 }
1045 
1046 /**
1047  * dcn60_program_perfmon - Program/transition perfmon probes for a commit.
1048  * @dc:      DC structure
1049  * @context: target state; probes, probe_count, and probe_status are
1050  *           read from and written to this object
1051  *
1052  * Routes each probe to the HW-block builder that owns its measurement type,
1053  * builds a single combined BLS sequence, executes it once, then updates
1054  * context->probe_status in plain C.
1055  */
dcn60_program_perfmon(struct dc * dc,struct dc_state * context)1056 void dcn60_program_perfmon(struct dc *dc, struct dc_state *context)
1057 {
1058 	int i;
1059 
1060 	if (!context)
1061 		return;
1062 
1063 	context->block_sequence_steps = 0;
1064 	memset(context->probe_status, 0, sizeof(context->probe_status));
1065 
1066 	for (i = 0; i < context->probe_count; i++) {
1067 		if (is_probe_measurement_type_for_hubbub(context->probes[i].type))
1068 			dcn60_build_hubbub_perfmon_sequence(dc, context, &context->probes[i],
1069 					&context->probe_status[i],
1070 					context->block_sequence,
1071 					&context->block_sequence_steps);
1072 	}
1073 
1074 	hwss_execute_sequence(dc, context->block_sequence, context->block_sequence_steps);
1075 
1076 	for (i = 0; i < context->probe_count; i++)
1077 		dcn60_update_probe_status(&context->probe_status[i]);
1078 }
1079 
dcn60_has_active_memory_request(const struct dc * dc)1080 static bool dcn60_has_active_memory_request(const struct dc *dc)
1081 {
1082 	int i;
1083 
1084 	/* Check for any streams with active planes but no static panel power features. */
1085 	for (i = 0; i < dc->current_state->stream_count; i++) {
1086 		const struct dc_link *link = dc->current_state->streams[i]->link;
1087 		bool panel_power_feature =
1088 			link && (link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED ||
1089 				 link->replay_settings.replay_feature_enabled);
1090 
1091 		if (dc->current_state->stream_status[i].plane_count && !panel_power_feature)
1092 			return true;
1093 	}
1094 
1095 	return false;
1096 }
1097 
dcn60_has_active_display(const struct dc * dc)1098 static bool dcn60_has_active_display(const struct dc *dc)
1099 {
1100 	int i;
1101 
1102 	for (i = 0; i < dc->current_state->stream_count; ++i) {
1103 		const struct dc_stream_state *stream = dc->current_state->streams[i];
1104 
1105 		if (dc_is_virtual_signal(stream->signal) ||
1106 		    dc_is_hdmi_tmds_signal(stream->signal) ||
1107 		    (dc_is_dp_signal(stream->signal) && !stream->dpms_off)) {
1108 			return true;
1109 		}
1110 	}
1111 
1112 	for (i = 0; i < dc->link_count; i++) {
1113 		const struct dc_link *link = dc->links[i];
1114 
1115 		if (link->link_status.link_active ||
1116 		    (link->link_enc && link->link_enc->funcs->is_dig_enabled &&
1117 		     link->link_enc->funcs->is_dig_enabled(link->link_enc))) {
1118 			return true;
1119 		}
1120 	}
1121 
1122 	return false;
1123 }
1124 
dcn60_notify_dmub_of_cab_status(struct dc * dc,bool enable)1125 static void dcn60_notify_dmub_of_cab_status(struct dc *dc, bool enable)
1126 {
1127 	union dmub_rb_cmd cmd;
1128 
1129 	if (!dc->ctx->dmub_srv || !dc->current_state)
1130 		return;
1131 
1132 	memset(&cmd, 0, sizeof(cmd));
1133 	cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS;
1134 	cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header);
1135 
1136 	if (enable) {
1137 		if (!dcn60_has_active_memory_request(dc)) {
1138 			DC_LOG_MALL("sending CAB action NO_DCN_REQ\n");
1139 			cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_DCN_REQ;
1140 		} else {
1141 			cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_NOT_FIT_IN_CAB;
1142 			DC_LOG_MALL("MALL unsupported, frame does not fit in CAB\n");
1143 		}
1144 	} else {
1145 		/* Disable CAB */
1146 		cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_IDLE_OPTIMIZATION;
1147 		DC_LOG_MALL("CAB idle optimization disabled\n");
1148 	}
1149 
1150 	dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
1151 }
1152 
dcn60_apply_idle_power_optimizations(struct dc * dc,bool enable)1153 bool dcn60_apply_idle_power_optimizations(struct dc *dc, bool enable)
1154 {
1155 	struct clk_mgr *clk_mgr = dc->clk_mgr;
1156 
1157 	dcn60_notify_dmub_of_cab_status(dc, enable);
1158 
1159 	/* Notify clock manager and PMFW to disable PHY refclk or DF coupling. */
1160 	if (dc->clk_mgr && dc->clk_mgr->funcs->set_idle_power_optimizations) {
1161 		const bool allow_idle = enable && !dcn60_has_active_display(dc);
1162 
1163 		clk_mgr->funcs->set_idle_power_optimizations(clk_mgr, allow_idle);
1164 	}
1165 
1166 	return true;
1167 }
1168