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
56 static void verify_allow_pstate_change_high(
57 struct dce_hwseq
*hws
)
59 /* pstate latency is ~20us so if we wait over 40us and pstate allow
60 * still not asserted, we are probably stuck and going to hang
62 static unsigned int pstate_wait_timeout_us
= 40;
63 static unsigned int max_sampled_pstate_wait_us
; /* data collection */
64 static bool forced_pstate_allow
; /* help with revert wa */
66 unsigned int debug_index
= 0x7;
67 unsigned int debug_data
;
68 unsigned int force_allow_pstate
= 0x30;
71 if (forced_pstate_allow
) {
72 /* we hacked to force pstate allow to prevent hang last time
73 * we verify_allow_pstate_change_high. so disable force
74 * here so we can check status
76 REG_WRITE(DCHUBBUB_ARB_DRAM_STATE_CNTL
, 0);
77 forced_pstate_allow
= false;
80 /* description "3-0: Pipe0 cursor0 QOS
81 * 7-4: Pipe1 cursor0 QOS
82 * 11-8: Pipe2 cursor0 QOS
83 * 15-12: Pipe3 cursor0 QOS
84 * 16: Pipe0 Plane0 Allow Pstate Change
85 * 17: Pipe1 Plane0 Allow Pstate Change
86 * 18: Pipe2 Plane0 Allow Pstate Change
87 * 19: Pipe3 Plane0 Allow Pstate Change
88 * 20: Pipe0 Plane1 Allow Pstate Change
89 * 21: Pipe1 Plane1 Allow Pstate Change
90 * 22: Pipe2 Plane1 Allow Pstate Change
91 * 23: Pipe3 Plane1 Allow Pstate Change
92 * 24: Pipe0 cursor0 Allow Pstate Change
93 * 25: Pipe1 cursor0 Allow Pstate Change
94 * 26: Pipe2 cursor0 Allow Pstate Change
95 * 27: Pipe3 cursor0 Allow Pstate Change
96 * 28: WB0 Allow Pstate Change
97 * 29: WB1 Allow Pstate Change
98 * 30: Arbiter's allow_pstate_change
99 * 31: SOC pstate change request
102 REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX
, debug_index
);
104 for (i
= 0; i
< pstate_wait_timeout_us
; i
++) {
105 debug_data
= REG_READ(DCHUBBUB_TEST_DEBUG_DATA
);
107 if (debug_data
& (1 << 30))
110 if (max_sampled_pstate_wait_us
< i
)
111 max_sampled_pstate_wait_us
= i
;
116 /* force pstate allow to prevent system hang
117 * and break to debugger to investigate
119 REG_WRITE(DCHUBBUB_ARB_DRAM_STATE_CNTL
, force_allow_pstate
);
120 forced_pstate_allow
= true;
124 static void enable_dppclk(
125 struct dce_hwseq
*hws
,
127 uint32_t requested_pix_clk
,
130 dm_logger_write(hws
->ctx
->logger
, LOG_SURFACE
,
131 "dppclk_rate_control for pipe %d programed to %d\n",
135 if (hws
->shifts
->DPPCLK_RATE_CONTROL
)
136 REG_UPDATE_2(DPP_CONTROL
[plane_id
],
137 DPPCLK_RATE_CONTROL
, dppclk_div
,
138 DPP_CLOCK_ENABLE
, 1);
140 REG_UPDATE(DPP_CONTROL
[plane_id
],
141 DPP_CLOCK_ENABLE
, 1);
144 static void enable_power_gating_plane(
145 struct dce_hwseq
*hws
,
148 bool force_on
= 1; /* disable power gating */
154 REG_UPDATE(DOMAIN0_PG_CONFIG
, DOMAIN0_POWER_FORCEON
, force_on
);
155 REG_UPDATE(DOMAIN2_PG_CONFIG
, DOMAIN2_POWER_FORCEON
, force_on
);
156 REG_UPDATE(DOMAIN4_PG_CONFIG
, DOMAIN4_POWER_FORCEON
, force_on
);
157 REG_UPDATE(DOMAIN6_PG_CONFIG
, DOMAIN6_POWER_FORCEON
, force_on
);
160 REG_UPDATE(DOMAIN1_PG_CONFIG
, DOMAIN1_POWER_FORCEON
, force_on
);
161 REG_UPDATE(DOMAIN3_PG_CONFIG
, DOMAIN3_POWER_FORCEON
, force_on
);
162 REG_UPDATE(DOMAIN5_PG_CONFIG
, DOMAIN5_POWER_FORCEON
, force_on
);
163 REG_UPDATE(DOMAIN7_PG_CONFIG
, DOMAIN7_POWER_FORCEON
, force_on
);
166 static void dpp_pg_control(
167 struct dce_hwseq
*hws
,
168 unsigned int dpp_inst
,
171 uint32_t power_gate
= power_on
? 0 : 1;
172 uint32_t pwr_status
= power_on
? 0 : 2;
174 if (hws
->ctx
->dc
->debug
.disable_dpp_power_gate
)
179 REG_UPDATE(DOMAIN1_PG_CONFIG
,
180 DOMAIN1_POWER_GATE
, power_gate
);
182 REG_WAIT(DOMAIN1_PG_STATUS
,
183 DOMAIN1_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
186 REG_UPDATE(DOMAIN3_PG_CONFIG
,
187 DOMAIN3_POWER_GATE
, power_gate
);
189 REG_WAIT(DOMAIN3_PG_STATUS
,
190 DOMAIN3_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
193 REG_UPDATE(DOMAIN5_PG_CONFIG
,
194 DOMAIN5_POWER_GATE
, power_gate
);
196 REG_WAIT(DOMAIN5_PG_STATUS
,
197 DOMAIN5_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
200 REG_UPDATE(DOMAIN7_PG_CONFIG
,
201 DOMAIN7_POWER_GATE
, power_gate
);
203 REG_WAIT(DOMAIN7_PG_STATUS
,
204 DOMAIN7_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
212 static void hubp_pg_control(
213 struct dce_hwseq
*hws
,
214 unsigned int hubp_inst
,
217 uint32_t power_gate
= power_on
? 0 : 1;
218 uint32_t pwr_status
= power_on
? 0 : 2;
220 if (hws
->ctx
->dc
->debug
.disable_hubp_power_gate
)
224 case 0: /* DCHUBP0 */
225 REG_UPDATE(DOMAIN0_PG_CONFIG
,
226 DOMAIN0_POWER_GATE
, power_gate
);
228 REG_WAIT(DOMAIN0_PG_STATUS
,
229 DOMAIN0_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
231 case 1: /* DCHUBP1 */
232 REG_UPDATE(DOMAIN2_PG_CONFIG
,
233 DOMAIN2_POWER_GATE
, power_gate
);
235 REG_WAIT(DOMAIN2_PG_STATUS
,
236 DOMAIN2_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
238 case 2: /* DCHUBP2 */
239 REG_UPDATE(DOMAIN4_PG_CONFIG
,
240 DOMAIN4_POWER_GATE
, power_gate
);
242 REG_WAIT(DOMAIN4_PG_STATUS
,
243 DOMAIN4_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
245 case 3: /* DCHUBP3 */
246 REG_UPDATE(DOMAIN6_PG_CONFIG
,
247 DOMAIN6_POWER_GATE
, power_gate
);
249 REG_WAIT(DOMAIN6_PG_STATUS
,
250 DOMAIN6_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
258 static void power_on_plane(
259 struct dce_hwseq
*hws
,
262 REG_SET(DC_IP_REQUEST_CNTL
, 0,
264 dpp_pg_control(hws
, plane_id
, true);
265 hubp_pg_control(hws
, plane_id
, true);
266 REG_SET(DC_IP_REQUEST_CNTL
, 0,
268 dm_logger_write(hws
->ctx
->logger
, LOG_DC
,
269 "Un-gated front end for pipe %d\n", plane_id
);
272 static void bios_golden_init(struct core_dc
*dc
)
274 struct dc_bios
*bp
= dc
->ctx
->dc_bios
;
277 /* initialize dcn global */
278 bp
->funcs
->enable_disp_power_gating(bp
,
279 CONTROLLER_ID_D0
, ASIC_PIPE_INIT
);
281 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
282 /* initialize dcn per pipe */
283 bp
->funcs
->enable_disp_power_gating(bp
,
284 CONTROLLER_ID_D0
+ i
, ASIC_PIPE_DISABLE
);
288 static void dcn10_init_hw(struct core_dc
*dc
)
291 struct abm
*abm
= dc
->res_pool
->abm
;
292 struct dce_hwseq
*hws
= dc
->hwseq
;
294 if (IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
)) {
295 REG_WRITE(REFCLK_CNTL
, 0);
296 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL
, DCHUBBUB_GLOBAL_TIMER_ENABLE
, 1);
297 REG_WRITE(DIO_MEM_PWR_CTRL
, 0);
299 if (!dc
->public.debug
.disable_clock_gate
) {
300 /* enable all DCN clock gating */
301 REG_WRITE(DCCG_GATE_DISABLE_CNTL
, 0);
303 REG_WRITE(DCCG_GATE_DISABLE_CNTL2
, 0);
305 REG_UPDATE(DCFCLK_CNTL
, DCFCLK_GATE_DIS
, 0);
308 enable_power_gating_plane(dc
->hwseq
, true);
311 /* end of FPGA. Below if real ASIC */
313 bios_golden_init(dc
);
315 for (i
= 0; i
< dc
->link_count
; i
++) {
316 /* Power up AND update implementation according to the
317 * required signal (which may be different from the
318 * default signal on connector).
320 struct core_link
*link
= dc
->links
[i
];
322 link
->link_enc
->funcs
->hw_init(link
->link_enc
);
325 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
326 struct transform
*xfm
= dc
->res_pool
->transforms
[i
];
327 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[i
];
328 struct mpcc
*mpcc
= dc
->res_pool
->mpcc
[i
];
329 struct mpcc_cfg mpcc_cfg
;
331 xfm
->funcs
->transform_reset(xfm
);
332 mpcc_cfg
.opp_id
= 0xf;
333 mpcc_cfg
.top_dpp_id
= 0xf;
334 mpcc_cfg
.bot_mpcc_id
= 0xf;
335 mpcc_cfg
.top_of_tree
= true;
336 mpcc
->funcs
->set(mpcc
, &mpcc_cfg
);
338 tg
->funcs
->disable_vga(tg
);
339 /* Blank controller using driver code instead of
342 tg
->funcs
->set_blank(tg
, true);
343 hwss_wait_for_blank_complete(tg
);
346 for (i
= 0; i
< dc
->res_pool
->audio_count
; i
++) {
347 struct audio
*audio
= dc
->res_pool
->audios
[i
];
349 audio
->funcs
->hw_init(audio
);
353 abm
->funcs
->init_backlight(abm
);
354 abm
->funcs
->abm_init(abm
);
357 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
358 REG_WRITE(DIO_MEM_PWR_CTRL
, 0);
360 if (!dc
->public.debug
.disable_clock_gate
) {
361 /* enable all DCN clock gating */
362 REG_WRITE(DCCG_GATE_DISABLE_CNTL
, 0);
364 REG_WRITE(DCCG_GATE_DISABLE_CNTL2
, 0);
366 REG_UPDATE(DCFCLK_CNTL
, DCFCLK_GATE_DIS
, 0);
369 enable_power_gating_plane(dc
->hwseq
, true);
372 static enum dc_status
dcn10_prog_pixclk_crtc_otg(
373 struct pipe_ctx
*pipe_ctx
,
374 struct validate_context
*context
,
377 struct core_stream
*stream
= pipe_ctx
->stream
;
378 enum dc_color_space color_space
;
379 struct tg_color black_color
= {0};
380 bool enableStereo
= stream
->public.timing
.timing_3d_format
== TIMING_3D_FORMAT_NONE
?
382 bool rightEyePolarity
= stream
->public.timing
.flags
.RIGHT_EYE_3D_POLARITY
;
385 /* by upper caller loop, pipe0 is parent pipe and be called first.
386 * back end is set up by for pipe0. Other children pipe share back end
387 * with pipe 0. No program is needed.
389 if (pipe_ctx
->top_pipe
!= NULL
)
392 /* TODO check if timing_changed, disable stream if timing changed */
394 /* HW program guide assume display already disable
395 * by unplug sequence. OTG assume stop.
397 pipe_ctx
->tg
->funcs
->enable_optc_clock(pipe_ctx
->tg
, true);
399 if (false == pipe_ctx
->clock_source
->funcs
->program_pix_clk(
400 pipe_ctx
->clock_source
,
401 &pipe_ctx
->pix_clk_params
,
402 &pipe_ctx
->pll_settings
)) {
404 return DC_ERROR_UNEXPECTED
;
406 pipe_ctx
->tg
->dlg_otg_param
.vready_offset
= pipe_ctx
->pipe_dlg_param
.vready_offset
;
407 pipe_ctx
->tg
->dlg_otg_param
.vstartup_start
= pipe_ctx
->pipe_dlg_param
.vstartup_start
;
408 pipe_ctx
->tg
->dlg_otg_param
.vupdate_offset
= pipe_ctx
->pipe_dlg_param
.vupdate_offset
;
409 pipe_ctx
->tg
->dlg_otg_param
.vupdate_width
= pipe_ctx
->pipe_dlg_param
.vupdate_width
;
411 pipe_ctx
->tg
->dlg_otg_param
.signal
= pipe_ctx
->stream
->signal
;
413 pipe_ctx
->tg
->funcs
->program_timing(
415 &stream
->public.timing
,
418 pipe_ctx
->opp
->funcs
->opp_set_stereo_polarity(
423 #if 0 /* move to after enable_crtc */
424 /* TODO: OPP FMT, ABM. etc. should be done here. */
425 /* or FPGA now. instance 0 only. TODO: move to opp.c */
427 inst_offset
= reg_offsets
[pipe_ctx
->tg
->inst
].fmt
;
429 pipe_ctx
->opp
->funcs
->opp_program_fmt(
431 &stream
->bit_depth_params
,
434 /* program otg blank color */
435 color_space
= stream
->public.output_color_space
;
436 color_space_to_black_color(dc
, color_space
, &black_color
);
437 pipe_ctx
->tg
->funcs
->set_blank_color(
441 pipe_ctx
->tg
->funcs
->set_blank(pipe_ctx
->tg
, true);
442 hwss_wait_for_blank_complete(pipe_ctx
->tg
);
444 /* VTG is within DCHUB command block. DCFCLK is always on */
445 if (false == pipe_ctx
->tg
->funcs
->enable_crtc(pipe_ctx
->tg
)) {
447 return DC_ERROR_UNEXPECTED
;
450 /* TODO program crtc source select for non-virtual signal*/
451 /* TODO program FMT */
452 /* TODO setup link_enc */
453 /* TODO set stream attributes */
454 /* TODO program audio */
455 /* TODO enable stream if timing changed */
456 /* TODO unblank stream if DP */
461 static void reset_back_end_for_pipe(
463 struct pipe_ctx
*pipe_ctx
,
464 struct validate_context
*context
)
468 if (pipe_ctx
->stream_enc
== NULL
) {
469 pipe_ctx
->stream
= NULL
;
473 /* TODOFPGA break core_link_disable_stream into 2 functions:
474 * disable_stream and disable_link. disable_link will disable PHYPLL
475 * which is used by otg. Move disable_link after disable_crtc
477 if (!IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
478 core_link_disable_stream(pipe_ctx
);
480 /* by upper caller loop, parent pipe: pipe0, will be reset last.
481 * back end share by all pipes and will be disable only when disable
484 if (pipe_ctx
->top_pipe
== NULL
) {
485 pipe_ctx
->tg
->funcs
->disable_crtc(pipe_ctx
->tg
);
487 pipe_ctx
->tg
->funcs
->enable_optc_clock(pipe_ctx
->tg
, false);
490 if (!IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
491 resource_unreference_clock_source(
492 &context
->res_ctx
, dc
->res_pool
,
493 &pipe_ctx
->clock_source
);
495 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
496 if (&dc
->current_context
->res_ctx
.pipe_ctx
[i
] == pipe_ctx
)
499 if (i
== dc
->res_pool
->pipe_count
)
502 pipe_ctx
->stream
= NULL
;
503 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
504 "Reset back end for pipe %d, tg:%d\n",
505 pipe_ctx
->pipe_idx
, pipe_ctx
->tg
->inst
);
508 static void plane_atomic_stop(
512 struct mpcc_cfg mpcc_cfg
;
513 struct mem_input
*mi
= dc
->res_pool
->mis
[fe_idx
];
514 struct transform
*xfm
= dc
->res_pool
->transforms
[fe_idx
];
515 struct mpcc
*mpcc
= dc
->res_pool
->mpcc
[fe_idx
];
516 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[mpcc
->opp_id
];
518 mi
->funcs
->dcc_control(mi
, false, false);
520 mpcc_cfg
.opp_id
= 0xf;
521 mpcc_cfg
.top_dpp_id
= 0xf;
522 mpcc_cfg
.bot_mpcc_id
= 0xf;
523 mpcc_cfg
.top_of_tree
= tg
->inst
== mpcc
->inst
;
524 mpcc
->funcs
->set(mpcc
, &mpcc_cfg
);
526 xfm
->funcs
->transform_reset(xfm
);
529 static void reset_front_end(
533 struct dce_hwseq
*hws
= dc
->hwseq
;
534 struct mem_input
*mi
= dc
->res_pool
->mis
[fe_idx
];
535 struct mpcc
*mpcc
= dc
->res_pool
->mpcc
[fe_idx
];
536 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[mpcc
->opp_id
];
537 unsigned int opp_id
= mpcc
->opp_id
;
545 plane_atomic_stop(dc
, fe_idx
);
547 REG_UPDATE(OTG_GLOBAL_SYNC_STATUS
[tg
->inst
], VUPDATE_NO_LOCK_EVENT_CLEAR
, 1);
548 tg
->funcs
->unlock(tg
);
550 if (dc
->public.debug
.sanity_checks
)
551 verify_allow_pstate_change_high(dc
->hwseq
);
553 if (tg
->ctx
->dce_environment
!= DCE_ENV_FPGA_MAXIMUS
)
554 REG_WAIT(OTG_GLOBAL_SYNC_STATUS
[tg
->inst
],
555 VUPDATE_NO_LOCK_EVENT_OCCURRED
, 1, 20000, 200000);
557 mpcc
->funcs
->wait_for_idle(mpcc
);
559 mi
->funcs
->set_blank(mi
, true);
561 if (dc
->public.debug
.sanity_checks
)
562 verify_allow_pstate_change_high(dc
->hwseq
);
564 REG_UPDATE(HUBP_CLK_CNTL
[fe_idx
],
565 HUBP_CLOCK_ENABLE
, 0);
566 REG_UPDATE(DPP_CONTROL
[fe_idx
],
567 DPP_CLOCK_ENABLE
, 0);
569 if (tg
->inst
== mpcc
->inst
)
570 REG_UPDATE(OPP_PIPE_CONTROL
[opp_id
],
571 OPP_PIPE_CLOCK_EN
, 0);
573 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
574 "Reset front end %d\n",
577 if (dc
->public.debug
.sanity_checks
)
578 verify_allow_pstate_change_high(dc
->hwseq
);
581 static void dcn10_power_down_fe(struct core_dc
*dc
, int fe_idx
)
583 struct dce_hwseq
*hws
= dc
->hwseq
;
585 reset_front_end(dc
, fe_idx
);
587 REG_SET(DC_IP_REQUEST_CNTL
, 0,
589 dpp_pg_control(hws
, fe_idx
, false);
590 hubp_pg_control(hws
, fe_idx
, false);
591 REG_SET(DC_IP_REQUEST_CNTL
, 0,
593 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
594 "Power gated front end %d\n", fe_idx
);
596 if (dc
->public.debug
.sanity_checks
)
597 verify_allow_pstate_change_high(dc
->hwseq
);
600 static void reset_hw_ctx_wrap(
602 struct validate_context
*context
)
607 for (i
= dc
->res_pool
->pipe_count
- 1; i
>= 0 ; i
--) {
608 struct pipe_ctx
*pipe_ctx_old
=
609 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
610 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
612 /*if (!pipe_ctx_old->stream)
615 if (!pipe_ctx
->stream
|| !pipe_ctx
->surface
)
616 dcn10_power_down_fe(dc
, i
);
617 else if (pipe_need_reprogram(pipe_ctx_old
, pipe_ctx
))
618 reset_front_end(dc
, i
);
621 for (i
= dc
->res_pool
->pipe_count
- 1; i
>= 0 ; i
--) {
622 struct pipe_ctx
*pipe_ctx_old
=
623 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
624 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
626 if (!pipe_ctx_old
->stream
)
629 if (!pipe_ctx
->stream
||
630 pipe_need_reprogram(pipe_ctx_old
, pipe_ctx
))
631 reset_back_end_for_pipe(dc
, pipe_ctx_old
, dc
->current_context
);
635 static bool patch_address_for_sbs_tb_stereo(
636 struct pipe_ctx
*pipe_ctx
, PHYSICAL_ADDRESS_LOC
*addr
)
638 struct core_surface
*surface
= pipe_ctx
->surface
;
639 bool sec_split
= pipe_ctx
->top_pipe
&&
640 pipe_ctx
->top_pipe
->surface
== pipe_ctx
->surface
;
641 if (sec_split
&& surface
->public.address
.type
== PLN_ADDR_TYPE_GRPH_STEREO
&&
642 (pipe_ctx
->stream
->public.timing
.timing_3d_format
==
643 TIMING_3D_FORMAT_SIDE_BY_SIDE
||
644 pipe_ctx
->stream
->public.timing
.timing_3d_format
==
645 TIMING_3D_FORMAT_TOP_AND_BOTTOM
)) {
646 *addr
= surface
->public.address
.grph_stereo
.left_addr
;
647 surface
->public.address
.grph_stereo
.left_addr
=
648 surface
->public.address
.grph_stereo
.right_addr
;
651 if (pipe_ctx
->stream
->public.view_format
!= VIEW_3D_FORMAT_NONE
&&
652 surface
->public.address
.type
!= PLN_ADDR_TYPE_GRPH_STEREO
) {
653 surface
->public.address
.type
= PLN_ADDR_TYPE_GRPH_STEREO
;
654 surface
->public.address
.grph_stereo
.right_addr
=
655 surface
->public.address
.grph_stereo
.left_addr
;
661 static void update_plane_addr(const struct core_dc
*dc
, struct pipe_ctx
*pipe_ctx
)
663 bool addr_patched
= false;
664 PHYSICAL_ADDRESS_LOC addr
;
665 struct core_surface
*surface
= pipe_ctx
->surface
;
669 addr_patched
= patch_address_for_sbs_tb_stereo(pipe_ctx
, &addr
);
670 pipe_ctx
->mi
->funcs
->mem_input_program_surface_flip_and_addr(
672 &surface
->public.address
,
673 surface
->public.flip_immediate
);
674 surface
->status
.requested_address
= surface
->public.address
;
676 pipe_ctx
->surface
->public.address
.grph_stereo
.left_addr
= addr
;
679 static bool dcn10_set_input_transfer_func(
680 struct pipe_ctx
*pipe_ctx
, const struct core_surface
*surface
)
682 struct input_pixel_processor
*ipp
= pipe_ctx
->ipp
;
683 const struct dc_transfer_func
*tf
= NULL
;
689 if (surface
->public.in_transfer_func
)
690 tf
= surface
->public.in_transfer_func
;
692 if (surface
->public.gamma_correction
&& dce_use_lut(surface
))
693 ipp
->funcs
->ipp_program_input_lut(ipp
,
694 surface
->public.gamma_correction
);
697 ipp
->funcs
->ipp_set_degamma(ipp
, IPP_DEGAMMA_MODE_BYPASS
);
698 else if (tf
->type
== TF_TYPE_PREDEFINED
) {
700 case TRANSFER_FUNCTION_SRGB
:
701 ipp
->funcs
->ipp_set_degamma(ipp
,
702 IPP_DEGAMMA_MODE_HW_sRGB
);
704 case TRANSFER_FUNCTION_BT709
:
705 ipp
->funcs
->ipp_set_degamma(ipp
,
706 IPP_DEGAMMA_MODE_HW_xvYCC
);
708 case TRANSFER_FUNCTION_LINEAR
:
709 ipp
->funcs
->ipp_set_degamma(ipp
,
710 IPP_DEGAMMA_MODE_BYPASS
);
712 case TRANSFER_FUNCTION_PQ
:
719 } else if (tf
->type
== TF_TYPE_BYPASS
) {
720 ipp
->funcs
->ipp_set_degamma(ipp
, IPP_DEGAMMA_MODE_BYPASS
);
722 /*TF_TYPE_DISTRIBUTED_POINTS*/
728 /*modify the method to handle rgb for arr_points*/
729 static bool convert_to_custom_float(
730 struct pwl_result_data
*rgb_resulted
,
731 struct curve_points
*arr_points
,
732 uint32_t hw_points_num
)
734 struct custom_float_format fmt
;
736 struct pwl_result_data
*rgb
= rgb_resulted
;
740 fmt
.exponenta_bits
= 6;
741 fmt
.mantissa_bits
= 12;
744 if (!convert_to_custom_float_format(
747 &arr_points
[0].custom_float_x
)) {
752 if (!convert_to_custom_float_format(
753 arr_points
[0].offset
,
755 &arr_points
[0].custom_float_offset
)) {
760 if (!convert_to_custom_float_format(
763 &arr_points
[0].custom_float_slope
)) {
768 fmt
.mantissa_bits
= 10;
771 if (!convert_to_custom_float_format(
774 &arr_points
[1].custom_float_x
)) {
779 if (!convert_to_custom_float_format(
782 &arr_points
[1].custom_float_y
)) {
787 if (!convert_to_custom_float_format(
790 &arr_points
[1].custom_float_slope
)) {
795 fmt
.mantissa_bits
= 12;
798 while (i
!= hw_points_num
) {
799 if (!convert_to_custom_float_format(
807 if (!convert_to_custom_float_format(
815 if (!convert_to_custom_float_format(
823 if (!convert_to_custom_float_format(
826 &rgb
->delta_red_reg
)) {
831 if (!convert_to_custom_float_format(
834 &rgb
->delta_green_reg
)) {
839 if (!convert_to_custom_float_format(
842 &rgb
->delta_blue_reg
)) {
853 #define MAX_REGIONS_NUMBER 34
854 #define MAX_LOW_POINT 25
855 #define NUMBER_SEGMENTS 32
857 static bool dcn10_translate_regamma_to_hw_format(const struct dc_transfer_func
858 *output_tf
, struct pwl_params
*regamma_params
)
860 struct curve_points
*arr_points
;
861 struct pwl_result_data
*rgb_resulted
;
862 struct pwl_result_data
*rgb
;
863 struct pwl_result_data
*rgb_plus_1
;
864 struct fixed31_32 y_r
;
865 struct fixed31_32 y_g
;
866 struct fixed31_32 y_b
;
867 struct fixed31_32 y1_min
;
868 struct fixed31_32 y3_max
;
870 int32_t segment_start
, segment_end
;
872 uint32_t j
, k
, seg_distr
[MAX_REGIONS_NUMBER
], increment
, start_index
, hw_points
;
874 if (output_tf
== NULL
|| regamma_params
== NULL
||
875 output_tf
->type
== TF_TYPE_BYPASS
)
878 arr_points
= regamma_params
->arr_points
;
879 rgb_resulted
= regamma_params
->rgb_resulted
;
882 memset(regamma_params
, 0, sizeof(struct pwl_params
));
883 memset(seg_distr
, 0, sizeof(seg_distr
));
885 if (output_tf
->tf
== TRANSFER_FUNCTION_PQ
) {
887 * segments are from 2^-25 to 2^7
889 for (i
= 0; i
< 32 ; i
++)
896 * segment is from 2^-10 to 2^0
897 * There are less than 256 points, for optimization
914 for (i
= segment_end
- segment_start
; i
< MAX_REGIONS_NUMBER
; i
++)
917 for (k
= 0; k
< MAX_REGIONS_NUMBER
; k
++) {
918 if (seg_distr
[k
] != -1)
919 hw_points
+= (1 << seg_distr
[k
]);
923 for (k
= 0; k
< (segment_end
- segment_start
); k
++) {
924 increment
= NUMBER_SEGMENTS
/ (1 << seg_distr
[k
]);
925 start_index
= (segment_start
+ k
+ MAX_LOW_POINT
) * NUMBER_SEGMENTS
;
926 for (i
= start_index
; i
< start_index
+ NUMBER_SEGMENTS
; i
+= increment
) {
927 if (j
== hw_points
- 1)
929 rgb_resulted
[j
].red
= output_tf
->tf_pts
.red
[i
];
930 rgb_resulted
[j
].green
= output_tf
->tf_pts
.green
[i
];
931 rgb_resulted
[j
].blue
= output_tf
->tf_pts
.blue
[i
];
937 start_index
= (segment_end
+ MAX_LOW_POINT
) * NUMBER_SEGMENTS
;
938 rgb_resulted
[hw_points
- 1].red
=
939 output_tf
->tf_pts
.red
[start_index
];
940 rgb_resulted
[hw_points
- 1].green
=
941 output_tf
->tf_pts
.green
[start_index
];
942 rgb_resulted
[hw_points
- 1].blue
=
943 output_tf
->tf_pts
.blue
[start_index
];
945 arr_points
[0].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
946 dal_fixed31_32_from_int(segment_start
));
947 arr_points
[1].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
948 dal_fixed31_32_from_int(segment_end
));
949 arr_points
[2].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
950 dal_fixed31_32_from_int(segment_end
));
952 y_r
= rgb_resulted
[0].red
;
953 y_g
= rgb_resulted
[0].green
;
954 y_b
= rgb_resulted
[0].blue
;
956 y1_min
= dal_fixed31_32_min(y_r
, dal_fixed31_32_min(y_g
, y_b
));
958 arr_points
[0].y
= y1_min
;
959 arr_points
[0].slope
= dal_fixed31_32_div(
962 y_r
= rgb_resulted
[hw_points
- 1].red
;
963 y_g
= rgb_resulted
[hw_points
- 1].green
;
964 y_b
= rgb_resulted
[hw_points
- 1].blue
;
966 /* see comment above, m_arrPoints[1].y should be the Y value for the
967 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
969 y3_max
= dal_fixed31_32_max(y_r
, dal_fixed31_32_max(y_g
, y_b
));
971 arr_points
[1].y
= y3_max
;
972 arr_points
[2].y
= y3_max
;
974 arr_points
[1].slope
= dal_fixed31_32_zero
;
975 arr_points
[2].slope
= dal_fixed31_32_zero
;
977 if (output_tf
->tf
== TRANSFER_FUNCTION_PQ
) {
978 /* for PQ, we want to have a straight line from last HW X point,
979 * and the slope to be such that we hit 1.0 at 10000 nits.
981 const struct fixed31_32 end_value
=
982 dal_fixed31_32_from_int(125);
984 arr_points
[1].slope
= dal_fixed31_32_div(
985 dal_fixed31_32_sub(dal_fixed31_32_one
, arr_points
[1].y
),
986 dal_fixed31_32_sub(end_value
, arr_points
[1].x
));
987 arr_points
[2].slope
= dal_fixed31_32_div(
988 dal_fixed31_32_sub(dal_fixed31_32_one
, arr_points
[1].y
),
989 dal_fixed31_32_sub(end_value
, arr_points
[1].x
));
992 regamma_params
->hw_points_num
= hw_points
;
995 for (k
= 0; k
< MAX_REGIONS_NUMBER
&& i
< MAX_REGIONS_NUMBER
; k
++) {
996 if (seg_distr
[k
] != -1) {
997 regamma_params
->arr_curve_points
[k
].segments_num
=
999 regamma_params
->arr_curve_points
[i
].offset
=
1000 regamma_params
->arr_curve_points
[k
].
1001 offset
+ (1 << seg_distr
[k
]);
1006 if (seg_distr
[k
] != -1)
1007 regamma_params
->arr_curve_points
[k
].segments_num
=
1011 rgb_plus_1
= rgb_resulted
+ 1;
1015 while (i
!= hw_points
+ 1) {
1016 if (dal_fixed31_32_lt(rgb_plus_1
->red
, rgb
->red
))
1017 rgb_plus_1
->red
= rgb
->red
;
1018 if (dal_fixed31_32_lt(rgb_plus_1
->green
, rgb
->green
))
1019 rgb_plus_1
->green
= rgb
->green
;
1020 if (dal_fixed31_32_lt(rgb_plus_1
->blue
, rgb
->blue
))
1021 rgb_plus_1
->blue
= rgb
->blue
;
1023 rgb
->delta_red
= dal_fixed31_32_sub(
1026 rgb
->delta_green
= dal_fixed31_32_sub(
1029 rgb
->delta_blue
= dal_fixed31_32_sub(
1038 convert_to_custom_float(rgb_resulted
, arr_points
, hw_points
);
1043 static bool dcn10_set_output_transfer_func(
1044 struct pipe_ctx
*pipe_ctx
,
1045 const struct core_stream
*stream
)
1047 struct output_pixel_processor
*opp
= pipe_ctx
->opp
;
1052 opp
->regamma_params
.hw_points_num
= GAMMA_HW_POINTS_NUM
;
1054 if (stream
->public.out_transfer_func
&&
1055 stream
->public.out_transfer_func
->type
==
1056 TF_TYPE_PREDEFINED
&&
1057 stream
->public.out_transfer_func
->tf
==
1058 TRANSFER_FUNCTION_SRGB
) {
1059 opp
->funcs
->opp_set_regamma_mode(opp
, OPP_REGAMMA_SRGB
);
1060 } else if (dcn10_translate_regamma_to_hw_format(
1061 stream
->public.out_transfer_func
, &opp
->regamma_params
)) {
1062 opp
->funcs
->opp_program_regamma_pwl(opp
, &opp
->regamma_params
);
1063 opp
->funcs
->opp_set_regamma_mode(opp
, OPP_REGAMMA_USER
);
1065 opp
->funcs
->opp_set_regamma_mode(opp
, OPP_REGAMMA_BYPASS
);
1071 static void dcn10_pipe_control_lock(
1073 struct pipe_ctx
*pipe
,
1076 /* use TG master update lock to lock everything on the TG
1077 * therefore only top pipe need to lock
1082 if (dc
->public.debug
.sanity_checks
)
1083 verify_allow_pstate_change_high(dc
->hwseq
);
1086 pipe
->tg
->funcs
->lock(pipe
->tg
);
1088 pipe
->tg
->funcs
->unlock(pipe
->tg
);
1090 if (dc
->public.debug
.sanity_checks
)
1091 verify_allow_pstate_change_high(dc
->hwseq
);
1094 static bool wait_for_reset_trigger_to_occur(
1095 struct dc_context
*dc_ctx
,
1096 struct timing_generator
*tg
)
1100 /* To avoid endless loop we wait at most
1101 * frames_to_wait_on_triggered_reset frames for the reset to occur. */
1102 const uint32_t frames_to_wait_on_triggered_reset
= 10;
1105 for (i
= 0; i
< frames_to_wait_on_triggered_reset
; i
++) {
1107 if (!tg
->funcs
->is_counter_moving(tg
)) {
1108 DC_ERROR("TG counter is not moving!\n");
1112 if (tg
->funcs
->did_triggered_reset_occur(tg
)) {
1114 /* usually occurs at i=1 */
1115 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
1120 /* Wait for one frame. */
1121 tg
->funcs
->wait_for_state(tg
, CRTC_STATE_VACTIVE
);
1122 tg
->funcs
->wait_for_state(tg
, CRTC_STATE_VBLANK
);
1126 DC_ERROR("GSL: Timeout on reset trigger!\n");
1131 static void dcn10_enable_timing_synchronization(
1135 struct pipe_ctx
*grouped_pipes
[])
1137 struct dc_context
*dc_ctx
= dc
->ctx
;
1140 DC_SYNC_INFO("Setting up OTG reset trigger\n");
1142 for (i
= 1; i
< group_size
; i
++)
1143 grouped_pipes
[i
]->tg
->funcs
->enable_reset_trigger(
1144 grouped_pipes
[i
]->tg
, grouped_pipes
[0]->tg
->inst
);
1147 DC_SYNC_INFO("Waiting for trigger\n");
1149 /* Need to get only check 1 pipe for having reset as all the others are
1150 * synchronized. Look at last pipe programmed to reset.
1152 wait_for_reset_trigger_to_occur(dc_ctx
, grouped_pipes
[1]->tg
);
1153 for (i
= 1; i
< group_size
; i
++)
1154 grouped_pipes
[i
]->tg
->funcs
->disable_reset_trigger(
1155 grouped_pipes
[i
]->tg
);
1157 DC_SYNC_INFO("Sync complete\n");
1160 static void print_rq_dlg_ttu(
1161 struct core_dc
*core_dc
,
1162 struct pipe_ctx
*pipe_ctx
)
1164 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1165 "\n============== DML TTU Output parameters [%d] ==============\n"
1166 "qos_level_low_wm: %d, \n"
1167 "qos_level_high_wm: %d, \n"
1168 "min_ttu_vblank: %d, \n"
1169 "qos_level_flip: %d, \n"
1170 "refcyc_per_req_delivery_l: %d, \n"
1171 "qos_level_fixed_l: %d, \n"
1172 "qos_ramp_disable_l: %d, \n"
1173 "refcyc_per_req_delivery_pre_l: %d, \n"
1174 "refcyc_per_req_delivery_c: %d, \n"
1175 "qos_level_fixed_c: %d, \n"
1176 "qos_ramp_disable_c: %d, \n"
1177 "refcyc_per_req_delivery_pre_c: %d\n"
1178 "=============================================================\n",
1180 pipe_ctx
->ttu_regs
.qos_level_low_wm
,
1181 pipe_ctx
->ttu_regs
.qos_level_high_wm
,
1182 pipe_ctx
->ttu_regs
.min_ttu_vblank
,
1183 pipe_ctx
->ttu_regs
.qos_level_flip
,
1184 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_l
,
1185 pipe_ctx
->ttu_regs
.qos_level_fixed_l
,
1186 pipe_ctx
->ttu_regs
.qos_ramp_disable_l
,
1187 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_pre_l
,
1188 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_c
,
1189 pipe_ctx
->ttu_regs
.qos_level_fixed_c
,
1190 pipe_ctx
->ttu_regs
.qos_ramp_disable_c
,
1191 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_pre_c
1194 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1195 "\n============== DML DLG Output parameters [%d] ==============\n"
1196 "refcyc_h_blank_end: %d, \n"
1197 "dlg_vblank_end: %d, \n"
1198 "min_dst_y_next_start: %d, \n"
1199 "refcyc_per_htotal: %d, \n"
1200 "refcyc_x_after_scaler: %d, \n"
1201 "dst_y_after_scaler: %d, \n"
1202 "dst_y_prefetch: %d, \n"
1203 "dst_y_per_vm_vblank: %d, \n"
1204 "dst_y_per_row_vblank: %d, \n"
1205 "ref_freq_to_pix_freq: %d, \n"
1206 "vratio_prefetch: %d, \n"
1207 "refcyc_per_pte_group_vblank_l: %d, \n"
1208 "refcyc_per_meta_chunk_vblank_l: %d, \n"
1209 "dst_y_per_pte_row_nom_l: %d, \n"
1210 "refcyc_per_pte_group_nom_l: %d, \n",
1212 pipe_ctx
->dlg_regs
.refcyc_h_blank_end
,
1213 pipe_ctx
->dlg_regs
.dlg_vblank_end
,
1214 pipe_ctx
->dlg_regs
.min_dst_y_next_start
,
1215 pipe_ctx
->dlg_regs
.refcyc_per_htotal
,
1216 pipe_ctx
->dlg_regs
.refcyc_x_after_scaler
,
1217 pipe_ctx
->dlg_regs
.dst_y_after_scaler
,
1218 pipe_ctx
->dlg_regs
.dst_y_prefetch
,
1219 pipe_ctx
->dlg_regs
.dst_y_per_vm_vblank
,
1220 pipe_ctx
->dlg_regs
.dst_y_per_row_vblank
,
1221 pipe_ctx
->dlg_regs
.ref_freq_to_pix_freq
,
1222 pipe_ctx
->dlg_regs
.vratio_prefetch
,
1223 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_vblank_l
,
1224 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_vblank_l
,
1225 pipe_ctx
->dlg_regs
.dst_y_per_pte_row_nom_l
,
1226 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_nom_l
1229 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1230 "\ndst_y_per_meta_row_nom_l: %d, \n"
1231 "refcyc_per_meta_chunk_nom_l: %d, \n"
1232 "refcyc_per_line_delivery_pre_l: %d, \n"
1233 "refcyc_per_line_delivery_l: %d, \n"
1234 "vratio_prefetch_c: %d, \n"
1235 "refcyc_per_pte_group_vblank_c: %d, \n"
1236 "refcyc_per_meta_chunk_vblank_c: %d, \n"
1237 "dst_y_per_pte_row_nom_c: %d, \n"
1238 "refcyc_per_pte_group_nom_c: %d, \n"
1239 "dst_y_per_meta_row_nom_c: %d, \n"
1240 "refcyc_per_meta_chunk_nom_c: %d, \n"
1241 "refcyc_per_line_delivery_pre_c: %d, \n"
1242 "refcyc_per_line_delivery_c: %d \n"
1243 "========================================================\n",
1244 pipe_ctx
->dlg_regs
.dst_y_per_meta_row_nom_l
,
1245 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_nom_l
,
1246 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_pre_l
,
1247 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_l
,
1248 pipe_ctx
->dlg_regs
.vratio_prefetch_c
,
1249 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_vblank_c
,
1250 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_vblank_c
,
1251 pipe_ctx
->dlg_regs
.dst_y_per_pte_row_nom_c
,
1252 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_nom_c
,
1253 pipe_ctx
->dlg_regs
.dst_y_per_meta_row_nom_c
,
1254 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_nom_c
,
1255 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_pre_c
,
1256 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_c
1259 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1260 "\n============== DML RQ Output parameters [%d] ==============\n"
1262 "min_chunk_size: %d \n"
1263 "meta_chunk_size: %d \n"
1264 "min_meta_chunk_size: %d \n"
1265 "dpte_group_size: %d \n"
1266 "mpte_group_size: %d \n"
1267 "swath_height: %d \n"
1268 "pte_row_height_linear: %d \n"
1269 "========================================================\n",
1271 pipe_ctx
->rq_regs
.rq_regs_l
.chunk_size
,
1272 pipe_ctx
->rq_regs
.rq_regs_l
.min_chunk_size
,
1273 pipe_ctx
->rq_regs
.rq_regs_l
.meta_chunk_size
,
1274 pipe_ctx
->rq_regs
.rq_regs_l
.min_meta_chunk_size
,
1275 pipe_ctx
->rq_regs
.rq_regs_l
.dpte_group_size
,
1276 pipe_ctx
->rq_regs
.rq_regs_l
.mpte_group_size
,
1277 pipe_ctx
->rq_regs
.rq_regs_l
.swath_height
,
1278 pipe_ctx
->rq_regs
.rq_regs_l
.pte_row_height_linear
1282 static void dcn10_power_on_fe(
1284 struct pipe_ctx
*pipe_ctx
,
1285 struct validate_context
*context
)
1287 struct dc_surface
*dc_surface
= &pipe_ctx
->surface
->public;
1288 struct dce_hwseq
*hws
= dc
->hwseq
;
1290 power_on_plane(dc
->hwseq
,
1291 pipe_ctx
->pipe_idx
);
1293 /* enable DCFCLK current DCHUB */
1294 REG_UPDATE(HUBP_CLK_CNTL
[pipe_ctx
->pipe_idx
],
1295 HUBP_CLOCK_ENABLE
, 1);
1297 /* make sure OPP_PIPE_CLOCK_EN = 1 */
1298 REG_UPDATE(OPP_PIPE_CONTROL
[pipe_ctx
->tg
->inst
],
1299 OPP_PIPE_CLOCK_EN
, 1);
1300 /*TODO: REG_UPDATE(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, 0x1f);*/
1303 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
1304 "Pipe:%d 0x%x: addr hi:0x%x, "
1307 " %d; dst: %d, %d, %d, %d;\n",
1310 dc_surface
->address
.grph
.addr
.high_part
,
1311 dc_surface
->address
.grph
.addr
.low_part
,
1312 dc_surface
->src_rect
.x
,
1313 dc_surface
->src_rect
.y
,
1314 dc_surface
->src_rect
.width
,
1315 dc_surface
->src_rect
.height
,
1316 dc_surface
->dst_rect
.x
,
1317 dc_surface
->dst_rect
.y
,
1318 dc_surface
->dst_rect
.width
,
1319 dc_surface
->dst_rect
.height
);
1321 dm_logger_write(dc
->ctx
->logger
, LOG_HW_SET_MODE
,
1322 "Pipe %d: width, height, x, y\n"
1323 "viewport:%d, %d, %d, %d\n"
1324 "recout: %d, %d, %d, %d\n",
1326 pipe_ctx
->scl_data
.viewport
.width
,
1327 pipe_ctx
->scl_data
.viewport
.height
,
1328 pipe_ctx
->scl_data
.viewport
.x
,
1329 pipe_ctx
->scl_data
.viewport
.y
,
1330 pipe_ctx
->scl_data
.recout
.width
,
1331 pipe_ctx
->scl_data
.recout
.height
,
1332 pipe_ctx
->scl_data
.recout
.x
,
1333 pipe_ctx
->scl_data
.recout
.y
);
1334 print_rq_dlg_ttu(dc
, pipe_ctx
);
1338 static void program_gamut_remap(struct pipe_ctx
*pipe_ctx
)
1340 struct xfm_grph_csc_adjustment adjust
;
1341 memset(&adjust
, 0, sizeof(adjust
));
1342 adjust
.gamut_adjust_type
= GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS
;
1345 if (pipe_ctx
->stream
->public.gamut_remap_matrix
.enable_remap
== true) {
1346 adjust
.gamut_adjust_type
= GRAPHICS_GAMUT_ADJUST_TYPE_SW
;
1347 adjust
.temperature_matrix
[0] =
1349 public.gamut_remap_matrix
.matrix
[0];
1350 adjust
.temperature_matrix
[1] =
1352 public.gamut_remap_matrix
.matrix
[1];
1353 adjust
.temperature_matrix
[2] =
1355 public.gamut_remap_matrix
.matrix
[2];
1356 adjust
.temperature_matrix
[3] =
1358 public.gamut_remap_matrix
.matrix
[4];
1359 adjust
.temperature_matrix
[4] =
1361 public.gamut_remap_matrix
.matrix
[5];
1362 adjust
.temperature_matrix
[5] =
1364 public.gamut_remap_matrix
.matrix
[6];
1365 adjust
.temperature_matrix
[6] =
1367 public.gamut_remap_matrix
.matrix
[8];
1368 adjust
.temperature_matrix
[7] =
1370 public.gamut_remap_matrix
.matrix
[9];
1371 adjust
.temperature_matrix
[8] =
1373 public.gamut_remap_matrix
.matrix
[10];
1376 pipe_ctx
->xfm
->funcs
->transform_set_gamut_remap(pipe_ctx
->xfm
, &adjust
);
1380 static void program_csc_matrix(struct pipe_ctx
*pipe_ctx
,
1381 enum dc_color_space colorspace
,
1385 struct out_csc_color_matrix tbl_entry
;
1387 if (pipe_ctx
->stream
->public.csc_color_matrix
.enable_adjustment
1389 enum dc_color_space color_space
=
1390 pipe_ctx
->stream
->public.output_color_space
;
1392 //uint16_t matrix[12];
1393 for (i
= 0; i
< 12; i
++)
1394 tbl_entry
.regval
[i
] = pipe_ctx
->stream
->public.csc_color_matrix
.matrix
[i
];
1396 tbl_entry
.color_space
= color_space
;
1397 //tbl_entry.regval = matrix;
1398 pipe_ctx
->opp
->funcs
->opp_set_csc_adjustment(pipe_ctx
->opp
, &tbl_entry
);
1401 static bool is_lower_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1403 if (pipe_ctx
->surface
->public.visible
)
1405 if (pipe_ctx
->bottom_pipe
&& is_lower_pipe_tree_visible(pipe_ctx
->bottom_pipe
))
1410 static bool is_upper_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1412 if (pipe_ctx
->surface
->public.visible
)
1414 if (pipe_ctx
->top_pipe
&& is_upper_pipe_tree_visible(pipe_ctx
->top_pipe
))
1419 static bool is_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1421 if (pipe_ctx
->surface
->public.visible
)
1423 if (pipe_ctx
->top_pipe
&& is_upper_pipe_tree_visible(pipe_ctx
->top_pipe
))
1425 if (pipe_ctx
->bottom_pipe
&& is_lower_pipe_tree_visible(pipe_ctx
->bottom_pipe
))
1430 static bool is_rgb_cspace(enum dc_color_space output_color_space
)
1432 switch (output_color_space
) {
1433 case COLOR_SPACE_SRGB
:
1434 case COLOR_SPACE_SRGB_LIMITED
:
1435 case COLOR_SPACE_2020_RGB_FULLRANGE
:
1436 case COLOR_SPACE_2020_RGB_LIMITEDRANGE
:
1437 case COLOR_SPACE_ADOBERGB
:
1439 case COLOR_SPACE_YCBCR601
:
1440 case COLOR_SPACE_YCBCR709
:
1441 case COLOR_SPACE_YCBCR601_LIMITED
:
1442 case COLOR_SPACE_YCBCR709_LIMITED
:
1443 case COLOR_SPACE_2020_YCBCR
:
1446 /* Add a case to switch */
1447 BREAK_TO_DEBUGGER();
1452 static void dcn10_get_surface_visual_confirm_color(
1453 const struct pipe_ctx
*pipe_ctx
,
1454 struct tg_color
*color
)
1456 uint32_t color_value
= MAX_TG_COLOR_VALUE
;
1458 switch (pipe_ctx
->scl_data
.format
) {
1459 case PIXEL_FORMAT_ARGB8888
:
1460 /* set boarder color to red */
1461 color
->color_r_cr
= color_value
;
1464 case PIXEL_FORMAT_ARGB2101010
:
1465 /* set boarder color to blue */
1466 color
->color_b_cb
= color_value
;
1468 case PIXEL_FORMAT_420BPP8
:
1469 /* set boarder color to green */
1470 color
->color_g_y
= color_value
;
1472 case PIXEL_FORMAT_420BPP10
:
1473 /* set boarder color to yellow */
1474 color
->color_g_y
= color_value
;
1475 color
->color_r_cr
= color_value
;
1477 case PIXEL_FORMAT_FP16
:
1478 /* set boarder color to white */
1479 color
->color_r_cr
= color_value
;
1480 color
->color_b_cb
= color_value
;
1481 color
->color_g_y
= color_value
;
1488 static void update_dchubp_dpp(
1490 struct pipe_ctx
*pipe_ctx
,
1491 struct validate_context
*context
)
1493 struct dce_hwseq
*hws
= dc
->hwseq
;
1494 struct mem_input
*mi
= pipe_ctx
->mi
;
1495 struct input_pixel_processor
*ipp
= pipe_ctx
->ipp
;
1496 struct core_surface
*surface
= pipe_ctx
->surface
;
1497 union plane_size size
= surface
->public.plane_size
;
1498 struct default_adjustment ocsc
= {0};
1499 struct tg_color black_color
= {0};
1500 struct mpcc_cfg mpcc_cfg
;
1501 bool per_pixel_alpha
= surface
->public.per_pixel_alpha
&& pipe_ctx
->bottom_pipe
;
1503 /* TODO: proper fix once fpga works */
1504 /* depends on DML calculation, DPP clock value may change dynamically */
1508 pipe_ctx
->pix_clk_params
.requested_pix_clk
,
1509 context
->bw
.dcn
.calc_clk
.dppclk_div
);
1510 dc
->current_context
->bw
.dcn
.cur_clk
.dppclk_div
=
1511 context
->bw
.dcn
.calc_clk
.dppclk_div
;
1512 context
->bw
.dcn
.cur_clk
.dppclk_div
= context
->bw
.dcn
.calc_clk
.dppclk_div
;
1514 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
1515 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
1516 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
1518 REG_UPDATE(DCHUBP_CNTL
[pipe_ctx
->pipe_idx
], HUBP_VTG_SEL
, pipe_ctx
->tg
->inst
);
1520 update_plane_addr(dc
, pipe_ctx
);
1522 mi
->funcs
->mem_input_setup(
1524 &pipe_ctx
->dlg_regs
,
1525 &pipe_ctx
->ttu_regs
,
1527 &pipe_ctx
->pipe_dlg_param
);
1529 size
.grph
.surface_size
= pipe_ctx
->scl_data
.viewport
;
1531 if (dc
->public.config
.gpu_vm_support
)
1532 mi
->funcs
->mem_input_program_pte_vm(
1534 surface
->public.format
,
1535 &surface
->public.tiling_info
,
1536 surface
->public.rotation
);
1538 ipp
->funcs
->ipp_setup(ipp
,
1539 surface
->public.format
,
1541 IPP_OUTPUT_FORMAT_12_BIT_FIX
);
1543 pipe_ctx
->scl_data
.lb_params
.alpha_en
= per_pixel_alpha
;
1544 mpcc_cfg
.top_dpp_id
= pipe_ctx
->pipe_idx
;
1545 if (pipe_ctx
->bottom_pipe
)
1546 mpcc_cfg
.bot_mpcc_id
= pipe_ctx
->bottom_pipe
->mpcc
->inst
;
1548 mpcc_cfg
.bot_mpcc_id
= 0xf;
1549 mpcc_cfg
.opp_id
= pipe_ctx
->tg
->inst
;
1550 mpcc_cfg
.top_of_tree
= pipe_ctx
->pipe_idx
== pipe_ctx
->tg
->inst
;
1551 mpcc_cfg
.per_pixel_alpha
= per_pixel_alpha
;
1552 /* DCN1.0 has output CM before MPC which seems to screw with
1553 * pre-multiplied alpha.
1555 mpcc_cfg
.pre_multiplied_alpha
= is_rgb_cspace(
1556 pipe_ctx
->stream
->public.output_color_space
)
1558 pipe_ctx
->mpcc
->funcs
->set(pipe_ctx
->mpcc
, &mpcc_cfg
);
1560 if (dc
->public.debug
.surface_visual_confirm
) {
1561 dcn10_get_surface_visual_confirm_color(pipe_ctx
, &black_color
);
1563 color_space_to_black_color(
1564 dc
, pipe_ctx
->stream
->public.output_color_space
,
1567 pipe_ctx
->mpcc
->funcs
->set_bg_color(pipe_ctx
->mpcc
, &black_color
);
1569 pipe_ctx
->scl_data
.lb_params
.depth
= LB_PIXEL_DEPTH_30BPP
;
1570 /* scaler configuration */
1571 pipe_ctx
->xfm
->funcs
->transform_set_scaler(
1572 pipe_ctx
->xfm
, &pipe_ctx
->scl_data
);
1573 mi
->funcs
->mem_program_viewport(mi
,
1574 &pipe_ctx
->scl_data
.viewport
, &pipe_ctx
->scl_data
.viewport_c
);
1577 program_gamut_remap(pipe_ctx
);
1579 /*TODO add adjustments parameters*/
1580 ocsc
.out_color_space
= pipe_ctx
->stream
->public.output_color_space
;
1581 pipe_ctx
->opp
->funcs
->opp_set_csc_default(pipe_ctx
->opp
, &ocsc
);
1583 mi
->funcs
->mem_input_program_surface_config(
1585 surface
->public.format
,
1586 &surface
->public.tiling_info
,
1588 surface
->public.rotation
,
1589 &surface
->public.dcc
,
1590 surface
->public.horizontal_mirror
);
1592 mi
->funcs
->set_blank(mi
, !is_pipe_tree_visible(pipe_ctx
));
1595 static void program_all_pipe_in_tree(
1597 struct pipe_ctx
*pipe_ctx
,
1598 struct validate_context
*context
)
1600 unsigned int ref_clk_mhz
= dc
->res_pool
->ref_clock_inKhz
/1000;
1602 if (pipe_ctx
->top_pipe
== NULL
) {
1604 /* lock otg_master_update to process all pipes associated with
1605 * this OTG. this is done only one time.
1607 /* watermark is for all pipes */
1608 pipe_ctx
->mi
->funcs
->program_watermarks(
1609 pipe_ctx
->mi
, &context
->bw
.dcn
.watermarks
, ref_clk_mhz
);
1611 if (dc
->public.debug
.sanity_checks
) {
1612 /* pstate stuck check after watermark update */
1613 verify_allow_pstate_change_high(dc
->hwseq
);
1616 pipe_ctx
->tg
->funcs
->lock(pipe_ctx
->tg
);
1618 pipe_ctx
->tg
->dlg_otg_param
.vready_offset
= pipe_ctx
->pipe_dlg_param
.vready_offset
;
1619 pipe_ctx
->tg
->dlg_otg_param
.vstartup_start
= pipe_ctx
->pipe_dlg_param
.vstartup_start
;
1620 pipe_ctx
->tg
->dlg_otg_param
.vupdate_offset
= pipe_ctx
->pipe_dlg_param
.vupdate_offset
;
1621 pipe_ctx
->tg
->dlg_otg_param
.vupdate_width
= pipe_ctx
->pipe_dlg_param
.vupdate_width
;
1622 pipe_ctx
->tg
->dlg_otg_param
.signal
= pipe_ctx
->stream
->signal
;
1624 pipe_ctx
->tg
->funcs
->program_global_sync(
1626 pipe_ctx
->tg
->funcs
->set_blank(pipe_ctx
->tg
, !is_pipe_tree_visible(pipe_ctx
));
1629 if (pipe_ctx
->surface
!= NULL
) {
1630 dcn10_power_on_fe(dc
, pipe_ctx
, context
);
1631 update_dchubp_dpp(dc
, pipe_ctx
, context
);
1634 if (dc
->public.debug
.sanity_checks
) {
1635 /* pstate stuck check after each pipe is programmed */
1636 verify_allow_pstate_change_high(dc
->hwseq
);
1639 if (pipe_ctx
->bottom_pipe
!= NULL
)
1640 program_all_pipe_in_tree(dc
, pipe_ctx
->bottom_pipe
, context
);
1643 static void dcn10_pplib_apply_display_requirements(
1645 struct validate_context
*context
)
1647 struct dm_pp_display_configuration
*pp_display_cfg
= &context
->pp_display_cfg
;
1649 pp_display_cfg
->all_displays_in_sync
= false;/*todo*/
1650 pp_display_cfg
->nb_pstate_switch_disable
= false;
1651 pp_display_cfg
->min_engine_clock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_khz
;
1652 pp_display_cfg
->min_memory_clock_khz
= context
->bw
.dcn
.cur_clk
.fclk_khz
;
1653 pp_display_cfg
->min_engine_clock_deep_sleep_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
;
1654 pp_display_cfg
->min_dcfc_deep_sleep_clock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
;
1655 pp_display_cfg
->avail_mclk_switch_time_us
=
1656 context
->bw
.dcn
.cur_clk
.dram_ccm_us
> 0 ? context
->bw
.dcn
.cur_clk
.dram_ccm_us
: 0;
1657 pp_display_cfg
->avail_mclk_switch_time_in_disp_active_us
=
1658 context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
> 0 ? context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
: 0;
1659 pp_display_cfg
->min_dcfclock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_khz
;
1660 pp_display_cfg
->disp_clk_khz
= context
->bw
.dcn
.cur_clk
.dispclk_khz
;
1661 dce110_fill_display_configs(context
, pp_display_cfg
);
1663 if (memcmp(&dc
->prev_display_config
, pp_display_cfg
, sizeof(
1664 struct dm_pp_display_configuration
)) != 0)
1665 dm_pp_apply_display_requirements(dc
->ctx
, pp_display_cfg
);
1667 dc
->prev_display_config
= *pp_display_cfg
;
1670 static void dcn10_apply_ctx_for_surface(
1672 struct core_surface
*surface
,
1673 struct validate_context
*context
)
1677 if (dc
->public.debug
.sanity_checks
)
1678 verify_allow_pstate_change_high(dc
->hwseq
);
1683 for (be_idx
= 0; be_idx
< dc
->res_pool
->pipe_count
; be_idx
++)
1684 if (surface
== context
->res_ctx
.pipe_ctx
[be_idx
].surface
)
1687 /* reset unused mpcc */
1688 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1689 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1690 struct pipe_ctx
*old_pipe_ctx
=
1691 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
1693 if (!pipe_ctx
->surface
&& !old_pipe_ctx
->surface
)
1697 * Powergate reused pipes that are not powergated
1698 * fairly hacky right now, using opp_id as indicator
1701 if (pipe_ctx
->surface
&& !old_pipe_ctx
->surface
) {
1702 if (pipe_ctx
->mpcc
->opp_id
!= 0xf && pipe_ctx
->tg
->inst
== be_idx
) {
1703 dcn10_power_down_fe(dc
, pipe_ctx
->pipe_idx
);
1705 * power down fe will unlock when calling reset, need
1706 * to lock it back here. Messy, need rework.
1708 pipe_ctx
->tg
->funcs
->lock(pipe_ctx
->tg
);
1713 if ((!pipe_ctx
->surface
&& old_pipe_ctx
->surface
)
1714 || (!pipe_ctx
->stream
&& old_pipe_ctx
->stream
)) {
1715 struct mpcc_cfg mpcc_cfg
;
1716 int opp_id_cached
= old_pipe_ctx
->mpcc
->opp_id
;
1718 if (old_pipe_ctx
->tg
->inst
!= be_idx
)
1721 if (!old_pipe_ctx
->top_pipe
) {
1727 mpcc_cfg
.opp_id
= 0xf;
1728 mpcc_cfg
.top_dpp_id
= 0xf;
1729 mpcc_cfg
.bot_mpcc_id
= 0xf;
1730 mpcc_cfg
.top_of_tree
= !old_pipe_ctx
->top_pipe
;
1731 old_pipe_ctx
->mpcc
->funcs
->set(old_pipe_ctx
->mpcc
, &mpcc_cfg
);
1733 if (dc
->public.debug
.sanity_checks
)
1734 verify_allow_pstate_change_high(dc
->hwseq
);
1737 * the mpcc is the only thing that keeps track of the mpcc
1738 * mapping for reset front end right now. Might need some
1741 old_pipe_ctx
->mpcc
->opp_id
= opp_id_cached
;
1743 old_pipe_ctx
->top_pipe
= NULL
;
1744 old_pipe_ctx
->bottom_pipe
= NULL
;
1745 old_pipe_ctx
->surface
= NULL
;
1747 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
1748 "Reset mpcc for pipe %d\n",
1749 old_pipe_ctx
->pipe_idx
);
1753 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1754 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1756 if (pipe_ctx
->surface
!= surface
)
1759 /* looking for top pipe to program */
1760 if (!pipe_ctx
->top_pipe
)
1761 program_all_pipe_in_tree(dc
, pipe_ctx
, context
);
1764 dm_logger_write(dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1765 "\n============== Watermark parameters ==============\n"
1766 "a.urgent_ns: %d \n"
1767 "a.cstate_enter_plus_exit: %d \n"
1768 "a.cstate_exit: %d \n"
1769 "a.pstate_change: %d \n"
1770 "a.pte_meta_urgent: %d \n"
1771 "b.urgent_ns: %d \n"
1772 "b.cstate_enter_plus_exit: %d \n"
1773 "b.cstate_exit: %d \n"
1774 "b.pstate_change: %d \n"
1775 "b.pte_meta_urgent: %d \n",
1776 context
->bw
.dcn
.watermarks
.a
.urgent_ns
,
1777 context
->bw
.dcn
.watermarks
.a
.cstate_pstate
.cstate_enter_plus_exit_ns
,
1778 context
->bw
.dcn
.watermarks
.a
.cstate_pstate
.cstate_exit_ns
,
1779 context
->bw
.dcn
.watermarks
.a
.cstate_pstate
.pstate_change_ns
,
1780 context
->bw
.dcn
.watermarks
.a
.pte_meta_urgent_ns
,
1781 context
->bw
.dcn
.watermarks
.b
.urgent_ns
,
1782 context
->bw
.dcn
.watermarks
.b
.cstate_pstate
.cstate_enter_plus_exit_ns
,
1783 context
->bw
.dcn
.watermarks
.b
.cstate_pstate
.cstate_exit_ns
,
1784 context
->bw
.dcn
.watermarks
.b
.cstate_pstate
.pstate_change_ns
,
1785 context
->bw
.dcn
.watermarks
.b
.pte_meta_urgent_ns
1787 dm_logger_write(dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1788 "\nc.urgent_ns: %d \n"
1789 "c.cstate_enter_plus_exit: %d \n"
1790 "c.cstate_exit: %d \n"
1791 "c.pstate_change: %d \n"
1792 "c.pte_meta_urgent: %d \n"
1793 "d.urgent_ns: %d \n"
1794 "d.cstate_enter_plus_exit: %d \n"
1795 "d.cstate_exit: %d \n"
1796 "d.pstate_change: %d \n"
1797 "d.pte_meta_urgent: %d \n"
1798 "========================================================\n",
1799 context
->bw
.dcn
.watermarks
.c
.urgent_ns
,
1800 context
->bw
.dcn
.watermarks
.c
.cstate_pstate
.cstate_enter_plus_exit_ns
,
1801 context
->bw
.dcn
.watermarks
.c
.cstate_pstate
.cstate_exit_ns
,
1802 context
->bw
.dcn
.watermarks
.c
.cstate_pstate
.pstate_change_ns
,
1803 context
->bw
.dcn
.watermarks
.c
.pte_meta_urgent_ns
,
1804 context
->bw
.dcn
.watermarks
.d
.urgent_ns
,
1805 context
->bw
.dcn
.watermarks
.d
.cstate_pstate
.cstate_enter_plus_exit_ns
,
1806 context
->bw
.dcn
.watermarks
.d
.cstate_pstate
.cstate_exit_ns
,
1807 context
->bw
.dcn
.watermarks
.d
.cstate_pstate
.pstate_change_ns
,
1808 context
->bw
.dcn
.watermarks
.d
.pte_meta_urgent_ns
1811 if (dc
->public.debug
.sanity_checks
)
1812 verify_allow_pstate_change_high(dc
->hwseq
);
1815 static void dcn10_set_bandwidth(
1817 struct validate_context
*context
,
1818 bool decrease_allowed
)
1820 struct dm_pp_clock_for_voltage_req clock
;
1822 if (IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
1825 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dispclk_khz
1826 > dc
->current_context
->bw
.dcn
.cur_clk
.dispclk_khz
) {
1827 dc
->res_pool
->display_clock
->funcs
->set_clock(
1828 dc
->res_pool
->display_clock
,
1829 context
->bw
.dcn
.calc_clk
.dispclk_khz
);
1830 dc
->current_context
->bw
.dcn
.cur_clk
.dispclk_khz
=
1831 context
->bw
.dcn
.calc_clk
.dispclk_khz
;
1833 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dcfclk_khz
1834 > dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_khz
) {
1835 clock
.clk_type
= DM_PP_CLOCK_TYPE_DCFCLK
;
1836 clock
.clocks_in_khz
= context
->bw
.dcn
.calc_clk
.dcfclk_khz
;
1837 dm_pp_apply_clock_for_voltage_request(dc
->ctx
, &clock
);
1838 dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_khz
= clock
.clocks_in_khz
;
1839 context
->bw
.dcn
.cur_clk
.dcfclk_khz
= clock
.clocks_in_khz
;
1841 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.fclk_khz
1842 > dc
->current_context
->bw
.dcn
.cur_clk
.fclk_khz
) {
1843 clock
.clk_type
= DM_PP_CLOCK_TYPE_FCLK
;
1844 clock
.clocks_in_khz
= context
->bw
.dcn
.calc_clk
.fclk_khz
;
1845 dm_pp_apply_clock_for_voltage_request(dc
->ctx
, &clock
);
1846 dc
->current_context
->bw
.dcn
.calc_clk
.fclk_khz
= clock
.clocks_in_khz
;
1847 context
->bw
.dcn
.cur_clk
.fclk_khz
= clock
.clocks_in_khz
;
1849 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
1850 > dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
) {
1851 dc
->current_context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
=
1852 context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
;
1853 context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
=
1854 context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
;
1856 /* Decrease in freq is increase in period so opposite comparison for dram_ccm */
1857 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dram_ccm_us
1858 < dc
->current_context
->bw
.dcn
.cur_clk
.dram_ccm_us
) {
1859 dc
->current_context
->bw
.dcn
.calc_clk
.dram_ccm_us
=
1860 context
->bw
.dcn
.calc_clk
.dram_ccm_us
;
1861 context
->bw
.dcn
.cur_clk
.dram_ccm_us
=
1862 context
->bw
.dcn
.calc_clk
.dram_ccm_us
;
1864 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
1865 < dc
->current_context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
) {
1866 dc
->current_context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
=
1867 context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
;
1868 context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
=
1869 context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
;
1871 dcn10_pplib_apply_display_requirements(dc
, context
);
1873 /* need to fix this function. not doing the right thing here */
1876 static void set_drr(struct pipe_ctx
**pipe_ctx
,
1877 int num_pipes
, int vmin
, int vmax
)
1880 struct drr_params params
= {0};
1882 params
.vertical_total_max
= vmax
;
1883 params
.vertical_total_min
= vmin
;
1885 /* TODO: If multiple pipes are to be supported, you need
1888 for (i
= 0; i
< num_pipes
; i
++) {
1889 pipe_ctx
[i
]->tg
->funcs
->set_drr(pipe_ctx
[i
]->tg
, ¶ms
);
1893 static void get_position(struct pipe_ctx
**pipe_ctx
,
1895 struct crtc_position
*position
)
1899 /* TODO: handle pipes > 1
1901 for (i
= 0; i
< num_pipes
; i
++)
1902 pipe_ctx
[i
]->tg
->funcs
->get_position(pipe_ctx
[i
]->tg
, position
);
1905 static void set_static_screen_control(struct pipe_ctx
**pipe_ctx
,
1906 int num_pipes
, const struct dc_static_screen_events
*events
)
1909 unsigned int value
= 0;
1911 if (events
->surface_update
)
1913 if (events
->cursor_update
)
1916 for (i
= 0; i
< num_pipes
; i
++)
1917 pipe_ctx
[i
]->tg
->funcs
->
1918 set_static_screen_control(pipe_ctx
[i
]->tg
, value
);
1921 static void set_plane_config(
1922 const struct core_dc
*dc
,
1923 struct pipe_ctx
*pipe_ctx
,
1924 struct resource_context
*res_ctx
)
1927 program_gamut_remap(pipe_ctx
);
1930 static void dcn10_config_stereo_parameters(
1931 struct core_stream
*stream
, struct crtc_stereo_flags
*flags
)
1933 enum view_3d_format view_format
= stream
->public.view_format
;
1934 enum dc_timing_3d_format timing_3d_format
=\
1935 stream
->public.timing
.timing_3d_format
;
1936 bool non_stereo_timing
= false;
1938 if (timing_3d_format
== TIMING_3D_FORMAT_NONE
||
1939 timing_3d_format
== TIMING_3D_FORMAT_SIDE_BY_SIDE
||
1940 timing_3d_format
== TIMING_3D_FORMAT_TOP_AND_BOTTOM
)
1941 non_stereo_timing
= true;
1943 if (non_stereo_timing
== false &&
1944 view_format
== VIEW_3D_FORMAT_FRAME_SEQUENTIAL
) {
1946 flags
->PROGRAM_STEREO
= 1;
1947 flags
->PROGRAM_POLARITY
= 1;
1948 if (timing_3d_format
== TIMING_3D_FORMAT_INBAND_FA
||
1949 timing_3d_format
== TIMING_3D_FORMAT_DP_HDMI_INBAND_FA
||
1950 timing_3d_format
== TIMING_3D_FORMAT_SIDEBAND_FA
) {
1951 enum display_dongle_type dongle
= \
1952 stream
->sink
->link
->public.ddc
->dongle_type
;
1953 if (dongle
== DISPLAY_DONGLE_DP_VGA_CONVERTER
||
1954 dongle
== DISPLAY_DONGLE_DP_DVI_CONVERTER
||
1955 dongle
== DISPLAY_DONGLE_DP_HDMI_CONVERTER
)
1956 flags
->DISABLE_STEREO_DP_SYNC
= 1;
1958 flags
->RIGHT_EYE_POLARITY
=\
1959 stream
->public.timing
.flags
.RIGHT_EYE_3D_POLARITY
;
1960 if (timing_3d_format
== TIMING_3D_FORMAT_HW_FRAME_PACKING
)
1961 flags
->FRAME_PACKED
= 1;
1967 static void dcn10_setup_stereo(struct pipe_ctx
*pipe_ctx
, struct core_dc
*dc
)
1969 struct crtc_stereo_flags flags
= { 0 };
1970 struct core_stream
*stream
= pipe_ctx
->stream
;
1972 dcn10_config_stereo_parameters(stream
, &flags
);
1974 pipe_ctx
->opp
->funcs
->opp_set_stereo_polarity(
1976 flags
.PROGRAM_STEREO
== 1 ? true:false,
1977 stream
->public.timing
.flags
.RIGHT_EYE_3D_POLARITY
== 1 ? true:false);
1979 pipe_ctx
->tg
->funcs
->program_stereo(
1981 &stream
->public.timing
,
1987 static void dcn10_log_hw_state(struct core_dc
*dc
)
1989 struct dc_context
*dc_ctx
= dc
->ctx
;
1990 struct dce_hwseq
*hws
= dc
->hwseq
;
1992 DTN_INFO("%s: Hello World", __func__
);
1994 if (REG(MPC_CRC_RESULT_GB
))
1995 DTN_INFO("MPC_CRC_RESULT_GB:%d MPC_CRC_RESULT_C:%d MPC_CRC_RESULT_AR:%d\n",
1996 REG_READ(MPC_CRC_RESULT_GB
), REG_READ(MPC_CRC_RESULT_C
), REG_READ(MPC_CRC_RESULT_AR
));
1997 if (REG(DPP_TOP0_DPP_CRC_VAL_B_A
))
1998 DTN_INFO("DPP_TOP0_DPP_CRC_VAL_B_A:%d DPP_TOP0_DPP_CRC_VAL_R_G:%d\n",
1999 REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A
), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G
));
2000 /* todo: add meaningful register reads and print out HW state
2005 static bool dcn10_dummy_display_power_gating(
2007 uint8_t controller_id
,
2008 struct dc_bios
*dcb
,
2009 enum pipe_gating_control power_gating
)
2014 void dcn10_update_pending_status(struct pipe_ctx
*pipe_ctx
)
2016 struct core_surface
*surface
= pipe_ctx
->surface
;
2017 struct timing_generator
*tg
= pipe_ctx
->tg
;
2019 if (surface
->ctx
->dc
->debug
.sanity_checks
) {
2020 struct core_dc
*dc
= DC_TO_CORE(surface
->ctx
->dc
);
2022 verify_allow_pstate_change_high(dc
->hwseq
);
2025 if (surface
== NULL
)
2028 surface
->status
.is_flip_pending
=
2029 pipe_ctx
->mi
->funcs
->mem_input_is_flip_pending(
2032 /* DCN we read INUSE address in MI, do we still need this wa? */
2033 if (surface
->status
.is_flip_pending
&&
2034 !surface
->public.visible
) {
2035 pipe_ctx
->mi
->current_address
=
2036 pipe_ctx
->mi
->request_address
;
2037 BREAK_TO_DEBUGGER();
2040 surface
->status
.current_address
= pipe_ctx
->mi
->current_address
;
2041 if (pipe_ctx
->mi
->current_address
.type
== PLN_ADDR_TYPE_GRPH_STEREO
&&
2042 tg
->funcs
->is_stereo_left_eye
) {
2043 surface
->status
.is_right_eye
=
2044 !tg
->funcs
->is_stereo_left_eye(pipe_ctx
->tg
);
2048 static const struct hw_sequencer_funcs dcn10_funcs
= {
2049 .program_gamut_remap
= program_gamut_remap
,
2050 .program_csc_matrix
= program_csc_matrix
,
2051 .init_hw
= dcn10_init_hw
,
2052 .apply_ctx_to_hw
= dce110_apply_ctx_to_hw
,
2053 .apply_ctx_for_surface
= dcn10_apply_ctx_for_surface
,
2054 .set_plane_config
= set_plane_config
,
2055 .update_plane_addr
= update_plane_addr
,
2056 .update_pending_status
= dcn10_update_pending_status
,
2057 .set_input_transfer_func
= dcn10_set_input_transfer_func
,
2058 .set_output_transfer_func
= dcn10_set_output_transfer_func
,
2059 .power_down
= dce110_power_down
,
2060 .enable_accelerated_mode
= dce110_enable_accelerated_mode
,
2061 .enable_timing_synchronization
= dcn10_enable_timing_synchronization
,
2062 .update_info_frame
= dce110_update_info_frame
,
2063 .enable_stream
= dce110_enable_stream
,
2064 .disable_stream
= dce110_disable_stream
,
2065 .unblank_stream
= dce110_unblank_stream
,
2066 .enable_display_power_gating
= dcn10_dummy_display_power_gating
,
2067 .power_down_front_end
= dcn10_power_down_fe
,
2068 .power_on_front_end
= dcn10_power_on_fe
,
2069 .pipe_control_lock
= dcn10_pipe_control_lock
,
2070 .set_bandwidth
= dcn10_set_bandwidth
,
2071 .reset_hw_ctx_wrap
= reset_hw_ctx_wrap
,
2072 .prog_pixclk_crtc_otg
= dcn10_prog_pixclk_crtc_otg
,
2074 .get_position
= get_position
,
2075 .set_static_screen_control
= set_static_screen_control
,
2076 .setup_stereo
= dcn10_setup_stereo
,
2077 .set_avmute
= dce110_set_avmute
,
2078 .log_hw_state
= dcn10_log_hw_state
2082 void dcn10_hw_sequencer_construct(struct core_dc
*dc
)
2084 dc
->hwss
= dcn10_funcs
;