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.
26 #include "dm_services.h"
27 #include "core_types.h"
29 #include "custom_float.h"
30 #include "dcn10_hw_sequencer.h"
31 #include "dce110/dce110_hw_sequencer.h"
32 #include "dce/dce_hwseq.h"
34 #include "dcn10/dcn10_dpp.h"
35 #include "dcn10/dcn10_mpc.h"
36 #include "mem_input.h"
37 #include "timing_generator.h"
41 #include "raven1/DCN/dcn_1_0_offset.h"
42 #include "raven1/DCN/dcn_1_0_sh_mask.h"
43 #include "vega10/soc15ip.h"
44 #include "reg_helper.h"
52 #define FN(reg_name, field_name) \
53 hws->shifts->field_name, hws->masks->field_name
55 static void enable_dppclk(
56 struct dce_hwseq
*hws
,
58 uint32_t requested_pix_clk
,
61 dm_logger_write(hws
->ctx
->logger
, LOG_SURFACE
,
62 "dppclk_rate_control for pipe %d programed to %d\n",
66 if (hws
->shifts
->DPPCLK_RATE_CONTROL
)
67 REG_UPDATE_2(DPP_CONTROL
[plane_id
],
68 DPPCLK_RATE_CONTROL
, dppclk_div
,
71 REG_UPDATE(DPP_CONTROL
[plane_id
],
75 static void enable_power_gating_plane(
76 struct dce_hwseq
*hws
,
79 bool force_on
= 1; /* disable power gating */
85 REG_UPDATE(DOMAIN0_PG_CONFIG
, DOMAIN0_POWER_FORCEON
, force_on
);
86 REG_UPDATE(DOMAIN2_PG_CONFIG
, DOMAIN2_POWER_FORCEON
, force_on
);
87 REG_UPDATE(DOMAIN4_PG_CONFIG
, DOMAIN4_POWER_FORCEON
, force_on
);
88 REG_UPDATE(DOMAIN6_PG_CONFIG
, DOMAIN6_POWER_FORCEON
, force_on
);
91 REG_UPDATE(DOMAIN1_PG_CONFIG
, DOMAIN1_POWER_FORCEON
, force_on
);
92 REG_UPDATE(DOMAIN3_PG_CONFIG
, DOMAIN3_POWER_FORCEON
, force_on
);
93 REG_UPDATE(DOMAIN5_PG_CONFIG
, DOMAIN5_POWER_FORCEON
, force_on
);
94 REG_UPDATE(DOMAIN7_PG_CONFIG
, DOMAIN7_POWER_FORCEON
, force_on
);
97 static void dpp_pg_control(
98 struct dce_hwseq
*hws
,
99 unsigned int dpp_inst
,
102 uint32_t power_gate
= power_on
? 0 : 1;
103 uint32_t pwr_status
= power_on
? 0 : 2;
105 if (hws
->ctx
->dc
->debug
.disable_dpp_power_gate
)
110 REG_UPDATE(DOMAIN1_PG_CONFIG
,
111 DOMAIN1_POWER_GATE
, power_gate
);
113 REG_WAIT(DOMAIN1_PG_STATUS
,
114 DOMAIN1_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
117 REG_UPDATE(DOMAIN3_PG_CONFIG
,
118 DOMAIN3_POWER_GATE
, power_gate
);
120 REG_WAIT(DOMAIN3_PG_STATUS
,
121 DOMAIN3_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
124 REG_UPDATE(DOMAIN5_PG_CONFIG
,
125 DOMAIN5_POWER_GATE
, power_gate
);
127 REG_WAIT(DOMAIN5_PG_STATUS
,
128 DOMAIN5_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
131 REG_UPDATE(DOMAIN7_PG_CONFIG
,
132 DOMAIN7_POWER_GATE
, power_gate
);
134 REG_WAIT(DOMAIN7_PG_STATUS
,
135 DOMAIN7_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
143 static void hubp_pg_control(
144 struct dce_hwseq
*hws
,
145 unsigned int hubp_inst
,
148 uint32_t power_gate
= power_on
? 0 : 1;
149 uint32_t pwr_status
= power_on
? 0 : 2;
151 if (hws
->ctx
->dc
->debug
.disable_hubp_power_gate
)
155 case 0: /* DCHUBP0 */
156 REG_UPDATE(DOMAIN0_PG_CONFIG
,
157 DOMAIN0_POWER_GATE
, power_gate
);
159 REG_WAIT(DOMAIN0_PG_STATUS
,
160 DOMAIN0_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
162 case 1: /* DCHUBP1 */
163 REG_UPDATE(DOMAIN2_PG_CONFIG
,
164 DOMAIN2_POWER_GATE
, power_gate
);
166 REG_WAIT(DOMAIN2_PG_STATUS
,
167 DOMAIN2_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
169 case 2: /* DCHUBP2 */
170 REG_UPDATE(DOMAIN4_PG_CONFIG
,
171 DOMAIN4_POWER_GATE
, power_gate
);
173 REG_WAIT(DOMAIN4_PG_STATUS
,
174 DOMAIN4_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
176 case 3: /* DCHUBP3 */
177 REG_UPDATE(DOMAIN6_PG_CONFIG
,
178 DOMAIN6_POWER_GATE
, power_gate
);
180 REG_WAIT(DOMAIN6_PG_STATUS
,
181 DOMAIN6_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
189 static void power_on_plane(
190 struct dce_hwseq
*hws
,
193 REG_SET(DC_IP_REQUEST_CNTL
, 0,
195 dpp_pg_control(hws
, plane_id
, true);
196 hubp_pg_control(hws
, plane_id
, true);
197 REG_SET(DC_IP_REQUEST_CNTL
, 0,
199 dm_logger_write(hws
->ctx
->logger
, LOG_DC
,
200 "Un-gated front end for pipe %d\n", plane_id
);
203 static void bios_golden_init(struct core_dc
*dc
)
205 struct dc_bios
*bp
= dc
->ctx
->dc_bios
;
208 /* initialize dcn global */
209 bp
->funcs
->enable_disp_power_gating(bp
,
210 CONTROLLER_ID_D0
, ASIC_PIPE_INIT
);
212 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
213 /* initialize dcn per pipe */
214 bp
->funcs
->enable_disp_power_gating(bp
,
215 CONTROLLER_ID_D0
+ i
, ASIC_PIPE_DISABLE
);
219 static void dcn10_init_hw(struct core_dc
*dc
)
222 struct abm
*abm
= dc
->res_pool
->abm
;
223 struct dce_hwseq
*hws
= dc
->hwseq
;
225 if (IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
)) {
226 REG_WRITE(REFCLK_CNTL
, 0);
227 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL
, DCHUBBUB_GLOBAL_TIMER_ENABLE
, 1);
228 REG_WRITE(DIO_MEM_PWR_CTRL
, 0);
230 if (!dc
->public.debug
.disable_clock_gate
) {
231 /* enable all DCN clock gating */
232 REG_WRITE(DCCG_GATE_DISABLE_CNTL
, 0);
234 REG_WRITE(DCCG_GATE_DISABLE_CNTL2
, 0);
236 REG_UPDATE(DCFCLK_CNTL
, DCFCLK_GATE_DIS
, 0);
239 enable_power_gating_plane(dc
->hwseq
, true);
242 /* end of FPGA. Below if real ASIC */
244 bios_golden_init(dc
);
246 for (i
= 0; i
< dc
->link_count
; i
++) {
247 /* Power up AND update implementation according to the
248 * required signal (which may be different from the
249 * default signal on connector).
251 struct core_link
*link
= dc
->links
[i
];
253 link
->link_enc
->funcs
->hw_init(link
->link_enc
);
256 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
257 struct transform
*xfm
= dc
->res_pool
->transforms
[i
];
258 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[i
];
259 struct mpcc
*mpcc
= dc
->res_pool
->mpcc
[i
];
260 struct mpcc_cfg mpcc_cfg
;
262 xfm
->funcs
->transform_reset(xfm
);
263 mpcc_cfg
.opp_id
= 0xf;
264 mpcc_cfg
.top_dpp_id
= 0xf;
265 mpcc_cfg
.bot_mpcc_id
= 0xf;
266 mpcc_cfg
.top_of_tree
= true;
267 mpcc
->funcs
->set(mpcc
, &mpcc_cfg
);
269 tg
->funcs
->disable_vga(tg
);
270 /* Blank controller using driver code instead of
273 tg
->funcs
->set_blank(tg
, true);
274 hwss_wait_for_blank_complete(tg
);
277 for (i
= 0; i
< dc
->res_pool
->audio_count
; i
++) {
278 struct audio
*audio
= dc
->res_pool
->audios
[i
];
280 audio
->funcs
->hw_init(audio
);
284 abm
->funcs
->init_backlight(abm
);
285 abm
->funcs
->abm_init(abm
);
288 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
289 REG_WRITE(DIO_MEM_PWR_CTRL
, 0);
291 if (!dc
->public.debug
.disable_clock_gate
) {
292 /* enable all DCN clock gating */
293 REG_WRITE(DCCG_GATE_DISABLE_CNTL
, 0);
295 REG_WRITE(DCCG_GATE_DISABLE_CNTL2
, 0);
297 REG_UPDATE(DCFCLK_CNTL
, DCFCLK_GATE_DIS
, 0);
300 enable_power_gating_plane(dc
->hwseq
, true);
303 static enum dc_status
dcn10_prog_pixclk_crtc_otg(
304 struct pipe_ctx
*pipe_ctx
,
305 struct validate_context
*context
,
308 struct core_stream
*stream
= pipe_ctx
->stream
;
309 enum dc_color_space color_space
;
310 struct tg_color black_color
= {0};
311 bool enableStereo
= stream
->public.timing
.timing_3d_format
== TIMING_3D_FORMAT_NONE
?
313 bool rightEyePolarity
= stream
->public.timing
.flags
.RIGHT_EYE_3D_POLARITY
;
316 /* by upper caller loop, pipe0 is parent pipe and be called first.
317 * back end is set up by for pipe0. Other children pipe share back end
318 * with pipe 0. No program is needed.
320 if (pipe_ctx
->top_pipe
!= NULL
)
323 /* TODO check if timing_changed, disable stream if timing changed */
325 /* HW program guide assume display already disable
326 * by unplug sequence. OTG assume stop.
328 pipe_ctx
->tg
->funcs
->enable_optc_clock(pipe_ctx
->tg
, true);
330 if (false == pipe_ctx
->clock_source
->funcs
->program_pix_clk(
331 pipe_ctx
->clock_source
,
332 &pipe_ctx
->pix_clk_params
,
333 &pipe_ctx
->pll_settings
)) {
335 return DC_ERROR_UNEXPECTED
;
337 pipe_ctx
->tg
->dlg_otg_param
.vready_offset
= pipe_ctx
->pipe_dlg_param
.vready_offset
;
338 pipe_ctx
->tg
->dlg_otg_param
.vstartup_start
= pipe_ctx
->pipe_dlg_param
.vstartup_start
;
339 pipe_ctx
->tg
->dlg_otg_param
.vupdate_offset
= pipe_ctx
->pipe_dlg_param
.vupdate_offset
;
340 pipe_ctx
->tg
->dlg_otg_param
.vupdate_width
= pipe_ctx
->pipe_dlg_param
.vupdate_width
;
342 pipe_ctx
->tg
->dlg_otg_param
.signal
= pipe_ctx
->stream
->signal
;
344 pipe_ctx
->tg
->funcs
->program_timing(
346 &stream
->public.timing
,
349 pipe_ctx
->opp
->funcs
->opp_set_stereo_polarity(
354 #if 0 /* move to after enable_crtc */
355 /* TODO: OPP FMT, ABM. etc. should be done here. */
356 /* or FPGA now. instance 0 only. TODO: move to opp.c */
358 inst_offset
= reg_offsets
[pipe_ctx
->tg
->inst
].fmt
;
360 pipe_ctx
->opp
->funcs
->opp_program_fmt(
362 &stream
->bit_depth_params
,
365 /* program otg blank color */
366 color_space
= stream
->public.output_color_space
;
367 color_space_to_black_color(dc
, color_space
, &black_color
);
368 pipe_ctx
->tg
->funcs
->set_blank_color(
372 pipe_ctx
->tg
->funcs
->set_blank(pipe_ctx
->tg
, true);
373 hwss_wait_for_blank_complete(pipe_ctx
->tg
);
375 /* VTG is within DCHUB command block. DCFCLK is always on */
376 if (false == pipe_ctx
->tg
->funcs
->enable_crtc(pipe_ctx
->tg
)) {
378 return DC_ERROR_UNEXPECTED
;
381 /* TODO program crtc source select for non-virtual signal*/
382 /* TODO program FMT */
383 /* TODO setup link_enc */
384 /* TODO set stream attributes */
385 /* TODO program audio */
386 /* TODO enable stream if timing changed */
387 /* TODO unblank stream if DP */
392 static void reset_back_end_for_pipe(
394 struct pipe_ctx
*pipe_ctx
,
395 struct validate_context
*context
)
399 if (pipe_ctx
->stream_enc
== NULL
) {
400 pipe_ctx
->stream
= NULL
;
404 /* TODOFPGA break core_link_disable_stream into 2 functions:
405 * disable_stream and disable_link. disable_link will disable PHYPLL
406 * which is used by otg. Move disable_link after disable_crtc
408 if (!IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
409 core_link_disable_stream(pipe_ctx
);
411 /* by upper caller loop, parent pipe: pipe0, will be reset last.
412 * back end share by all pipes and will be disable only when disable
415 if (pipe_ctx
->top_pipe
== NULL
) {
416 pipe_ctx
->tg
->funcs
->disable_crtc(pipe_ctx
->tg
);
418 pipe_ctx
->tg
->funcs
->enable_optc_clock(pipe_ctx
->tg
, false);
421 if (!IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
422 resource_unreference_clock_source(
423 &context
->res_ctx
, dc
->res_pool
,
424 &pipe_ctx
->clock_source
);
426 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
427 if (&dc
->current_context
->res_ctx
.pipe_ctx
[i
] == pipe_ctx
)
430 if (i
== dc
->res_pool
->pipe_count
)
433 pipe_ctx
->stream
= NULL
;
434 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
435 "Reset back end for pipe %d, tg:%d\n",
436 pipe_ctx
->pipe_idx
, pipe_ctx
->tg
->inst
);
439 static void plane_atomic_stop(
443 struct mpcc_cfg mpcc_cfg
;
444 struct mem_input
*mi
= dc
->res_pool
->mis
[fe_idx
];
445 struct transform
*xfm
= dc
->res_pool
->transforms
[fe_idx
];
446 struct mpcc
*mpcc
= dc
->res_pool
->mpcc
[fe_idx
];
447 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[mpcc
->opp_id
];
449 mi
->funcs
->dcc_control(mi
, false, false);
451 mpcc_cfg
.opp_id
= 0xf;
452 mpcc_cfg
.top_dpp_id
= 0xf;
453 mpcc_cfg
.bot_mpcc_id
= 0xf;
454 mpcc_cfg
.top_of_tree
= tg
->inst
== mpcc
->inst
;
455 mpcc
->funcs
->set(mpcc
, &mpcc_cfg
);
457 xfm
->funcs
->transform_reset(xfm
);
460 static void reset_front_end(
464 struct dce_hwseq
*hws
= dc
->hwseq
;
465 struct mem_input
*mi
= dc
->res_pool
->mis
[fe_idx
];
466 struct mpcc
*mpcc
= dc
->res_pool
->mpcc
[fe_idx
];
467 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[mpcc
->opp_id
];
468 unsigned int opp_id
= mpcc
->opp_id
;
476 plane_atomic_stop(dc
, fe_idx
);
478 REG_UPDATE(OTG_GLOBAL_SYNC_STATUS
[tg
->inst
], VUPDATE_NO_LOCK_EVENT_CLEAR
, 1);
479 tg
->funcs
->unlock(tg
);
480 REG_WAIT(OTG_GLOBAL_SYNC_STATUS
[tg
->inst
], VUPDATE_NO_LOCK_EVENT_OCCURRED
, 1, 20000, 200000);
482 mpcc
->funcs
->wait_for_idle(mpcc
);
484 mi
->funcs
->set_blank(mi
, true);
486 REG_UPDATE(HUBP_CLK_CNTL
[fe_idx
],
487 HUBP_CLOCK_ENABLE
, 0);
488 REG_UPDATE(DPP_CONTROL
[fe_idx
],
489 DPP_CLOCK_ENABLE
, 0);
491 if (tg
->inst
== mpcc
->inst
)
492 REG_UPDATE(OPP_PIPE_CONTROL
[opp_id
],
493 OPP_PIPE_CLOCK_EN
, 0);
495 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
496 "Reset front end %d\n",
500 static void dcn10_power_down_fe(struct core_dc
*dc
, int fe_idx
)
502 struct dce_hwseq
*hws
= dc
->hwseq
;
504 reset_front_end(dc
, fe_idx
);
506 REG_SET(DC_IP_REQUEST_CNTL
, 0,
508 dpp_pg_control(hws
, fe_idx
, false);
509 hubp_pg_control(hws
, fe_idx
, false);
510 REG_SET(DC_IP_REQUEST_CNTL
, 0,
512 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
513 "Power gated front end %d\n", fe_idx
);
516 static void reset_hw_ctx_wrap(
518 struct validate_context
*context
)
523 for (i
= dc
->res_pool
->pipe_count
- 1; i
>= 0 ; i
--) {
524 struct pipe_ctx
*pipe_ctx_old
=
525 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
526 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
528 /*if (!pipe_ctx_old->stream)
531 if (!pipe_ctx
->stream
|| !pipe_ctx
->surface
)
532 dcn10_power_down_fe(dc
, i
);
533 else if (pipe_need_reprogram(pipe_ctx_old
, pipe_ctx
))
534 reset_front_end(dc
, i
);
537 for (i
= dc
->res_pool
->pipe_count
- 1; i
>= 0 ; i
--) {
538 struct pipe_ctx
*pipe_ctx_old
=
539 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
540 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
542 if (!pipe_ctx_old
->stream
)
545 if (!pipe_ctx
->stream
||
546 pipe_need_reprogram(pipe_ctx_old
, pipe_ctx
))
547 reset_back_end_for_pipe(dc
, pipe_ctx_old
, dc
->current_context
);
551 static bool patch_address_for_sbs_tb_stereo(
552 struct pipe_ctx
*pipe_ctx
, PHYSICAL_ADDRESS_LOC
*addr
)
554 struct core_surface
*surface
= pipe_ctx
->surface
;
555 bool sec_split
= pipe_ctx
->top_pipe
&&
556 pipe_ctx
->top_pipe
->surface
== pipe_ctx
->surface
;
557 if (sec_split
&& surface
->public.address
.type
== PLN_ADDR_TYPE_GRPH_STEREO
&&
558 (pipe_ctx
->stream
->public.timing
.timing_3d_format
==
559 TIMING_3D_FORMAT_SIDE_BY_SIDE
||
560 pipe_ctx
->stream
->public.timing
.timing_3d_format
==
561 TIMING_3D_FORMAT_TOP_AND_BOTTOM
)) {
562 *addr
= surface
->public.address
.grph_stereo
.left_addr
;
563 surface
->public.address
.grph_stereo
.left_addr
=
564 surface
->public.address
.grph_stereo
.right_addr
;
567 if (pipe_ctx
->stream
->public.view_format
!= VIEW_3D_FORMAT_NONE
&&
568 surface
->public.address
.type
!= PLN_ADDR_TYPE_GRPH_STEREO
) {
569 surface
->public.address
.type
= PLN_ADDR_TYPE_GRPH_STEREO
;
570 surface
->public.address
.grph_stereo
.right_addr
=
571 surface
->public.address
.grph_stereo
.left_addr
;
577 static void update_plane_addr(const struct core_dc
*dc
, struct pipe_ctx
*pipe_ctx
)
579 bool addr_patched
= false;
580 PHYSICAL_ADDRESS_LOC addr
;
581 struct core_surface
*surface
= pipe_ctx
->surface
;
585 addr_patched
= patch_address_for_sbs_tb_stereo(pipe_ctx
, &addr
);
586 pipe_ctx
->mi
->funcs
->mem_input_program_surface_flip_and_addr(
588 &surface
->public.address
,
589 surface
->public.flip_immediate
);
590 surface
->status
.requested_address
= surface
->public.address
;
592 pipe_ctx
->surface
->public.address
.grph_stereo
.left_addr
= addr
;
595 static bool dcn10_set_input_transfer_func(
596 struct pipe_ctx
*pipe_ctx
, const struct core_surface
*surface
)
598 struct input_pixel_processor
*ipp
= pipe_ctx
->ipp
;
599 const struct dc_transfer_func
*tf
= NULL
;
605 if (surface
->public.in_transfer_func
)
606 tf
= surface
->public.in_transfer_func
;
608 if (surface
->public.gamma_correction
&& dce_use_lut(surface
))
609 ipp
->funcs
->ipp_program_input_lut(ipp
,
610 surface
->public.gamma_correction
);
613 ipp
->funcs
->ipp_set_degamma(ipp
, IPP_DEGAMMA_MODE_BYPASS
);
614 else if (tf
->type
== TF_TYPE_PREDEFINED
) {
616 case TRANSFER_FUNCTION_SRGB
:
617 ipp
->funcs
->ipp_set_degamma(ipp
,
618 IPP_DEGAMMA_MODE_HW_sRGB
);
620 case TRANSFER_FUNCTION_BT709
:
621 ipp
->funcs
->ipp_set_degamma(ipp
,
622 IPP_DEGAMMA_MODE_HW_xvYCC
);
624 case TRANSFER_FUNCTION_LINEAR
:
625 ipp
->funcs
->ipp_set_degamma(ipp
,
626 IPP_DEGAMMA_MODE_BYPASS
);
628 case TRANSFER_FUNCTION_PQ
:
635 } else if (tf
->type
== TF_TYPE_BYPASS
) {
636 ipp
->funcs
->ipp_set_degamma(ipp
, IPP_DEGAMMA_MODE_BYPASS
);
638 /*TF_TYPE_DISTRIBUTED_POINTS*/
644 /*modify the method to handle rgb for arr_points*/
645 static bool convert_to_custom_float(
646 struct pwl_result_data
*rgb_resulted
,
647 struct curve_points
*arr_points
,
648 uint32_t hw_points_num
)
650 struct custom_float_format fmt
;
652 struct pwl_result_data
*rgb
= rgb_resulted
;
656 fmt
.exponenta_bits
= 6;
657 fmt
.mantissa_bits
= 12;
660 if (!convert_to_custom_float_format(
663 &arr_points
[0].custom_float_x
)) {
668 if (!convert_to_custom_float_format(
669 arr_points
[0].offset
,
671 &arr_points
[0].custom_float_offset
)) {
676 if (!convert_to_custom_float_format(
679 &arr_points
[0].custom_float_slope
)) {
684 fmt
.mantissa_bits
= 10;
687 if (!convert_to_custom_float_format(
690 &arr_points
[1].custom_float_x
)) {
695 if (!convert_to_custom_float_format(
698 &arr_points
[1].custom_float_y
)) {
703 if (!convert_to_custom_float_format(
706 &arr_points
[1].custom_float_slope
)) {
711 fmt
.mantissa_bits
= 12;
714 while (i
!= hw_points_num
) {
715 if (!convert_to_custom_float_format(
723 if (!convert_to_custom_float_format(
731 if (!convert_to_custom_float_format(
739 if (!convert_to_custom_float_format(
742 &rgb
->delta_red_reg
)) {
747 if (!convert_to_custom_float_format(
750 &rgb
->delta_green_reg
)) {
755 if (!convert_to_custom_float_format(
758 &rgb
->delta_blue_reg
)) {
769 #define MAX_REGIONS_NUMBER 34
770 #define MAX_LOW_POINT 25
771 #define NUMBER_SEGMENTS 32
773 static bool dcn10_translate_regamma_to_hw_format(const struct dc_transfer_func
774 *output_tf
, struct pwl_params
*regamma_params
)
776 struct curve_points
*arr_points
;
777 struct pwl_result_data
*rgb_resulted
;
778 struct pwl_result_data
*rgb
;
779 struct pwl_result_data
*rgb_plus_1
;
780 struct fixed31_32 y_r
;
781 struct fixed31_32 y_g
;
782 struct fixed31_32 y_b
;
783 struct fixed31_32 y1_min
;
784 struct fixed31_32 y3_max
;
786 int32_t segment_start
, segment_end
;
788 uint32_t j
, k
, seg_distr
[MAX_REGIONS_NUMBER
], increment
, start_index
, hw_points
;
790 if (output_tf
== NULL
|| regamma_params
== NULL
||
791 output_tf
->type
== TF_TYPE_BYPASS
)
794 arr_points
= regamma_params
->arr_points
;
795 rgb_resulted
= regamma_params
->rgb_resulted
;
798 memset(regamma_params
, 0, sizeof(struct pwl_params
));
799 memset(seg_distr
, 0, sizeof(seg_distr
));
801 if (output_tf
->tf
== TRANSFER_FUNCTION_PQ
) {
803 * segments are from 2^-25 to 2^7
805 for (i
= 0; i
< 32 ; i
++)
812 * segment is from 2^-10 to 2^0
813 * There are less than 256 points, for optimization
830 for (i
= segment_end
- segment_start
; i
< MAX_REGIONS_NUMBER
; i
++)
833 for (k
= 0; k
< MAX_REGIONS_NUMBER
; k
++) {
834 if (seg_distr
[k
] != -1)
835 hw_points
+= (1 << seg_distr
[k
]);
839 for (k
= 0; k
< (segment_end
- segment_start
); k
++) {
840 increment
= NUMBER_SEGMENTS
/ (1 << seg_distr
[k
]);
841 start_index
= (segment_start
+ k
+ MAX_LOW_POINT
) * NUMBER_SEGMENTS
;
842 for (i
= start_index
; i
< start_index
+ NUMBER_SEGMENTS
; i
+= increment
) {
843 if (j
== hw_points
- 1)
845 rgb_resulted
[j
].red
= output_tf
->tf_pts
.red
[i
];
846 rgb_resulted
[j
].green
= output_tf
->tf_pts
.green
[i
];
847 rgb_resulted
[j
].blue
= output_tf
->tf_pts
.blue
[i
];
853 start_index
= (segment_end
+ MAX_LOW_POINT
) * NUMBER_SEGMENTS
;
854 rgb_resulted
[hw_points
- 1].red
=
855 output_tf
->tf_pts
.red
[start_index
];
856 rgb_resulted
[hw_points
- 1].green
=
857 output_tf
->tf_pts
.green
[start_index
];
858 rgb_resulted
[hw_points
- 1].blue
=
859 output_tf
->tf_pts
.blue
[start_index
];
861 arr_points
[0].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
862 dal_fixed31_32_from_int(segment_start
));
863 arr_points
[1].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
864 dal_fixed31_32_from_int(segment_end
));
865 arr_points
[2].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
866 dal_fixed31_32_from_int(segment_end
));
868 y_r
= rgb_resulted
[0].red
;
869 y_g
= rgb_resulted
[0].green
;
870 y_b
= rgb_resulted
[0].blue
;
872 y1_min
= dal_fixed31_32_min(y_r
, dal_fixed31_32_min(y_g
, y_b
));
874 arr_points
[0].y
= y1_min
;
875 arr_points
[0].slope
= dal_fixed31_32_div(
878 y_r
= rgb_resulted
[hw_points
- 1].red
;
879 y_g
= rgb_resulted
[hw_points
- 1].green
;
880 y_b
= rgb_resulted
[hw_points
- 1].blue
;
882 /* see comment above, m_arrPoints[1].y should be the Y value for the
883 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
885 y3_max
= dal_fixed31_32_max(y_r
, dal_fixed31_32_max(y_g
, y_b
));
887 arr_points
[1].y
= y3_max
;
888 arr_points
[2].y
= y3_max
;
890 arr_points
[1].slope
= dal_fixed31_32_zero
;
891 arr_points
[2].slope
= dal_fixed31_32_zero
;
893 if (output_tf
->tf
== TRANSFER_FUNCTION_PQ
) {
894 /* for PQ, we want to have a straight line from last HW X point,
895 * and the slope to be such that we hit 1.0 at 10000 nits.
897 const struct fixed31_32 end_value
=
898 dal_fixed31_32_from_int(125);
900 arr_points
[1].slope
= dal_fixed31_32_div(
901 dal_fixed31_32_sub(dal_fixed31_32_one
, arr_points
[1].y
),
902 dal_fixed31_32_sub(end_value
, arr_points
[1].x
));
903 arr_points
[2].slope
= dal_fixed31_32_div(
904 dal_fixed31_32_sub(dal_fixed31_32_one
, arr_points
[1].y
),
905 dal_fixed31_32_sub(end_value
, arr_points
[1].x
));
908 regamma_params
->hw_points_num
= hw_points
;
911 for (k
= 0; k
< MAX_REGIONS_NUMBER
&& i
< MAX_REGIONS_NUMBER
; k
++) {
912 if (seg_distr
[k
] != -1) {
913 regamma_params
->arr_curve_points
[k
].segments_num
=
915 regamma_params
->arr_curve_points
[i
].offset
=
916 regamma_params
->arr_curve_points
[k
].
917 offset
+ (1 << seg_distr
[k
]);
922 if (seg_distr
[k
] != -1)
923 regamma_params
->arr_curve_points
[k
].segments_num
=
927 rgb_plus_1
= rgb_resulted
+ 1;
931 while (i
!= hw_points
+ 1) {
932 if (dal_fixed31_32_lt(rgb_plus_1
->red
, rgb
->red
))
933 rgb_plus_1
->red
= rgb
->red
;
934 if (dal_fixed31_32_lt(rgb_plus_1
->green
, rgb
->green
))
935 rgb_plus_1
->green
= rgb
->green
;
936 if (dal_fixed31_32_lt(rgb_plus_1
->blue
, rgb
->blue
))
937 rgb_plus_1
->blue
= rgb
->blue
;
939 rgb
->delta_red
= dal_fixed31_32_sub(
942 rgb
->delta_green
= dal_fixed31_32_sub(
945 rgb
->delta_blue
= dal_fixed31_32_sub(
954 convert_to_custom_float(rgb_resulted
, arr_points
, hw_points
);
959 static bool dcn10_set_output_transfer_func(
960 struct pipe_ctx
*pipe_ctx
,
961 const struct core_stream
*stream
)
963 struct output_pixel_processor
*opp
= pipe_ctx
->opp
;
968 opp
->regamma_params
.hw_points_num
= GAMMA_HW_POINTS_NUM
;
970 if (stream
->public.out_transfer_func
&&
971 stream
->public.out_transfer_func
->type
==
972 TF_TYPE_PREDEFINED
&&
973 stream
->public.out_transfer_func
->tf
==
974 TRANSFER_FUNCTION_SRGB
) {
975 opp
->funcs
->opp_set_regamma_mode(opp
, OPP_REGAMMA_SRGB
);
976 } else if (dcn10_translate_regamma_to_hw_format(
977 stream
->public.out_transfer_func
, &opp
->regamma_params
)) {
978 opp
->funcs
->opp_program_regamma_pwl(opp
, &opp
->regamma_params
);
979 opp
->funcs
->opp_set_regamma_mode(opp
, OPP_REGAMMA_USER
);
981 opp
->funcs
->opp_set_regamma_mode(opp
, OPP_REGAMMA_BYPASS
);
987 static void dcn10_pipe_control_lock(
989 struct pipe_ctx
*pipe
,
992 /* use TG master update lock to lock everything on the TG
993 * therefore only top pipe need to lock
999 pipe
->tg
->funcs
->lock(pipe
->tg
);
1001 pipe
->tg
->funcs
->unlock(pipe
->tg
);
1004 static bool wait_for_reset_trigger_to_occur(
1005 struct dc_context
*dc_ctx
,
1006 struct timing_generator
*tg
)
1010 /* To avoid endless loop we wait at most
1011 * frames_to_wait_on_triggered_reset frames for the reset to occur. */
1012 const uint32_t frames_to_wait_on_triggered_reset
= 10;
1015 for (i
= 0; i
< frames_to_wait_on_triggered_reset
; i
++) {
1017 if (!tg
->funcs
->is_counter_moving(tg
)) {
1018 DC_ERROR("TG counter is not moving!\n");
1022 if (tg
->funcs
->did_triggered_reset_occur(tg
)) {
1024 /* usually occurs at i=1 */
1025 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
1030 /* Wait for one frame. */
1031 tg
->funcs
->wait_for_state(tg
, CRTC_STATE_VACTIVE
);
1032 tg
->funcs
->wait_for_state(tg
, CRTC_STATE_VBLANK
);
1036 DC_ERROR("GSL: Timeout on reset trigger!\n");
1041 static void dcn10_enable_timing_synchronization(
1045 struct pipe_ctx
*grouped_pipes
[])
1047 struct dc_context
*dc_ctx
= dc
->ctx
;
1050 DC_SYNC_INFO("Setting up OTG reset trigger\n");
1052 for (i
= 1; i
< group_size
; i
++)
1053 grouped_pipes
[i
]->tg
->funcs
->enable_reset_trigger(
1054 grouped_pipes
[i
]->tg
, grouped_pipes
[0]->tg
->inst
);
1057 DC_SYNC_INFO("Waiting for trigger\n");
1059 /* Need to get only check 1 pipe for having reset as all the others are
1060 * synchronized. Look at last pipe programmed to reset.
1062 wait_for_reset_trigger_to_occur(dc_ctx
, grouped_pipes
[1]->tg
);
1063 for (i
= 1; i
< group_size
; i
++)
1064 grouped_pipes
[i
]->tg
->funcs
->disable_reset_trigger(
1065 grouped_pipes
[i
]->tg
);
1067 DC_SYNC_INFO("Sync complete\n");
1070 static void print_rq_dlg_ttu(
1071 struct core_dc
*core_dc
,
1072 struct pipe_ctx
*pipe_ctx
)
1074 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1075 "\n============== DML TTU Output parameters [%d] ==============\n"
1076 "qos_level_low_wm: %d, \n"
1077 "qos_level_high_wm: %d, \n"
1078 "min_ttu_vblank: %d, \n"
1079 "qos_level_flip: %d, \n"
1080 "refcyc_per_req_delivery_l: %d, \n"
1081 "qos_level_fixed_l: %d, \n"
1082 "qos_ramp_disable_l: %d, \n"
1083 "refcyc_per_req_delivery_pre_l: %d, \n"
1084 "refcyc_per_req_delivery_c: %d, \n"
1085 "qos_level_fixed_c: %d, \n"
1086 "qos_ramp_disable_c: %d, \n"
1087 "refcyc_per_req_delivery_pre_c: %d\n"
1088 "=============================================================\n",
1090 pipe_ctx
->ttu_regs
.qos_level_low_wm
,
1091 pipe_ctx
->ttu_regs
.qos_level_high_wm
,
1092 pipe_ctx
->ttu_regs
.min_ttu_vblank
,
1093 pipe_ctx
->ttu_regs
.qos_level_flip
,
1094 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_l
,
1095 pipe_ctx
->ttu_regs
.qos_level_fixed_l
,
1096 pipe_ctx
->ttu_regs
.qos_ramp_disable_l
,
1097 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_pre_l
,
1098 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_c
,
1099 pipe_ctx
->ttu_regs
.qos_level_fixed_c
,
1100 pipe_ctx
->ttu_regs
.qos_ramp_disable_c
,
1101 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_pre_c
1104 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1105 "\n============== DML DLG Output parameters [%d] ==============\n"
1106 "refcyc_h_blank_end: %d, \n"
1107 "dlg_vblank_end: %d, \n"
1108 "min_dst_y_next_start: %d, \n"
1109 "refcyc_per_htotal: %d, \n"
1110 "refcyc_x_after_scaler: %d, \n"
1111 "dst_y_after_scaler: %d, \n"
1112 "dst_y_prefetch: %d, \n"
1113 "dst_y_per_vm_vblank: %d, \n"
1114 "dst_y_per_row_vblank: %d, \n"
1115 "ref_freq_to_pix_freq: %d, \n"
1116 "vratio_prefetch: %d, \n"
1117 "refcyc_per_pte_group_vblank_l: %d, \n"
1118 "refcyc_per_meta_chunk_vblank_l: %d, \n"
1119 "dst_y_per_pte_row_nom_l: %d, \n"
1120 "refcyc_per_pte_group_nom_l: %d, \n",
1122 pipe_ctx
->dlg_regs
.refcyc_h_blank_end
,
1123 pipe_ctx
->dlg_regs
.dlg_vblank_end
,
1124 pipe_ctx
->dlg_regs
.min_dst_y_next_start
,
1125 pipe_ctx
->dlg_regs
.refcyc_per_htotal
,
1126 pipe_ctx
->dlg_regs
.refcyc_x_after_scaler
,
1127 pipe_ctx
->dlg_regs
.dst_y_after_scaler
,
1128 pipe_ctx
->dlg_regs
.dst_y_prefetch
,
1129 pipe_ctx
->dlg_regs
.dst_y_per_vm_vblank
,
1130 pipe_ctx
->dlg_regs
.dst_y_per_row_vblank
,
1131 pipe_ctx
->dlg_regs
.ref_freq_to_pix_freq
,
1132 pipe_ctx
->dlg_regs
.vratio_prefetch
,
1133 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_vblank_l
,
1134 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_vblank_l
,
1135 pipe_ctx
->dlg_regs
.dst_y_per_pte_row_nom_l
,
1136 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_nom_l
1139 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1140 "\ndst_y_per_meta_row_nom_l: %d, \n"
1141 "refcyc_per_meta_chunk_nom_l: %d, \n"
1142 "refcyc_per_line_delivery_pre_l: %d, \n"
1143 "refcyc_per_line_delivery_l: %d, \n"
1144 "vratio_prefetch_c: %d, \n"
1145 "refcyc_per_pte_group_vblank_c: %d, \n"
1146 "refcyc_per_meta_chunk_vblank_c: %d, \n"
1147 "dst_y_per_pte_row_nom_c: %d, \n"
1148 "refcyc_per_pte_group_nom_c: %d, \n"
1149 "dst_y_per_meta_row_nom_c: %d, \n"
1150 "refcyc_per_meta_chunk_nom_c: %d, \n"
1151 "refcyc_per_line_delivery_pre_c: %d, \n"
1152 "refcyc_per_line_delivery_c: %d \n"
1153 "========================================================\n",
1154 pipe_ctx
->dlg_regs
.dst_y_per_meta_row_nom_l
,
1155 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_nom_l
,
1156 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_pre_l
,
1157 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_l
,
1158 pipe_ctx
->dlg_regs
.vratio_prefetch_c
,
1159 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_vblank_c
,
1160 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_vblank_c
,
1161 pipe_ctx
->dlg_regs
.dst_y_per_pte_row_nom_c
,
1162 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_nom_c
,
1163 pipe_ctx
->dlg_regs
.dst_y_per_meta_row_nom_c
,
1164 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_nom_c
,
1165 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_pre_c
,
1166 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_c
1169 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1170 "\n============== DML RQ Output parameters [%d] ==============\n"
1172 "min_chunk_size: %d \n"
1173 "meta_chunk_size: %d \n"
1174 "min_meta_chunk_size: %d \n"
1175 "dpte_group_size: %d \n"
1176 "mpte_group_size: %d \n"
1177 "swath_height: %d \n"
1178 "pte_row_height_linear: %d \n"
1179 "========================================================\n",
1181 pipe_ctx
->rq_regs
.rq_regs_l
.chunk_size
,
1182 pipe_ctx
->rq_regs
.rq_regs_l
.min_chunk_size
,
1183 pipe_ctx
->rq_regs
.rq_regs_l
.meta_chunk_size
,
1184 pipe_ctx
->rq_regs
.rq_regs_l
.min_meta_chunk_size
,
1185 pipe_ctx
->rq_regs
.rq_regs_l
.dpte_group_size
,
1186 pipe_ctx
->rq_regs
.rq_regs_l
.mpte_group_size
,
1187 pipe_ctx
->rq_regs
.rq_regs_l
.swath_height
,
1188 pipe_ctx
->rq_regs
.rq_regs_l
.pte_row_height_linear
1192 static void dcn10_power_on_fe(
1194 struct pipe_ctx
*pipe_ctx
,
1195 struct validate_context
*context
)
1197 struct dc_surface
*dc_surface
= &pipe_ctx
->surface
->public;
1198 struct dce_hwseq
*hws
= dc
->hwseq
;
1200 power_on_plane(dc
->hwseq
,
1201 pipe_ctx
->pipe_idx
);
1203 /* enable DCFCLK current DCHUB */
1204 REG_UPDATE(HUBP_CLK_CNTL
[pipe_ctx
->pipe_idx
],
1205 HUBP_CLOCK_ENABLE
, 1);
1207 /* make sure OPP_PIPE_CLOCK_EN = 1 */
1208 REG_UPDATE(OPP_PIPE_CONTROL
[pipe_ctx
->tg
->inst
],
1209 OPP_PIPE_CLOCK_EN
, 1);
1212 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
1213 "Pipe:%d 0x%x: addr hi:0x%x, "
1216 " %d; dst: %d, %d, %d, %d;\n",
1219 dc_surface
->address
.grph
.addr
.high_part
,
1220 dc_surface
->address
.grph
.addr
.low_part
,
1221 dc_surface
->src_rect
.x
,
1222 dc_surface
->src_rect
.y
,
1223 dc_surface
->src_rect
.width
,
1224 dc_surface
->src_rect
.height
,
1225 dc_surface
->dst_rect
.x
,
1226 dc_surface
->dst_rect
.y
,
1227 dc_surface
->dst_rect
.width
,
1228 dc_surface
->dst_rect
.height
);
1230 dm_logger_write(dc
->ctx
->logger
, LOG_HW_SET_MODE
,
1231 "Pipe %d: width, height, x, y\n"
1232 "viewport:%d, %d, %d, %d\n"
1233 "recout: %d, %d, %d, %d\n",
1235 pipe_ctx
->scl_data
.viewport
.width
,
1236 pipe_ctx
->scl_data
.viewport
.height
,
1237 pipe_ctx
->scl_data
.viewport
.x
,
1238 pipe_ctx
->scl_data
.viewport
.y
,
1239 pipe_ctx
->scl_data
.recout
.width
,
1240 pipe_ctx
->scl_data
.recout
.height
,
1241 pipe_ctx
->scl_data
.recout
.x
,
1242 pipe_ctx
->scl_data
.recout
.y
);
1243 print_rq_dlg_ttu(dc
, pipe_ctx
);
1247 static void program_gamut_remap(struct pipe_ctx
*pipe_ctx
)
1249 struct xfm_grph_csc_adjustment adjust
;
1250 memset(&adjust
, 0, sizeof(adjust
));
1251 adjust
.gamut_adjust_type
= GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS
;
1254 if (pipe_ctx
->stream
->public.gamut_remap_matrix
.enable_remap
== true) {
1255 adjust
.gamut_adjust_type
= GRAPHICS_GAMUT_ADJUST_TYPE_SW
;
1256 adjust
.temperature_matrix
[0] =
1258 public.gamut_remap_matrix
.matrix
[0];
1259 adjust
.temperature_matrix
[1] =
1261 public.gamut_remap_matrix
.matrix
[1];
1262 adjust
.temperature_matrix
[2] =
1264 public.gamut_remap_matrix
.matrix
[2];
1265 adjust
.temperature_matrix
[3] =
1267 public.gamut_remap_matrix
.matrix
[4];
1268 adjust
.temperature_matrix
[4] =
1270 public.gamut_remap_matrix
.matrix
[5];
1271 adjust
.temperature_matrix
[5] =
1273 public.gamut_remap_matrix
.matrix
[6];
1274 adjust
.temperature_matrix
[6] =
1276 public.gamut_remap_matrix
.matrix
[8];
1277 adjust
.temperature_matrix
[7] =
1279 public.gamut_remap_matrix
.matrix
[9];
1280 adjust
.temperature_matrix
[8] =
1282 public.gamut_remap_matrix
.matrix
[10];
1285 pipe_ctx
->xfm
->funcs
->transform_set_gamut_remap(pipe_ctx
->xfm
, &adjust
);
1289 static void program_csc_matrix(struct pipe_ctx
*pipe_ctx
,
1290 enum dc_color_space colorspace
,
1294 struct out_csc_color_matrix tbl_entry
;
1296 if (pipe_ctx
->stream
->public.csc_color_matrix
.enable_adjustment
1298 enum dc_color_space color_space
=
1299 pipe_ctx
->stream
->public.output_color_space
;
1301 //uint16_t matrix[12];
1302 for (i
= 0; i
< 12; i
++)
1303 tbl_entry
.regval
[i
] = pipe_ctx
->stream
->public.csc_color_matrix
.matrix
[i
];
1305 tbl_entry
.color_space
= color_space
;
1306 //tbl_entry.regval = matrix;
1307 pipe_ctx
->opp
->funcs
->opp_set_csc_adjustment(pipe_ctx
->opp
, &tbl_entry
);
1310 static bool is_lower_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1312 if (pipe_ctx
->surface
->public.visible
)
1314 if (pipe_ctx
->bottom_pipe
&& is_lower_pipe_tree_visible(pipe_ctx
->bottom_pipe
))
1319 static bool is_upper_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1321 if (pipe_ctx
->surface
->public.visible
)
1323 if (pipe_ctx
->top_pipe
&& is_upper_pipe_tree_visible(pipe_ctx
->top_pipe
))
1328 static bool is_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1330 if (pipe_ctx
->surface
->public.visible
)
1332 if (pipe_ctx
->top_pipe
&& is_upper_pipe_tree_visible(pipe_ctx
->top_pipe
))
1334 if (pipe_ctx
->bottom_pipe
&& is_lower_pipe_tree_visible(pipe_ctx
->bottom_pipe
))
1339 static bool is_rgb_cspace(enum dc_color_space output_color_space
)
1341 switch (output_color_space
) {
1342 case COLOR_SPACE_SRGB
:
1343 case COLOR_SPACE_SRGB_LIMITED
:
1344 case COLOR_SPACE_2020_RGB_FULLRANGE
:
1345 case COLOR_SPACE_2020_RGB_LIMITEDRANGE
:
1346 case COLOR_SPACE_ADOBERGB
:
1348 case COLOR_SPACE_YCBCR601
:
1349 case COLOR_SPACE_YCBCR709
:
1350 case COLOR_SPACE_YCBCR601_LIMITED
:
1351 case COLOR_SPACE_YCBCR709_LIMITED
:
1352 case COLOR_SPACE_2020_YCBCR
:
1355 /* Add a case to switch */
1356 BREAK_TO_DEBUGGER();
1361 static void dcn10_get_surface_visual_confirm_color(
1362 const struct pipe_ctx
*pipe_ctx
,
1363 struct tg_color
*color
)
1365 uint32_t color_value
= MAX_TG_COLOR_VALUE
;
1367 switch (pipe_ctx
->scl_data
.format
) {
1368 case PIXEL_FORMAT_ARGB8888
:
1369 /* set boarder color to red */
1370 color
->color_r_cr
= color_value
;
1373 case PIXEL_FORMAT_ARGB2101010
:
1374 /* set boarder color to blue */
1375 color
->color_b_cb
= color_value
;
1377 case PIXEL_FORMAT_420BPP8
:
1378 /* set boarder color to green */
1379 color
->color_g_y
= color_value
;
1381 case PIXEL_FORMAT_420BPP10
:
1382 /* set boarder color to yellow */
1383 color
->color_g_y
= color_value
;
1384 color
->color_r_cr
= color_value
;
1386 case PIXEL_FORMAT_FP16
:
1387 /* set boarder color to white */
1388 color
->color_r_cr
= color_value
;
1389 color
->color_b_cb
= color_value
;
1390 color
->color_g_y
= color_value
;
1397 static void update_dchubp_dpp(
1399 struct pipe_ctx
*pipe_ctx
,
1400 struct validate_context
*context
)
1402 struct dce_hwseq
*hws
= dc
->hwseq
;
1403 struct mem_input
*mi
= pipe_ctx
->mi
;
1404 struct input_pixel_processor
*ipp
= pipe_ctx
->ipp
;
1405 struct core_surface
*surface
= pipe_ctx
->surface
;
1406 union plane_size size
= surface
->public.plane_size
;
1407 struct default_adjustment ocsc
= {0};
1408 struct tg_color black_color
= {0};
1409 struct mpcc_cfg mpcc_cfg
;
1410 bool per_pixel_alpha
= surface
->public.per_pixel_alpha
&& pipe_ctx
->bottom_pipe
;
1412 /* TODO: proper fix once fpga works */
1413 /* depends on DML calculation, DPP clock value may change dynamically */
1417 pipe_ctx
->pix_clk_params
.requested_pix_clk
,
1418 context
->bw
.dcn
.calc_clk
.dppclk_div
);
1419 dc
->current_context
->bw
.dcn
.cur_clk
.dppclk_div
=
1420 context
->bw
.dcn
.calc_clk
.dppclk_div
;
1421 context
->bw
.dcn
.cur_clk
.dppclk_div
= context
->bw
.dcn
.calc_clk
.dppclk_div
;
1423 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
1424 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
1425 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
1427 REG_UPDATE(DCHUBP_CNTL
[pipe_ctx
->pipe_idx
], HUBP_VTG_SEL
, pipe_ctx
->tg
->inst
);
1429 update_plane_addr(dc
, pipe_ctx
);
1431 mi
->funcs
->mem_input_setup(
1433 &pipe_ctx
->dlg_regs
,
1434 &pipe_ctx
->ttu_regs
,
1436 &pipe_ctx
->pipe_dlg_param
);
1438 size
.grph
.surface_size
= pipe_ctx
->scl_data
.viewport
;
1440 if (dc
->public.config
.gpu_vm_support
)
1441 mi
->funcs
->mem_input_program_pte_vm(
1443 surface
->public.format
,
1444 &surface
->public.tiling_info
,
1445 surface
->public.rotation
);
1447 ipp
->funcs
->ipp_setup(ipp
,
1448 surface
->public.format
,
1450 IPP_OUTPUT_FORMAT_12_BIT_FIX
);
1452 pipe_ctx
->scl_data
.lb_params
.alpha_en
= per_pixel_alpha
;
1453 mpcc_cfg
.top_dpp_id
= pipe_ctx
->pipe_idx
;
1454 if (pipe_ctx
->bottom_pipe
)
1455 mpcc_cfg
.bot_mpcc_id
= pipe_ctx
->bottom_pipe
->mpcc
->inst
;
1457 mpcc_cfg
.bot_mpcc_id
= 0xf;
1458 mpcc_cfg
.opp_id
= pipe_ctx
->tg
->inst
;
1459 mpcc_cfg
.top_of_tree
= pipe_ctx
->pipe_idx
== pipe_ctx
->tg
->inst
;
1460 mpcc_cfg
.per_pixel_alpha
= per_pixel_alpha
;
1461 /* DCN1.0 has output CM before MPC which seems to screw with
1462 * pre-multiplied alpha.
1464 mpcc_cfg
.pre_multiplied_alpha
= is_rgb_cspace(
1465 pipe_ctx
->stream
->public.output_color_space
)
1467 pipe_ctx
->mpcc
->funcs
->set(pipe_ctx
->mpcc
, &mpcc_cfg
);
1469 if (dc
->public.debug
.surface_visual_confirm
) {
1470 dcn10_get_surface_visual_confirm_color(pipe_ctx
, &black_color
);
1472 color_space_to_black_color(
1473 dc
, pipe_ctx
->stream
->public.output_color_space
,
1476 pipe_ctx
->mpcc
->funcs
->set_bg_color(pipe_ctx
->mpcc
, &black_color
);
1478 pipe_ctx
->scl_data
.lb_params
.depth
= LB_PIXEL_DEPTH_30BPP
;
1479 /* scaler configuration */
1480 pipe_ctx
->xfm
->funcs
->transform_set_scaler(
1481 pipe_ctx
->xfm
, &pipe_ctx
->scl_data
);
1482 mi
->funcs
->mem_program_viewport(mi
,
1483 &pipe_ctx
->scl_data
.viewport
, &pipe_ctx
->scl_data
.viewport_c
);
1486 program_gamut_remap(pipe_ctx
);
1488 /*TODO add adjustments parameters*/
1489 ocsc
.out_color_space
= pipe_ctx
->stream
->public.output_color_space
;
1490 pipe_ctx
->opp
->funcs
->opp_set_csc_default(pipe_ctx
->opp
, &ocsc
);
1492 mi
->funcs
->mem_input_program_surface_config(
1494 surface
->public.format
,
1495 &surface
->public.tiling_info
,
1497 surface
->public.rotation
,
1498 &surface
->public.dcc
,
1499 surface
->public.horizontal_mirror
);
1501 mi
->funcs
->set_blank(mi
, !is_pipe_tree_visible(pipe_ctx
));
1504 static void program_all_pipe_in_tree(
1506 struct pipe_ctx
*pipe_ctx
,
1507 struct validate_context
*context
)
1509 unsigned int ref_clk_mhz
= dc
->res_pool
->ref_clock_inKhz
/1000;
1511 if (pipe_ctx
->top_pipe
== NULL
) {
1513 /* lock otg_master_update to process all pipes associated with
1514 * this OTG. this is done only one time.
1516 /* watermark is for all pipes */
1517 pipe_ctx
->mi
->funcs
->program_watermarks(
1518 pipe_ctx
->mi
, &context
->bw
.dcn
.watermarks
, ref_clk_mhz
);
1519 pipe_ctx
->tg
->funcs
->lock(pipe_ctx
->tg
);
1521 pipe_ctx
->tg
->dlg_otg_param
.vready_offset
= pipe_ctx
->pipe_dlg_param
.vready_offset
;
1522 pipe_ctx
->tg
->dlg_otg_param
.vstartup_start
= pipe_ctx
->pipe_dlg_param
.vstartup_start
;
1523 pipe_ctx
->tg
->dlg_otg_param
.vupdate_offset
= pipe_ctx
->pipe_dlg_param
.vupdate_offset
;
1524 pipe_ctx
->tg
->dlg_otg_param
.vupdate_width
= pipe_ctx
->pipe_dlg_param
.vupdate_width
;
1525 pipe_ctx
->tg
->dlg_otg_param
.signal
= pipe_ctx
->stream
->signal
;
1527 pipe_ctx
->tg
->funcs
->program_global_sync(
1529 pipe_ctx
->tg
->funcs
->set_blank(pipe_ctx
->tg
, !is_pipe_tree_visible(pipe_ctx
));
1532 if (pipe_ctx
->surface
!= NULL
) {
1533 dcn10_power_on_fe(dc
, pipe_ctx
, context
);
1534 update_dchubp_dpp(dc
, pipe_ctx
, context
);
1537 if (pipe_ctx
->bottom_pipe
!= NULL
)
1538 program_all_pipe_in_tree(dc
, pipe_ctx
->bottom_pipe
, context
);
1541 static void dcn10_pplib_apply_display_requirements(
1543 struct validate_context
*context
)
1545 struct dm_pp_display_configuration
*pp_display_cfg
= &context
->pp_display_cfg
;
1547 pp_display_cfg
->all_displays_in_sync
= false;/*todo*/
1548 pp_display_cfg
->nb_pstate_switch_disable
= false;
1549 pp_display_cfg
->min_engine_clock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_khz
;
1550 pp_display_cfg
->min_memory_clock_khz
= context
->bw
.dcn
.cur_clk
.fclk_khz
;
1551 pp_display_cfg
->min_engine_clock_deep_sleep_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
;
1552 pp_display_cfg
->min_dcfc_deep_sleep_clock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
;
1553 pp_display_cfg
->avail_mclk_switch_time_us
=
1554 context
->bw
.dcn
.cur_clk
.dram_ccm_us
> 0 ? context
->bw
.dcn
.cur_clk
.dram_ccm_us
: 0;
1555 pp_display_cfg
->avail_mclk_switch_time_in_disp_active_us
=
1556 context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
> 0 ? context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
: 0;
1557 pp_display_cfg
->min_dcfclock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_khz
;
1558 pp_display_cfg
->disp_clk_khz
= context
->bw
.dcn
.cur_clk
.dispclk_khz
;
1559 dce110_fill_display_configs(context
, pp_display_cfg
);
1561 if (memcmp(&dc
->prev_display_config
, pp_display_cfg
, sizeof(
1562 struct dm_pp_display_configuration
)) != 0)
1563 dm_pp_apply_display_requirements(dc
->ctx
, pp_display_cfg
);
1565 dc
->prev_display_config
= *pp_display_cfg
;
1568 static void dcn10_apply_ctx_for_surface(
1570 struct core_surface
*surface
,
1571 struct validate_context
*context
)
1575 /* reset unused mpcc */
1576 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1577 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1578 struct pipe_ctx
*old_pipe_ctx
=
1579 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
1581 if ((!pipe_ctx
->surface
&& old_pipe_ctx
->surface
)
1582 || (!pipe_ctx
->stream
&& old_pipe_ctx
->stream
)) {
1583 struct mpcc_cfg mpcc_cfg
;
1584 int opp_id_cached
= old_pipe_ctx
->mpcc
->opp_id
;
1586 if (!old_pipe_ctx
->top_pipe
) {
1591 mpcc_cfg
.opp_id
= 0xf;
1592 mpcc_cfg
.top_dpp_id
= 0xf;
1593 mpcc_cfg
.bot_mpcc_id
= 0xf;
1594 mpcc_cfg
.top_of_tree
= !old_pipe_ctx
->top_pipe
;
1595 old_pipe_ctx
->mpcc
->funcs
->set(old_pipe_ctx
->mpcc
, &mpcc_cfg
);
1597 * the mpcc is the only thing that keeps track of the mpcc
1598 * mapping for reset front end right now. Might need some
1601 old_pipe_ctx
->mpcc
->opp_id
= opp_id_cached
;
1603 old_pipe_ctx
->top_pipe
= NULL
;
1604 old_pipe_ctx
->bottom_pipe
= NULL
;
1605 old_pipe_ctx
->surface
= NULL
;
1607 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
1608 "Reset mpcc for pipe %d\n",
1609 old_pipe_ctx
->pipe_idx
);
1616 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1617 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1619 if (pipe_ctx
->surface
!= surface
)
1622 /* looking for top pipe to program */
1623 if (!pipe_ctx
->top_pipe
)
1624 program_all_pipe_in_tree(dc
, pipe_ctx
, context
);
1627 dm_logger_write(dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1628 "\n============== Watermark parameters ==============\n"
1629 "a.urgent_ns: %d \n"
1630 "a.cstate_enter_plus_exit: %d \n"
1631 "a.cstate_exit: %d \n"
1632 "a.pstate_change: %d \n"
1633 "a.pte_meta_urgent: %d \n"
1634 "b.urgent_ns: %d \n"
1635 "b.cstate_enter_plus_exit: %d \n"
1636 "b.cstate_exit: %d \n"
1637 "b.pstate_change: %d \n"
1638 "b.pte_meta_urgent: %d \n",
1639 context
->bw
.dcn
.watermarks
.a
.urgent_ns
,
1640 context
->bw
.dcn
.watermarks
.a
.cstate_pstate
.cstate_enter_plus_exit_ns
,
1641 context
->bw
.dcn
.watermarks
.a
.cstate_pstate
.cstate_exit_ns
,
1642 context
->bw
.dcn
.watermarks
.a
.cstate_pstate
.pstate_change_ns
,
1643 context
->bw
.dcn
.watermarks
.a
.pte_meta_urgent_ns
,
1644 context
->bw
.dcn
.watermarks
.b
.urgent_ns
,
1645 context
->bw
.dcn
.watermarks
.b
.cstate_pstate
.cstate_enter_plus_exit_ns
,
1646 context
->bw
.dcn
.watermarks
.b
.cstate_pstate
.cstate_exit_ns
,
1647 context
->bw
.dcn
.watermarks
.b
.cstate_pstate
.pstate_change_ns
,
1648 context
->bw
.dcn
.watermarks
.b
.pte_meta_urgent_ns
1650 dm_logger_write(dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1651 "\nc.urgent_ns: %d \n"
1652 "c.cstate_enter_plus_exit: %d \n"
1653 "c.cstate_exit: %d \n"
1654 "c.pstate_change: %d \n"
1655 "c.pte_meta_urgent: %d \n"
1656 "d.urgent_ns: %d \n"
1657 "d.cstate_enter_plus_exit: %d \n"
1658 "d.cstate_exit: %d \n"
1659 "d.pstate_change: %d \n"
1660 "d.pte_meta_urgent: %d \n"
1661 "========================================================\n",
1662 context
->bw
.dcn
.watermarks
.c
.urgent_ns
,
1663 context
->bw
.dcn
.watermarks
.c
.cstate_pstate
.cstate_enter_plus_exit_ns
,
1664 context
->bw
.dcn
.watermarks
.c
.cstate_pstate
.cstate_exit_ns
,
1665 context
->bw
.dcn
.watermarks
.c
.cstate_pstate
.pstate_change_ns
,
1666 context
->bw
.dcn
.watermarks
.c
.pte_meta_urgent_ns
,
1667 context
->bw
.dcn
.watermarks
.d
.urgent_ns
,
1668 context
->bw
.dcn
.watermarks
.d
.cstate_pstate
.cstate_enter_plus_exit_ns
,
1669 context
->bw
.dcn
.watermarks
.d
.cstate_pstate
.cstate_exit_ns
,
1670 context
->bw
.dcn
.watermarks
.d
.cstate_pstate
.pstate_change_ns
,
1671 context
->bw
.dcn
.watermarks
.d
.pte_meta_urgent_ns
1675 static void dcn10_set_bandwidth(
1677 struct validate_context
*context
,
1678 bool decrease_allowed
)
1680 struct dm_pp_clock_for_voltage_req clock
;
1682 if (IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
1685 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dispclk_khz
1686 > dc
->current_context
->bw
.dcn
.cur_clk
.dispclk_khz
) {
1687 dc
->res_pool
->display_clock
->funcs
->set_clock(
1688 dc
->res_pool
->display_clock
,
1689 context
->bw
.dcn
.calc_clk
.dispclk_khz
);
1690 dc
->current_context
->bw
.dcn
.cur_clk
.dispclk_khz
=
1691 context
->bw
.dcn
.calc_clk
.dispclk_khz
;
1693 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dcfclk_khz
1694 > dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_khz
) {
1695 clock
.clk_type
= DM_PP_CLOCK_TYPE_DCFCLK
;
1696 clock
.clocks_in_khz
= context
->bw
.dcn
.calc_clk
.dcfclk_khz
;
1697 dm_pp_apply_clock_for_voltage_request(dc
->ctx
, &clock
);
1698 dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_khz
= clock
.clocks_in_khz
;
1699 context
->bw
.dcn
.cur_clk
.dcfclk_khz
= clock
.clocks_in_khz
;
1701 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.fclk_khz
1702 > dc
->current_context
->bw
.dcn
.cur_clk
.fclk_khz
) {
1703 clock
.clk_type
= DM_PP_CLOCK_TYPE_FCLK
;
1704 clock
.clocks_in_khz
= context
->bw
.dcn
.calc_clk
.fclk_khz
;
1705 dm_pp_apply_clock_for_voltage_request(dc
->ctx
, &clock
);
1706 dc
->current_context
->bw
.dcn
.calc_clk
.fclk_khz
= clock
.clocks_in_khz
;
1707 context
->bw
.dcn
.cur_clk
.fclk_khz
= clock
.clocks_in_khz
;
1709 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
1710 > dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
) {
1711 dc
->current_context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
=
1712 context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
;
1713 context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
=
1714 context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
;
1716 /* Decrease in freq is increase in period so opposite comparison for dram_ccm */
1717 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dram_ccm_us
1718 < dc
->current_context
->bw
.dcn
.cur_clk
.dram_ccm_us
) {
1719 dc
->current_context
->bw
.dcn
.calc_clk
.dram_ccm_us
=
1720 context
->bw
.dcn
.calc_clk
.dram_ccm_us
;
1721 context
->bw
.dcn
.cur_clk
.dram_ccm_us
=
1722 context
->bw
.dcn
.calc_clk
.dram_ccm_us
;
1724 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
1725 < dc
->current_context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
) {
1726 dc
->current_context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
=
1727 context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
;
1728 context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
=
1729 context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
;
1731 dcn10_pplib_apply_display_requirements(dc
, context
);
1734 static void set_drr(struct pipe_ctx
**pipe_ctx
,
1735 int num_pipes
, int vmin
, int vmax
)
1738 struct drr_params params
= {0};
1740 params
.vertical_total_max
= vmax
;
1741 params
.vertical_total_min
= vmin
;
1743 /* TODO: If multiple pipes are to be supported, you need
1746 for (i
= 0; i
< num_pipes
; i
++) {
1747 pipe_ctx
[i
]->tg
->funcs
->set_drr(pipe_ctx
[i
]->tg
, ¶ms
);
1751 static void get_position(struct pipe_ctx
**pipe_ctx
,
1753 struct crtc_position
*position
)
1757 /* TODO: handle pipes > 1
1759 for (i
= 0; i
< num_pipes
; i
++)
1760 pipe_ctx
[i
]->tg
->funcs
->get_position(pipe_ctx
[i
]->tg
, position
);
1763 static void set_static_screen_control(struct pipe_ctx
**pipe_ctx
,
1764 int num_pipes
, const struct dc_static_screen_events
*events
)
1767 unsigned int value
= 0;
1769 if (events
->surface_update
)
1771 if (events
->cursor_update
)
1774 for (i
= 0; i
< num_pipes
; i
++)
1775 pipe_ctx
[i
]->tg
->funcs
->
1776 set_static_screen_control(pipe_ctx
[i
]->tg
, value
);
1779 static void set_plane_config(
1780 const struct core_dc
*dc
,
1781 struct pipe_ctx
*pipe_ctx
,
1782 struct resource_context
*res_ctx
)
1785 program_gamut_remap(pipe_ctx
);
1788 static void dcn10_config_stereo_parameters(
1789 struct core_stream
*stream
, struct crtc_stereo_flags
*flags
)
1791 enum view_3d_format view_format
= stream
->public.view_format
;
1792 enum dc_timing_3d_format timing_3d_format
=\
1793 stream
->public.timing
.timing_3d_format
;
1794 bool non_stereo_timing
= false;
1796 if (timing_3d_format
== TIMING_3D_FORMAT_NONE
||
1797 timing_3d_format
== TIMING_3D_FORMAT_SIDE_BY_SIDE
||
1798 timing_3d_format
== TIMING_3D_FORMAT_TOP_AND_BOTTOM
)
1799 non_stereo_timing
= true;
1801 if (non_stereo_timing
== false &&
1802 view_format
== VIEW_3D_FORMAT_FRAME_SEQUENTIAL
) {
1804 flags
->PROGRAM_STEREO
= 1;
1805 flags
->PROGRAM_POLARITY
= 1;
1806 if (timing_3d_format
== TIMING_3D_FORMAT_INBAND_FA
||
1807 timing_3d_format
== TIMING_3D_FORMAT_DP_HDMI_INBAND_FA
||
1808 timing_3d_format
== TIMING_3D_FORMAT_SIDEBAND_FA
) {
1809 enum display_dongle_type dongle
= \
1810 stream
->sink
->link
->public.ddc
->dongle_type
;
1811 if (dongle
== DISPLAY_DONGLE_DP_VGA_CONVERTER
||
1812 dongle
== DISPLAY_DONGLE_DP_DVI_CONVERTER
||
1813 dongle
== DISPLAY_DONGLE_DP_HDMI_CONVERTER
)
1814 flags
->DISABLE_STEREO_DP_SYNC
= 1;
1816 flags
->RIGHT_EYE_POLARITY
=\
1817 stream
->public.timing
.flags
.RIGHT_EYE_3D_POLARITY
;
1818 if (timing_3d_format
== TIMING_3D_FORMAT_HW_FRAME_PACKING
)
1819 flags
->FRAME_PACKED
= 1;
1825 static void dcn10_setup_stereo(struct pipe_ctx
*pipe_ctx
, struct core_dc
*dc
)
1827 struct crtc_stereo_flags flags
= { 0 };
1828 struct core_stream
*stream
= pipe_ctx
->stream
;
1830 dcn10_config_stereo_parameters(stream
, &flags
);
1832 pipe_ctx
->opp
->funcs
->opp_set_stereo_polarity(
1834 flags
.PROGRAM_STEREO
== 1 ? true:false,
1835 stream
->public.timing
.flags
.RIGHT_EYE_3D_POLARITY
== 1 ? true:false);
1837 pipe_ctx
->tg
->funcs
->program_stereo(
1839 &stream
->public.timing
,
1845 static bool dcn10_dummy_display_power_gating(
1847 uint8_t controller_id
,
1848 struct dc_bios
*dcb
,
1849 enum pipe_gating_control power_gating
) {return true; }
1851 static const struct hw_sequencer_funcs dcn10_funcs
= {
1852 .program_gamut_remap
= program_gamut_remap
,
1853 .program_csc_matrix
= program_csc_matrix
,
1854 .init_hw
= dcn10_init_hw
,
1855 .apply_ctx_to_hw
= dce110_apply_ctx_to_hw
,
1856 .apply_ctx_for_surface
= dcn10_apply_ctx_for_surface
,
1857 .set_plane_config
= set_plane_config
,
1858 .update_plane_addr
= update_plane_addr
,
1859 .update_pending_status
= dce110_update_pending_status
,
1860 .set_input_transfer_func
= dcn10_set_input_transfer_func
,
1861 .set_output_transfer_func
= dcn10_set_output_transfer_func
,
1862 .power_down
= dce110_power_down
,
1863 .enable_accelerated_mode
= dce110_enable_accelerated_mode
,
1864 .enable_timing_synchronization
= dcn10_enable_timing_synchronization
,
1865 .update_info_frame
= dce110_update_info_frame
,
1866 .enable_stream
= dce110_enable_stream
,
1867 .disable_stream
= dce110_disable_stream
,
1868 .unblank_stream
= dce110_unblank_stream
,
1869 .enable_display_power_gating
= dcn10_dummy_display_power_gating
,
1870 .power_down_front_end
= dcn10_power_down_fe
,
1871 .power_on_front_end
= dcn10_power_on_fe
,
1872 .pipe_control_lock
= dcn10_pipe_control_lock
,
1873 .set_bandwidth
= dcn10_set_bandwidth
,
1874 .reset_hw_ctx_wrap
= reset_hw_ctx_wrap
,
1875 .prog_pixclk_crtc_otg
= dcn10_prog_pixclk_crtc_otg
,
1877 .get_position
= get_position
,
1878 .set_static_screen_control
= set_static_screen_control
,
1879 .setup_stereo
= dcn10_setup_stereo
,
1880 .set_avmute
= dce110_set_avmute
,
1884 void dcn10_hw_sequencer_construct(struct core_dc
*dc
)
1886 dc
->hwss
= dcn10_funcs
;