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
,
313 bottom_opp
->funcs
->opp_set_disp_pattern_generator(
315 CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR
,
316 CONTROLLER_DP_COLOR_SPACE_UDEFINED
,
317 COLOR_DEPTH_UNDEFINED
,
323 hws
->funcs
.wait_for_blank_complete(opp
);
326 void dcn20_dsc_pg_control(
327 struct dce_hwseq
*hws
,
328 unsigned int dsc_inst
,
331 uint32_t power_gate
= power_on
? 0 : 1;
332 uint32_t pwr_status
= power_on
? 0 : 2;
333 uint32_t org_ip_request_cntl
= 0;
335 if (hws
->ctx
->dc
->debug
.disable_dsc_power_gate
)
338 if (REG(DOMAIN16_PG_CONFIG
) == 0)
341 REG_GET(DC_IP_REQUEST_CNTL
, IP_REQUEST_EN
, &org_ip_request_cntl
);
342 if (org_ip_request_cntl
== 0)
343 REG_SET(DC_IP_REQUEST_CNTL
, 0, IP_REQUEST_EN
, 1);
347 REG_UPDATE(DOMAIN16_PG_CONFIG
,
348 DOMAIN16_POWER_GATE
, power_gate
);
350 REG_WAIT(DOMAIN16_PG_STATUS
,
351 DOMAIN16_PGFSM_PWR_STATUS
, pwr_status
,
355 REG_UPDATE(DOMAIN17_PG_CONFIG
,
356 DOMAIN17_POWER_GATE
, power_gate
);
358 REG_WAIT(DOMAIN17_PG_STATUS
,
359 DOMAIN17_PGFSM_PWR_STATUS
, pwr_status
,
363 REG_UPDATE(DOMAIN18_PG_CONFIG
,
364 DOMAIN18_POWER_GATE
, power_gate
);
366 REG_WAIT(DOMAIN18_PG_STATUS
,
367 DOMAIN18_PGFSM_PWR_STATUS
, pwr_status
,
371 REG_UPDATE(DOMAIN19_PG_CONFIG
,
372 DOMAIN19_POWER_GATE
, power_gate
);
374 REG_WAIT(DOMAIN19_PG_STATUS
,
375 DOMAIN19_PGFSM_PWR_STATUS
, pwr_status
,
379 REG_UPDATE(DOMAIN20_PG_CONFIG
,
380 DOMAIN20_POWER_GATE
, power_gate
);
382 REG_WAIT(DOMAIN20_PG_STATUS
,
383 DOMAIN20_PGFSM_PWR_STATUS
, pwr_status
,
387 REG_UPDATE(DOMAIN21_PG_CONFIG
,
388 DOMAIN21_POWER_GATE
, power_gate
);
390 REG_WAIT(DOMAIN21_PG_STATUS
,
391 DOMAIN21_PGFSM_PWR_STATUS
, pwr_status
,
399 if (org_ip_request_cntl
== 0)
400 REG_SET(DC_IP_REQUEST_CNTL
, 0, IP_REQUEST_EN
, 0);
403 void dcn20_dpp_pg_control(
404 struct dce_hwseq
*hws
,
405 unsigned int dpp_inst
,
408 uint32_t power_gate
= power_on
? 0 : 1;
409 uint32_t pwr_status
= power_on
? 0 : 2;
411 if (hws
->ctx
->dc
->debug
.disable_dpp_power_gate
)
413 if (REG(DOMAIN1_PG_CONFIG
) == 0)
418 REG_UPDATE(DOMAIN1_PG_CONFIG
,
419 DOMAIN1_POWER_GATE
, power_gate
);
421 REG_WAIT(DOMAIN1_PG_STATUS
,
422 DOMAIN1_PGFSM_PWR_STATUS
, pwr_status
,
426 REG_UPDATE(DOMAIN3_PG_CONFIG
,
427 DOMAIN3_POWER_GATE
, power_gate
);
429 REG_WAIT(DOMAIN3_PG_STATUS
,
430 DOMAIN3_PGFSM_PWR_STATUS
, pwr_status
,
434 REG_UPDATE(DOMAIN5_PG_CONFIG
,
435 DOMAIN5_POWER_GATE
, power_gate
);
437 REG_WAIT(DOMAIN5_PG_STATUS
,
438 DOMAIN5_PGFSM_PWR_STATUS
, pwr_status
,
442 REG_UPDATE(DOMAIN7_PG_CONFIG
,
443 DOMAIN7_POWER_GATE
, power_gate
);
445 REG_WAIT(DOMAIN7_PG_STATUS
,
446 DOMAIN7_PGFSM_PWR_STATUS
, pwr_status
,
450 REG_UPDATE(DOMAIN9_PG_CONFIG
,
451 DOMAIN9_POWER_GATE
, power_gate
);
453 REG_WAIT(DOMAIN9_PG_STATUS
,
454 DOMAIN9_PGFSM_PWR_STATUS
, pwr_status
,
459 * Do not power gate DPP5, should be left at HW default, power on permanently.
460 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard
462 * REG_UPDATE(DOMAIN11_PG_CONFIG,
463 * DOMAIN11_POWER_GATE, power_gate);
465 * REG_WAIT(DOMAIN11_PG_STATUS,
466 * DOMAIN11_PGFSM_PWR_STATUS, pwr_status,
477 void dcn20_hubp_pg_control(
478 struct dce_hwseq
*hws
,
479 unsigned int hubp_inst
,
482 uint32_t power_gate
= power_on
? 0 : 1;
483 uint32_t pwr_status
= power_on
? 0 : 2;
485 if (hws
->ctx
->dc
->debug
.disable_hubp_power_gate
)
487 if (REG(DOMAIN0_PG_CONFIG
) == 0)
491 case 0: /* DCHUBP0 */
492 REG_UPDATE(DOMAIN0_PG_CONFIG
,
493 DOMAIN0_POWER_GATE
, power_gate
);
495 REG_WAIT(DOMAIN0_PG_STATUS
,
496 DOMAIN0_PGFSM_PWR_STATUS
, pwr_status
,
499 case 1: /* DCHUBP1 */
500 REG_UPDATE(DOMAIN2_PG_CONFIG
,
501 DOMAIN2_POWER_GATE
, power_gate
);
503 REG_WAIT(DOMAIN2_PG_STATUS
,
504 DOMAIN2_PGFSM_PWR_STATUS
, pwr_status
,
507 case 2: /* DCHUBP2 */
508 REG_UPDATE(DOMAIN4_PG_CONFIG
,
509 DOMAIN4_POWER_GATE
, power_gate
);
511 REG_WAIT(DOMAIN4_PG_STATUS
,
512 DOMAIN4_PGFSM_PWR_STATUS
, pwr_status
,
515 case 3: /* DCHUBP3 */
516 REG_UPDATE(DOMAIN6_PG_CONFIG
,
517 DOMAIN6_POWER_GATE
, power_gate
);
519 REG_WAIT(DOMAIN6_PG_STATUS
,
520 DOMAIN6_PGFSM_PWR_STATUS
, pwr_status
,
523 case 4: /* DCHUBP4 */
524 REG_UPDATE(DOMAIN8_PG_CONFIG
,
525 DOMAIN8_POWER_GATE
, power_gate
);
527 REG_WAIT(DOMAIN8_PG_STATUS
,
528 DOMAIN8_PGFSM_PWR_STATUS
, pwr_status
,
531 case 5: /* DCHUBP5 */
533 * Do not power gate DCHUB5, should be left at HW default, power on permanently.
534 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard
536 * REG_UPDATE(DOMAIN10_PG_CONFIG,
537 * DOMAIN10_POWER_GATE, power_gate);
539 * REG_WAIT(DOMAIN10_PG_STATUS,
540 * DOMAIN10_PGFSM_PWR_STATUS, pwr_status,
551 /* disable HW used by plane.
552 * note: cannot disable until disconnect is complete
554 void dcn20_plane_atomic_disable(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
556 struct dce_hwseq
*hws
= dc
->hwseq
;
557 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
558 struct dpp
*dpp
= pipe_ctx
->plane_res
.dpp
;
560 dc
->hwss
.wait_for_mpcc_disconnect(dc
, dc
->res_pool
, pipe_ctx
);
562 /* In flip immediate with pipe splitting case GSL is used for
563 * synchronization so we must disable it when the plane is disabled.
565 if (pipe_ctx
->stream_res
.gsl_group
!= 0)
566 dcn20_setup_gsl_group_as_lock(dc
, pipe_ctx
, false);
568 dc
->hwss
.set_flip_control_gsl(pipe_ctx
, false);
570 hubp
->funcs
->hubp_clk_cntl(hubp
, false);
572 dpp
->funcs
->dpp_dppclk_control(dpp
, false, false);
574 hubp
->power_gated
= true;
575 dc
->optimized_required
= false; /* We're powering off, no need to optimize */
577 hws
->funcs
.plane_atomic_power_down(dc
,
578 pipe_ctx
->plane_res
.dpp
,
579 pipe_ctx
->plane_res
.hubp
);
581 pipe_ctx
->stream
= NULL
;
582 memset(&pipe_ctx
->stream_res
, 0, sizeof(pipe_ctx
->stream_res
));
583 memset(&pipe_ctx
->plane_res
, 0, sizeof(pipe_ctx
->plane_res
));
584 pipe_ctx
->top_pipe
= NULL
;
585 pipe_ctx
->bottom_pipe
= NULL
;
586 pipe_ctx
->plane_state
= NULL
;
590 void dcn20_disable_plane(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
592 DC_LOGGER_INIT(dc
->ctx
->logger
);
594 if (!pipe_ctx
->plane_res
.hubp
|| pipe_ctx
->plane_res
.hubp
->power_gated
)
597 dcn20_plane_atomic_disable(dc
, pipe_ctx
);
599 DC_LOG_DC("Power down front end %d\n",
603 enum dc_status
dcn20_enable_stream_timing(
604 struct pipe_ctx
*pipe_ctx
,
605 struct dc_state
*context
,
608 struct dce_hwseq
*hws
= dc
->hwseq
;
609 struct dc_stream_state
*stream
= pipe_ctx
->stream
;
610 struct drr_params params
= {0};
611 unsigned int event_triggers
= 0;
612 struct pipe_ctx
*odm_pipe
;
614 int opp_inst
[MAX_PIPES
] = { pipe_ctx
->stream_res
.opp
->inst
};
616 /* by upper caller loop, pipe0 is parent pipe and be called first.
617 * back end is set up by for pipe0. Other children pipe share back end
618 * with pipe 0. No program is needed.
620 if (pipe_ctx
->top_pipe
!= NULL
)
623 /* TODO check if timing_changed, disable stream if timing changed */
625 for (odm_pipe
= pipe_ctx
->next_odm_pipe
; odm_pipe
; odm_pipe
= odm_pipe
->next_odm_pipe
) {
626 opp_inst
[opp_cnt
] = odm_pipe
->stream_res
.opp
->inst
;
631 pipe_ctx
->stream_res
.tg
->funcs
->set_odm_combine(
632 pipe_ctx
->stream_res
.tg
,
634 &pipe_ctx
->stream
->timing
);
636 /* HW program guide assume display already disable
637 * by unplug sequence. OTG assume stop.
639 pipe_ctx
->stream_res
.tg
->funcs
->enable_optc_clock(pipe_ctx
->stream_res
.tg
, true);
641 if (false == pipe_ctx
->clock_source
->funcs
->program_pix_clk(
642 pipe_ctx
->clock_source
,
643 &pipe_ctx
->stream_res
.pix_clk_params
,
644 &pipe_ctx
->pll_settings
)) {
646 return DC_ERROR_UNEXPECTED
;
649 pipe_ctx
->stream_res
.tg
->funcs
->program_timing(
650 pipe_ctx
->stream_res
.tg
,
652 pipe_ctx
->pipe_dlg_param
.vready_offset
,
653 pipe_ctx
->pipe_dlg_param
.vstartup_start
,
654 pipe_ctx
->pipe_dlg_param
.vupdate_offset
,
655 pipe_ctx
->pipe_dlg_param
.vupdate_width
,
656 pipe_ctx
->stream
->signal
,
659 for (odm_pipe
= pipe_ctx
->next_odm_pipe
; odm_pipe
; odm_pipe
= odm_pipe
->next_odm_pipe
)
660 odm_pipe
->stream_res
.opp
->funcs
->opp_pipe_clock_control(
661 odm_pipe
->stream_res
.opp
,
664 pipe_ctx
->stream_res
.opp
->funcs
->opp_pipe_clock_control(
665 pipe_ctx
->stream_res
.opp
,
668 hws
->funcs
.blank_pixel_data(dc
, pipe_ctx
, true);
670 /* VTG is within DCHUB command block. DCFCLK is always on */
671 if (false == pipe_ctx
->stream_res
.tg
->funcs
->enable_crtc(pipe_ctx
->stream_res
.tg
)) {
673 return DC_ERROR_UNEXPECTED
;
676 hws
->funcs
.wait_for_blank_complete(pipe_ctx
->stream_res
.opp
);
678 params
.vertical_total_min
= stream
->adjust
.v_total_min
;
679 params
.vertical_total_max
= stream
->adjust
.v_total_max
;
680 params
.vertical_total_mid
= stream
->adjust
.v_total_mid
;
681 params
.vertical_total_mid_frame_num
= stream
->adjust
.v_total_mid_frame_num
;
682 if (pipe_ctx
->stream_res
.tg
->funcs
->set_drr
)
683 pipe_ctx
->stream_res
.tg
->funcs
->set_drr(
684 pipe_ctx
->stream_res
.tg
, ¶ms
);
686 // DRR should set trigger event to monitor surface update event
687 if (stream
->adjust
.v_total_min
!= 0 && stream
->adjust
.v_total_max
!= 0)
688 event_triggers
= 0x80;
689 /* Event triggers and num frames initialized for DRR, but can be
690 * later updated for PSR use. Note DRR trigger events are generated
691 * regardless of whether num frames met.
693 if (pipe_ctx
->stream_res
.tg
->funcs
->set_static_screen_control
)
694 pipe_ctx
->stream_res
.tg
->funcs
->set_static_screen_control(
695 pipe_ctx
->stream_res
.tg
, event_triggers
, 2);
697 /* TODO program crtc source select for non-virtual signal*/
698 /* TODO program FMT */
699 /* TODO setup link_enc */
700 /* TODO set stream attributes */
701 /* TODO program audio */
702 /* TODO enable stream if timing changed */
703 /* TODO unblank stream if DP */
708 void dcn20_program_output_csc(struct dc
*dc
,
709 struct pipe_ctx
*pipe_ctx
,
710 enum dc_color_space colorspace
,
714 struct mpc
*mpc
= dc
->res_pool
->mpc
;
715 enum mpc_output_csc_mode ocsc_mode
= MPC_OUTPUT_CSC_COEF_A
;
716 int mpcc_id
= pipe_ctx
->plane_res
.hubp
->inst
;
718 if (mpc
->funcs
->power_on_mpc_mem_pwr
)
719 mpc
->funcs
->power_on_mpc_mem_pwr(mpc
, mpcc_id
, true);
721 if (pipe_ctx
->stream
->csc_color_matrix
.enable_adjustment
== true) {
722 if (mpc
->funcs
->set_output_csc
!= NULL
)
723 mpc
->funcs
->set_output_csc(mpc
,
728 if (mpc
->funcs
->set_ocsc_default
!= NULL
)
729 mpc
->funcs
->set_ocsc_default(mpc
,
736 bool dcn20_set_output_transfer_func(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
,
737 const struct dc_stream_state
*stream
)
739 int mpcc_id
= pipe_ctx
->plane_res
.hubp
->inst
;
740 struct mpc
*mpc
= pipe_ctx
->stream_res
.opp
->ctx
->dc
->res_pool
->mpc
;
741 struct pwl_params
*params
= NULL
;
743 * program OGAM only for the top pipe
744 * if there is a pipe split then fix diagnostic is required:
745 * how to pass OGAM parameter for stream.
746 * if programming for all pipes is required then remove condition
747 * pipe_ctx->top_pipe == NULL ,but then fix the diagnostic.
749 if (mpc
->funcs
->power_on_mpc_mem_pwr
)
750 mpc
->funcs
->power_on_mpc_mem_pwr(mpc
, mpcc_id
, true);
751 if (pipe_ctx
->top_pipe
== NULL
752 && mpc
->funcs
->set_output_gamma
&& stream
->out_transfer_func
) {
753 if (stream
->out_transfer_func
->type
== TF_TYPE_HWPWL
)
754 params
= &stream
->out_transfer_func
->pwl
;
755 else if (pipe_ctx
->stream
->out_transfer_func
->type
==
756 TF_TYPE_DISTRIBUTED_POINTS
&&
757 cm_helper_translate_curve_to_hw_format(
758 stream
->out_transfer_func
,
759 &mpc
->blender_params
, false))
760 params
= &mpc
->blender_params
;
764 if (stream
->out_transfer_func
->type
== TF_TYPE_PREDEFINED
)
768 * if above if is not executed then 'params' equal to 0 and set in bypass
770 mpc
->funcs
->set_output_gamma(mpc
, mpcc_id
, params
);
775 bool dcn20_set_blend_lut(
776 struct pipe_ctx
*pipe_ctx
, const struct dc_plane_state
*plane_state
)
778 struct dpp
*dpp_base
= pipe_ctx
->plane_res
.dpp
;
780 struct pwl_params
*blend_lut
= NULL
;
782 if (plane_state
->blend_tf
) {
783 if (plane_state
->blend_tf
->type
== TF_TYPE_HWPWL
)
784 blend_lut
= &plane_state
->blend_tf
->pwl
;
785 else if (plane_state
->blend_tf
->type
== TF_TYPE_DISTRIBUTED_POINTS
) {
786 cm_helper_translate_curve_to_hw_format(
787 plane_state
->blend_tf
,
788 &dpp_base
->regamma_params
, false);
789 blend_lut
= &dpp_base
->regamma_params
;
792 result
= dpp_base
->funcs
->dpp_program_blnd_lut(dpp_base
, blend_lut
);
797 bool dcn20_set_shaper_3dlut(
798 struct pipe_ctx
*pipe_ctx
, const struct dc_plane_state
*plane_state
)
800 struct dpp
*dpp_base
= pipe_ctx
->plane_res
.dpp
;
802 struct pwl_params
*shaper_lut
= NULL
;
804 if (plane_state
->in_shaper_func
) {
805 if (plane_state
->in_shaper_func
->type
== TF_TYPE_HWPWL
)
806 shaper_lut
= &plane_state
->in_shaper_func
->pwl
;
807 else if (plane_state
->in_shaper_func
->type
== TF_TYPE_DISTRIBUTED_POINTS
) {
808 cm_helper_translate_curve_to_hw_format(
809 plane_state
->in_shaper_func
,
810 &dpp_base
->shaper_params
, true);
811 shaper_lut
= &dpp_base
->shaper_params
;
815 result
= dpp_base
->funcs
->dpp_program_shaper_lut(dpp_base
, shaper_lut
);
816 if (plane_state
->lut3d_func
&&
817 plane_state
->lut3d_func
->state
.bits
.initialized
== 1)
818 result
= dpp_base
->funcs
->dpp_program_3dlut(dpp_base
,
819 &plane_state
->lut3d_func
->lut_3d
);
821 result
= dpp_base
->funcs
->dpp_program_3dlut(dpp_base
, NULL
);
826 bool dcn20_set_input_transfer_func(struct dc
*dc
,
827 struct pipe_ctx
*pipe_ctx
,
828 const struct dc_plane_state
*plane_state
)
830 struct dce_hwseq
*hws
= dc
->hwseq
;
831 struct dpp
*dpp_base
= pipe_ctx
->plane_res
.dpp
;
832 const struct dc_transfer_func
*tf
= NULL
;
834 bool use_degamma_ram
= false;
836 if (dpp_base
== NULL
|| plane_state
== NULL
)
839 hws
->funcs
.set_shaper_3dlut(pipe_ctx
, plane_state
);
840 hws
->funcs
.set_blend_lut(pipe_ctx
, plane_state
);
842 if (plane_state
->in_transfer_func
)
843 tf
= plane_state
->in_transfer_func
;
847 dpp_base
->funcs
->dpp_set_degamma(dpp_base
,
848 IPP_DEGAMMA_MODE_BYPASS
);
852 if (tf
->type
== TF_TYPE_HWPWL
|| tf
->type
== TF_TYPE_DISTRIBUTED_POINTS
)
853 use_degamma_ram
= true;
855 if (use_degamma_ram
== true) {
856 if (tf
->type
== TF_TYPE_HWPWL
)
857 dpp_base
->funcs
->dpp_program_degamma_pwl(dpp_base
,
859 else if (tf
->type
== TF_TYPE_DISTRIBUTED_POINTS
) {
860 cm_helper_translate_curve_to_degamma_hw_format(tf
,
861 &dpp_base
->degamma_params
);
862 dpp_base
->funcs
->dpp_program_degamma_pwl(dpp_base
,
863 &dpp_base
->degamma_params
);
867 /* handle here the optimized cases when de-gamma ROM could be used.
870 if (tf
->type
== TF_TYPE_PREDEFINED
) {
872 case TRANSFER_FUNCTION_SRGB
:
873 dpp_base
->funcs
->dpp_set_degamma(dpp_base
,
874 IPP_DEGAMMA_MODE_HW_sRGB
);
876 case TRANSFER_FUNCTION_BT709
:
877 dpp_base
->funcs
->dpp_set_degamma(dpp_base
,
878 IPP_DEGAMMA_MODE_HW_xvYCC
);
880 case TRANSFER_FUNCTION_LINEAR
:
881 dpp_base
->funcs
->dpp_set_degamma(dpp_base
,
882 IPP_DEGAMMA_MODE_BYPASS
);
884 case TRANSFER_FUNCTION_PQ
:
885 dpp_base
->funcs
->dpp_set_degamma(dpp_base
, IPP_DEGAMMA_MODE_USER_PWL
);
886 cm_helper_translate_curve_to_degamma_hw_format(tf
, &dpp_base
->degamma_params
);
887 dpp_base
->funcs
->dpp_program_degamma_pwl(dpp_base
, &dpp_base
->degamma_params
);
894 } else if (tf
->type
== TF_TYPE_BYPASS
)
895 dpp_base
->funcs
->dpp_set_degamma(dpp_base
,
896 IPP_DEGAMMA_MODE_BYPASS
);
899 * if we are here, we did not handle correctly.
900 * fix is required for this use case
903 dpp_base
->funcs
->dpp_set_degamma(dpp_base
,
904 IPP_DEGAMMA_MODE_BYPASS
);
910 void dcn20_update_odm(struct dc
*dc
, struct dc_state
*context
, struct pipe_ctx
*pipe_ctx
)
912 struct pipe_ctx
*odm_pipe
;
914 int opp_inst
[MAX_PIPES
] = { pipe_ctx
->stream_res
.opp
->inst
};
916 for (odm_pipe
= pipe_ctx
->next_odm_pipe
; odm_pipe
; odm_pipe
= odm_pipe
->next_odm_pipe
) {
917 opp_inst
[opp_cnt
] = odm_pipe
->stream_res
.opp
->inst
;
922 pipe_ctx
->stream_res
.tg
->funcs
->set_odm_combine(
923 pipe_ctx
->stream_res
.tg
,
925 &pipe_ctx
->stream
->timing
);
927 pipe_ctx
->stream_res
.tg
->funcs
->set_odm_bypass(
928 pipe_ctx
->stream_res
.tg
, &pipe_ctx
->stream
->timing
);
931 void dcn20_blank_pixel_data(
933 struct pipe_ctx
*pipe_ctx
,
936 struct tg_color black_color
= {0};
937 struct stream_resource
*stream_res
= &pipe_ctx
->stream_res
;
938 struct dc_stream_state
*stream
= pipe_ctx
->stream
;
939 enum dc_color_space color_space
= stream
->output_color_space
;
940 enum controller_dp_test_pattern test_pattern
= CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR
;
941 enum controller_dp_color_space test_pattern_color_space
= CONTROLLER_DP_COLOR_SPACE_UDEFINED
;
942 struct pipe_ctx
*odm_pipe
;
945 int width
= stream
->timing
.h_addressable
+ stream
->timing
.h_border_left
+ stream
->timing
.h_border_right
;
946 int height
= stream
->timing
.v_addressable
+ stream
->timing
.v_border_bottom
+ stream
->timing
.v_border_top
;
948 if (stream
->link
->test_pattern_enabled
)
951 /* get opp dpg blank color */
952 color_space_to_black_color(dc
, color_space
, &black_color
);
954 for (odm_pipe
= pipe_ctx
->next_odm_pipe
; odm_pipe
; odm_pipe
= odm_pipe
->next_odm_pipe
)
957 width
= width
/ odm_cnt
;
961 stream_res
->abm
->funcs
->set_abm_immediate_disable(stream_res
->abm
);
963 if (dc
->debug
.visual_confirm
!= VISUAL_CONFIRM_DISABLE
) {
964 test_pattern
= CONTROLLER_DP_TEST_PATTERN_COLORSQUARES
;
965 test_pattern_color_space
= CONTROLLER_DP_COLOR_SPACE_RGB
;
968 test_pattern
= CONTROLLER_DP_TEST_PATTERN_VIDEOMODE
;
971 stream_res
->opp
->funcs
->opp_set_disp_pattern_generator(
974 test_pattern_color_space
,
975 stream
->timing
.display_color_depth
,
980 for (odm_pipe
= pipe_ctx
->next_odm_pipe
; odm_pipe
; odm_pipe
= odm_pipe
->next_odm_pipe
) {
981 odm_pipe
->stream_res
.opp
->funcs
->opp_set_disp_pattern_generator(
982 odm_pipe
->stream_res
.opp
,
983 dc
->debug
.visual_confirm
!= VISUAL_CONFIRM_DISABLE
&& blank
?
984 CONTROLLER_DP_TEST_PATTERN_COLORRAMP
: test_pattern
,
985 test_pattern_color_space
,
986 stream
->timing
.display_color_depth
,
993 if (stream_res
->abm
) {
994 stream_res
->abm
->funcs
->set_pipe(stream_res
->abm
, stream_res
->tg
->inst
+ 1);
995 stream_res
->abm
->funcs
->set_abm_level(stream_res
->abm
, stream
->abm_level
);
1000 static void dcn20_power_on_plane(
1001 struct dce_hwseq
*hws
,
1002 struct pipe_ctx
*pipe_ctx
)
1004 DC_LOGGER_INIT(hws
->ctx
->logger
);
1005 if (REG(DC_IP_REQUEST_CNTL
)) {
1006 REG_SET(DC_IP_REQUEST_CNTL
, 0,
1008 dcn20_dpp_pg_control(hws
, pipe_ctx
->plane_res
.dpp
->inst
, true);
1009 dcn20_hubp_pg_control(hws
, pipe_ctx
->plane_res
.hubp
->inst
, true);
1010 REG_SET(DC_IP_REQUEST_CNTL
, 0,
1013 "Un-gated front end for pipe %d\n", pipe_ctx
->plane_res
.hubp
->inst
);
1017 void dcn20_enable_plane(
1019 struct pipe_ctx
*pipe_ctx
,
1020 struct dc_state
*context
)
1022 //if (dc->debug.sanity_checks) {
1023 // dcn10_verify_allow_pstate_change_high(dc);
1025 dcn20_power_on_plane(dc
->hwseq
, pipe_ctx
);
1027 /* enable DCFCLK current DCHUB */
1028 pipe_ctx
->plane_res
.hubp
->funcs
->hubp_clk_cntl(pipe_ctx
->plane_res
.hubp
, true);
1030 /* initialize HUBP on power up */
1031 pipe_ctx
->plane_res
.hubp
->funcs
->hubp_init(pipe_ctx
->plane_res
.hubp
);
1033 /* make sure OPP_PIPE_CLOCK_EN = 1 */
1034 pipe_ctx
->stream_res
.opp
->funcs
->opp_pipe_clock_control(
1035 pipe_ctx
->stream_res
.opp
,
1038 /* TODO: enable/disable in dm as per update type.
1040 DC_LOG_DC(dc->ctx->logger,
1041 "Pipe:%d 0x%x: addr hi:0x%x, "
1044 " %d; dst: %d, %d, %d, %d;\n",
1047 plane_state->address.grph.addr.high_part,
1048 plane_state->address.grph.addr.low_part,
1049 plane_state->src_rect.x,
1050 plane_state->src_rect.y,
1051 plane_state->src_rect.width,
1052 plane_state->src_rect.height,
1053 plane_state->dst_rect.x,
1054 plane_state->dst_rect.y,
1055 plane_state->dst_rect.width,
1056 plane_state->dst_rect.height);
1058 DC_LOG_DC(dc->ctx->logger,
1059 "Pipe %d: width, height, x, y format:%d\n"
1060 "viewport:%d, %d, %d, %d\n"
1061 "recout: %d, %d, %d, %d\n",
1063 plane_state->format,
1064 pipe_ctx->plane_res.scl_data.viewport.width,
1065 pipe_ctx->plane_res.scl_data.viewport.height,
1066 pipe_ctx->plane_res.scl_data.viewport.x,
1067 pipe_ctx->plane_res.scl_data.viewport.y,
1068 pipe_ctx->plane_res.scl_data.recout.width,
1069 pipe_ctx->plane_res.scl_data.recout.height,
1070 pipe_ctx->plane_res.scl_data.recout.x,
1071 pipe_ctx->plane_res.scl_data.recout.y);
1072 print_rq_dlg_ttu(dc, pipe_ctx);
1075 if (dc
->vm_pa_config
.valid
) {
1076 struct vm_system_aperture_param apt
;
1078 apt
.sys_default
.quad_part
= 0;
1080 apt
.sys_low
.quad_part
= dc
->vm_pa_config
.system_aperture
.start_addr
;
1081 apt
.sys_high
.quad_part
= dc
->vm_pa_config
.system_aperture
.end_addr
;
1083 // Program system aperture settings
1084 pipe_ctx
->plane_res
.hubp
->funcs
->hubp_set_vm_system_aperture_settings(pipe_ctx
->plane_res
.hubp
, &apt
);
1087 // if (dc->debug.sanity_checks) {
1088 // dcn10_verify_allow_pstate_change_high(dc);
1093 void dcn20_pipe_control_lock_global(
1095 struct pipe_ctx
*pipe
,
1099 pipe
->stream_res
.tg
->funcs
->lock_doublebuffer_enable(
1100 pipe
->stream_res
.tg
);
1101 pipe
->stream_res
.tg
->funcs
->lock(pipe
->stream_res
.tg
);
1103 pipe
->stream_res
.tg
->funcs
->unlock(pipe
->stream_res
.tg
);
1104 pipe
->stream_res
.tg
->funcs
->wait_for_state(pipe
->stream_res
.tg
,
1105 CRTC_STATE_VACTIVE
);
1106 pipe
->stream_res
.tg
->funcs
->wait_for_state(pipe
->stream_res
.tg
,
1108 pipe
->stream_res
.tg
->funcs
->wait_for_state(pipe
->stream_res
.tg
,
1109 CRTC_STATE_VACTIVE
);
1110 pipe
->stream_res
.tg
->funcs
->lock_doublebuffer_disable(
1111 pipe
->stream_res
.tg
);
1115 void dcn20_pipe_control_lock(
1117 struct pipe_ctx
*pipe
,
1120 bool flip_immediate
= false;
1122 /* use TG master update lock to lock everything on the TG
1123 * therefore only top pipe need to lock
1128 if (pipe
->plane_state
!= NULL
)
1129 flip_immediate
= pipe
->plane_state
->flip_immediate
;
1131 if (flip_immediate
&& lock
) {
1132 const int TIMEOUT_FOR_FLIP_PENDING
= 100000;
1135 for (i
= 0; i
< TIMEOUT_FOR_FLIP_PENDING
; ++i
) {
1136 if (!pipe
->plane_res
.hubp
->funcs
->hubp_is_flip_pending(pipe
->plane_res
.hubp
))
1141 if (pipe
->bottom_pipe
!= NULL
) {
1142 for (i
= 0; i
< TIMEOUT_FOR_FLIP_PENDING
; ++i
) {
1143 if (!pipe
->bottom_pipe
->plane_res
.hubp
->funcs
->hubp_is_flip_pending(pipe
->bottom_pipe
->plane_res
.hubp
))
1150 /* In flip immediate and pipe splitting case, we need to use GSL
1151 * for synchronization. Only do setup on locking and on flip type change.
1153 if (lock
&& pipe
->bottom_pipe
!= NULL
)
1154 if ((flip_immediate
&& pipe
->stream_res
.gsl_group
== 0) ||
1155 (!flip_immediate
&& pipe
->stream_res
.gsl_group
> 0))
1156 dcn20_setup_gsl_group_as_lock(dc
, pipe
, flip_immediate
);
1158 if (pipe
->plane_state
!= NULL
&& pipe
->plane_state
->triplebuffer_flips
) {
1160 pipe
->stream_res
.tg
->funcs
->triplebuffer_lock(pipe
->stream_res
.tg
);
1162 pipe
->stream_res
.tg
->funcs
->triplebuffer_unlock(pipe
->stream_res
.tg
);
1165 pipe
->stream_res
.tg
->funcs
->lock(pipe
->stream_res
.tg
);
1167 pipe
->stream_res
.tg
->funcs
->unlock(pipe
->stream_res
.tg
);
1171 static void dcn20_detect_pipe_changes(struct pipe_ctx
*old_pipe
, struct pipe_ctx
*new_pipe
)
1173 new_pipe
->update_flags
.raw
= 0;
1175 /* Exit on unchanged, unused pipe */
1176 if (!old_pipe
->plane_state
&& !new_pipe
->plane_state
)
1178 /* Detect pipe enable/disable */
1179 if (!old_pipe
->plane_state
&& new_pipe
->plane_state
) {
1180 new_pipe
->update_flags
.bits
.enable
= 1;
1181 new_pipe
->update_flags
.bits
.mpcc
= 1;
1182 new_pipe
->update_flags
.bits
.dppclk
= 1;
1183 new_pipe
->update_flags
.bits
.hubp_interdependent
= 1;
1184 new_pipe
->update_flags
.bits
.hubp_rq_dlg_ttu
= 1;
1185 new_pipe
->update_flags
.bits
.gamut_remap
= 1;
1186 new_pipe
->update_flags
.bits
.scaler
= 1;
1187 new_pipe
->update_flags
.bits
.viewport
= 1;
1188 if (!new_pipe
->top_pipe
&& !new_pipe
->prev_odm_pipe
) {
1189 new_pipe
->update_flags
.bits
.odm
= 1;
1190 new_pipe
->update_flags
.bits
.global_sync
= 1;
1194 if (old_pipe
->plane_state
&& !new_pipe
->plane_state
) {
1195 new_pipe
->update_flags
.bits
.disable
= 1;
1199 /* Detect top pipe only changes */
1200 if (!new_pipe
->top_pipe
&& !new_pipe
->prev_odm_pipe
) {
1201 /* Detect odm changes */
1202 if ((old_pipe
->next_odm_pipe
&& new_pipe
->next_odm_pipe
1203 && old_pipe
->next_odm_pipe
->pipe_idx
!= new_pipe
->next_odm_pipe
->pipe_idx
)
1204 || (!old_pipe
->next_odm_pipe
&& new_pipe
->next_odm_pipe
)
1205 || (old_pipe
->next_odm_pipe
&& !new_pipe
->next_odm_pipe
)
1206 || old_pipe
->stream_res
.opp
!= new_pipe
->stream_res
.opp
)
1207 new_pipe
->update_flags
.bits
.odm
= 1;
1209 /* Detect global sync changes */
1210 if (old_pipe
->pipe_dlg_param
.vready_offset
!= new_pipe
->pipe_dlg_param
.vready_offset
1211 || old_pipe
->pipe_dlg_param
.vstartup_start
!= new_pipe
->pipe_dlg_param
.vstartup_start
1212 || old_pipe
->pipe_dlg_param
.vupdate_offset
!= new_pipe
->pipe_dlg_param
.vupdate_offset
1213 || old_pipe
->pipe_dlg_param
.vupdate_width
!= new_pipe
->pipe_dlg_param
.vupdate_width
)
1214 new_pipe
->update_flags
.bits
.global_sync
= 1;
1218 * Detect opp / tg change, only set on change, not on enable
1219 * Assume mpcc inst = pipe index, if not this code needs to be updated
1220 * since mpcc is what is affected by these. In fact all of our sequence
1221 * makes this assumption at the moment with how hubp reset is matched to
1222 * same index mpcc reset.
1224 if (old_pipe
->stream_res
.opp
!= new_pipe
->stream_res
.opp
)
1225 new_pipe
->update_flags
.bits
.opp_changed
= 1;
1226 if (old_pipe
->stream_res
.tg
!= new_pipe
->stream_res
.tg
)
1227 new_pipe
->update_flags
.bits
.tg_changed
= 1;
1229 /* Detect mpcc blending changes, only dpp inst and bot matter here */
1230 if (old_pipe
->plane_res
.dpp
!= new_pipe
->plane_res
.dpp
1231 || old_pipe
->stream_res
.opp
!= new_pipe
->stream_res
.opp
1232 || (!old_pipe
->bottom_pipe
&& new_pipe
->bottom_pipe
)
1233 || (old_pipe
->bottom_pipe
&& !new_pipe
->bottom_pipe
)
1234 || (old_pipe
->bottom_pipe
&& new_pipe
->bottom_pipe
1235 && old_pipe
->bottom_pipe
->plane_res
.mpcc_inst
1236 != new_pipe
->bottom_pipe
->plane_res
.mpcc_inst
))
1237 new_pipe
->update_flags
.bits
.mpcc
= 1;
1239 /* Detect dppclk change */
1240 if (old_pipe
->plane_res
.bw
.dppclk_khz
!= new_pipe
->plane_res
.bw
.dppclk_khz
)
1241 new_pipe
->update_flags
.bits
.dppclk
= 1;
1243 /* Check for scl update */
1244 if (memcmp(&old_pipe
->plane_res
.scl_data
, &new_pipe
->plane_res
.scl_data
, sizeof(struct scaler_data
)))
1245 new_pipe
->update_flags
.bits
.scaler
= 1;
1246 /* Check for vp update */
1247 if (memcmp(&old_pipe
->plane_res
.scl_data
.viewport
, &new_pipe
->plane_res
.scl_data
.viewport
, sizeof(struct rect
))
1248 || memcmp(&old_pipe
->plane_res
.scl_data
.viewport_c
,
1249 &new_pipe
->plane_res
.scl_data
.viewport_c
, sizeof(struct rect
)))
1250 new_pipe
->update_flags
.bits
.viewport
= 1;
1252 /* Detect dlg/ttu/rq updates */
1254 struct _vcs_dpi_display_dlg_regs_st old_dlg_attr
= old_pipe
->dlg_regs
;
1255 struct _vcs_dpi_display_ttu_regs_st old_ttu_attr
= old_pipe
->ttu_regs
;
1256 struct _vcs_dpi_display_dlg_regs_st
*new_dlg_attr
= &new_pipe
->dlg_regs
;
1257 struct _vcs_dpi_display_ttu_regs_st
*new_ttu_attr
= &new_pipe
->ttu_regs
;
1259 /* Detect pipe interdependent updates */
1260 if (old_dlg_attr
.dst_y_prefetch
!= new_dlg_attr
->dst_y_prefetch
||
1261 old_dlg_attr
.vratio_prefetch
!= new_dlg_attr
->vratio_prefetch
||
1262 old_dlg_attr
.vratio_prefetch_c
!= new_dlg_attr
->vratio_prefetch_c
||
1263 old_dlg_attr
.dst_y_per_vm_vblank
!= new_dlg_attr
->dst_y_per_vm_vblank
||
1264 old_dlg_attr
.dst_y_per_row_vblank
!= new_dlg_attr
->dst_y_per_row_vblank
||
1265 old_dlg_attr
.dst_y_per_vm_flip
!= new_dlg_attr
->dst_y_per_vm_flip
||
1266 old_dlg_attr
.dst_y_per_row_flip
!= new_dlg_attr
->dst_y_per_row_flip
||
1267 old_dlg_attr
.refcyc_per_meta_chunk_vblank_l
!= new_dlg_attr
->refcyc_per_meta_chunk_vblank_l
||
1268 old_dlg_attr
.refcyc_per_meta_chunk_vblank_c
!= new_dlg_attr
->refcyc_per_meta_chunk_vblank_c
||
1269 old_dlg_attr
.refcyc_per_meta_chunk_flip_l
!= new_dlg_attr
->refcyc_per_meta_chunk_flip_l
||
1270 old_dlg_attr
.refcyc_per_line_delivery_pre_l
!= new_dlg_attr
->refcyc_per_line_delivery_pre_l
||
1271 old_dlg_attr
.refcyc_per_line_delivery_pre_c
!= new_dlg_attr
->refcyc_per_line_delivery_pre_c
||
1272 old_ttu_attr
.refcyc_per_req_delivery_pre_l
!= new_ttu_attr
->refcyc_per_req_delivery_pre_l
||
1273 old_ttu_attr
.refcyc_per_req_delivery_pre_c
!= new_ttu_attr
->refcyc_per_req_delivery_pre_c
||
1274 old_ttu_attr
.refcyc_per_req_delivery_pre_cur0
!= new_ttu_attr
->refcyc_per_req_delivery_pre_cur0
||
1275 old_ttu_attr
.refcyc_per_req_delivery_pre_cur1
!= new_ttu_attr
->refcyc_per_req_delivery_pre_cur1
||
1276 old_ttu_attr
.min_ttu_vblank
!= new_ttu_attr
->min_ttu_vblank
||
1277 old_ttu_attr
.qos_level_flip
!= new_ttu_attr
->qos_level_flip
) {
1278 old_dlg_attr
.dst_y_prefetch
= new_dlg_attr
->dst_y_prefetch
;
1279 old_dlg_attr
.vratio_prefetch
= new_dlg_attr
->vratio_prefetch
;
1280 old_dlg_attr
.vratio_prefetch_c
= new_dlg_attr
->vratio_prefetch_c
;
1281 old_dlg_attr
.dst_y_per_vm_vblank
= new_dlg_attr
->dst_y_per_vm_vblank
;
1282 old_dlg_attr
.dst_y_per_row_vblank
= new_dlg_attr
->dst_y_per_row_vblank
;
1283 old_dlg_attr
.dst_y_per_vm_flip
= new_dlg_attr
->dst_y_per_vm_flip
;
1284 old_dlg_attr
.dst_y_per_row_flip
= new_dlg_attr
->dst_y_per_row_flip
;
1285 old_dlg_attr
.refcyc_per_meta_chunk_vblank_l
= new_dlg_attr
->refcyc_per_meta_chunk_vblank_l
;
1286 old_dlg_attr
.refcyc_per_meta_chunk_vblank_c
= new_dlg_attr
->refcyc_per_meta_chunk_vblank_c
;
1287 old_dlg_attr
.refcyc_per_meta_chunk_flip_l
= new_dlg_attr
->refcyc_per_meta_chunk_flip_l
;
1288 old_dlg_attr
.refcyc_per_line_delivery_pre_l
= new_dlg_attr
->refcyc_per_line_delivery_pre_l
;
1289 old_dlg_attr
.refcyc_per_line_delivery_pre_c
= new_dlg_attr
->refcyc_per_line_delivery_pre_c
;
1290 old_ttu_attr
.refcyc_per_req_delivery_pre_l
= new_ttu_attr
->refcyc_per_req_delivery_pre_l
;
1291 old_ttu_attr
.refcyc_per_req_delivery_pre_c
= new_ttu_attr
->refcyc_per_req_delivery_pre_c
;
1292 old_ttu_attr
.refcyc_per_req_delivery_pre_cur0
= new_ttu_attr
->refcyc_per_req_delivery_pre_cur0
;
1293 old_ttu_attr
.refcyc_per_req_delivery_pre_cur1
= new_ttu_attr
->refcyc_per_req_delivery_pre_cur1
;
1294 old_ttu_attr
.min_ttu_vblank
= new_ttu_attr
->min_ttu_vblank
;
1295 old_ttu_attr
.qos_level_flip
= new_ttu_attr
->qos_level_flip
;
1296 new_pipe
->update_flags
.bits
.hubp_interdependent
= 1;
1298 /* Detect any other updates to ttu/rq/dlg */
1299 if (memcmp(&old_dlg_attr
, &new_pipe
->dlg_regs
, sizeof(old_dlg_attr
)) ||
1300 memcmp(&old_ttu_attr
, &new_pipe
->ttu_regs
, sizeof(old_ttu_attr
)) ||
1301 memcmp(&old_pipe
->rq_regs
, &new_pipe
->rq_regs
, sizeof(old_pipe
->rq_regs
)))
1302 new_pipe
->update_flags
.bits
.hubp_rq_dlg_ttu
= 1;
1306 static void dcn20_update_dchubp_dpp(
1308 struct pipe_ctx
*pipe_ctx
,
1309 struct dc_state
*context
)
1311 struct dce_hwseq
*hws
= dc
->hwseq
;
1312 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
1313 struct dpp
*dpp
= pipe_ctx
->plane_res
.dpp
;
1314 struct dc_plane_state
*plane_state
= pipe_ctx
->plane_state
;
1315 bool viewport_changed
= false;
1317 if (pipe_ctx
->update_flags
.bits
.dppclk
)
1318 dpp
->funcs
->dpp_dppclk_control(dpp
, false, true);
1320 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
1321 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
1322 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
1324 if (pipe_ctx
->update_flags
.bits
.hubp_rq_dlg_ttu
) {
1325 hubp
->funcs
->hubp_vtg_sel(hubp
, pipe_ctx
->stream_res
.tg
->inst
);
1327 hubp
->funcs
->hubp_setup(
1329 &pipe_ctx
->dlg_regs
,
1330 &pipe_ctx
->ttu_regs
,
1332 &pipe_ctx
->pipe_dlg_param
);
1334 if (pipe_ctx
->update_flags
.bits
.hubp_interdependent
)
1335 hubp
->funcs
->hubp_setup_interdependent(
1337 &pipe_ctx
->dlg_regs
,
1338 &pipe_ctx
->ttu_regs
);
1340 if (pipe_ctx
->update_flags
.bits
.enable
||
1341 plane_state
->update_flags
.bits
.bpp_change
||
1342 plane_state
->update_flags
.bits
.input_csc_change
||
1343 plane_state
->update_flags
.bits
.color_space_change
||
1344 plane_state
->update_flags
.bits
.coeff_reduction_change
) {
1345 struct dc_bias_and_scale bns_params
= {0};
1347 // program the input csc
1348 dpp
->funcs
->dpp_setup(dpp
,
1349 plane_state
->format
,
1350 EXPANSION_MODE_ZERO
,
1351 plane_state
->input_csc_color_matrix
,
1352 plane_state
->color_space
,
1355 if (dpp
->funcs
->dpp_program_bias_and_scale
) {
1356 //TODO :for CNVC set scale and bias registers if necessary
1357 build_prescale_params(&bns_params
, plane_state
);
1358 dpp
->funcs
->dpp_program_bias_and_scale(dpp
, &bns_params
);
1362 if (pipe_ctx
->update_flags
.bits
.mpcc
1363 || plane_state
->update_flags
.bits
.global_alpha_change
1364 || plane_state
->update_flags
.bits
.per_pixel_alpha_change
) {
1365 // MPCC inst is equal to pipe index in practice
1366 int mpcc_inst
= hubp
->inst
;
1368 int opp_count
= dc
->res_pool
->pipe_count
;
1370 for (opp_inst
= 0; opp_inst
< opp_count
; opp_inst
++) {
1371 if (dc
->res_pool
->opps
[opp_inst
]->mpcc_disconnect_pending
[mpcc_inst
]) {
1372 dc
->res_pool
->mpc
->funcs
->wait_for_idle(dc
->res_pool
->mpc
, mpcc_inst
);
1373 dc
->res_pool
->opps
[opp_inst
]->mpcc_disconnect_pending
[mpcc_inst
] = false;
1377 hws
->funcs
.update_mpcc(dc
, pipe_ctx
);
1380 if (pipe_ctx
->update_flags
.bits
.scaler
||
1381 plane_state
->update_flags
.bits
.scaling_change
||
1382 plane_state
->update_flags
.bits
.position_change
||
1383 plane_state
->update_flags
.bits
.per_pixel_alpha_change
||
1384 pipe_ctx
->stream
->update_flags
.bits
.scaling
) {
1385 pipe_ctx
->plane_res
.scl_data
.lb_params
.alpha_en
= pipe_ctx
->plane_state
->per_pixel_alpha
;
1386 ASSERT(pipe_ctx
->plane_res
.scl_data
.lb_params
.depth
== LB_PIXEL_DEPTH_30BPP
);
1387 /* scaler configuration */
1388 pipe_ctx
->plane_res
.dpp
->funcs
->dpp_set_scaler(
1389 pipe_ctx
->plane_res
.dpp
, &pipe_ctx
->plane_res
.scl_data
);
1392 if (pipe_ctx
->update_flags
.bits
.viewport
||
1393 (context
== dc
->current_state
&& plane_state
->update_flags
.bits
.scaling_change
) ||
1394 (context
== dc
->current_state
&& pipe_ctx
->stream
->update_flags
.bits
.scaling
)) {
1396 hubp
->funcs
->mem_program_viewport(
1398 &pipe_ctx
->plane_res
.scl_data
.viewport
,
1399 &pipe_ctx
->plane_res
.scl_data
.viewport_c
);
1400 viewport_changed
= true;
1403 /* Any updates are handled in dc interface, just need to apply existing for plane enable */
1404 if ((pipe_ctx
->update_flags
.bits
.enable
|| pipe_ctx
->update_flags
.bits
.opp_changed
||
1405 pipe_ctx
->update_flags
.bits
.scaler
|| pipe_ctx
->update_flags
.bits
.viewport
)
1406 && pipe_ctx
->stream
->cursor_attributes
.address
.quad_part
!= 0) {
1407 dc
->hwss
.set_cursor_position(pipe_ctx
);
1408 dc
->hwss
.set_cursor_attribute(pipe_ctx
);
1410 if (dc
->hwss
.set_cursor_sdr_white_level
)
1411 dc
->hwss
.set_cursor_sdr_white_level(pipe_ctx
);
1414 /* Any updates are handled in dc interface, just need
1415 * to apply existing for plane enable / opp change */
1416 if (pipe_ctx
->update_flags
.bits
.enable
|| pipe_ctx
->update_flags
.bits
.opp_changed
1417 || pipe_ctx
->stream
->update_flags
.bits
.gamut_remap
1418 || pipe_ctx
->stream
->update_flags
.bits
.out_csc
) {
1419 /* dpp/cm gamut remap*/
1420 dc
->hwss
.program_gamut_remap(pipe_ctx
);
1422 /*call the dcn2 method which uses mpc csc*/
1423 dc
->hwss
.program_output_csc(dc
,
1425 pipe_ctx
->stream
->output_color_space
,
1426 pipe_ctx
->stream
->csc_color_matrix
.matrix
,
1430 if (pipe_ctx
->update_flags
.bits
.enable
||
1431 pipe_ctx
->update_flags
.bits
.opp_changed
||
1432 plane_state
->update_flags
.bits
.pixel_format_change
||
1433 plane_state
->update_flags
.bits
.horizontal_mirror_change
||
1434 plane_state
->update_flags
.bits
.rotation_change
||
1435 plane_state
->update_flags
.bits
.swizzle_change
||
1436 plane_state
->update_flags
.bits
.dcc_change
||
1437 plane_state
->update_flags
.bits
.bpp_change
||
1438 plane_state
->update_flags
.bits
.scaling_change
||
1439 plane_state
->update_flags
.bits
.plane_size_change
) {
1440 struct plane_size size
= plane_state
->plane_size
;
1442 size
.surface_size
= pipe_ctx
->plane_res
.scl_data
.viewport
;
1443 hubp
->funcs
->hubp_program_surface_config(
1445 plane_state
->format
,
1446 &plane_state
->tiling_info
,
1448 plane_state
->rotation
,
1450 plane_state
->horizontal_mirror
,
1452 hubp
->power_gated
= false;
1455 if (hubp
->funcs
->apply_PLAT_54186_wa
&& viewport_changed
)
1456 hubp
->funcs
->apply_PLAT_54186_wa(hubp
, &plane_state
->address
);
1458 if (pipe_ctx
->update_flags
.bits
.enable
|| plane_state
->update_flags
.bits
.addr_update
)
1459 hws
->funcs
.update_plane_addr(dc
, pipe_ctx
);
1463 if (pipe_ctx
->update_flags
.bits
.enable
)
1464 hubp
->funcs
->set_blank(hubp
, false);
1468 static void dcn20_program_pipe(
1470 struct pipe_ctx
*pipe_ctx
,
1471 struct dc_state
*context
)
1473 struct dce_hwseq
*hws
= dc
->hwseq
;
1474 /* Only need to unblank on top pipe */
1475 if ((pipe_ctx
->update_flags
.bits
.enable
|| pipe_ctx
->stream
->update_flags
.bits
.abm_level
)
1476 && !pipe_ctx
->top_pipe
&& !pipe_ctx
->prev_odm_pipe
)
1477 hws
->funcs
.blank_pixel_data(dc
, pipe_ctx
, !pipe_ctx
->plane_state
->visible
);
1479 if (pipe_ctx
->update_flags
.bits
.global_sync
) {
1480 pipe_ctx
->stream_res
.tg
->funcs
->program_global_sync(
1481 pipe_ctx
->stream_res
.tg
,
1482 pipe_ctx
->pipe_dlg_param
.vready_offset
,
1483 pipe_ctx
->pipe_dlg_param
.vstartup_start
,
1484 pipe_ctx
->pipe_dlg_param
.vupdate_offset
,
1485 pipe_ctx
->pipe_dlg_param
.vupdate_width
);
1487 pipe_ctx
->stream_res
.tg
->funcs
->set_vtg_params(
1488 pipe_ctx
->stream_res
.tg
, &pipe_ctx
->stream
->timing
);
1490 if (hws
->funcs
.setup_vupdate_interrupt
)
1491 hws
->funcs
.setup_vupdate_interrupt(dc
, pipe_ctx
);
1494 if (pipe_ctx
->update_flags
.bits
.odm
)
1495 hws
->funcs
.update_odm(dc
, context
, pipe_ctx
);
1497 if (pipe_ctx
->update_flags
.bits
.enable
)
1498 dcn20_enable_plane(dc
, pipe_ctx
, context
);
1500 if (pipe_ctx
->update_flags
.raw
|| pipe_ctx
->plane_state
->update_flags
.raw
|| pipe_ctx
->stream
->update_flags
.raw
)
1501 dcn20_update_dchubp_dpp(dc
, pipe_ctx
, context
);
1503 if (pipe_ctx
->update_flags
.bits
.enable
1504 || pipe_ctx
->plane_state
->update_flags
.bits
.hdr_mult
)
1505 hws
->funcs
.set_hdr_multiplier(pipe_ctx
);
1507 if (pipe_ctx
->update_flags
.bits
.enable
||
1508 pipe_ctx
->plane_state
->update_flags
.bits
.in_transfer_func_change
||
1509 pipe_ctx
->plane_state
->update_flags
.bits
.gamma_change
)
1510 hws
->funcs
.set_input_transfer_func(dc
, pipe_ctx
, pipe_ctx
->plane_state
);
1512 /* dcn10_translate_regamma_to_hw_format takes 750us to finish
1513 * only do gamma programming for powering on, internal memcmp to avoid
1514 * updating on slave planes
1516 if (pipe_ctx
->update_flags
.bits
.enable
|| pipe_ctx
->stream
->update_flags
.bits
.out_tf
)
1517 hws
->funcs
.set_output_transfer_func(dc
, pipe_ctx
, pipe_ctx
->stream
);
1519 /* If the pipe has been enabled or has a different opp, we
1520 * should reprogram the fmt. This deals with cases where
1521 * interation between mpc and odm combine on different streams
1522 * causes a different pipe to be chosen to odm combine with.
1524 if (pipe_ctx
->update_flags
.bits
.enable
1525 || pipe_ctx
->update_flags
.bits
.opp_changed
) {
1527 pipe_ctx
->stream_res
.opp
->funcs
->opp_set_dyn_expansion(
1528 pipe_ctx
->stream_res
.opp
,
1529 COLOR_SPACE_YCBCR601
,
1530 pipe_ctx
->stream
->timing
.display_color_depth
,
1531 pipe_ctx
->stream
->signal
);
1533 pipe_ctx
->stream_res
.opp
->funcs
->opp_program_fmt(
1534 pipe_ctx
->stream_res
.opp
,
1535 &pipe_ctx
->stream
->bit_depth_params
,
1536 &pipe_ctx
->stream
->clamping
);
1540 static bool does_pipe_need_lock(struct pipe_ctx
*pipe
)
1542 if ((pipe
->plane_state
&& pipe
->plane_state
->update_flags
.raw
)
1543 || pipe
->update_flags
.raw
)
1545 if (pipe
->bottom_pipe
)
1546 return does_pipe_need_lock(pipe
->bottom_pipe
);
1551 void dcn20_program_front_end_for_ctx(
1553 struct dc_state
*context
)
1555 const unsigned int TIMEOUT_FOR_PIPE_ENABLE_MS
= 100;
1557 struct dce_hwseq
*hws
= dc
->hwseq
;
1558 bool pipe_locked
[MAX_PIPES
] = {false};
1559 DC_LOGGER_INIT(dc
->ctx
->logger
);
1561 /* Carry over GSL groups in case the context is changing. */
1562 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
1563 if (context
->res_ctx
.pipe_ctx
[i
].stream
== dc
->current_state
->res_ctx
.pipe_ctx
[i
].stream
)
1564 context
->res_ctx
.pipe_ctx
[i
].stream_res
.gsl_group
=
1565 dc
->current_state
->res_ctx
.pipe_ctx
[i
].stream_res
.gsl_group
;
1567 /* Set pipe update flags and lock pipes */
1568 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
1569 dcn20_detect_pipe_changes(&dc
->current_state
->res_ctx
.pipe_ctx
[i
],
1570 &context
->res_ctx
.pipe_ctx
[i
]);
1571 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
1572 if (!context
->res_ctx
.pipe_ctx
[i
].top_pipe
&&
1573 does_pipe_need_lock(&context
->res_ctx
.pipe_ctx
[i
])) {
1574 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1576 if (pipe_ctx
->update_flags
.bits
.tg_changed
|| pipe_ctx
->update_flags
.bits
.enable
)
1577 dc
->hwss
.pipe_control_lock(dc
, pipe_ctx
, true);
1578 if (!pipe_ctx
->update_flags
.bits
.enable
)
1579 dc
->hwss
.pipe_control_lock(dc
, &dc
->current_state
->res_ctx
.pipe_ctx
[i
], true);
1580 pipe_locked
[i
] = true;
1583 /* OTG blank before disabling all front ends */
1584 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
1585 if (context
->res_ctx
.pipe_ctx
[i
].update_flags
.bits
.disable
1586 && !context
->res_ctx
.pipe_ctx
[i
].top_pipe
1587 && !context
->res_ctx
.pipe_ctx
[i
].prev_odm_pipe
1588 && context
->res_ctx
.pipe_ctx
[i
].stream
)
1589 hws
->funcs
.blank_pixel_data(dc
, &context
->res_ctx
.pipe_ctx
[i
], true);
1591 /* Disconnect mpcc */
1592 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
1593 if (context
->res_ctx
.pipe_ctx
[i
].update_flags
.bits
.disable
1594 || context
->res_ctx
.pipe_ctx
[i
].update_flags
.bits
.opp_changed
) {
1595 hws
->funcs
.plane_atomic_disconnect(dc
, &dc
->current_state
->res_ctx
.pipe_ctx
[i
]);
1596 DC_LOG_DC("Reset mpcc for pipe %d\n", dc
->current_state
->res_ctx
.pipe_ctx
[i
].pipe_idx
);
1600 * Program all updated pipes, order matters for mpcc setup. Start with
1601 * top pipe and program all pipes that follow in order
1603 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1604 struct pipe_ctx
*pipe
= &context
->res_ctx
.pipe_ctx
[i
];
1606 if (pipe
->plane_state
&& !pipe
->top_pipe
) {
1608 dcn20_program_pipe(dc
, pipe
, context
);
1609 pipe
= pipe
->bottom_pipe
;
1611 /* Program secondary blending tree and writeback pipes */
1612 pipe
= &context
->res_ctx
.pipe_ctx
[i
];
1613 if (!pipe
->prev_odm_pipe
&& pipe
->stream
->num_wb_info
> 0
1614 && (pipe
->update_flags
.raw
|| pipe
->plane_state
->update_flags
.raw
|| pipe
->stream
->update_flags
.raw
)
1615 && hws
->funcs
.program_all_writeback_pipes_in_tree
)
1616 hws
->funcs
.program_all_writeback_pipes_in_tree(dc
, pipe
->stream
, context
);
1620 /* Unlock all locked pipes */
1621 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
1622 if (pipe_locked
[i
]) {
1623 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1625 if (pipe_ctx
->update_flags
.bits
.tg_changed
|| pipe_ctx
->update_flags
.bits
.enable
)
1626 dc
->hwss
.pipe_control_lock(dc
, pipe_ctx
, false);
1627 if (!pipe_ctx
->update_flags
.bits
.enable
)
1628 dc
->hwss
.pipe_control_lock(dc
, &dc
->current_state
->res_ctx
.pipe_ctx
[i
], false);
1631 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
1632 if (context
->res_ctx
.pipe_ctx
[i
].update_flags
.bits
.disable
)
1633 dc
->hwss
.disable_plane(dc
, &dc
->current_state
->res_ctx
.pipe_ctx
[i
]);
1636 * If we are enabling a pipe, we need to wait for pending clear as this is a critical
1637 * part of the enable operation otherwise, DM may request an immediate flip which
1638 * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which
1639 * is unsupported on DCN.
1641 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1642 struct pipe_ctx
*pipe
= &context
->res_ctx
.pipe_ctx
[i
];
1644 if (pipe
->plane_state
&& !pipe
->top_pipe
&& pipe
->update_flags
.bits
.enable
) {
1645 struct hubp
*hubp
= pipe
->plane_res
.hubp
;
1648 for (j
= 0; j
< TIMEOUT_FOR_PIPE_ENABLE_MS
*1000
1649 && hubp
->funcs
->hubp_is_flip_pending(hubp
); j
++)
1654 /* WA to apply WM setting*/
1655 if (dc
->hwseq
->wa
.DEGVIDCN21
)
1656 dc
->res_pool
->hubbub
->funcs
->apply_DEDCN21_147_wa(dc
->res_pool
->hubbub
);
1660 void dcn20_prepare_bandwidth(
1662 struct dc_state
*context
)
1664 struct hubbub
*hubbub
= dc
->res_pool
->hubbub
;
1666 dc
->clk_mgr
->funcs
->update_clocks(
1671 /* program dchubbub watermarks */
1672 hubbub
->funcs
->program_watermarks(hubbub
,
1673 &context
->bw_ctx
.bw
.dcn
.watermarks
,
1674 dc
->res_pool
->ref_clocks
.dchub_ref_clock_inKhz
/ 1000,
1678 void dcn20_optimize_bandwidth(
1680 struct dc_state
*context
)
1682 struct hubbub
*hubbub
= dc
->res_pool
->hubbub
;
1684 /* program dchubbub watermarks */
1685 hubbub
->funcs
->program_watermarks(hubbub
,
1686 &context
->bw_ctx
.bw
.dcn
.watermarks
,
1687 dc
->res_pool
->ref_clocks
.dchub_ref_clock_inKhz
/ 1000,
1690 dc
->clk_mgr
->funcs
->update_clocks(
1696 bool dcn20_update_bandwidth(
1698 struct dc_state
*context
)
1701 struct dce_hwseq
*hws
= dc
->hwseq
;
1703 /* recalculate DML parameters */
1704 if (!dc
->res_pool
->funcs
->validate_bandwidth(dc
, context
, false))
1707 /* apply updated bandwidth parameters */
1708 dc
->hwss
.prepare_bandwidth(dc
, context
);
1710 /* update hubp configs for all pipes */
1711 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1712 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1714 if (pipe_ctx
->plane_state
== NULL
)
1717 if (pipe_ctx
->top_pipe
== NULL
) {
1718 bool blank
= !is_pipe_tree_visible(pipe_ctx
);
1720 pipe_ctx
->stream_res
.tg
->funcs
->program_global_sync(
1721 pipe_ctx
->stream_res
.tg
,
1722 pipe_ctx
->pipe_dlg_param
.vready_offset
,
1723 pipe_ctx
->pipe_dlg_param
.vstartup_start
,
1724 pipe_ctx
->pipe_dlg_param
.vupdate_offset
,
1725 pipe_ctx
->pipe_dlg_param
.vupdate_width
);
1727 pipe_ctx
->stream_res
.tg
->funcs
->set_vtg_params(
1728 pipe_ctx
->stream_res
.tg
, &pipe_ctx
->stream
->timing
);
1730 if (pipe_ctx
->prev_odm_pipe
== NULL
)
1731 hws
->funcs
.blank_pixel_data(dc
, pipe_ctx
, blank
);
1733 if (hws
->funcs
.setup_vupdate_interrupt
)
1734 hws
->funcs
.setup_vupdate_interrupt(dc
, pipe_ctx
);
1737 pipe_ctx
->plane_res
.hubp
->funcs
->hubp_setup(
1738 pipe_ctx
->plane_res
.hubp
,
1739 &pipe_ctx
->dlg_regs
,
1740 &pipe_ctx
->ttu_regs
,
1742 &pipe_ctx
->pipe_dlg_param
);
1748 void dcn20_enable_writeback(
1750 struct dc_writeback_info
*wb_info
,
1751 struct dc_state
*context
)
1754 struct mcif_wb
*mcif_wb
;
1755 struct timing_generator
*optc
;
1757 ASSERT(wb_info
->dwb_pipe_inst
< MAX_DWB_PIPES
);
1758 ASSERT(wb_info
->wb_enabled
);
1759 dwb
= dc
->res_pool
->dwbc
[wb_info
->dwb_pipe_inst
];
1760 mcif_wb
= dc
->res_pool
->mcif_wb
[wb_info
->dwb_pipe_inst
];
1762 /* set the OPTC source mux */
1763 optc
= dc
->res_pool
->timing_generators
[dwb
->otg_inst
];
1764 optc
->funcs
->set_dwb_source(optc
, wb_info
->dwb_pipe_inst
);
1765 /* set MCIF_WB buffer and arbitration configuration */
1766 mcif_wb
->funcs
->config_mcif_buf(mcif_wb
, &wb_info
->mcif_buf_params
, wb_info
->dwb_params
.dest_height
);
1767 mcif_wb
->funcs
->config_mcif_arb(mcif_wb
, &context
->bw_ctx
.bw
.dcn
.bw_writeback
.mcif_wb_arb
[wb_info
->dwb_pipe_inst
]);
1768 /* Enable MCIF_WB */
1769 mcif_wb
->funcs
->enable_mcif(mcif_wb
);
1771 dwb
->funcs
->enable(dwb
, &wb_info
->dwb_params
);
1772 /* TODO: add sequence to enable/disable warmup */
1775 void dcn20_disable_writeback(
1777 unsigned int dwb_pipe_inst
)
1780 struct mcif_wb
*mcif_wb
;
1782 ASSERT(dwb_pipe_inst
< MAX_DWB_PIPES
);
1783 dwb
= dc
->res_pool
->dwbc
[dwb_pipe_inst
];
1784 mcif_wb
= dc
->res_pool
->mcif_wb
[dwb_pipe_inst
];
1786 dwb
->funcs
->disable(dwb
);
1787 mcif_wb
->funcs
->disable_mcif(mcif_wb
);
1790 bool dcn20_wait_for_blank_complete(
1791 struct output_pixel_processor
*opp
)
1795 for (counter
= 0; counter
< 1000; counter
++) {
1796 if (opp
->funcs
->dpg_is_blanked(opp
))
1802 if (counter
== 1000) {
1803 dm_error("DC: failed to blank crtc!\n");
1810 bool dcn20_dmdata_status_done(struct pipe_ctx
*pipe_ctx
)
1812 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
1816 return hubp
->funcs
->dmdata_status_done(hubp
);
1819 void dcn20_disable_stream_gating(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
1821 struct dce_hwseq
*hws
= dc
->hwseq
;
1823 if (pipe_ctx
->stream_res
.dsc
) {
1824 struct pipe_ctx
*odm_pipe
= pipe_ctx
->next_odm_pipe
;
1826 dcn20_dsc_pg_control(hws
, pipe_ctx
->stream_res
.dsc
->inst
, true);
1828 dcn20_dsc_pg_control(hws
, odm_pipe
->stream_res
.dsc
->inst
, true);
1829 odm_pipe
= odm_pipe
->next_odm_pipe
;
1834 void dcn20_enable_stream_gating(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
1836 struct dce_hwseq
*hws
= dc
->hwseq
;
1838 if (pipe_ctx
->stream_res
.dsc
) {
1839 struct pipe_ctx
*odm_pipe
= pipe_ctx
->next_odm_pipe
;
1841 dcn20_dsc_pg_control(hws
, pipe_ctx
->stream_res
.dsc
->inst
, false);
1843 dcn20_dsc_pg_control(hws
, odm_pipe
->stream_res
.dsc
->inst
, false);
1844 odm_pipe
= odm_pipe
->next_odm_pipe
;
1849 void dcn20_set_dmdata_attributes(struct pipe_ctx
*pipe_ctx
)
1851 struct dc_dmdata_attributes attr
= { 0 };
1852 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
1854 attr
.dmdata_mode
= DMDATA_HW_MODE
;
1856 dc_is_hdmi_signal(pipe_ctx
->stream
->signal
) ? 32 : 36;
1857 attr
.address
.quad_part
=
1858 pipe_ctx
->stream
->dmdata_address
.quad_part
;
1859 attr
.dmdata_dl_delta
= 0;
1860 attr
.dmdata_qos_mode
= 0;
1861 attr
.dmdata_qos_level
= 0;
1862 attr
.dmdata_repeat
= 1; /* always repeat */
1863 attr
.dmdata_updated
= 1;
1864 attr
.dmdata_sw_data
= NULL
;
1866 hubp
->funcs
->dmdata_set_attributes(hubp
, &attr
);
1869 void dcn20_init_vm_ctx(
1870 struct dce_hwseq
*hws
,
1872 struct dc_virtual_addr_space_config
*va_config
,
1875 struct dcn_hubbub_virt_addr_config config
;
1878 ASSERT(0); /* VMID cannot be 0 for vm context */
1882 config
.page_table_start_addr
= va_config
->page_table_start_addr
;
1883 config
.page_table_end_addr
= va_config
->page_table_end_addr
;
1884 config
.page_table_block_size
= va_config
->page_table_block_size_in_bytes
;
1885 config
.page_table_depth
= va_config
->page_table_depth
;
1886 config
.page_table_base_addr
= va_config
->page_table_base_addr
;
1888 dc
->res_pool
->hubbub
->funcs
->init_vm_ctx(dc
->res_pool
->hubbub
, &config
, vmid
);
1891 int dcn20_init_sys_ctx(struct dce_hwseq
*hws
, struct dc
*dc
, struct dc_phy_addr_space_config
*pa_config
)
1893 struct dcn_hubbub_phys_addr_config config
;
1895 config
.system_aperture
.fb_top
= pa_config
->system_aperture
.fb_top
;
1896 config
.system_aperture
.fb_offset
= pa_config
->system_aperture
.fb_offset
;
1897 config
.system_aperture
.fb_base
= pa_config
->system_aperture
.fb_base
;
1898 config
.system_aperture
.agp_top
= pa_config
->system_aperture
.agp_top
;
1899 config
.system_aperture
.agp_bot
= pa_config
->system_aperture
.agp_bot
;
1900 config
.system_aperture
.agp_base
= pa_config
->system_aperture
.agp_base
;
1901 config
.gart_config
.page_table_start_addr
= pa_config
->gart_config
.page_table_start_addr
;
1902 config
.gart_config
.page_table_end_addr
= pa_config
->gart_config
.page_table_end_addr
;
1903 config
.gart_config
.page_table_base_addr
= pa_config
->gart_config
.page_table_base_addr
;
1904 config
.page_table_default_page_addr
= pa_config
->page_table_default_page_addr
;
1906 return dc
->res_pool
->hubbub
->funcs
->init_dchub_sys_ctx(dc
->res_pool
->hubbub
, &config
);
1909 static bool patch_address_for_sbs_tb_stereo(
1910 struct pipe_ctx
*pipe_ctx
, PHYSICAL_ADDRESS_LOC
*addr
)
1912 struct dc_plane_state
*plane_state
= pipe_ctx
->plane_state
;
1913 bool sec_split
= pipe_ctx
->top_pipe
&&
1914 pipe_ctx
->top_pipe
->plane_state
== pipe_ctx
->plane_state
;
1915 if (sec_split
&& plane_state
->address
.type
== PLN_ADDR_TYPE_GRPH_STEREO
&&
1916 (pipe_ctx
->stream
->timing
.timing_3d_format
==
1917 TIMING_3D_FORMAT_SIDE_BY_SIDE
||
1918 pipe_ctx
->stream
->timing
.timing_3d_format
==
1919 TIMING_3D_FORMAT_TOP_AND_BOTTOM
)) {
1920 *addr
= plane_state
->address
.grph_stereo
.left_addr
;
1921 plane_state
->address
.grph_stereo
.left_addr
=
1922 plane_state
->address
.grph_stereo
.right_addr
;
1926 if (pipe_ctx
->stream
->view_format
!= VIEW_3D_FORMAT_NONE
&&
1927 plane_state
->address
.type
!= PLN_ADDR_TYPE_GRPH_STEREO
) {
1928 plane_state
->address
.type
= PLN_ADDR_TYPE_GRPH_STEREO
;
1929 plane_state
->address
.grph_stereo
.right_addr
=
1930 plane_state
->address
.grph_stereo
.left_addr
;
1935 void dcn20_update_plane_addr(const struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
1937 bool addr_patched
= false;
1938 PHYSICAL_ADDRESS_LOC addr
;
1939 struct dc_plane_state
*plane_state
= pipe_ctx
->plane_state
;
1941 if (plane_state
== NULL
)
1944 addr_patched
= patch_address_for_sbs_tb_stereo(pipe_ctx
, &addr
);
1946 // Call Helper to track VMID use
1947 vm_helper_mark_vmid_used(dc
->vm_helper
, plane_state
->address
.vmid
, pipe_ctx
->plane_res
.hubp
->inst
);
1949 pipe_ctx
->plane_res
.hubp
->funcs
->hubp_program_surface_flip_and_addr(
1950 pipe_ctx
->plane_res
.hubp
,
1951 &plane_state
->address
,
1952 plane_state
->flip_immediate
);
1954 plane_state
->status
.requested_address
= plane_state
->address
;
1956 if (plane_state
->flip_immediate
)
1957 plane_state
->status
.current_address
= plane_state
->address
;
1960 pipe_ctx
->plane_state
->address
.grph_stereo
.left_addr
= addr
;
1963 void dcn20_unblank_stream(struct pipe_ctx
*pipe_ctx
,
1964 struct dc_link_settings
*link_settings
)
1966 struct encoder_unblank_param params
= { { 0 } };
1967 struct dc_stream_state
*stream
= pipe_ctx
->stream
;
1968 struct dc_link
*link
= stream
->link
;
1969 struct dce_hwseq
*hws
= link
->dc
->hwseq
;
1970 struct pipe_ctx
*odm_pipe
;
1973 for (odm_pipe
= pipe_ctx
->next_odm_pipe
; odm_pipe
; odm_pipe
= odm_pipe
->next_odm_pipe
) {
1976 /* only 3 items below are used by unblank */
1977 params
.timing
= pipe_ctx
->stream
->timing
;
1979 params
.link_settings
.link_rate
= link_settings
->link_rate
;
1981 if (dc_is_dp_signal(pipe_ctx
->stream
->signal
)) {
1982 if (optc2_is_two_pixels_per_containter(&stream
->timing
) || params
.opp_cnt
> 1)
1983 params
.timing
.pix_clk_100hz
/= 2;
1984 pipe_ctx
->stream_res
.stream_enc
->funcs
->dp_set_odm_combine(
1985 pipe_ctx
->stream_res
.stream_enc
, params
.opp_cnt
> 1);
1986 pipe_ctx
->stream_res
.stream_enc
->funcs
->dp_unblank(pipe_ctx
->stream_res
.stream_enc
, ¶ms
);
1989 if (link
->local_sink
&& link
->local_sink
->sink_signal
== SIGNAL_TYPE_EDP
) {
1990 hws
->funcs
.edp_backlight_control(link
, true);
1994 void dcn20_setup_vupdate_interrupt(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
1996 struct timing_generator
*tg
= pipe_ctx
->stream_res
.tg
;
1997 int start_line
= dc
->hwss
.get_vupdate_offset_from_vsync(pipe_ctx
);
2002 if (tg
->funcs
->setup_vertical_interrupt2
)
2003 tg
->funcs
->setup_vertical_interrupt2(tg
, start_line
);
2006 static void dcn20_reset_back_end_for_pipe(
2008 struct pipe_ctx
*pipe_ctx
,
2009 struct dc_state
*context
)
2012 struct dc_link
*link
;
2013 DC_LOGGER_INIT(dc
->ctx
->logger
);
2014 if (pipe_ctx
->stream_res
.stream_enc
== NULL
) {
2015 pipe_ctx
->stream
= NULL
;
2019 if (!IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
)) {
2020 link
= pipe_ctx
->stream
->link
;
2021 /* DPMS may already disable or */
2022 /* dpms_off status is incorrect due to fastboot
2023 * feature. When system resume from S4 with second
2024 * screen only, the dpms_off would be true but
2025 * VBIOS lit up eDP, so check link status too.
2027 if (!pipe_ctx
->stream
->dpms_off
|| link
->link_status
.link_active
)
2028 core_link_disable_stream(pipe_ctx
);
2029 else if (pipe_ctx
->stream_res
.audio
)
2030 dc
->hwss
.disable_audio_stream(pipe_ctx
);
2032 /* free acquired resources */
2033 if (pipe_ctx
->stream_res
.audio
) {
2034 /*disable az_endpoint*/
2035 pipe_ctx
->stream_res
.audio
->funcs
->az_disable(pipe_ctx
->stream_res
.audio
);
2038 if (dc
->caps
.dynamic_audio
== true) {
2039 /*we have to dynamic arbitrate the audio endpoints*/
2040 /*we free the resource, need reset is_audio_acquired*/
2041 update_audio_usage(&dc
->current_state
->res_ctx
, dc
->res_pool
,
2042 pipe_ctx
->stream_res
.audio
, false);
2043 pipe_ctx
->stream_res
.audio
= NULL
;
2047 else if (pipe_ctx
->stream_res
.dsc
) {
2048 dp_set_dsc_enable(pipe_ctx
, false);
2051 /* by upper caller loop, parent pipe: pipe0, will be reset last.
2052 * back end share by all pipes and will be disable only when disable
2055 if (pipe_ctx
->top_pipe
== NULL
) {
2056 pipe_ctx
->stream_res
.tg
->funcs
->disable_crtc(pipe_ctx
->stream_res
.tg
);
2058 pipe_ctx
->stream_res
.tg
->funcs
->enable_optc_clock(pipe_ctx
->stream_res
.tg
, false);
2059 if (pipe_ctx
->stream_res
.tg
->funcs
->set_odm_bypass
)
2060 pipe_ctx
->stream_res
.tg
->funcs
->set_odm_bypass(
2061 pipe_ctx
->stream_res
.tg
, &pipe_ctx
->stream
->timing
);
2063 if (pipe_ctx
->stream_res
.tg
->funcs
->set_drr
)
2064 pipe_ctx
->stream_res
.tg
->funcs
->set_drr(
2065 pipe_ctx
->stream_res
.tg
, NULL
);
2068 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
2069 if (&dc
->current_state
->res_ctx
.pipe_ctx
[i
] == pipe_ctx
)
2072 if (i
== dc
->res_pool
->pipe_count
)
2075 pipe_ctx
->stream
= NULL
;
2076 DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
2077 pipe_ctx
->pipe_idx
, pipe_ctx
->stream_res
.tg
->inst
);
2080 void dcn20_reset_hw_ctx_wrap(
2082 struct dc_state
*context
)
2085 struct dce_hwseq
*hws
= dc
->hwseq
;
2088 for (i
= dc
->res_pool
->pipe_count
- 1; i
>= 0 ; i
--) {
2089 struct pipe_ctx
*pipe_ctx_old
=
2090 &dc
->current_state
->res_ctx
.pipe_ctx
[i
];
2091 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
2093 if (!pipe_ctx_old
->stream
)
2096 if (pipe_ctx_old
->top_pipe
|| pipe_ctx_old
->prev_odm_pipe
)
2099 if (!pipe_ctx
->stream
||
2100 pipe_need_reprogram(pipe_ctx_old
, pipe_ctx
)) {
2101 struct clock_source
*old_clk
= pipe_ctx_old
->clock_source
;
2103 dcn20_reset_back_end_for_pipe(dc
, pipe_ctx_old
, dc
->current_state
);
2104 if (hws
->funcs
.enable_stream_gating
)
2105 hws
->funcs
.enable_stream_gating(dc
, pipe_ctx
);
2107 old_clk
->funcs
->cs_power_down(old_clk
);
2112 void dcn20_get_mpctree_visual_confirm_color(
2113 struct pipe_ctx
*pipe_ctx
,
2114 struct tg_color
*color
)
2116 const struct tg_color pipe_colors
[6] = {
2117 {MAX_TG_COLOR_VALUE
, 0, 0}, // red
2118 {MAX_TG_COLOR_VALUE
, 0, MAX_TG_COLOR_VALUE
}, // yellow
2119 {0, MAX_TG_COLOR_VALUE
, 0}, // blue
2120 {MAX_TG_COLOR_VALUE
/ 2, 0, MAX_TG_COLOR_VALUE
/ 2}, // purple
2121 {0, 0, MAX_TG_COLOR_VALUE
}, // green
2122 {MAX_TG_COLOR_VALUE
, MAX_TG_COLOR_VALUE
* 2 / 3, 0}, // orange
2125 struct pipe_ctx
*top_pipe
= pipe_ctx
;
2127 while (top_pipe
->top_pipe
) {
2128 top_pipe
= top_pipe
->top_pipe
;
2131 *color
= pipe_colors
[top_pipe
->pipe_idx
];
2134 void dcn20_update_mpcc(struct dc
*dc
, struct pipe_ctx
*pipe_ctx
)
2136 struct dce_hwseq
*hws
= dc
->hwseq
;
2137 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
2138 struct mpcc_blnd_cfg blnd_cfg
= { {0} };
2139 bool per_pixel_alpha
= pipe_ctx
->plane_state
->per_pixel_alpha
;
2141 struct mpcc
*new_mpcc
;
2142 struct mpc
*mpc
= dc
->res_pool
->mpc
;
2143 struct mpc_tree
*mpc_tree_params
= &(pipe_ctx
->stream_res
.opp
->mpc_tree_params
);
2145 // input to MPCC is always RGB, by default leave black_color at 0
2146 if (dc
->debug
.visual_confirm
== VISUAL_CONFIRM_HDR
) {
2147 hws
->funcs
.get_hdr_visual_confirm_color(
2148 pipe_ctx
, &blnd_cfg
.black_color
);
2149 } else if (dc
->debug
.visual_confirm
== VISUAL_CONFIRM_SURFACE
) {
2150 hws
->funcs
.get_surface_visual_confirm_color(
2151 pipe_ctx
, &blnd_cfg
.black_color
);
2152 } else if (dc
->debug
.visual_confirm
== VISUAL_CONFIRM_MPCTREE
) {
2153 dcn20_get_mpctree_visual_confirm_color(
2154 pipe_ctx
, &blnd_cfg
.black_color
);
2157 if (per_pixel_alpha
)
2158 blnd_cfg
.alpha_mode
= MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA
;
2160 blnd_cfg
.alpha_mode
= MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA
;
2162 blnd_cfg
.overlap_only
= false;
2163 blnd_cfg
.global_gain
= 0xff;
2165 if (pipe_ctx
->plane_state
->global_alpha
)
2166 blnd_cfg
.global_alpha
= pipe_ctx
->plane_state
->global_alpha_value
;
2168 blnd_cfg
.global_alpha
= 0xff;
2170 blnd_cfg
.background_color_bpc
= 4;
2171 blnd_cfg
.bottom_gain_mode
= 0;
2172 blnd_cfg
.top_gain
= 0x1f000;
2173 blnd_cfg
.bottom_inside_gain
= 0x1f000;
2174 blnd_cfg
.bottom_outside_gain
= 0x1f000;
2175 blnd_cfg
.pre_multiplied_alpha
= per_pixel_alpha
;
2179 * Note: currently there is a bug in init_hw such that
2180 * on resume from hibernate, BIOS sets up MPCC0, and
2181 * we do mpcc_remove but the mpcc cannot go to idle
2182 * after remove. This cause us to pick mpcc1 here,
2183 * which causes a pstate hang for yet unknown reason.
2185 mpcc_id
= hubp
->inst
;
2187 /* check if this MPCC is already being used */
2188 new_mpcc
= mpc
->funcs
->get_mpcc_for_dpp(mpc_tree_params
, mpcc_id
);
2189 /* remove MPCC if being used */
2190 if (new_mpcc
!= NULL
)
2191 mpc
->funcs
->remove_mpcc(mpc
, mpc_tree_params
, new_mpcc
);
2193 if (dc
->debug
.sanity_checks
)
2194 mpc
->funcs
->assert_mpcc_idle_before_connect(
2195 dc
->res_pool
->mpc
, mpcc_id
);
2197 /* Call MPC to insert new plane */
2198 new_mpcc
= mpc
->funcs
->insert_plane(dc
->res_pool
->mpc
,
2206 ASSERT(new_mpcc
!= NULL
);
2207 hubp
->opp_id
= pipe_ctx
->stream_res
.opp
->inst
;
2208 hubp
->mpcc_id
= mpcc_id
;
2211 void dcn20_enable_stream(struct pipe_ctx
*pipe_ctx
)
2213 enum dc_lane_count lane_count
=
2214 pipe_ctx
->stream
->link
->cur_link_settings
.lane_count
;
2216 struct dc_crtc_timing
*timing
= &pipe_ctx
->stream
->timing
;
2217 struct dc_link
*link
= pipe_ctx
->stream
->link
;
2219 uint32_t active_total_with_borders
;
2220 uint32_t early_control
= 0;
2221 struct timing_generator
*tg
= pipe_ctx
->stream_res
.tg
;
2223 /* For MST, there are multiply stream go to only one link.
2224 * connect DIG back_end to front_end while enable_stream and
2225 * disconnect them during disable_stream
2226 * BY this, it is logic clean to separate stream and link
2228 link
->link_enc
->funcs
->connect_dig_be_to_fe(link
->link_enc
,
2229 pipe_ctx
->stream_res
.stream_enc
->id
, true);
2231 if (pipe_ctx
->plane_state
&& pipe_ctx
->plane_state
->flip_immediate
!= 1) {
2232 if (link
->dc
->hwss
.program_dmdata_engine
)
2233 link
->dc
->hwss
.program_dmdata_engine(pipe_ctx
);
2236 link
->dc
->hwss
.update_info_frame(pipe_ctx
);
2238 /* enable early control to avoid corruption on DP monitor*/
2239 active_total_with_borders
=
2240 timing
->h_addressable
2241 + timing
->h_border_left
2242 + timing
->h_border_right
;
2244 if (lane_count
!= 0)
2245 early_control
= active_total_with_borders
% lane_count
;
2247 if (early_control
== 0)
2248 early_control
= lane_count
;
2250 tg
->funcs
->set_early_control(tg
, early_control
);
2252 /* enable audio only within mode set */
2253 if (pipe_ctx
->stream_res
.audio
!= NULL
) {
2254 if (dc_is_dp_signal(pipe_ctx
->stream
->signal
))
2255 pipe_ctx
->stream_res
.stream_enc
->funcs
->dp_audio_enable(pipe_ctx
->stream_res
.stream_enc
);
2259 void dcn20_program_dmdata_engine(struct pipe_ctx
*pipe_ctx
)
2261 struct dc_stream_state
*stream
= pipe_ctx
->stream
;
2262 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
2263 bool enable
= false;
2264 struct stream_encoder
*stream_enc
= pipe_ctx
->stream_res
.stream_enc
;
2265 enum dynamic_metadata_mode mode
= dc_is_dp_signal(stream
->signal
)
2269 /* if using dynamic meta, don't set up generic infopackets */
2270 if (pipe_ctx
->stream
->dmdata_address
.quad_part
!= 0) {
2271 pipe_ctx
->stream_res
.encoder_info_frame
.hdrsmd
.valid
= false;
2278 if (!stream_enc
|| !stream_enc
->funcs
->set_dynamic_metadata
)
2281 stream_enc
->funcs
->set_dynamic_metadata(stream_enc
, enable
,
2285 void dcn20_fpga_init_hw(struct dc
*dc
)
2288 struct dce_hwseq
*hws
= dc
->hwseq
;
2289 struct resource_pool
*res_pool
= dc
->res_pool
;
2290 struct dc_state
*context
= dc
->current_state
;
2292 if (dc
->clk_mgr
&& dc
->clk_mgr
->funcs
->init_clocks
)
2293 dc
->clk_mgr
->funcs
->init_clocks(dc
->clk_mgr
);
2295 // Initialize the dccg
2296 if (res_pool
->dccg
->funcs
->dccg_init
)
2297 res_pool
->dccg
->funcs
->dccg_init(res_pool
->dccg
);
2299 //Enable ability to power gate / don't force power on permanently
2300 hws
->funcs
.enable_power_gating_plane(hws
, true);
2302 // Specific to FPGA dccg and registers
2303 REG_WRITE(RBBMIF_TIMEOUT_DIS
, 0xFFFFFFFF);
2304 REG_WRITE(RBBMIF_TIMEOUT_DIS_2
, 0xFFFFFFFF);
2306 hws
->funcs
.dccg_init(hws
);
2308 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL
, DCHUBBUB_GLOBAL_TIMER_REFDIV
, 2);
2309 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL
, DCHUBBUB_GLOBAL_TIMER_ENABLE
, 1);
2310 REG_WRITE(REFCLK_CNTL
, 0);
2314 /* Blank pixel data with OPP DPG */
2315 for (i
= 0; i
< dc
->res_pool
->timing_generator_count
; i
++) {
2316 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[i
];
2318 if (tg
->funcs
->is_tg_enabled(tg
))
2319 dcn20_init_blank(dc
, tg
);
2322 for (i
= 0; i
< res_pool
->timing_generator_count
; i
++) {
2323 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[i
];
2325 if (tg
->funcs
->is_tg_enabled(tg
))
2326 tg
->funcs
->lock(tg
);
2329 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
2330 struct dpp
*dpp
= res_pool
->dpps
[i
];
2332 dpp
->funcs
->dpp_reset(dpp
);
2335 /* Reset all MPCC muxes */
2336 res_pool
->mpc
->funcs
->mpc_init(res_pool
->mpc
);
2338 /* initialize OPP mpc_tree parameter */
2339 for (i
= 0; i
< dc
->res_pool
->res_cap
->num_opp
; i
++) {
2340 res_pool
->opps
[i
]->mpc_tree_params
.opp_id
= res_pool
->opps
[i
]->inst
;
2341 res_pool
->opps
[i
]->mpc_tree_params
.opp_list
= NULL
;
2342 for (j
= 0; j
< MAX_PIPES
; j
++)
2343 res_pool
->opps
[i
]->mpcc_disconnect_pending
[j
] = false;
2346 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
2347 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[i
];
2348 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
2349 struct hubp
*hubp
= dc
->res_pool
->hubps
[i
];
2350 struct dpp
*dpp
= dc
->res_pool
->dpps
[i
];
2352 pipe_ctx
->stream_res
.tg
= tg
;
2353 pipe_ctx
->pipe_idx
= i
;
2355 pipe_ctx
->plane_res
.hubp
= hubp
;
2356 pipe_ctx
->plane_res
.dpp
= dpp
;
2357 pipe_ctx
->plane_res
.mpcc_inst
= dpp
->inst
;
2358 hubp
->mpcc_id
= dpp
->inst
;
2359 hubp
->opp_id
= OPP_ID_INVALID
;
2360 hubp
->power_gated
= false;
2361 pipe_ctx
->stream_res
.opp
= NULL
;
2363 hubp
->funcs
->hubp_init(hubp
);
2365 //dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst;
2366 //dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
2367 dc
->res_pool
->opps
[i
]->mpcc_disconnect_pending
[pipe_ctx
->plane_res
.mpcc_inst
] = true;
2368 pipe_ctx
->stream_res
.opp
= dc
->res_pool
->opps
[i
];
2370 hws
->funcs
.plane_atomic_disconnect(dc
, pipe_ctx
);
2373 /* initialize DWB pointer to MCIF_WB */
2374 for (i
= 0; i
< res_pool
->res_cap
->num_dwb
; i
++)
2375 res_pool
->dwbc
[i
]->mcif
= res_pool
->mcif_wb
[i
];
2377 for (i
= 0; i
< dc
->res_pool
->timing_generator_count
; i
++) {
2378 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[i
];
2380 if (tg
->funcs
->is_tg_enabled(tg
))
2381 tg
->funcs
->unlock(tg
);
2384 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
2385 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
2387 dc
->hwss
.disable_plane(dc
, pipe_ctx
);
2389 pipe_ctx
->stream_res
.tg
= NULL
;
2390 pipe_ctx
->plane_res
.hubp
= NULL
;
2393 for (i
= 0; i
< dc
->res_pool
->timing_generator_count
; i
++) {
2394 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[i
];
2396 tg
->funcs
->tg_init(tg
);