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, ¶ms);
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