2 * Copyright 2016 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
25 #include <linux/delay.h>
27 #include "dm_services.h"
28 #include "basics/dc_common.h"
29 #include "dm_helpers.h"
30 #include "core_types.h"
32 #include "dcn20_resource.h"
33 #include "dcn20_hwseq.h"
34 #include "dce/dce_hwseq.h"
35 #include "dcn20_dsc.h"
36 #include "dcn20_optc.h"
41 #include "timing_generator.h"
47 #include "reg_helper.h"
48 #include "dcn10/dcn10_cm_common.h"
49 #include "dc_link_dp.h"
50 #include "vm_helper.h"
53 #define DC_LOGGER_INIT(logger)
61 #define FN(reg_name, field_name) \
62 hws->shifts->field_name, hws->masks->field_name
64 static int find_free_gsl_group(const struct dc
*dc
)
66 if (dc
->res_pool
->gsl_groups
.gsl_0
== 0)
68 if (dc
->res_pool
->gsl_groups
.gsl_1
== 0)
70 if (dc
->res_pool
->gsl_groups
.gsl_2
== 0)
76 /* NOTE: This is not a generic setup_gsl function (hence the suffix as_lock)
77 * This is only used to lock pipes in pipe splitting case with immediate flip
78 * Ordinary MPC/OTG locks suppress VUPDATE which doesn't help with immediate,
79 * so we get tearing with freesync since we cannot flip multiple pipes
81 * We use GSL for this:
82 * - immediate flip: find first available GSL group if not already assigned
83 * program gsl with that group, set current OTG as master
84 * and always us 0x4 = AND of flip_ready from all pipes
85 * - vsync flip: disable GSL if used
87 * Groups in stream_res are stored as +1 from HW registers, i.e.
88 * gsl_0 <=> pipe_ctx->stream_res.gsl_group == 1
89 * Using a magic value like -1 would require tracking all inits/resets
91 static void dcn20_setup_gsl_group_as_lock(
93 struct pipe_ctx
*pipe_ctx
,
96 struct gsl_params gsl
;
99 memset(&gsl
, 0, sizeof(struct gsl_params
));
102 /* return if group already assigned since GSL was set up
103 * for vsync flip, we would unassign so it can't be "left over"
105 if (pipe_ctx
->stream_res
.gsl_group
> 0)
108 group_idx
= find_free_gsl_group(dc
);
109 ASSERT(group_idx
!= 0);
110 pipe_ctx
->stream_res
.gsl_group
= group_idx
;
112 /* set gsl group reg field and mark resource used */
116 dc
->res_pool
->gsl_groups
.gsl_0
= 1;
120 dc
->res_pool
->gsl_groups
.gsl_1
= 1;
124 dc
->res_pool
->gsl_groups
.gsl_2
= 1;
128 return; // invalid case
130 gsl
.gsl_master_en
= 1;
132 group_idx
= pipe_ctx
->stream_res
.gsl_group
;
134 return; // if not in use, just return
136 pipe_ctx
->stream_res
.gsl_group
= 0;
138 /* unset gsl group reg field and mark resource free */
142 dc
->res_pool
->gsl_groups
.gsl_0
= 0;
146 dc
->res_pool
->gsl_groups
.gsl_1
= 0;
150 dc
->res_pool
->gsl_groups
.gsl_2
= 0;
156 gsl
.gsl_master_en
= 0;
159 /* at this point we want to program whether it's to enable or disable */
160 if (pipe_ctx
->stream_res
.tg
->funcs
->set_gsl
!= NULL
&&
161 pipe_ctx
->stream_res
.tg
->funcs
->set_gsl_source_select
!= NULL
) {
162 pipe_ctx
->stream_res
.tg
->funcs
->set_gsl(
163 pipe_ctx
->stream_res
.tg
,
166 pipe_ctx
->stream_res
.tg
->funcs
->set_gsl_source_select(
167 pipe_ctx
->stream_res
.tg
, group_idx
, enable
? 4 : 0);
172 void dcn20_set_flip_control_gsl(
173 struct pipe_ctx
*pipe_ctx
,
176 if (pipe_ctx
&& pipe_ctx
->plane_res
.hubp
->funcs
->hubp_set_flip_control_surface_gsl
)
177 pipe_ctx
->plane_res
.hubp
->funcs
->hubp_set_flip_control_surface_gsl(
178 pipe_ctx
->plane_res
.hubp
, flip_immediate
);
182 void dcn20_enable_power_gating_plane(
183 struct dce_hwseq
*hws
,
186 bool force_on
= true; /* disable power gating */
191 /* DCHUBP0/1/2/3/4/5 */
192 REG_UPDATE(DOMAIN0_PG_CONFIG
, DOMAIN0_POWER_FORCEON
, force_on
);
193 REG_UPDATE(DOMAIN2_PG_CONFIG
, DOMAIN2_POWER_FORCEON
, force_on
);
194 REG_UPDATE(DOMAIN4_PG_CONFIG
, DOMAIN4_POWER_FORCEON
, force_on
);
195 REG_UPDATE(DOMAIN6_PG_CONFIG
, DOMAIN6_POWER_FORCEON
, force_on
);
196 if (REG(DOMAIN8_PG_CONFIG
))
197 REG_UPDATE(DOMAIN8_PG_CONFIG
, DOMAIN8_POWER_FORCEON
, force_on
);
198 if (REG(DOMAIN10_PG_CONFIG
))
199 REG_UPDATE(DOMAIN10_PG_CONFIG
, DOMAIN8_POWER_FORCEON
, force_on
);
202 REG_UPDATE(DOMAIN1_PG_CONFIG
, DOMAIN1_POWER_FORCEON
, force_on
);
203 REG_UPDATE(DOMAIN3_PG_CONFIG
, DOMAIN3_POWER_FORCEON
, force_on
);
204 REG_UPDATE(DOMAIN5_PG_CONFIG
, DOMAIN5_POWER_FORCEON
, force_on
);
205 REG_UPDATE(DOMAIN7_PG_CONFIG
, DOMAIN7_POWER_FORCEON
, force_on
);
206 if (REG(DOMAIN9_PG_CONFIG
))
207 REG_UPDATE(DOMAIN9_PG_CONFIG
, DOMAIN9_POWER_FORCEON
, force_on
);
208 if (REG(DOMAIN11_PG_CONFIG
))
209 REG_UPDATE(DOMAIN11_PG_CONFIG
, DOMAIN9_POWER_FORCEON
, force_on
);
212 REG_UPDATE(DOMAIN16_PG_CONFIG
, DOMAIN16_POWER_FORCEON
, force_on
);
213 REG_UPDATE(DOMAIN17_PG_CONFIG
, DOMAIN17_POWER_FORCEON
, force_on
);
214 REG_UPDATE(DOMAIN18_PG_CONFIG
, DOMAIN18_POWER_FORCEON
, force_on
);
215 if (REG(DOMAIN19_PG_CONFIG
))
216 REG_UPDATE(DOMAIN19_PG_CONFIG
, DOMAIN19_POWER_FORCEON
, force_on
);
217 if (REG(DOMAIN20_PG_CONFIG
))
218 REG_UPDATE(DOMAIN20_PG_CONFIG
, DOMAIN20_POWER_FORCEON
, force_on
);
219 if (REG(DOMAIN21_PG_CONFIG
))
220 REG_UPDATE(DOMAIN21_PG_CONFIG
, DOMAIN21_POWER_FORCEON
, force_on
);
223 void dcn20_dccg_init(struct dce_hwseq
*hws
)
226 * set MICROSECOND_TIME_BASE_DIV
227 * 100Mhz refclk -> 0x120264
228 * 27Mhz refclk -> 0x12021b
229 * 48Mhz refclk -> 0x120230
232 REG_WRITE(MICROSECOND_TIME_BASE_DIV
, 0x120264);
235 * set MILLISECOND_TIME_BASE_DIV
236 * 100Mhz refclk -> 0x1186a0
237 * 27Mhz refclk -> 0x106978
238 * 48Mhz refclk -> 0x10bb80
241 REG_WRITE(MILLISECOND_TIME_BASE_DIV
, 0x1186a0);
243 /* This value is dependent on the hardware pipeline delay so set once per SOC */
244 REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL
, 0x801003c);
247 void dcn20_disable_vga(
248 struct dce_hwseq
*hws
)
250 REG_WRITE(D1VGA_CONTROL
, 0);
251 REG_WRITE(D2VGA_CONTROL
, 0);
252 REG_WRITE(D3VGA_CONTROL
, 0);
253 REG_WRITE(D4VGA_CONTROL
, 0);
254 REG_WRITE(D5VGA_CONTROL
, 0);
255 REG_WRITE(D6VGA_CONTROL
, 0);
258 void dcn20_program_triple_buffer(
260 struct pipe_ctx
*pipe_ctx
,
261 bool enable_triple_buffer
)
263 if (pipe_ctx
->plane_res
.hubp
&& pipe_ctx
->plane_res
.hubp
->funcs
) {
264 pipe_ctx
->plane_res
.hubp
->funcs
->hubp_enable_tripleBuffer(
265 pipe_ctx
->plane_res
.hubp
,
266 enable_triple_buffer
);
270 /* Blank pixel data during initialization */
271 void dcn20_init_blank(
273 struct timing_generator
*tg
)
275 struct dce_hwseq
*hws
= dc
->hwseq
;
276 enum dc_color_space color_space
;
277 struct tg_color black_color
= {0};
278 struct output_pixel_processor
*opp
= NULL
;
279 struct output_pixel_processor
*bottom_opp
= NULL
;
280 uint32_t num_opps
, opp_id_src0
, opp_id_src1
;
281 uint32_t otg_active_width
, otg_active_height
;
283 /* program opp dpg blank color */
284 color_space
= COLOR_SPACE_SRGB
;
285 color_space_to_black_color(dc
, color_space
, &black_color
);
287 /* get the OTG active size */
288 tg
->funcs
->get_otg_active_size(tg
,
292 /* get the OPTC source */
293 tg
->funcs
->get_optc_source(tg
, &num_opps
, &opp_id_src0
, &opp_id_src1
);
294 ASSERT(opp_id_src0
< dc
->res_pool
->res_cap
->num_opp
);
295 opp
= dc
->res_pool
->opps
[opp_id_src0
];
298 otg_active_width
= otg_active_width
/ 2;
299 ASSERT(opp_id_src1
< dc
->res_pool
->res_cap
->num_opp
);
300 bottom_opp
= dc
->res_pool
->opps
[opp_id_src1
];
303 opp
->funcs
->opp_set_disp_pattern_generator(
305 CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR
,
306 CONTROLLER_DP_COLOR_SPACE_UDEFINED
,
307 COLOR_DEPTH_UNDEFINED
,
314 bottom_opp
->funcs
->opp_set_disp_pattern_generator(
316 CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR
,
317 CONTROLLER_DP_COLOR_SPACE_UDEFINED
,
318 COLOR_DEPTH_UNDEFINED
,
325 hws
->funcs
.wait_for_blank_complete(opp
);
328 void dcn20_dsc_pg_control(
329 struct dce_hwseq
*hws
,
330 unsigned int dsc_inst
,
333 uint32_t power_gate
= power_on
? 0 : 1;
334 uint32_t pwr_status
= power_on
? 0 : 2;
335 uint32_t org_ip_request_cntl
= 0;
337 if (hws
->ctx
->dc
->debug
.disable_dsc_power_gate
)
340 if (REG(DOMAIN16_PG_CONFIG
) == 0)
343 REG_GET(DC_IP_REQUEST_CNTL
, IP_REQUEST_EN
, &org_ip_request_cntl
);
344 if (org_ip_request_cntl
== 0)
345 REG_SET(DC_IP_REQUEST_CNTL
, 0, IP_REQUEST_EN
, 1);
349 REG_UPDATE(DOMAIN16_PG_CONFIG
,
350 DOMAIN16_POWER_GATE
, power_gate
);
352 REG_WAIT(DOMAIN16_PG_STATUS
,
353 DOMAIN16_PGFSM_PWR_STATUS
, pwr_status
,
357 REG_UPDATE(DOMAIN17_PG_CONFIG
,
358 DOMAIN17_POWER_GATE
, power_gate
);
360 REG_WAIT(DOMAIN17_PG_STATUS
,
361 DOMAIN17_PGFSM_PWR_STATUS
, pwr_status
,
365 REG_UPDATE(DOMAIN18_PG_CONFIG
,
366 DOMAIN18_POWER_GATE
, power_gate
);
368 REG_WAIT(DOMAIN18_PG_STATUS
,
369 DOMAIN18_PGFSM_PWR_STATUS
, pwr_status
,
373 REG_UPDATE(DOMAIN19_PG_CONFIG
,
374 DOMAIN19_POWER_GATE
, power_gate
);
376 REG_WAIT(DOMAIN19_PG_STATUS
,
377 DOMAIN19_PGFSM_PWR_STATUS
, pwr_status
,
381 REG_UPDATE(DOMAIN20_PG_CONFIG
,
382 DOMAIN20_POWER_GATE
, power_gate
);
384 REG_WAIT(DOMAIN20_PG_STATUS
,
385 DOMAIN20_PGFSM_PWR_STATUS
, pwr_status
,
389 REG_UPDATE(DOMAIN21_PG_CONFIG
,
390 DOMAIN21_POWER_GATE
, power_gate
);
392 REG_WAIT(DOMAIN21_PG_STATUS
,
393 DOMAIN21_PGFSM_PWR_STATUS
, pwr_status
,
401 if (org_ip_request_cntl
== 0)
402 REG_SET(DC_IP_REQUEST_CNTL
, 0, IP_REQUEST_EN
, 0);
405 void dcn20_dpp_pg_control(
406 struct dce_hwseq
*hws
,
407 unsigned int dpp_inst
,
410 uint32_t power_gate
= power_on
? 0 : 1;
411 uint32_t pwr_status
= power_on
? 0 : 2;
413 if (hws
->ctx
->dc
->debug
.disable_dpp_power_gate
)
415 if (REG(DOMAIN1_PG_CONFIG
) == 0)
420 REG_UPDATE(DOMAIN1_PG_CONFIG
,
421 DOMAIN1_POWER_GATE
, power_gate
);
423 REG_WAIT(DOMAIN1_PG_STATUS
,
424 DOMAIN1_PGFSM_PWR_STATUS
, pwr_status
,
428 REG_UPDATE(DOMAIN3_PG_CONFIG
,
429 DOMAIN3_POWER_GATE
, power_gate
);
431 REG_WAIT(DOMAIN3_PG_STATUS
,
432 DOMAIN3_PGFSM_PWR_STATUS
, pwr_status
,
436 REG_UPDATE(DOMAIN5_PG_CONFIG
,
437 DOMAIN5_POWER_GATE
, power_gate
);
439 REG_WAIT(DOMAIN5_PG_STATUS
,
440 DOMAIN5_PGFSM_PWR_STATUS
, pwr_status
,
444 REG_UPDATE(DOMAIN7_PG_CONFIG
,
445 DOMAIN7_POWER_GATE
, power_gate
);
447 REG_WAIT(DOMAIN7_PG_STATUS
,
448 DOMAIN7_PGFSM_PWR_STATUS
, pwr_status
,
452 REG_UPDATE(DOMAIN9_PG_CONFIG
,
453 DOMAIN9_POWER_GATE
, power_gate
);
455 REG_WAIT(DOMAIN9_PG_STATUS
,
456 DOMAIN9_PGFSM_PWR_STATUS
, pwr_status
,
461 * Do not power gate DPP5, should be left at HW default, power on permanently.
462 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard
464 * REG_UPDATE(DOMAIN11_PG_CONFIG,
465 * DOMAIN11_POWER_GATE, power_gate);
467 * REG_WAIT(DOMAIN11_PG_STATUS,
468 * DOMAIN11_PGFSM_PWR_STATUS, pwr_status,
479 void dcn20_hubp_pg_control(
480 struct dce_hwseq
*hws
,
481 unsigned int hubp_inst
,
484 uint32_t power_gate
= power_on
? 0 : 1;
485 uint32_t pwr_status
= power_on
? 0 : 2;
487 if (hws
->ctx
->dc
->debug
.disable_hubp_power_gate
)
489 if (REG(DOMAIN0_PG_CONFIG
) == 0)
493 case 0: /* DCHUBP0 */
494 REG_UPDATE(DOMAIN0_PG_CONFIG
,
495 DOMAIN0_POWER_GATE
, power_gate
);
497 REG_WAIT(DOMAIN0_PG_STATUS
,
498 DOMAIN0_PGFSM_PWR_STATUS
, pwr_status
,
501 case 1: /* DCHUBP1 */
502 REG_UPDATE(DOMAIN2_PG_CONFIG
,
503 DOMAIN2_POWER_GATE
, power_gate
);
505 REG_WAIT(DOMAIN2_PG_STATUS
,
506 DOMAIN2_PGFSM_PWR_STATUS
, pwr_status
,
509 case 2: /* DCHUBP2 */
510 REG_UPDATE(DOMAIN4_PG_CONFIG
,
511 DOMAIN4_POWER_GATE
, power_gate
);
513 REG_WAIT(DOMAIN4_PG_STATUS
,
514 DOMAIN4_PGFSM_PWR_STATUS
, pwr_status
,
517 case 3: /* DCHUBP3 */
518 REG_UPDATE(DOMAIN6_PG_CONFIG
,
519 DOMAIN6_POWER_GATE
, power_gate
);
521 REG_WAIT(DOMAIN6_PG_STATUS
,
522 DOMAIN6_PGFSM_PWR_STATUS
, pwr_status
,
525 case 4: /* DCHUBP4 */
526 REG_UPDATE(DOMAIN8_PG_CONFIG
,
527 DOMAIN8_POWER_GATE
, power_gate
);
529 REG_WAIT(DOMAIN8_PG_STATUS
,
530 DOMAIN8_PGFSM_PWR_STATUS
, pwr_status
,
533 case 5: /* DCHUBP5 */
535 * Do not power gate DCHUB5, should be left at HW default, power on permanently.
536 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard
538 * REG_UPDATE(DOMAIN10_PG_CONFIG,
539 * DOMAIN10_POWER_GATE, power_gate);
541 * REG_WAIT(DOMAIN10_PG_STATUS,
542 * DOMAIN10_PGFSM_PWR_STATUS, pwr_status,
553 /* disable HW used by plane.
554 * note: cannot disable until disconnect is complete
556 void dcn20_plane_atomic_disable(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
558 struct dce_hwseq
*hws
= dc
->hwseq
;
559 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
560 struct dpp
*dpp
= pipe_ctx
->plane_res
.dpp
;
562 dc
->hwss
.wait_for_mpcc_disconnect(dc
, dc
->res_pool
, pipe_ctx
);
564 /* In flip immediate with pipe splitting case GSL is used for
565 * synchronization so we must disable it when the plane is disabled.
567 if (pipe_ctx
->stream_res
.gsl_group
!= 0)
568 dcn20_setup_gsl_group_as_lock(dc
, pipe_ctx
, false);
570 dc
->hwss
.set_flip_control_gsl(pipe_ctx
, false);
572 hubp
->funcs
->hubp_clk_cntl(hubp
, false);
574 dpp
->funcs
->dpp_dppclk_control(dpp
, false, false);
576 hubp
->power_gated
= true;
578 hws
->funcs
.plane_atomic_power_down(dc
,
579 pipe_ctx
->plane_res
.dpp
,
580 pipe_ctx
->plane_res
.hubp
);
582 pipe_ctx
->stream
= NULL
;
583 memset(&pipe_ctx
->stream_res
, 0, sizeof(pipe_ctx
->stream_res
));
584 memset(&pipe_ctx
->plane_res
, 0, sizeof(pipe_ctx
->plane_res
));
585 pipe_ctx
->top_pipe
= NULL
;
586 pipe_ctx
->bottom_pipe
= NULL
;
587 pipe_ctx
->plane_state
= NULL
;
591 void dcn20_disable_plane(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
593 DC_LOGGER_INIT(dc
->ctx
->logger
);
595 if (!pipe_ctx
->plane_res
.hubp
|| pipe_ctx
->plane_res
.hubp
->power_gated
)
598 dcn20_plane_atomic_disable(dc
, pipe_ctx
);
600 DC_LOG_DC("Power down front end %d\n",
604 enum dc_status
dcn20_enable_stream_timing(
605 struct pipe_ctx
*pipe_ctx
,
606 struct dc_state
*context
,
609 struct dce_hwseq
*hws
= dc
->hwseq
;
610 struct dc_stream_state
*stream
= pipe_ctx
->stream
;
611 struct drr_params params
= {0};
612 unsigned int event_triggers
= 0;
613 struct pipe_ctx
*odm_pipe
;
615 int opp_inst
[MAX_PIPES
] = { pipe_ctx
->stream_res
.opp
->inst
};
617 /* by upper caller loop, pipe0 is parent pipe and be called first.
618 * back end is set up by for pipe0. Other children pipe share back end
619 * with pipe 0. No program is needed.
621 if (pipe_ctx
->top_pipe
!= NULL
)
624 /* TODO check if timing_changed, disable stream if timing changed */
626 for (odm_pipe
= pipe_ctx
->next_odm_pipe
; odm_pipe
; odm_pipe
= odm_pipe
->next_odm_pipe
) {
627 opp_inst
[opp_cnt
] = odm_pipe
->stream_res
.opp
->inst
;
632 pipe_ctx
->stream_res
.tg
->funcs
->set_odm_combine(
633 pipe_ctx
->stream_res
.tg
,
635 &pipe_ctx
->stream
->timing
);
637 /* HW program guide assume display already disable
638 * by unplug sequence. OTG assume stop.
640 pipe_ctx
->stream_res
.tg
->funcs
->enable_optc_clock(pipe_ctx
->stream_res
.tg
, true);
642 if (false == pipe_ctx
->clock_source
->funcs
->program_pix_clk(
643 pipe_ctx
->clock_source
,
644 &pipe_ctx
->stream_res
.pix_clk_params
,
645 &pipe_ctx
->pll_settings
)) {
647 return DC_ERROR_UNEXPECTED
;
650 if (dc
->hwseq
->funcs
.PLAT_58856_wa
&& (!dc_is_dp_signal(stream
->signal
)))
651 dc
->hwseq
->funcs
.PLAT_58856_wa(context
, pipe_ctx
);
653 pipe_ctx
->stream_res
.tg
->funcs
->program_timing(
654 pipe_ctx
->stream_res
.tg
,
656 pipe_ctx
->pipe_dlg_param
.vready_offset
,
657 pipe_ctx
->pipe_dlg_param
.vstartup_start
,
658 pipe_ctx
->pipe_dlg_param
.vupdate_offset
,
659 pipe_ctx
->pipe_dlg_param
.vupdate_width
,
660 pipe_ctx
->stream
->signal
,
663 for (odm_pipe
= pipe_ctx
->next_odm_pipe
; odm_pipe
; odm_pipe
= odm_pipe
->next_odm_pipe
)
664 odm_pipe
->stream_res
.opp
->funcs
->opp_pipe_clock_control(
665 odm_pipe
->stream_res
.opp
,
668 pipe_ctx
->stream_res
.opp
->funcs
->opp_pipe_clock_control(
669 pipe_ctx
->stream_res
.opp
,
672 hws
->funcs
.blank_pixel_data(dc
, pipe_ctx
, true);
674 /* VTG is within DCHUB command block. DCFCLK is always on */
675 if (false == pipe_ctx
->stream_res
.tg
->funcs
->enable_crtc(pipe_ctx
->stream_res
.tg
)) {
677 return DC_ERROR_UNEXPECTED
;
680 hws
->funcs
.wait_for_blank_complete(pipe_ctx
->stream_res
.opp
);
682 params
.vertical_total_min
= stream
->adjust
.v_total_min
;
683 params
.vertical_total_max
= stream
->adjust
.v_total_max
;
684 params
.vertical_total_mid
= stream
->adjust
.v_total_mid
;
685 params
.vertical_total_mid_frame_num
= stream
->adjust
.v_total_mid_frame_num
;
686 if (pipe_ctx
->stream_res
.tg
->funcs
->set_drr
)
687 pipe_ctx
->stream_res
.tg
->funcs
->set_drr(
688 pipe_ctx
->stream_res
.tg
, ¶ms
);
690 // DRR should set trigger event to monitor surface update event
691 if (stream
->adjust
.v_total_min
!= 0 && stream
->adjust
.v_total_max
!= 0)
692 event_triggers
= 0x80;
693 /* Event triggers and num frames initialized for DRR, but can be
694 * later updated for PSR use. Note DRR trigger events are generated
695 * regardless of whether num frames met.
697 if (pipe_ctx
->stream_res
.tg
->funcs
->set_static_screen_control
)
698 pipe_ctx
->stream_res
.tg
->funcs
->set_static_screen_control(
699 pipe_ctx
->stream_res
.tg
, event_triggers
, 2);
701 /* TODO program crtc source select for non-virtual signal*/
702 /* TODO program FMT */
703 /* TODO setup link_enc */
704 /* TODO set stream attributes */
705 /* TODO program audio */
706 /* TODO enable stream if timing changed */
707 /* TODO unblank stream if DP */
712 void dcn20_program_output_csc(struct dc
*dc
,
713 struct pipe_ctx
*pipe_ctx
,
714 enum dc_color_space colorspace
,
718 struct mpc
*mpc
= dc
->res_pool
->mpc
;
719 enum mpc_output_csc_mode ocsc_mode
= MPC_OUTPUT_CSC_COEF_A
;
720 int mpcc_id
= pipe_ctx
->plane_res
.hubp
->inst
;
722 if (mpc
->funcs
->power_on_mpc_mem_pwr
)
723 mpc
->funcs
->power_on_mpc_mem_pwr(mpc
, mpcc_id
, true);
725 if (pipe_ctx
->stream
->csc_color_matrix
.enable_adjustment
== true) {
726 if (mpc
->funcs
->set_output_csc
!= NULL
)
727 mpc
->funcs
->set_output_csc(mpc
,
732 if (mpc
->funcs
->set_ocsc_default
!= NULL
)
733 mpc
->funcs
->set_ocsc_default(mpc
,
740 bool dcn20_set_output_transfer_func(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
,
741 const struct dc_stream_state
*stream
)
743 int mpcc_id
= pipe_ctx
->plane_res
.hubp
->inst
;
744 struct mpc
*mpc
= pipe_ctx
->stream_res
.opp
->ctx
->dc
->res_pool
->mpc
;
745 struct pwl_params
*params
= NULL
;
747 * program OGAM only for the top pipe
748 * if there is a pipe split then fix diagnostic is required:
749 * how to pass OGAM parameter for stream.
750 * if programming for all pipes is required then remove condition
751 * pipe_ctx->top_pipe == NULL ,but then fix the diagnostic.
753 if (mpc
->funcs
->power_on_mpc_mem_pwr
)
754 mpc
->funcs
->power_on_mpc_mem_pwr(mpc
, mpcc_id
, true);
755 if (pipe_ctx
->top_pipe
== NULL
756 && mpc
->funcs
->set_output_gamma
&& stream
->out_transfer_func
) {
757 if (stream
->out_transfer_func
->type
== TF_TYPE_HWPWL
)
758 params
= &stream
->out_transfer_func
->pwl
;
759 else if (pipe_ctx
->stream
->out_transfer_func
->type
==
760 TF_TYPE_DISTRIBUTED_POINTS
&&
761 cm_helper_translate_curve_to_hw_format(
762 stream
->out_transfer_func
,
763 &mpc
->blender_params
, false))
764 params
= &mpc
->blender_params
;
768 if (stream
->out_transfer_func
->type
== TF_TYPE_PREDEFINED
)
772 * if above if is not executed then 'params' equal to 0 and set in bypass
774 mpc
->funcs
->set_output_gamma(mpc
, mpcc_id
, params
);
779 bool dcn20_set_blend_lut(
780 struct pipe_ctx
*pipe_ctx
, const struct dc_plane_state
*plane_state
)
782 struct dpp
*dpp_base
= pipe_ctx
->plane_res
.dpp
;
784 struct pwl_params
*blend_lut
= NULL
;
786 if (plane_state
->blend_tf
) {
787 if (plane_state
->blend_tf
->type
== TF_TYPE_HWPWL
)
788 blend_lut
= &plane_state
->blend_tf
->pwl
;
789 else if (plane_state
->blend_tf
->type
== TF_TYPE_DISTRIBUTED_POINTS
) {
790 cm_helper_translate_curve_to_hw_format(
791 plane_state
->blend_tf
,
792 &dpp_base
->regamma_params
, false);
793 blend_lut
= &dpp_base
->regamma_params
;
796 result
= dpp_base
->funcs
->dpp_program_blnd_lut(dpp_base
, blend_lut
);
801 bool dcn20_set_shaper_3dlut(
802 struct pipe_ctx
*pipe_ctx
, const struct dc_plane_state
*plane_state
)
804 struct dpp
*dpp_base
= pipe_ctx
->plane_res
.dpp
;
806 struct pwl_params
*shaper_lut
= NULL
;
808 if (plane_state
->in_shaper_func
) {
809 if (plane_state
->in_shaper_func
->type
== TF_TYPE_HWPWL
)
810 shaper_lut
= &plane_state
->in_shaper_func
->pwl
;
811 else if (plane_state
->in_shaper_func
->type
== TF_TYPE_DISTRIBUTED_POINTS
) {
812 cm_helper_translate_curve_to_hw_format(
813 plane_state
->in_shaper_func
,
814 &dpp_base
->shaper_params
, true);
815 shaper_lut
= &dpp_base
->shaper_params
;
819 result
= dpp_base
->funcs
->dpp_program_shaper_lut(dpp_base
, shaper_lut
);
820 if (plane_state
->lut3d_func
&&
821 plane_state
->lut3d_func
->state
.bits
.initialized
== 1)
822 result
= dpp_base
->funcs
->dpp_program_3dlut(dpp_base
,
823 &plane_state
->lut3d_func
->lut_3d
);
825 result
= dpp_base
->funcs
->dpp_program_3dlut(dpp_base
, NULL
);
830 bool dcn20_set_input_transfer_func(struct dc
*dc
,
831 struct pipe_ctx
*pipe_ctx
,
832 const struct dc_plane_state
*plane_state
)
834 struct dce_hwseq
*hws
= dc
->hwseq
;
835 struct dpp
*dpp_base
= pipe_ctx
->plane_res
.dpp
;
836 const struct dc_transfer_func
*tf
= NULL
;
838 bool use_degamma_ram
= false;
840 if (dpp_base
== NULL
|| plane_state
== NULL
)
843 hws
->funcs
.set_shaper_3dlut(pipe_ctx
, plane_state
);
844 hws
->funcs
.set_blend_lut(pipe_ctx
, plane_state
);
846 if (plane_state
->in_transfer_func
)
847 tf
= plane_state
->in_transfer_func
;
851 dpp_base
->funcs
->dpp_set_degamma(dpp_base
,
852 IPP_DEGAMMA_MODE_BYPASS
);
856 if (tf
->type
== TF_TYPE_HWPWL
|| tf
->type
== TF_TYPE_DISTRIBUTED_POINTS
)
857 use_degamma_ram
= true;
859 if (use_degamma_ram
== true) {
860 if (tf
->type
== TF_TYPE_HWPWL
)
861 dpp_base
->funcs
->dpp_program_degamma_pwl(dpp_base
,
863 else if (tf
->type
== TF_TYPE_DISTRIBUTED_POINTS
) {
864 cm_helper_translate_curve_to_degamma_hw_format(tf
,
865 &dpp_base
->degamma_params
);
866 dpp_base
->funcs
->dpp_program_degamma_pwl(dpp_base
,
867 &dpp_base
->degamma_params
);
871 /* handle here the optimized cases when de-gamma ROM could be used.
874 if (tf
->type
== TF_TYPE_PREDEFINED
) {
876 case TRANSFER_FUNCTION_SRGB
:
877 dpp_base
->funcs
->dpp_set_degamma(dpp_base
,
878 IPP_DEGAMMA_MODE_HW_sRGB
);
880 case TRANSFER_FUNCTION_BT709
:
881 dpp_base
->funcs
->dpp_set_degamma(dpp_base
,
882 IPP_DEGAMMA_MODE_HW_xvYCC
);
884 case TRANSFER_FUNCTION_LINEAR
:
885 dpp_base
->funcs
->dpp_set_degamma(dpp_base
,
886 IPP_DEGAMMA_MODE_BYPASS
);
888 case TRANSFER_FUNCTION_PQ
:
889 dpp_base
->funcs
->dpp_set_degamma(dpp_base
, IPP_DEGAMMA_MODE_USER_PWL
);
890 cm_helper_translate_curve_to_degamma_hw_format(tf
, &dpp_base
->degamma_params
);
891 dpp_base
->funcs
->dpp_program_degamma_pwl(dpp_base
, &dpp_base
->degamma_params
);
898 } else if (tf
->type
== TF_TYPE_BYPASS
)
899 dpp_base
->funcs
->dpp_set_degamma(dpp_base
,
900 IPP_DEGAMMA_MODE_BYPASS
);
903 * if we are here, we did not handle correctly.
904 * fix is required for this use case
907 dpp_base
->funcs
->dpp_set_degamma(dpp_base
,
908 IPP_DEGAMMA_MODE_BYPASS
);
914 void dcn20_update_odm(struct dc
*dc
, struct dc_state
*context
, struct pipe_ctx
*pipe_ctx
)
916 struct pipe_ctx
*odm_pipe
;
918 int opp_inst
[MAX_PIPES
] = { pipe_ctx
->stream_res
.opp
->inst
};
920 for (odm_pipe
= pipe_ctx
->next_odm_pipe
; odm_pipe
; odm_pipe
= odm_pipe
->next_odm_pipe
) {
921 opp_inst
[opp_cnt
] = odm_pipe
->stream_res
.opp
->inst
;
926 pipe_ctx
->stream_res
.tg
->funcs
->set_odm_combine(
927 pipe_ctx
->stream_res
.tg
,
929 &pipe_ctx
->stream
->timing
);
931 pipe_ctx
->stream_res
.tg
->funcs
->set_odm_bypass(
932 pipe_ctx
->stream_res
.tg
, &pipe_ctx
->stream
->timing
);
935 void dcn20_blank_pixel_data(
937 struct pipe_ctx
*pipe_ctx
,
940 struct tg_color black_color
= {0};
941 struct stream_resource
*stream_res
= &pipe_ctx
->stream_res
;
942 struct dc_stream_state
*stream
= pipe_ctx
->stream
;
943 enum dc_color_space color_space
= stream
->output_color_space
;
944 enum controller_dp_test_pattern test_pattern
= CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR
;
945 enum controller_dp_color_space test_pattern_color_space
= CONTROLLER_DP_COLOR_SPACE_UDEFINED
;
946 struct pipe_ctx
*odm_pipe
;
949 int width
= stream
->timing
.h_addressable
+ stream
->timing
.h_border_left
+ stream
->timing
.h_border_right
;
950 int height
= stream
->timing
.v_addressable
+ stream
->timing
.v_border_bottom
+ stream
->timing
.v_border_top
;
952 if (stream
->link
->test_pattern_enabled
)
955 /* get opp dpg blank color */
956 color_space_to_black_color(dc
, color_space
, &black_color
);
958 for (odm_pipe
= pipe_ctx
->next_odm_pipe
; odm_pipe
; odm_pipe
= odm_pipe
->next_odm_pipe
)
961 width
= width
/ odm_cnt
;
965 stream_res
->abm
->funcs
->set_abm_immediate_disable(stream_res
->abm
);
967 if (dc
->debug
.visual_confirm
!= VISUAL_CONFIRM_DISABLE
) {
968 test_pattern
= CONTROLLER_DP_TEST_PATTERN_COLORSQUARES
;
969 test_pattern_color_space
= CONTROLLER_DP_COLOR_SPACE_RGB
;
972 test_pattern
= CONTROLLER_DP_TEST_PATTERN_VIDEOMODE
;
975 stream_res
->opp
->funcs
->opp_set_disp_pattern_generator(
978 test_pattern_color_space
,
979 stream
->timing
.display_color_depth
,
985 for (odm_pipe
= pipe_ctx
->next_odm_pipe
; odm_pipe
; odm_pipe
= odm_pipe
->next_odm_pipe
) {
986 odm_pipe
->stream_res
.opp
->funcs
->opp_set_disp_pattern_generator(
987 odm_pipe
->stream_res
.opp
,
988 dc
->debug
.visual_confirm
!= VISUAL_CONFIRM_DISABLE
&& blank
?
989 CONTROLLER_DP_TEST_PATTERN_COLORRAMP
: test_pattern
,
990 test_pattern_color_space
,
991 stream
->timing
.display_color_depth
,
999 if (stream_res
->abm
) {
1000 stream_res
->abm
->funcs
->set_pipe(stream_res
->abm
, stream_res
->tg
->inst
+ 1);
1001 stream_res
->abm
->funcs
->set_abm_level(stream_res
->abm
, stream
->abm_level
);
1006 static void dcn20_power_on_plane(
1007 struct dce_hwseq
*hws
,
1008 struct pipe_ctx
*pipe_ctx
)
1010 DC_LOGGER_INIT(hws
->ctx
->logger
);
1011 if (REG(DC_IP_REQUEST_CNTL
)) {
1012 REG_SET(DC_IP_REQUEST_CNTL
, 0,
1014 dcn20_dpp_pg_control(hws
, pipe_ctx
->plane_res
.dpp
->inst
, true);
1015 dcn20_hubp_pg_control(hws
, pipe_ctx
->plane_res
.hubp
->inst
, true);
1016 REG_SET(DC_IP_REQUEST_CNTL
, 0,
1019 "Un-gated front end for pipe %d\n", pipe_ctx
->plane_res
.hubp
->inst
);
1023 void dcn20_enable_plane(
1025 struct pipe_ctx
*pipe_ctx
,
1026 struct dc_state
*context
)
1028 //if (dc->debug.sanity_checks) {
1029 // dcn10_verify_allow_pstate_change_high(dc);
1031 dcn20_power_on_plane(dc
->hwseq
, pipe_ctx
);
1033 /* enable DCFCLK current DCHUB */
1034 pipe_ctx
->plane_res
.hubp
->funcs
->hubp_clk_cntl(pipe_ctx
->plane_res
.hubp
, true);
1036 /* initialize HUBP on power up */
1037 pipe_ctx
->plane_res
.hubp
->funcs
->hubp_init(pipe_ctx
->plane_res
.hubp
);
1039 /* make sure OPP_PIPE_CLOCK_EN = 1 */
1040 pipe_ctx
->stream_res
.opp
->funcs
->opp_pipe_clock_control(
1041 pipe_ctx
->stream_res
.opp
,
1044 /* TODO: enable/disable in dm as per update type.
1046 DC_LOG_DC(dc->ctx->logger,
1047 "Pipe:%d 0x%x: addr hi:0x%x, "
1050 " %d; dst: %d, %d, %d, %d;\n",
1053 plane_state->address.grph.addr.high_part,
1054 plane_state->address.grph.addr.low_part,
1055 plane_state->src_rect.x,
1056 plane_state->src_rect.y,
1057 plane_state->src_rect.width,
1058 plane_state->src_rect.height,
1059 plane_state->dst_rect.x,
1060 plane_state->dst_rect.y,
1061 plane_state->dst_rect.width,
1062 plane_state->dst_rect.height);
1064 DC_LOG_DC(dc->ctx->logger,
1065 "Pipe %d: width, height, x, y format:%d\n"
1066 "viewport:%d, %d, %d, %d\n"
1067 "recout: %d, %d, %d, %d\n",
1069 plane_state->format,
1070 pipe_ctx->plane_res.scl_data.viewport.width,
1071 pipe_ctx->plane_res.scl_data.viewport.height,
1072 pipe_ctx->plane_res.scl_data.viewport.x,
1073 pipe_ctx->plane_res.scl_data.viewport.y,
1074 pipe_ctx->plane_res.scl_data.recout.width,
1075 pipe_ctx->plane_res.scl_data.recout.height,
1076 pipe_ctx->plane_res.scl_data.recout.x,
1077 pipe_ctx->plane_res.scl_data.recout.y);
1078 print_rq_dlg_ttu(dc, pipe_ctx);
1081 if (dc
->vm_pa_config
.valid
) {
1082 struct vm_system_aperture_param apt
;
1084 apt
.sys_default
.quad_part
= 0;
1086 apt
.sys_low
.quad_part
= dc
->vm_pa_config
.system_aperture
.start_addr
;
1087 apt
.sys_high
.quad_part
= dc
->vm_pa_config
.system_aperture
.end_addr
;
1089 // Program system aperture settings
1090 pipe_ctx
->plane_res
.hubp
->funcs
->hubp_set_vm_system_aperture_settings(pipe_ctx
->plane_res
.hubp
, &apt
);
1093 // if (dc->debug.sanity_checks) {
1094 // dcn10_verify_allow_pstate_change_high(dc);
1098 void dcn20_pipe_control_lock(
1100 struct pipe_ctx
*pipe
,
1103 bool flip_immediate
= false;
1105 /* use TG master update lock to lock everything on the TG
1106 * therefore only top pipe need to lock
1108 if (!pipe
|| pipe
->top_pipe
)
1111 if (pipe
->plane_state
!= NULL
)
1112 flip_immediate
= pipe
->plane_state
->flip_immediate
;
1114 if (flip_immediate
&& lock
) {
1115 const int TIMEOUT_FOR_FLIP_PENDING
= 100000;
1118 for (i
= 0; i
< TIMEOUT_FOR_FLIP_PENDING
; ++i
) {
1119 if (!pipe
->plane_res
.hubp
->funcs
->hubp_is_flip_pending(pipe
->plane_res
.hubp
))
1124 if (pipe
->bottom_pipe
!= NULL
) {
1125 for (i
= 0; i
< TIMEOUT_FOR_FLIP_PENDING
; ++i
) {
1126 if (!pipe
->bottom_pipe
->plane_res
.hubp
->funcs
->hubp_is_flip_pending(pipe
->bottom_pipe
->plane_res
.hubp
))
1133 /* In flip immediate and pipe splitting case, we need to use GSL
1134 * for synchronization. Only do setup on locking and on flip type change.
1136 if (lock
&& pipe
->bottom_pipe
!= NULL
)
1137 if ((flip_immediate
&& pipe
->stream_res
.gsl_group
== 0) ||
1138 (!flip_immediate
&& pipe
->stream_res
.gsl_group
> 0))
1139 dcn20_setup_gsl_group_as_lock(dc
, pipe
, flip_immediate
);
1141 if (pipe
->plane_state
!= NULL
&& pipe
->plane_state
->triplebuffer_flips
) {
1143 pipe
->stream_res
.tg
->funcs
->triplebuffer_lock(pipe
->stream_res
.tg
);
1145 pipe
->stream_res
.tg
->funcs
->triplebuffer_unlock(pipe
->stream_res
.tg
);
1148 pipe
->stream_res
.tg
->funcs
->lock(pipe
->stream_res
.tg
);
1150 pipe
->stream_res
.tg
->funcs
->unlock(pipe
->stream_res
.tg
);
1154 static void dcn20_detect_pipe_changes(struct pipe_ctx
*old_pipe
, struct pipe_ctx
*new_pipe
)
1156 new_pipe
->update_flags
.raw
= 0;
1158 /* Exit on unchanged, unused pipe */
1159 if (!old_pipe
->plane_state
&& !new_pipe
->plane_state
)
1161 /* Detect pipe enable/disable */
1162 if (!old_pipe
->plane_state
&& new_pipe
->plane_state
) {
1163 new_pipe
->update_flags
.bits
.enable
= 1;
1164 new_pipe
->update_flags
.bits
.mpcc
= 1;
1165 new_pipe
->update_flags
.bits
.dppclk
= 1;
1166 new_pipe
->update_flags
.bits
.hubp_interdependent
= 1;
1167 new_pipe
->update_flags
.bits
.hubp_rq_dlg_ttu
= 1;
1168 new_pipe
->update_flags
.bits
.gamut_remap
= 1;
1169 new_pipe
->update_flags
.bits
.scaler
= 1;
1170 new_pipe
->update_flags
.bits
.viewport
= 1;
1171 if (!new_pipe
->top_pipe
&& !new_pipe
->prev_odm_pipe
) {
1172 new_pipe
->update_flags
.bits
.odm
= 1;
1173 new_pipe
->update_flags
.bits
.global_sync
= 1;
1177 if (old_pipe
->plane_state
&& !new_pipe
->plane_state
) {
1178 new_pipe
->update_flags
.bits
.disable
= 1;
1182 /* Detect top pipe only changes */
1183 if (!new_pipe
->top_pipe
&& !new_pipe
->prev_odm_pipe
) {
1184 /* Detect odm changes */
1185 if ((old_pipe
->next_odm_pipe
&& new_pipe
->next_odm_pipe
1186 && old_pipe
->next_odm_pipe
->pipe_idx
!= new_pipe
->next_odm_pipe
->pipe_idx
)
1187 || (!old_pipe
->next_odm_pipe
&& new_pipe
->next_odm_pipe
)
1188 || (old_pipe
->next_odm_pipe
&& !new_pipe
->next_odm_pipe
)
1189 || old_pipe
->stream_res
.opp
!= new_pipe
->stream_res
.opp
)
1190 new_pipe
->update_flags
.bits
.odm
= 1;
1192 /* Detect global sync changes */
1193 if (old_pipe
->pipe_dlg_param
.vready_offset
!= new_pipe
->pipe_dlg_param
.vready_offset
1194 || old_pipe
->pipe_dlg_param
.vstartup_start
!= new_pipe
->pipe_dlg_param
.vstartup_start
1195 || old_pipe
->pipe_dlg_param
.vupdate_offset
!= new_pipe
->pipe_dlg_param
.vupdate_offset
1196 || old_pipe
->pipe_dlg_param
.vupdate_width
!= new_pipe
->pipe_dlg_param
.vupdate_width
)
1197 new_pipe
->update_flags
.bits
.global_sync
= 1;
1201 * Detect opp / tg change, only set on change, not on enable
1202 * Assume mpcc inst = pipe index, if not this code needs to be updated
1203 * since mpcc is what is affected by these. In fact all of our sequence
1204 * makes this assumption at the moment with how hubp reset is matched to
1205 * same index mpcc reset.
1207 if (old_pipe
->stream_res
.opp
!= new_pipe
->stream_res
.opp
)
1208 new_pipe
->update_flags
.bits
.opp_changed
= 1;
1209 if (old_pipe
->stream_res
.tg
!= new_pipe
->stream_res
.tg
)
1210 new_pipe
->update_flags
.bits
.tg_changed
= 1;
1212 /* Detect mpcc blending changes, only dpp inst and bot matter here */
1213 if (old_pipe
->plane_res
.dpp
!= new_pipe
->plane_res
.dpp
1214 || old_pipe
->stream_res
.opp
!= new_pipe
->stream_res
.opp
1215 || (!old_pipe
->bottom_pipe
&& new_pipe
->bottom_pipe
)
1216 || (old_pipe
->bottom_pipe
&& !new_pipe
->bottom_pipe
)
1217 || (old_pipe
->bottom_pipe
&& new_pipe
->bottom_pipe
1218 && old_pipe
->bottom_pipe
->plane_res
.mpcc_inst
1219 != new_pipe
->bottom_pipe
->plane_res
.mpcc_inst
))
1220 new_pipe
->update_flags
.bits
.mpcc
= 1;
1222 /* Detect dppclk change */
1223 if (old_pipe
->plane_res
.bw
.dppclk_khz
!= new_pipe
->plane_res
.bw
.dppclk_khz
)
1224 new_pipe
->update_flags
.bits
.dppclk
= 1;
1226 /* Check for scl update */
1227 if (memcmp(&old_pipe
->plane_res
.scl_data
, &new_pipe
->plane_res
.scl_data
, sizeof(struct scaler_data
)))
1228 new_pipe
->update_flags
.bits
.scaler
= 1;
1229 /* Check for vp update */
1230 if (memcmp(&old_pipe
->plane_res
.scl_data
.viewport
, &new_pipe
->plane_res
.scl_data
.viewport
, sizeof(struct rect
))
1231 || memcmp(&old_pipe
->plane_res
.scl_data
.viewport_c
,
1232 &new_pipe
->plane_res
.scl_data
.viewport_c
, sizeof(struct rect
)))
1233 new_pipe
->update_flags
.bits
.viewport
= 1;
1235 /* Detect dlg/ttu/rq updates */
1237 struct _vcs_dpi_display_dlg_regs_st old_dlg_attr
= old_pipe
->dlg_regs
;
1238 struct _vcs_dpi_display_ttu_regs_st old_ttu_attr
= old_pipe
->ttu_regs
;
1239 struct _vcs_dpi_display_dlg_regs_st
*new_dlg_attr
= &new_pipe
->dlg_regs
;
1240 struct _vcs_dpi_display_ttu_regs_st
*new_ttu_attr
= &new_pipe
->ttu_regs
;
1242 /* Detect pipe interdependent updates */
1243 if (old_dlg_attr
.dst_y_prefetch
!= new_dlg_attr
->dst_y_prefetch
||
1244 old_dlg_attr
.vratio_prefetch
!= new_dlg_attr
->vratio_prefetch
||
1245 old_dlg_attr
.vratio_prefetch_c
!= new_dlg_attr
->vratio_prefetch_c
||
1246 old_dlg_attr
.dst_y_per_vm_vblank
!= new_dlg_attr
->dst_y_per_vm_vblank
||
1247 old_dlg_attr
.dst_y_per_row_vblank
!= new_dlg_attr
->dst_y_per_row_vblank
||
1248 old_dlg_attr
.dst_y_per_vm_flip
!= new_dlg_attr
->dst_y_per_vm_flip
||
1249 old_dlg_attr
.dst_y_per_row_flip
!= new_dlg_attr
->dst_y_per_row_flip
||
1250 old_dlg_attr
.refcyc_per_meta_chunk_vblank_l
!= new_dlg_attr
->refcyc_per_meta_chunk_vblank_l
||
1251 old_dlg_attr
.refcyc_per_meta_chunk_vblank_c
!= new_dlg_attr
->refcyc_per_meta_chunk_vblank_c
||
1252 old_dlg_attr
.refcyc_per_meta_chunk_flip_l
!= new_dlg_attr
->refcyc_per_meta_chunk_flip_l
||
1253 old_dlg_attr
.refcyc_per_line_delivery_pre_l
!= new_dlg_attr
->refcyc_per_line_delivery_pre_l
||
1254 old_dlg_attr
.refcyc_per_line_delivery_pre_c
!= new_dlg_attr
->refcyc_per_line_delivery_pre_c
||
1255 old_ttu_attr
.refcyc_per_req_delivery_pre_l
!= new_ttu_attr
->refcyc_per_req_delivery_pre_l
||
1256 old_ttu_attr
.refcyc_per_req_delivery_pre_c
!= new_ttu_attr
->refcyc_per_req_delivery_pre_c
||
1257 old_ttu_attr
.refcyc_per_req_delivery_pre_cur0
!= new_ttu_attr
->refcyc_per_req_delivery_pre_cur0
||
1258 old_ttu_attr
.refcyc_per_req_delivery_pre_cur1
!= new_ttu_attr
->refcyc_per_req_delivery_pre_cur1
||
1259 old_ttu_attr
.min_ttu_vblank
!= new_ttu_attr
->min_ttu_vblank
||
1260 old_ttu_attr
.qos_level_flip
!= new_ttu_attr
->qos_level_flip
) {
1261 old_dlg_attr
.dst_y_prefetch
= new_dlg_attr
->dst_y_prefetch
;
1262 old_dlg_attr
.vratio_prefetch
= new_dlg_attr
->vratio_prefetch
;
1263 old_dlg_attr
.vratio_prefetch_c
= new_dlg_attr
->vratio_prefetch_c
;
1264 old_dlg_attr
.dst_y_per_vm_vblank
= new_dlg_attr
->dst_y_per_vm_vblank
;
1265 old_dlg_attr
.dst_y_per_row_vblank
= new_dlg_attr
->dst_y_per_row_vblank
;
1266 old_dlg_attr
.dst_y_per_vm_flip
= new_dlg_attr
->dst_y_per_vm_flip
;
1267 old_dlg_attr
.dst_y_per_row_flip
= new_dlg_attr
->dst_y_per_row_flip
;
1268 old_dlg_attr
.refcyc_per_meta_chunk_vblank_l
= new_dlg_attr
->refcyc_per_meta_chunk_vblank_l
;
1269 old_dlg_attr
.refcyc_per_meta_chunk_vblank_c
= new_dlg_attr
->refcyc_per_meta_chunk_vblank_c
;
1270 old_dlg_attr
.refcyc_per_meta_chunk_flip_l
= new_dlg_attr
->refcyc_per_meta_chunk_flip_l
;
1271 old_dlg_attr
.refcyc_per_line_delivery_pre_l
= new_dlg_attr
->refcyc_per_line_delivery_pre_l
;
1272 old_dlg_attr
.refcyc_per_line_delivery_pre_c
= new_dlg_attr
->refcyc_per_line_delivery_pre_c
;
1273 old_ttu_attr
.refcyc_per_req_delivery_pre_l
= new_ttu_attr
->refcyc_per_req_delivery_pre_l
;
1274 old_ttu_attr
.refcyc_per_req_delivery_pre_c
= new_ttu_attr
->refcyc_per_req_delivery_pre_c
;
1275 old_ttu_attr
.refcyc_per_req_delivery_pre_cur0
= new_ttu_attr
->refcyc_per_req_delivery_pre_cur0
;
1276 old_ttu_attr
.refcyc_per_req_delivery_pre_cur1
= new_ttu_attr
->refcyc_per_req_delivery_pre_cur1
;
1277 old_ttu_attr
.min_ttu_vblank
= new_ttu_attr
->min_ttu_vblank
;
1278 old_ttu_attr
.qos_level_flip
= new_ttu_attr
->qos_level_flip
;
1279 new_pipe
->update_flags
.bits
.hubp_interdependent
= 1;
1281 /* Detect any other updates to ttu/rq/dlg */
1282 if (memcmp(&old_dlg_attr
, &new_pipe
->dlg_regs
, sizeof(old_dlg_attr
)) ||
1283 memcmp(&old_ttu_attr
, &new_pipe
->ttu_regs
, sizeof(old_ttu_attr
)) ||
1284 memcmp(&old_pipe
->rq_regs
, &new_pipe
->rq_regs
, sizeof(old_pipe
->rq_regs
)))
1285 new_pipe
->update_flags
.bits
.hubp_rq_dlg_ttu
= 1;
1289 static void dcn20_update_dchubp_dpp(
1291 struct pipe_ctx
*pipe_ctx
,
1292 struct dc_state
*context
)
1294 struct dce_hwseq
*hws
= dc
->hwseq
;
1295 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
1296 struct dpp
*dpp
= pipe_ctx
->plane_res
.dpp
;
1297 struct dc_plane_state
*plane_state
= pipe_ctx
->plane_state
;
1298 bool viewport_changed
= false;
1300 if (pipe_ctx
->update_flags
.bits
.dppclk
)
1301 dpp
->funcs
->dpp_dppclk_control(dpp
, false, true);
1303 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
1304 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
1305 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
1307 if (pipe_ctx
->update_flags
.bits
.hubp_rq_dlg_ttu
) {
1308 hubp
->funcs
->hubp_vtg_sel(hubp
, pipe_ctx
->stream_res
.tg
->inst
);
1310 hubp
->funcs
->hubp_setup(
1312 &pipe_ctx
->dlg_regs
,
1313 &pipe_ctx
->ttu_regs
,
1315 &pipe_ctx
->pipe_dlg_param
);
1317 if (pipe_ctx
->update_flags
.bits
.hubp_interdependent
)
1318 hubp
->funcs
->hubp_setup_interdependent(
1320 &pipe_ctx
->dlg_regs
,
1321 &pipe_ctx
->ttu_regs
);
1323 if (pipe_ctx
->update_flags
.bits
.enable
||
1324 plane_state
->update_flags
.bits
.bpp_change
||
1325 plane_state
->update_flags
.bits
.input_csc_change
||
1326 plane_state
->update_flags
.bits
.color_space_change
||
1327 plane_state
->update_flags
.bits
.coeff_reduction_change
) {
1328 struct dc_bias_and_scale bns_params
= {0};
1330 // program the input csc
1331 dpp
->funcs
->dpp_setup(dpp
,
1332 plane_state
->format
,
1333 EXPANSION_MODE_ZERO
,
1334 plane_state
->input_csc_color_matrix
,
1335 plane_state
->color_space
,
1338 if (dpp
->funcs
->dpp_program_bias_and_scale
) {
1339 //TODO :for CNVC set scale and bias registers if necessary
1340 build_prescale_params(&bns_params
, plane_state
);
1341 dpp
->funcs
->dpp_program_bias_and_scale(dpp
, &bns_params
);
1345 if (pipe_ctx
->update_flags
.bits
.mpcc
1346 || plane_state
->update_flags
.bits
.global_alpha_change
1347 || plane_state
->update_flags
.bits
.per_pixel_alpha_change
) {
1348 // MPCC inst is equal to pipe index in practice
1349 int mpcc_inst
= hubp
->inst
;
1351 int opp_count
= dc
->res_pool
->pipe_count
;
1353 for (opp_inst
= 0; opp_inst
< opp_count
; opp_inst
++) {
1354 if (dc
->res_pool
->opps
[opp_inst
]->mpcc_disconnect_pending
[mpcc_inst
]) {
1355 dc
->res_pool
->mpc
->funcs
->wait_for_idle(dc
->res_pool
->mpc
, mpcc_inst
);
1356 dc
->res_pool
->opps
[opp_inst
]->mpcc_disconnect_pending
[mpcc_inst
] = false;
1360 hws
->funcs
.update_mpcc(dc
, pipe_ctx
);
1363 if (pipe_ctx
->update_flags
.bits
.scaler
||
1364 plane_state
->update_flags
.bits
.scaling_change
||
1365 plane_state
->update_flags
.bits
.position_change
||
1366 plane_state
->update_flags
.bits
.per_pixel_alpha_change
||
1367 pipe_ctx
->stream
->update_flags
.bits
.scaling
) {
1368 pipe_ctx
->plane_res
.scl_data
.lb_params
.alpha_en
= pipe_ctx
->plane_state
->per_pixel_alpha
;
1369 ASSERT(pipe_ctx
->plane_res
.scl_data
.lb_params
.depth
== LB_PIXEL_DEPTH_30BPP
);
1370 /* scaler configuration */
1371 pipe_ctx
->plane_res
.dpp
->funcs
->dpp_set_scaler(
1372 pipe_ctx
->plane_res
.dpp
, &pipe_ctx
->plane_res
.scl_data
);
1375 if (pipe_ctx
->update_flags
.bits
.viewport
||
1376 (context
== dc
->current_state
&& plane_state
->update_flags
.bits
.position_change
) ||
1377 (context
== dc
->current_state
&& plane_state
->update_flags
.bits
.scaling_change
) ||
1378 (context
== dc
->current_state
&& pipe_ctx
->stream
->update_flags
.bits
.scaling
)) {
1380 hubp
->funcs
->mem_program_viewport(
1382 &pipe_ctx
->plane_res
.scl_data
.viewport
,
1383 &pipe_ctx
->plane_res
.scl_data
.viewport_c
);
1384 viewport_changed
= true;
1387 /* Any updates are handled in dc interface, just need to apply existing for plane enable */
1388 if ((pipe_ctx
->update_flags
.bits
.enable
|| pipe_ctx
->update_flags
.bits
.opp_changed
||
1389 pipe_ctx
->update_flags
.bits
.scaler
|| pipe_ctx
->update_flags
.bits
.viewport
)
1390 && pipe_ctx
->stream
->cursor_attributes
.address
.quad_part
!= 0) {
1391 dc
->hwss
.set_cursor_position(pipe_ctx
);
1392 dc
->hwss
.set_cursor_attribute(pipe_ctx
);
1394 if (dc
->hwss
.set_cursor_sdr_white_level
)
1395 dc
->hwss
.set_cursor_sdr_white_level(pipe_ctx
);
1398 /* Any updates are handled in dc interface, just need
1399 * to apply existing for plane enable / opp change */
1400 if (pipe_ctx
->update_flags
.bits
.enable
|| pipe_ctx
->update_flags
.bits
.opp_changed
1401 || pipe_ctx
->stream
->update_flags
.bits
.gamut_remap
1402 || pipe_ctx
->stream
->update_flags
.bits
.out_csc
) {
1403 /* dpp/cm gamut remap*/
1404 dc
->hwss
.program_gamut_remap(pipe_ctx
);
1406 /*call the dcn2 method which uses mpc csc*/
1407 dc
->hwss
.program_output_csc(dc
,
1409 pipe_ctx
->stream
->output_color_space
,
1410 pipe_ctx
->stream
->csc_color_matrix
.matrix
,
1414 if (pipe_ctx
->update_flags
.bits
.enable
||
1415 pipe_ctx
->update_flags
.bits
.opp_changed
||
1416 plane_state
->update_flags
.bits
.pixel_format_change
||
1417 plane_state
->update_flags
.bits
.horizontal_mirror_change
||
1418 plane_state
->update_flags
.bits
.rotation_change
||
1419 plane_state
->update_flags
.bits
.swizzle_change
||
1420 plane_state
->update_flags
.bits
.dcc_change
||
1421 plane_state
->update_flags
.bits
.bpp_change
||
1422 plane_state
->update_flags
.bits
.scaling_change
||
1423 plane_state
->update_flags
.bits
.plane_size_change
) {
1424 struct plane_size size
= plane_state
->plane_size
;
1426 size
.surface_size
= pipe_ctx
->plane_res
.scl_data
.viewport
;
1427 hubp
->funcs
->hubp_program_surface_config(
1429 plane_state
->format
,
1430 &plane_state
->tiling_info
,
1432 plane_state
->rotation
,
1434 plane_state
->horizontal_mirror
,
1436 hubp
->power_gated
= false;
1439 if (hubp
->funcs
->apply_PLAT_54186_wa
&& viewport_changed
)
1440 hubp
->funcs
->apply_PLAT_54186_wa(hubp
, &plane_state
->address
);
1442 if (pipe_ctx
->update_flags
.bits
.enable
|| plane_state
->update_flags
.bits
.addr_update
)
1443 hws
->funcs
.update_plane_addr(dc
, pipe_ctx
);
1447 if (pipe_ctx
->update_flags
.bits
.enable
)
1448 hubp
->funcs
->set_blank(hubp
, false);
1452 static void dcn20_program_pipe(
1454 struct pipe_ctx
*pipe_ctx
,
1455 struct dc_state
*context
)
1457 struct dce_hwseq
*hws
= dc
->hwseq
;
1458 /* Only need to unblank on top pipe */
1459 if ((pipe_ctx
->update_flags
.bits
.enable
|| pipe_ctx
->stream
->update_flags
.bits
.abm_level
)
1460 && !pipe_ctx
->top_pipe
&& !pipe_ctx
->prev_odm_pipe
)
1461 hws
->funcs
.blank_pixel_data(dc
, pipe_ctx
, !pipe_ctx
->plane_state
->visible
);
1463 if (pipe_ctx
->update_flags
.bits
.global_sync
) {
1464 pipe_ctx
->stream_res
.tg
->funcs
->program_global_sync(
1465 pipe_ctx
->stream_res
.tg
,
1466 pipe_ctx
->pipe_dlg_param
.vready_offset
,
1467 pipe_ctx
->pipe_dlg_param
.vstartup_start
,
1468 pipe_ctx
->pipe_dlg_param
.vupdate_offset
,
1469 pipe_ctx
->pipe_dlg_param
.vupdate_width
);
1471 pipe_ctx
->stream_res
.tg
->funcs
->set_vtg_params(
1472 pipe_ctx
->stream_res
.tg
, &pipe_ctx
->stream
->timing
);
1474 if (hws
->funcs
.setup_vupdate_interrupt
)
1475 hws
->funcs
.setup_vupdate_interrupt(dc
, pipe_ctx
);
1478 if (pipe_ctx
->update_flags
.bits
.odm
)
1479 hws
->funcs
.update_odm(dc
, context
, pipe_ctx
);
1481 if (pipe_ctx
->update_flags
.bits
.enable
)
1482 dcn20_enable_plane(dc
, pipe_ctx
, context
);
1484 if (pipe_ctx
->update_flags
.raw
|| pipe_ctx
->plane_state
->update_flags
.raw
|| pipe_ctx
->stream
->update_flags
.raw
)
1485 dcn20_update_dchubp_dpp(dc
, pipe_ctx
, context
);
1487 if (pipe_ctx
->update_flags
.bits
.enable
1488 || pipe_ctx
->plane_state
->update_flags
.bits
.hdr_mult
)
1489 hws
->funcs
.set_hdr_multiplier(pipe_ctx
);
1491 if (pipe_ctx
->update_flags
.bits
.enable
||
1492 pipe_ctx
->plane_state
->update_flags
.bits
.in_transfer_func_change
||
1493 pipe_ctx
->plane_state
->update_flags
.bits
.gamma_change
)
1494 hws
->funcs
.set_input_transfer_func(dc
, pipe_ctx
, pipe_ctx
->plane_state
);
1496 /* dcn10_translate_regamma_to_hw_format takes 750us to finish
1497 * only do gamma programming for powering on, internal memcmp to avoid
1498 * updating on slave planes
1500 if (pipe_ctx
->update_flags
.bits
.enable
|| pipe_ctx
->stream
->update_flags
.bits
.out_tf
)
1501 hws
->funcs
.set_output_transfer_func(dc
, pipe_ctx
, pipe_ctx
->stream
);
1503 /* If the pipe has been enabled or has a different opp, we
1504 * should reprogram the fmt. This deals with cases where
1505 * interation between mpc and odm combine on different streams
1506 * causes a different pipe to be chosen to odm combine with.
1508 if (pipe_ctx
->update_flags
.bits
.enable
1509 || pipe_ctx
->update_flags
.bits
.opp_changed
) {
1511 pipe_ctx
->stream_res
.opp
->funcs
->opp_set_dyn_expansion(
1512 pipe_ctx
->stream_res
.opp
,
1513 COLOR_SPACE_YCBCR601
,
1514 pipe_ctx
->stream
->timing
.display_color_depth
,
1515 pipe_ctx
->stream
->signal
);
1517 pipe_ctx
->stream_res
.opp
->funcs
->opp_program_fmt(
1518 pipe_ctx
->stream_res
.opp
,
1519 &pipe_ctx
->stream
->bit_depth_params
,
1520 &pipe_ctx
->stream
->clamping
);
1524 void dcn20_program_front_end_for_ctx(
1526 struct dc_state
*context
)
1529 struct dce_hwseq
*hws
= dc
->hwseq
;
1530 DC_LOGGER_INIT(dc
->ctx
->logger
);
1532 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1533 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1535 if (!pipe_ctx
->top_pipe
&& !pipe_ctx
->prev_odm_pipe
&& pipe_ctx
->plane_state
) {
1536 ASSERT(!pipe_ctx
->plane_state
->triplebuffer_flips
);
1537 if (dc
->hwss
.program_triplebuffer
!= NULL
&&
1538 !dc
->debug
.disable_tri_buf
) {
1539 /*turn off triple buffer for full update*/
1540 dc
->hwss
.program_triplebuffer(
1541 dc
, pipe_ctx
, pipe_ctx
->plane_state
->triplebuffer_flips
);
1546 /* Set pipe update flags and lock pipes */
1547 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
1548 dcn20_detect_pipe_changes(&dc
->current_state
->res_ctx
.pipe_ctx
[i
],
1549 &context
->res_ctx
.pipe_ctx
[i
]);
1551 /* OTG blank before disabling all front ends */
1552 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
1553 if (context
->res_ctx
.pipe_ctx
[i
].update_flags
.bits
.disable
1554 && !context
->res_ctx
.pipe_ctx
[i
].top_pipe
1555 && !context
->res_ctx
.pipe_ctx
[i
].prev_odm_pipe
1556 && context
->res_ctx
.pipe_ctx
[i
].stream
)
1557 hws
->funcs
.blank_pixel_data(dc
, &context
->res_ctx
.pipe_ctx
[i
], true);
1559 /* Disconnect mpcc */
1560 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
1561 if (context
->res_ctx
.pipe_ctx
[i
].update_flags
.bits
.disable
1562 || context
->res_ctx
.pipe_ctx
[i
].update_flags
.bits
.opp_changed
) {
1563 hws
->funcs
.plane_atomic_disconnect(dc
, &dc
->current_state
->res_ctx
.pipe_ctx
[i
]);
1564 DC_LOG_DC("Reset mpcc for pipe %d\n", dc
->current_state
->res_ctx
.pipe_ctx
[i
].pipe_idx
);
1568 * Program all updated pipes, order matters for mpcc setup. Start with
1569 * top pipe and program all pipes that follow in order
1571 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1572 struct pipe_ctx
*pipe
= &context
->res_ctx
.pipe_ctx
[i
];
1574 if (pipe
->plane_state
&& !pipe
->top_pipe
) {
1576 dcn20_program_pipe(dc
, pipe
, context
);
1577 pipe
= pipe
->bottom_pipe
;
1579 /* Program secondary blending tree and writeback pipes */
1580 pipe
= &context
->res_ctx
.pipe_ctx
[i
];
1581 if (!pipe
->prev_odm_pipe
&& pipe
->stream
->num_wb_info
> 0
1582 && (pipe
->update_flags
.raw
|| pipe
->plane_state
->update_flags
.raw
|| pipe
->stream
->update_flags
.raw
)
1583 && hws
->funcs
.program_all_writeback_pipes_in_tree
)
1584 hws
->funcs
.program_all_writeback_pipes_in_tree(dc
, pipe
->stream
, context
);
1589 void dcn20_post_unlock_program_front_end(
1591 struct dc_state
*context
)
1594 const unsigned int TIMEOUT_FOR_PIPE_ENABLE_MS
= 100;
1595 struct dce_hwseq
*hwseq
= dc
->hwseq
;
1597 DC_LOGGER_INIT(dc
->ctx
->logger
);
1599 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
1600 if (context
->res_ctx
.pipe_ctx
[i
].update_flags
.bits
.disable
)
1601 dc
->hwss
.disable_plane(dc
, &dc
->current_state
->res_ctx
.pipe_ctx
[i
]);
1604 * If we are enabling a pipe, we need to wait for pending clear as this is a critical
1605 * part of the enable operation otherwise, DM may request an immediate flip which
1606 * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which
1607 * is unsupported on DCN.
1609 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1610 struct pipe_ctx
*pipe
= &context
->res_ctx
.pipe_ctx
[i
];
1612 if (pipe
->plane_state
&& !pipe
->top_pipe
&& pipe
->update_flags
.bits
.enable
) {
1613 struct hubp
*hubp
= pipe
->plane_res
.hubp
;
1616 for (j
= 0; j
< TIMEOUT_FOR_PIPE_ENABLE_MS
*1000
1617 && hubp
->funcs
->hubp_is_flip_pending(hubp
); j
++)
1622 /* WA to apply WM setting*/
1623 if (hwseq
->wa
.DEGVIDCN21
)
1624 dc
->res_pool
->hubbub
->funcs
->apply_DEDCN21_147_wa(dc
->res_pool
->hubbub
);
1627 /* WA for stutter underflow during MPO transitions when adding 2nd plane */
1628 if (hwseq
->wa
.disallow_self_refresh_during_multi_plane_transition
) {
1630 if (dc
->current_state
->stream_status
[0].plane_count
== 1 &&
1631 context
->stream_status
[0].plane_count
> 1) {
1633 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[0];
1635 dc
->res_pool
->hubbub
->funcs
->allow_self_refresh_control(dc
->res_pool
->hubbub
, false);
1637 hwseq
->wa_state
.disallow_self_refresh_during_multi_plane_transition_applied
= true;
1638 hwseq
->wa_state
.disallow_self_refresh_during_multi_plane_transition_applied_on_frame
= tg
->funcs
->get_frame_count(tg
);
1643 void dcn20_prepare_bandwidth(
1645 struct dc_state
*context
)
1647 struct hubbub
*hubbub
= dc
->res_pool
->hubbub
;
1649 dc
->clk_mgr
->funcs
->update_clocks(
1654 /* program dchubbub watermarks */
1655 dc
->wm_optimized_required
= hubbub
->funcs
->program_watermarks(hubbub
,
1656 &context
->bw_ctx
.bw
.dcn
.watermarks
,
1657 dc
->res_pool
->ref_clocks
.dchub_ref_clock_inKhz
/ 1000,
1661 void dcn20_optimize_bandwidth(
1663 struct dc_state
*context
)
1665 struct hubbub
*hubbub
= dc
->res_pool
->hubbub
;
1667 /* program dchubbub watermarks */
1668 hubbub
->funcs
->program_watermarks(hubbub
,
1669 &context
->bw_ctx
.bw
.dcn
.watermarks
,
1670 dc
->res_pool
->ref_clocks
.dchub_ref_clock_inKhz
/ 1000,
1673 dc
->clk_mgr
->funcs
->update_clocks(
1679 bool dcn20_update_bandwidth(
1681 struct dc_state
*context
)
1684 struct dce_hwseq
*hws
= dc
->hwseq
;
1686 /* recalculate DML parameters */
1687 if (!dc
->res_pool
->funcs
->validate_bandwidth(dc
, context
, false))
1690 /* apply updated bandwidth parameters */
1691 dc
->hwss
.prepare_bandwidth(dc
, context
);
1693 /* update hubp configs for all pipes */
1694 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1695 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1697 if (pipe_ctx
->plane_state
== NULL
)
1700 if (pipe_ctx
->top_pipe
== NULL
) {
1701 bool blank
= !is_pipe_tree_visible(pipe_ctx
);
1703 pipe_ctx
->stream_res
.tg
->funcs
->program_global_sync(
1704 pipe_ctx
->stream_res
.tg
,
1705 pipe_ctx
->pipe_dlg_param
.vready_offset
,
1706 pipe_ctx
->pipe_dlg_param
.vstartup_start
,
1707 pipe_ctx
->pipe_dlg_param
.vupdate_offset
,
1708 pipe_ctx
->pipe_dlg_param
.vupdate_width
);
1710 pipe_ctx
->stream_res
.tg
->funcs
->set_vtg_params(
1711 pipe_ctx
->stream_res
.tg
, &pipe_ctx
->stream
->timing
);
1713 if (pipe_ctx
->prev_odm_pipe
== NULL
)
1714 hws
->funcs
.blank_pixel_data(dc
, pipe_ctx
, blank
);
1716 if (hws
->funcs
.setup_vupdate_interrupt
)
1717 hws
->funcs
.setup_vupdate_interrupt(dc
, pipe_ctx
);
1720 pipe_ctx
->plane_res
.hubp
->funcs
->hubp_setup(
1721 pipe_ctx
->plane_res
.hubp
,
1722 &pipe_ctx
->dlg_regs
,
1723 &pipe_ctx
->ttu_regs
,
1725 &pipe_ctx
->pipe_dlg_param
);
1731 void dcn20_enable_writeback(
1733 struct dc_writeback_info
*wb_info
,
1734 struct dc_state
*context
)
1737 struct mcif_wb
*mcif_wb
;
1738 struct timing_generator
*optc
;
1740 ASSERT(wb_info
->dwb_pipe_inst
< MAX_DWB_PIPES
);
1741 ASSERT(wb_info
->wb_enabled
);
1742 dwb
= dc
->res_pool
->dwbc
[wb_info
->dwb_pipe_inst
];
1743 mcif_wb
= dc
->res_pool
->mcif_wb
[wb_info
->dwb_pipe_inst
];
1745 /* set the OPTC source mux */
1746 optc
= dc
->res_pool
->timing_generators
[dwb
->otg_inst
];
1747 optc
->funcs
->set_dwb_source(optc
, wb_info
->dwb_pipe_inst
);
1748 /* set MCIF_WB buffer and arbitration configuration */
1749 mcif_wb
->funcs
->config_mcif_buf(mcif_wb
, &wb_info
->mcif_buf_params
, wb_info
->dwb_params
.dest_height
);
1750 mcif_wb
->funcs
->config_mcif_arb(mcif_wb
, &context
->bw_ctx
.bw
.dcn
.bw_writeback
.mcif_wb_arb
[wb_info
->dwb_pipe_inst
]);
1751 /* Enable MCIF_WB */
1752 mcif_wb
->funcs
->enable_mcif(mcif_wb
);
1754 dwb
->funcs
->enable(dwb
, &wb_info
->dwb_params
);
1755 /* TODO: add sequence to enable/disable warmup */
1758 void dcn20_disable_writeback(
1760 unsigned int dwb_pipe_inst
)
1763 struct mcif_wb
*mcif_wb
;
1765 ASSERT(dwb_pipe_inst
< MAX_DWB_PIPES
);
1766 dwb
= dc
->res_pool
->dwbc
[dwb_pipe_inst
];
1767 mcif_wb
= dc
->res_pool
->mcif_wb
[dwb_pipe_inst
];
1769 dwb
->funcs
->disable(dwb
);
1770 mcif_wb
->funcs
->disable_mcif(mcif_wb
);
1773 bool dcn20_wait_for_blank_complete(
1774 struct output_pixel_processor
*opp
)
1778 for (counter
= 0; counter
< 1000; counter
++) {
1779 if (opp
->funcs
->dpg_is_blanked(opp
))
1785 if (counter
== 1000) {
1786 dm_error("DC: failed to blank crtc!\n");
1793 bool dcn20_dmdata_status_done(struct pipe_ctx
*pipe_ctx
)
1795 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
1799 return hubp
->funcs
->dmdata_status_done(hubp
);
1802 void dcn20_disable_stream_gating(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
1804 struct dce_hwseq
*hws
= dc
->hwseq
;
1806 if (pipe_ctx
->stream_res
.dsc
) {
1807 struct pipe_ctx
*odm_pipe
= pipe_ctx
->next_odm_pipe
;
1809 dcn20_dsc_pg_control(hws
, pipe_ctx
->stream_res
.dsc
->inst
, true);
1811 dcn20_dsc_pg_control(hws
, odm_pipe
->stream_res
.dsc
->inst
, true);
1812 odm_pipe
= odm_pipe
->next_odm_pipe
;
1817 void dcn20_enable_stream_gating(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
1819 struct dce_hwseq
*hws
= dc
->hwseq
;
1821 if (pipe_ctx
->stream_res
.dsc
) {
1822 struct pipe_ctx
*odm_pipe
= pipe_ctx
->next_odm_pipe
;
1824 dcn20_dsc_pg_control(hws
, pipe_ctx
->stream_res
.dsc
->inst
, false);
1826 dcn20_dsc_pg_control(hws
, odm_pipe
->stream_res
.dsc
->inst
, false);
1827 odm_pipe
= odm_pipe
->next_odm_pipe
;
1832 void dcn20_set_dmdata_attributes(struct pipe_ctx
*pipe_ctx
)
1834 struct dc_dmdata_attributes attr
= { 0 };
1835 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
1837 attr
.dmdata_mode
= DMDATA_HW_MODE
;
1839 dc_is_hdmi_signal(pipe_ctx
->stream
->signal
) ? 32 : 36;
1840 attr
.address
.quad_part
=
1841 pipe_ctx
->stream
->dmdata_address
.quad_part
;
1842 attr
.dmdata_dl_delta
= 0;
1843 attr
.dmdata_qos_mode
= 0;
1844 attr
.dmdata_qos_level
= 0;
1845 attr
.dmdata_repeat
= 1; /* always repeat */
1846 attr
.dmdata_updated
= 1;
1847 attr
.dmdata_sw_data
= NULL
;
1849 hubp
->funcs
->dmdata_set_attributes(hubp
, &attr
);
1852 void dcn20_init_vm_ctx(
1853 struct dce_hwseq
*hws
,
1855 struct dc_virtual_addr_space_config
*va_config
,
1858 struct dcn_hubbub_virt_addr_config config
;
1861 ASSERT(0); /* VMID cannot be 0 for vm context */
1865 config
.page_table_start_addr
= va_config
->page_table_start_addr
;
1866 config
.page_table_end_addr
= va_config
->page_table_end_addr
;
1867 config
.page_table_block_size
= va_config
->page_table_block_size_in_bytes
;
1868 config
.page_table_depth
= va_config
->page_table_depth
;
1869 config
.page_table_base_addr
= va_config
->page_table_base_addr
;
1871 dc
->res_pool
->hubbub
->funcs
->init_vm_ctx(dc
->res_pool
->hubbub
, &config
, vmid
);
1874 int dcn20_init_sys_ctx(struct dce_hwseq
*hws
, struct dc
*dc
, struct dc_phy_addr_space_config
*pa_config
)
1876 struct dcn_hubbub_phys_addr_config config
;
1878 config
.system_aperture
.fb_top
= pa_config
->system_aperture
.fb_top
;
1879 config
.system_aperture
.fb_offset
= pa_config
->system_aperture
.fb_offset
;
1880 config
.system_aperture
.fb_base
= pa_config
->system_aperture
.fb_base
;
1881 config
.system_aperture
.agp_top
= pa_config
->system_aperture
.agp_top
;
1882 config
.system_aperture
.agp_bot
= pa_config
->system_aperture
.agp_bot
;
1883 config
.system_aperture
.agp_base
= pa_config
->system_aperture
.agp_base
;
1884 config
.gart_config
.page_table_start_addr
= pa_config
->gart_config
.page_table_start_addr
;
1885 config
.gart_config
.page_table_end_addr
= pa_config
->gart_config
.page_table_end_addr
;
1886 config
.gart_config
.page_table_base_addr
= pa_config
->gart_config
.page_table_base_addr
;
1887 config
.page_table_default_page_addr
= pa_config
->page_table_default_page_addr
;
1889 return dc
->res_pool
->hubbub
->funcs
->init_dchub_sys_ctx(dc
->res_pool
->hubbub
, &config
);
1892 static bool patch_address_for_sbs_tb_stereo(
1893 struct pipe_ctx
*pipe_ctx
, PHYSICAL_ADDRESS_LOC
*addr
)
1895 struct dc_plane_state
*plane_state
= pipe_ctx
->plane_state
;
1896 bool sec_split
= pipe_ctx
->top_pipe
&&
1897 pipe_ctx
->top_pipe
->plane_state
== pipe_ctx
->plane_state
;
1898 if (sec_split
&& plane_state
->address
.type
== PLN_ADDR_TYPE_GRPH_STEREO
&&
1899 (pipe_ctx
->stream
->timing
.timing_3d_format
==
1900 TIMING_3D_FORMAT_SIDE_BY_SIDE
||
1901 pipe_ctx
->stream
->timing
.timing_3d_format
==
1902 TIMING_3D_FORMAT_TOP_AND_BOTTOM
)) {
1903 *addr
= plane_state
->address
.grph_stereo
.left_addr
;
1904 plane_state
->address
.grph_stereo
.left_addr
=
1905 plane_state
->address
.grph_stereo
.right_addr
;
1909 if (pipe_ctx
->stream
->view_format
!= VIEW_3D_FORMAT_NONE
&&
1910 plane_state
->address
.type
!= PLN_ADDR_TYPE_GRPH_STEREO
) {
1911 plane_state
->address
.type
= PLN_ADDR_TYPE_GRPH_STEREO
;
1912 plane_state
->address
.grph_stereo
.right_addr
=
1913 plane_state
->address
.grph_stereo
.left_addr
;
1918 void dcn20_update_plane_addr(const struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
1920 bool addr_patched
= false;
1921 PHYSICAL_ADDRESS_LOC addr
;
1922 struct dc_plane_state
*plane_state
= pipe_ctx
->plane_state
;
1924 if (plane_state
== NULL
)
1927 addr_patched
= patch_address_for_sbs_tb_stereo(pipe_ctx
, &addr
);
1929 // Call Helper to track VMID use
1930 vm_helper_mark_vmid_used(dc
->vm_helper
, plane_state
->address
.vmid
, pipe_ctx
->plane_res
.hubp
->inst
);
1932 pipe_ctx
->plane_res
.hubp
->funcs
->hubp_program_surface_flip_and_addr(
1933 pipe_ctx
->plane_res
.hubp
,
1934 &plane_state
->address
,
1935 plane_state
->flip_immediate
);
1937 plane_state
->status
.requested_address
= plane_state
->address
;
1939 if (plane_state
->flip_immediate
)
1940 plane_state
->status
.current_address
= plane_state
->address
;
1943 pipe_ctx
->plane_state
->address
.grph_stereo
.left_addr
= addr
;
1946 void dcn20_unblank_stream(struct pipe_ctx
*pipe_ctx
,
1947 struct dc_link_settings
*link_settings
)
1949 struct encoder_unblank_param params
= { { 0 } };
1950 struct dc_stream_state
*stream
= pipe_ctx
->stream
;
1951 struct dc_link
*link
= stream
->link
;
1952 struct dce_hwseq
*hws
= link
->dc
->hwseq
;
1953 struct pipe_ctx
*odm_pipe
;
1956 for (odm_pipe
= pipe_ctx
->next_odm_pipe
; odm_pipe
; odm_pipe
= odm_pipe
->next_odm_pipe
) {
1959 /* only 3 items below are used by unblank */
1960 params
.timing
= pipe_ctx
->stream
->timing
;
1962 params
.link_settings
.link_rate
= link_settings
->link_rate
;
1964 if (dc_is_dp_signal(pipe_ctx
->stream
->signal
)) {
1965 if (optc2_is_two_pixels_per_containter(&stream
->timing
) || params
.opp_cnt
> 1)
1966 params
.timing
.pix_clk_100hz
/= 2;
1967 pipe_ctx
->stream_res
.stream_enc
->funcs
->dp_set_odm_combine(
1968 pipe_ctx
->stream_res
.stream_enc
, params
.opp_cnt
> 1);
1969 pipe_ctx
->stream_res
.stream_enc
->funcs
->dp_unblank(pipe_ctx
->stream_res
.stream_enc
, ¶ms
);
1972 if (link
->local_sink
&& link
->local_sink
->sink_signal
== SIGNAL_TYPE_EDP
) {
1973 hws
->funcs
.edp_backlight_control(link
, true);
1977 void dcn20_setup_vupdate_interrupt(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
1979 struct timing_generator
*tg
= pipe_ctx
->stream_res
.tg
;
1980 int start_line
= dc
->hwss
.get_vupdate_offset_from_vsync(pipe_ctx
);
1985 if (tg
->funcs
->setup_vertical_interrupt2
)
1986 tg
->funcs
->setup_vertical_interrupt2(tg
, start_line
);
1989 static void dcn20_reset_back_end_for_pipe(
1991 struct pipe_ctx
*pipe_ctx
,
1992 struct dc_state
*context
)
1995 struct dc_link
*link
;
1996 DC_LOGGER_INIT(dc
->ctx
->logger
);
1997 if (pipe_ctx
->stream_res
.stream_enc
== NULL
) {
1998 pipe_ctx
->stream
= NULL
;
2002 if (!IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
)) {
2003 link
= pipe_ctx
->stream
->link
;
2004 /* DPMS may already disable or */
2005 /* dpms_off status is incorrect due to fastboot
2006 * feature. When system resume from S4 with second
2007 * screen only, the dpms_off would be true but
2008 * VBIOS lit up eDP, so check link status too.
2010 if (!pipe_ctx
->stream
->dpms_off
|| link
->link_status
.link_active
)
2011 core_link_disable_stream(pipe_ctx
);
2012 else if (pipe_ctx
->stream_res
.audio
)
2013 dc
->hwss
.disable_audio_stream(pipe_ctx
);
2015 /* free acquired resources */
2016 if (pipe_ctx
->stream_res
.audio
) {
2017 /*disable az_endpoint*/
2018 pipe_ctx
->stream_res
.audio
->funcs
->az_disable(pipe_ctx
->stream_res
.audio
);
2021 if (dc
->caps
.dynamic_audio
== true) {
2022 /*we have to dynamic arbitrate the audio endpoints*/
2023 /*we free the resource, need reset is_audio_acquired*/
2024 update_audio_usage(&dc
->current_state
->res_ctx
, dc
->res_pool
,
2025 pipe_ctx
->stream_res
.audio
, false);
2026 pipe_ctx
->stream_res
.audio
= NULL
;
2030 else if (pipe_ctx
->stream_res
.dsc
) {
2031 dp_set_dsc_enable(pipe_ctx
, false);
2034 /* by upper caller loop, parent pipe: pipe0, will be reset last.
2035 * back end share by all pipes and will be disable only when disable
2038 if (pipe_ctx
->top_pipe
== NULL
) {
2040 if (pipe_ctx
->stream_res
.abm
)
2041 pipe_ctx
->stream_res
.abm
->funcs
->set_abm_immediate_disable(pipe_ctx
->stream_res
.abm
);
2043 pipe_ctx
->stream_res
.tg
->funcs
->disable_crtc(pipe_ctx
->stream_res
.tg
);
2045 pipe_ctx
->stream_res
.tg
->funcs
->enable_optc_clock(pipe_ctx
->stream_res
.tg
, false);
2046 if (pipe_ctx
->stream_res
.tg
->funcs
->set_odm_bypass
)
2047 pipe_ctx
->stream_res
.tg
->funcs
->set_odm_bypass(
2048 pipe_ctx
->stream_res
.tg
, &pipe_ctx
->stream
->timing
);
2050 if (pipe_ctx
->stream_res
.tg
->funcs
->set_drr
)
2051 pipe_ctx
->stream_res
.tg
->funcs
->set_drr(
2052 pipe_ctx
->stream_res
.tg
, NULL
);
2055 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
2056 if (&dc
->current_state
->res_ctx
.pipe_ctx
[i
] == pipe_ctx
)
2059 if (i
== dc
->res_pool
->pipe_count
)
2062 pipe_ctx
->stream
= NULL
;
2063 DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
2064 pipe_ctx
->pipe_idx
, pipe_ctx
->stream_res
.tg
->inst
);
2067 void dcn20_reset_hw_ctx_wrap(
2069 struct dc_state
*context
)
2072 struct dce_hwseq
*hws
= dc
->hwseq
;
2075 for (i
= dc
->res_pool
->pipe_count
- 1; i
>= 0 ; i
--) {
2076 struct pipe_ctx
*pipe_ctx_old
=
2077 &dc
->current_state
->res_ctx
.pipe_ctx
[i
];
2078 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
2080 if (!pipe_ctx_old
->stream
)
2083 if (pipe_ctx_old
->top_pipe
|| pipe_ctx_old
->prev_odm_pipe
)
2086 if (!pipe_ctx
->stream
||
2087 pipe_need_reprogram(pipe_ctx_old
, pipe_ctx
)) {
2088 struct clock_source
*old_clk
= pipe_ctx_old
->clock_source
;
2090 dcn20_reset_back_end_for_pipe(dc
, pipe_ctx_old
, dc
->current_state
);
2091 if (hws
->funcs
.enable_stream_gating
)
2092 hws
->funcs
.enable_stream_gating(dc
, pipe_ctx
);
2094 old_clk
->funcs
->cs_power_down(old_clk
);
2099 void dcn20_get_mpctree_visual_confirm_color(
2100 struct pipe_ctx
*pipe_ctx
,
2101 struct tg_color
*color
)
2103 const struct tg_color pipe_colors
[6] = {
2104 {MAX_TG_COLOR_VALUE
, 0, 0}, // red
2105 {MAX_TG_COLOR_VALUE
, 0, MAX_TG_COLOR_VALUE
}, // yellow
2106 {0, MAX_TG_COLOR_VALUE
, 0}, // blue
2107 {MAX_TG_COLOR_VALUE
/ 2, 0, MAX_TG_COLOR_VALUE
/ 2}, // purple
2108 {0, 0, MAX_TG_COLOR_VALUE
}, // green
2109 {MAX_TG_COLOR_VALUE
, MAX_TG_COLOR_VALUE
* 2 / 3, 0}, // orange
2112 struct pipe_ctx
*top_pipe
= pipe_ctx
;
2114 while (top_pipe
->top_pipe
) {
2115 top_pipe
= top_pipe
->top_pipe
;
2118 *color
= pipe_colors
[top_pipe
->pipe_idx
];
2121 void dcn20_update_mpcc(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
2123 struct dce_hwseq
*hws
= dc
->hwseq
;
2124 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
2125 struct mpcc_blnd_cfg blnd_cfg
= { {0} };
2126 bool per_pixel_alpha
= pipe_ctx
->plane_state
->per_pixel_alpha
;
2128 struct mpcc
*new_mpcc
;
2129 struct mpc
*mpc
= dc
->res_pool
->mpc
;
2130 struct mpc_tree
*mpc_tree_params
= &(pipe_ctx
->stream_res
.opp
->mpc_tree_params
);
2132 // input to MPCC is always RGB, by default leave black_color at 0
2133 if (dc
->debug
.visual_confirm
== VISUAL_CONFIRM_HDR
) {
2134 hws
->funcs
.get_hdr_visual_confirm_color(
2135 pipe_ctx
, &blnd_cfg
.black_color
);
2136 } else if (dc
->debug
.visual_confirm
== VISUAL_CONFIRM_SURFACE
) {
2137 hws
->funcs
.get_surface_visual_confirm_color(
2138 pipe_ctx
, &blnd_cfg
.black_color
);
2139 } else if (dc
->debug
.visual_confirm
== VISUAL_CONFIRM_MPCTREE
) {
2140 dcn20_get_mpctree_visual_confirm_color(
2141 pipe_ctx
, &blnd_cfg
.black_color
);
2144 if (per_pixel_alpha
)
2145 blnd_cfg
.alpha_mode
= MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA
;
2147 blnd_cfg
.alpha_mode
= MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA
;
2149 blnd_cfg
.overlap_only
= false;
2150 blnd_cfg
.global_gain
= 0xff;
2152 if (pipe_ctx
->plane_state
->global_alpha
)
2153 blnd_cfg
.global_alpha
= pipe_ctx
->plane_state
->global_alpha_value
;
2155 blnd_cfg
.global_alpha
= 0xff;
2157 blnd_cfg
.background_color_bpc
= 4;
2158 blnd_cfg
.bottom_gain_mode
= 0;
2159 blnd_cfg
.top_gain
= 0x1f000;
2160 blnd_cfg
.bottom_inside_gain
= 0x1f000;
2161 blnd_cfg
.bottom_outside_gain
= 0x1f000;
2162 blnd_cfg
.pre_multiplied_alpha
= per_pixel_alpha
;
2166 * Note: currently there is a bug in init_hw such that
2167 * on resume from hibernate, BIOS sets up MPCC0, and
2168 * we do mpcc_remove but the mpcc cannot go to idle
2169 * after remove. This cause us to pick mpcc1 here,
2170 * which causes a pstate hang for yet unknown reason.
2172 mpcc_id
= hubp
->inst
;
2174 /* check if this MPCC is already being used */
2175 new_mpcc
= mpc
->funcs
->get_mpcc_for_dpp(mpc_tree_params
, mpcc_id
);
2176 /* remove MPCC if being used */
2177 if (new_mpcc
!= NULL
)
2178 mpc
->funcs
->remove_mpcc(mpc
, mpc_tree_params
, new_mpcc
);
2180 if (dc
->debug
.sanity_checks
)
2181 mpc
->funcs
->assert_mpcc_idle_before_connect(
2182 dc
->res_pool
->mpc
, mpcc_id
);
2184 /* Call MPC to insert new plane */
2185 new_mpcc
= mpc
->funcs
->insert_plane(dc
->res_pool
->mpc
,
2193 ASSERT(new_mpcc
!= NULL
);
2194 hubp
->opp_id
= pipe_ctx
->stream_res
.opp
->inst
;
2195 hubp
->mpcc_id
= mpcc_id
;
2198 void dcn20_enable_stream(struct pipe_ctx
*pipe_ctx
)
2200 enum dc_lane_count lane_count
=
2201 pipe_ctx
->stream
->link
->cur_link_settings
.lane_count
;
2203 struct dc_crtc_timing
*timing
= &pipe_ctx
->stream
->timing
;
2204 struct dc_link
*link
= pipe_ctx
->stream
->link
;
2206 uint32_t active_total_with_borders
;
2207 uint32_t early_control
= 0;
2208 struct timing_generator
*tg
= pipe_ctx
->stream_res
.tg
;
2210 /* For MST, there are multiply stream go to only one link.
2211 * connect DIG back_end to front_end while enable_stream and
2212 * disconnect them during disable_stream
2213 * BY this, it is logic clean to separate stream and link
2215 link
->link_enc
->funcs
->connect_dig_be_to_fe(link
->link_enc
,
2216 pipe_ctx
->stream_res
.stream_enc
->id
, true);
2218 if (pipe_ctx
->plane_state
&& pipe_ctx
->plane_state
->flip_immediate
!= 1) {
2219 if (link
->dc
->hwss
.program_dmdata_engine
)
2220 link
->dc
->hwss
.program_dmdata_engine(pipe_ctx
);
2223 link
->dc
->hwss
.update_info_frame(pipe_ctx
);
2225 /* enable early control to avoid corruption on DP monitor*/
2226 active_total_with_borders
=
2227 timing
->h_addressable
2228 + timing
->h_border_left
2229 + timing
->h_border_right
;
2231 if (lane_count
!= 0)
2232 early_control
= active_total_with_borders
% lane_count
;
2234 if (early_control
== 0)
2235 early_control
= lane_count
;
2237 tg
->funcs
->set_early_control(tg
, early_control
);
2239 /* enable audio only within mode set */
2240 if (pipe_ctx
->stream_res
.audio
!= NULL
) {
2241 if (dc_is_dp_signal(pipe_ctx
->stream
->signal
))
2242 pipe_ctx
->stream_res
.stream_enc
->funcs
->dp_audio_enable(pipe_ctx
->stream_res
.stream_enc
);
2246 void dcn20_program_dmdata_engine(struct pipe_ctx
*pipe_ctx
)
2248 struct dc_stream_state
*stream
= pipe_ctx
->stream
;
2249 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
2250 bool enable
= false;
2251 struct stream_encoder
*stream_enc
= pipe_ctx
->stream_res
.stream_enc
;
2252 enum dynamic_metadata_mode mode
= dc_is_dp_signal(stream
->signal
)
2256 /* if using dynamic meta, don't set up generic infopackets */
2257 if (pipe_ctx
->stream
->dmdata_address
.quad_part
!= 0) {
2258 pipe_ctx
->stream_res
.encoder_info_frame
.hdrsmd
.valid
= false;
2265 if (!stream_enc
|| !stream_enc
->funcs
->set_dynamic_metadata
)
2268 stream_enc
->funcs
->set_dynamic_metadata(stream_enc
, enable
,
2272 void dcn20_fpga_init_hw(struct dc
*dc
)
2275 struct dce_hwseq
*hws
= dc
->hwseq
;
2276 struct resource_pool
*res_pool
= dc
->res_pool
;
2277 struct dc_state
*context
= dc
->current_state
;
2279 if (dc
->clk_mgr
&& dc
->clk_mgr
->funcs
->init_clocks
)
2280 dc
->clk_mgr
->funcs
->init_clocks(dc
->clk_mgr
);
2282 // Initialize the dccg
2283 if (res_pool
->dccg
->funcs
->dccg_init
)
2284 res_pool
->dccg
->funcs
->dccg_init(res_pool
->dccg
);
2286 //Enable ability to power gate / don't force power on permanently
2287 hws
->funcs
.enable_power_gating_plane(hws
, true);
2289 // Specific to FPGA dccg and registers
2290 REG_WRITE(RBBMIF_TIMEOUT_DIS
, 0xFFFFFFFF);
2291 REG_WRITE(RBBMIF_TIMEOUT_DIS_2
, 0xFFFFFFFF);
2293 hws
->funcs
.dccg_init(hws
);
2295 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL
, DCHUBBUB_GLOBAL_TIMER_REFDIV
, 2);
2296 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL
, DCHUBBUB_GLOBAL_TIMER_ENABLE
, 1);
2297 if (REG(REFCLK_CNTL
))
2298 REG_WRITE(REFCLK_CNTL
, 0);
2302 /* Blank pixel data with OPP DPG */
2303 for (i
= 0; i
< dc
->res_pool
->timing_generator_count
; i
++) {
2304 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[i
];
2306 if (tg
->funcs
->is_tg_enabled(tg
))
2307 dcn20_init_blank(dc
, tg
);
2310 for (i
= 0; i
< res_pool
->timing_generator_count
; i
++) {
2311 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[i
];
2313 if (tg
->funcs
->is_tg_enabled(tg
))
2314 tg
->funcs
->lock(tg
);
2317 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
2318 struct dpp
*dpp
= res_pool
->dpps
[i
];
2320 dpp
->funcs
->dpp_reset(dpp
);
2323 /* Reset all MPCC muxes */
2324 res_pool
->mpc
->funcs
->mpc_init(res_pool
->mpc
);
2326 /* initialize OPP mpc_tree parameter */
2327 for (i
= 0; i
< dc
->res_pool
->res_cap
->num_opp
; i
++) {
2328 res_pool
->opps
[i
]->mpc_tree_params
.opp_id
= res_pool
->opps
[i
]->inst
;
2329 res_pool
->opps
[i
]->mpc_tree_params
.opp_list
= NULL
;
2330 for (j
= 0; j
< MAX_PIPES
; j
++)
2331 res_pool
->opps
[i
]->mpcc_disconnect_pending
[j
] = false;
2334 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
2335 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[i
];
2336 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
2337 struct hubp
*hubp
= dc
->res_pool
->hubps
[i
];
2338 struct dpp
*dpp
= dc
->res_pool
->dpps
[i
];
2340 pipe_ctx
->stream_res
.tg
= tg
;
2341 pipe_ctx
->pipe_idx
= i
;
2343 pipe_ctx
->plane_res
.hubp
= hubp
;
2344 pipe_ctx
->plane_res
.dpp
= dpp
;
2345 pipe_ctx
->plane_res
.mpcc_inst
= dpp
->inst
;
2346 hubp
->mpcc_id
= dpp
->inst
;
2347 hubp
->opp_id
= OPP_ID_INVALID
;
2348 hubp
->power_gated
= false;
2349 pipe_ctx
->stream_res
.opp
= NULL
;
2351 hubp
->funcs
->hubp_init(hubp
);
2353 //dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst;
2354 //dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
2355 dc
->res_pool
->opps
[i
]->mpcc_disconnect_pending
[pipe_ctx
->plane_res
.mpcc_inst
] = true;
2356 pipe_ctx
->stream_res
.opp
= dc
->res_pool
->opps
[i
];
2358 hws
->funcs
.plane_atomic_disconnect(dc
, pipe_ctx
);
2361 /* initialize DWB pointer to MCIF_WB */
2362 for (i
= 0; i
< res_pool
->res_cap
->num_dwb
; i
++)
2363 res_pool
->dwbc
[i
]->mcif
= res_pool
->mcif_wb
[i
];
2365 for (i
= 0; i
< dc
->res_pool
->timing_generator_count
; i
++) {
2366 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[i
];
2368 if (tg
->funcs
->is_tg_enabled(tg
))
2369 tg
->funcs
->unlock(tg
);
2372 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
2373 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
2375 dc
->hwss
.disable_plane(dc
, pipe_ctx
);
2377 pipe_ctx
->stream_res
.tg
= NULL
;
2378 pipe_ctx
->plane_res
.hubp
= NULL
;
2381 for (i
= 0; i
< dc
->res_pool
->timing_generator_count
; i
++) {
2382 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[i
];
2384 tg
->funcs
->tg_init(tg
);