Merge tag 'soc-drivers-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-block.git] / drivers / gpu / drm / amd / display / dc / hwss / dcn20 / dcn20_hwseq.c
CommitLineData
7ed4e635
HW
1/*
2 * Copyright 2016 Advanced Micro Devices, Inc.
3 *
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:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
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.
21 *
22 * Authors: AMD
23 *
24 */
c602b36f 25#include <linux/delay.h>
7ed4e635
HW
26
27#include "dm_services.h"
78c77382 28#include "basics/dc_common.h"
7ed4e635
HW
29#include "dm_helpers.h"
30#include "core_types.h"
31#include "resource.h"
e53524cd 32#include "dcn20/dcn20_resource.h"
7ed4e635
HW
33#include "dcn20_hwseq.h"
34#include "dce/dce_hwseq.h"
e53524cd
MA
35#include "dcn20/dcn20_dsc.h"
36#include "dcn20/dcn20_optc.h"
7ed4e635
HW
37#include "abm.h"
38#include "clk_mgr.h"
39#include "dmcu.h"
40#include "hubp.h"
41#include "timing_generator.h"
42#include "opp.h"
43#include "ipp.h"
44#include "mpc.h"
45#include "mcif_wb.h"
78c77382 46#include "dchubbub.h"
7ed4e635
HW
47#include "reg_helper.h"
48#include "dcn10/dcn10_cm_common.h"
7ed4e635
HW
49#include "vm_helper.h"
50#include "dccg.h"
dc6e2448
WW
51#include "dc_dmub_srv.h"
52#include "dce/dmub_hw_lock_mgr.h"
60df8441 53#include "hw_sequencer.h"
3550d622 54#include "dpcd_defs.h"
0d4b4253 55#include "inc/link_enc_cfg.h"
dfabe597 56#include "link_hwss.h"
d5a43956 57#include "link.h"
09a4ec5d 58#include "dc_state_priv.h"
7ed4e635 59
5d72e247
HM
60#define DC_LOGGER \
61 dc_logger
62#define DC_LOGGER_INIT(logger) \
63 struct dal_logger *dc_logger = logger
7ed4e635
HW
64
65#define CTX \
66 hws->ctx
67#define REG(reg)\
68 hws->regs->reg
69
70#undef FN
71#define FN(reg_name, field_name) \
72 hws->shifts->field_name, hws->masks->field_name
73
78c77382
AK
74static int find_free_gsl_group(const struct dc *dc)
75{
76 if (dc->res_pool->gsl_groups.gsl_0 == 0)
77 return 1;
78 if (dc->res_pool->gsl_groups.gsl_1 == 0)
79 return 2;
80 if (dc->res_pool->gsl_groups.gsl_2 == 0)
81 return 3;
82
83 return 0;
84}
85
86/* NOTE: This is not a generic setup_gsl function (hence the suffix as_lock)
87 * This is only used to lock pipes in pipe splitting case with immediate flip
88 * Ordinary MPC/OTG locks suppress VUPDATE which doesn't help with immediate,
89 * so we get tearing with freesync since we cannot flip multiple pipes
90 * atomically.
91 * We use GSL for this:
92 * - immediate flip: find first available GSL group if not already assigned
93 * program gsl with that group, set current OTG as master
94 * and always us 0x4 = AND of flip_ready from all pipes
95 * - vsync flip: disable GSL if used
96 *
97 * Groups in stream_res are stored as +1 from HW registers, i.e.
98 * gsl_0 <=> pipe_ctx->stream_res.gsl_group == 1
99 * Using a magic value like -1 would require tracking all inits/resets
100 */
9fc64ead 101 void dcn20_setup_gsl_group_as_lock(
78c77382
AK
102 const struct dc *dc,
103 struct pipe_ctx *pipe_ctx,
104 bool enable)
105{
106 struct gsl_params gsl;
107 int group_idx;
108
109 memset(&gsl, 0, sizeof(struct gsl_params));
110
111 if (enable) {
112 /* return if group already assigned since GSL was set up
113 * for vsync flip, we would unassign so it can't be "left over"
114 */
115 if (pipe_ctx->stream_res.gsl_group > 0)
116 return;
117
118 group_idx = find_free_gsl_group(dc);
119 ASSERT(group_idx != 0);
120 pipe_ctx->stream_res.gsl_group = group_idx;
121
122 /* set gsl group reg field and mark resource used */
123 switch (group_idx) {
124 case 1:
125 gsl.gsl0_en = 1;
126 dc->res_pool->gsl_groups.gsl_0 = 1;
127 break;
128 case 2:
129 gsl.gsl1_en = 1;
130 dc->res_pool->gsl_groups.gsl_1 = 1;
131 break;
132 case 3:
133 gsl.gsl2_en = 1;
134 dc->res_pool->gsl_groups.gsl_2 = 1;
135 break;
136 default:
137 BREAK_TO_DEBUGGER();
138 return; // invalid case
139 }
140 gsl.gsl_master_en = 1;
141 } else {
142 group_idx = pipe_ctx->stream_res.gsl_group;
143 if (group_idx == 0)
144 return; // if not in use, just return
145
146 pipe_ctx->stream_res.gsl_group = 0;
147
148 /* unset gsl group reg field and mark resource free */
149 switch (group_idx) {
150 case 1:
151 gsl.gsl0_en = 0;
152 dc->res_pool->gsl_groups.gsl_0 = 0;
153 break;
154 case 2:
155 gsl.gsl1_en = 0;
156 dc->res_pool->gsl_groups.gsl_1 = 0;
157 break;
158 case 3:
159 gsl.gsl2_en = 0;
160 dc->res_pool->gsl_groups.gsl_2 = 0;
161 break;
162 default:
163 BREAK_TO_DEBUGGER();
164 return;
165 }
166 gsl.gsl_master_en = 0;
167 }
168
169 /* at this point we want to program whether it's to enable or disable */
170 if (pipe_ctx->stream_res.tg->funcs->set_gsl != NULL &&
171 pipe_ctx->stream_res.tg->funcs->set_gsl_source_select != NULL) {
172 pipe_ctx->stream_res.tg->funcs->set_gsl(
173 pipe_ctx->stream_res.tg,
174 &gsl);
175
176 pipe_ctx->stream_res.tg->funcs->set_gsl_source_select(
177 pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0);
178 } else
179 BREAK_TO_DEBUGGER();
180}
181
182void dcn20_set_flip_control_gsl(
183 struct pipe_ctx *pipe_ctx,
184 bool flip_immediate)
185{
186 if (pipe_ctx && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl)
187 pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl(
188 pipe_ctx->plane_res.hubp, flip_immediate);
189
190}
191
192void dcn20_enable_power_gating_plane(
7ed4e635
HW
193 struct dce_hwseq *hws,
194 bool enable)
195{
0bb80369 196 bool force_on = true; /* disable power gating */
504d3cae 197 uint32_t org_ip_request_cntl = 0;
7ed4e635
HW
198
199 if (enable)
0bb80369 200 force_on = false;
7ed4e635 201
504d3cae
HW
202 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
203 if (org_ip_request_cntl == 0)
204 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
205
7ed4e635
HW
206 /* DCHUBP0/1/2/3/4/5 */
207 REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on);
208 REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on);
209 REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on);
210 REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on);
46825fcf
TC
211 if (REG(DOMAIN8_PG_CONFIG))
212 REG_UPDATE(DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on);
213 if (REG(DOMAIN10_PG_CONFIG))
214 REG_UPDATE(DOMAIN10_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on);
7ed4e635
HW
215
216 /* DPP0/1/2/3/4/5 */
217 REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on);
218 REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on);
219 REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on);
220 REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on);
46825fcf
TC
221 if (REG(DOMAIN9_PG_CONFIG))
222 REG_UPDATE(DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on);
223 if (REG(DOMAIN11_PG_CONFIG))
224 REG_UPDATE(DOMAIN11_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on);
7ed4e635 225
46825fcf 226 /* DCS0/1/2/3/4/5 */
7ed4e635
HW
227 REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, force_on);
228 REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, force_on);
229 REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, force_on);
46825fcf
TC
230 if (REG(DOMAIN19_PG_CONFIG))
231 REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, force_on);
232 if (REG(DOMAIN20_PG_CONFIG))
233 REG_UPDATE(DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, force_on);
234 if (REG(DOMAIN21_PG_CONFIG))
235 REG_UPDATE(DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, force_on);
504d3cae
HW
236
237 if (org_ip_request_cntl == 0)
238 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
239
7ed4e635
HW
240}
241
c70b4016 242void dcn20_dccg_init(struct dce_hwseq *hws)
7ed4e635
HW
243{
244 /*
245 * set MICROSECOND_TIME_BASE_DIV
246 * 100Mhz refclk -> 0x120264
247 * 27Mhz refclk -> 0x12021b
248 * 48Mhz refclk -> 0x120230
249 *
250 */
251 REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x120264);
252
253 /*
254 * set MILLISECOND_TIME_BASE_DIV
255 * 100Mhz refclk -> 0x1186a0
256 * 27Mhz refclk -> 0x106978
257 * 48Mhz refclk -> 0x10bb80
258 *
259 */
260 REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x1186a0);
261
262 /* This value is dependent on the hardware pipeline delay so set once per SOC */
3577e167 263 REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0xe01003c);
7ed4e635
HW
264}
265
8a31820b 266void dcn20_disable_vga(
7ed4e635
HW
267 struct dce_hwseq *hws)
268{
269 REG_WRITE(D1VGA_CONTROL, 0);
270 REG_WRITE(D2VGA_CONTROL, 0);
271 REG_WRITE(D3VGA_CONTROL, 0);
272 REG_WRITE(D4VGA_CONTROL, 0);
273 REG_WRITE(D5VGA_CONTROL, 0);
274 REG_WRITE(D6VGA_CONTROL, 0);
275}
276
78c77382 277void dcn20_program_triple_buffer(
7ed4e635
HW
278 const struct dc *dc,
279 struct pipe_ctx *pipe_ctx,
78c77382 280 bool enable_triple_buffer)
7ed4e635
HW
281{
282 if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs) {
283 pipe_ctx->plane_res.hubp->funcs->hubp_enable_tripleBuffer(
284 pipe_ctx->plane_res.hubp,
78c77382 285 enable_triple_buffer);
7ed4e635
HW
286 }
287}
288
289/* Blank pixel data during initialization */
c70b4016 290void dcn20_init_blank(
7ed4e635
HW
291 struct dc *dc,
292 struct timing_generator *tg)
293{
f42ea55b 294 struct dce_hwseq *hws = dc->hwseq;
7ed4e635
HW
295 enum dc_color_space color_space;
296 struct tg_color black_color = {0};
297 struct output_pixel_processor *opp = NULL;
298 struct output_pixel_processor *bottom_opp = NULL;
299 uint32_t num_opps, opp_id_src0, opp_id_src1;
300 uint32_t otg_active_width, otg_active_height;
301
302 /* program opp dpg blank color */
303 color_space = COLOR_SPACE_SRGB;
304 color_space_to_black_color(dc, color_space, &black_color);
305
306 /* get the OTG active size */
307 tg->funcs->get_otg_active_size(tg,
308 &otg_active_width,
309 &otg_active_height);
310
311 /* get the OPTC source */
312 tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
245a0221
AC
313
314 if (opp_id_src0 >= dc->res_pool->res_cap->num_opp) {
315 ASSERT(false);
316 return;
317 }
7ed4e635
HW
318 opp = dc->res_pool->opps[opp_id_src0];
319
7052a801
MM
320 /* don't override the blank pattern if already enabled with the correct one. */
321 if (opp->funcs->dpg_is_blanked && opp->funcs->dpg_is_blanked(opp))
322 return;
323
7ed4e635
HW
324 if (num_opps == 2) {
325 otg_active_width = otg_active_width / 2;
245a0221
AC
326
327 if (opp_id_src1 >= dc->res_pool->res_cap->num_opp) {
328 ASSERT(false);
329 return;
330 }
7ed4e635
HW
331 bottom_opp = dc->res_pool->opps[opp_id_src1];
332 }
333
334 opp->funcs->opp_set_disp_pattern_generator(
335 opp,
336 CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
2057b7e1 337 CONTROLLER_DP_COLOR_SPACE_UDEFINED,
7ed4e635
HW
338 COLOR_DEPTH_UNDEFINED,
339 &black_color,
340 otg_active_width,
10b4e64e
WL
341 otg_active_height,
342 0);
7ed4e635
HW
343
344 if (num_opps == 2) {
345 bottom_opp->funcs->opp_set_disp_pattern_generator(
346 bottom_opp,
347 CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
2057b7e1 348 CONTROLLER_DP_COLOR_SPACE_UDEFINED,
7ed4e635
HW
349 COLOR_DEPTH_UNDEFINED,
350 &black_color,
351 otg_active_width,
10b4e64e
WL
352 otg_active_height,
353 0);
7ed4e635
HW
354 }
355
f42ea55b 356 hws->funcs.wait_for_blank_complete(opp);
7ed4e635
HW
357}
358
78c77382 359void dcn20_dsc_pg_control(
97bda032
HW
360 struct dce_hwseq *hws,
361 unsigned int dsc_inst,
362 bool power_on)
363{
364 uint32_t power_gate = power_on ? 0 : 1;
365 uint32_t pwr_status = power_on ? 0 : 2;
98ce8cc1 366 uint32_t org_ip_request_cntl = 0;
97bda032
HW
367
368 if (hws->ctx->dc->debug.disable_dsc_power_gate)
369 return;
370
371 if (REG(DOMAIN16_PG_CONFIG) == 0)
372 return;
373
98ce8cc1
NC
374 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
375 if (org_ip_request_cntl == 0)
376 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
377
97bda032
HW
378 switch (dsc_inst) {
379 case 0: /* DSC0 */
380 REG_UPDATE(DOMAIN16_PG_CONFIG,
381 DOMAIN16_POWER_GATE, power_gate);
382
383 REG_WAIT(DOMAIN16_PG_STATUS,
384 DOMAIN16_PGFSM_PWR_STATUS, pwr_status,
385 1, 1000);
386 break;
387 case 1: /* DSC1 */
388 REG_UPDATE(DOMAIN17_PG_CONFIG,
389 DOMAIN17_POWER_GATE, power_gate);
390
391 REG_WAIT(DOMAIN17_PG_STATUS,
392 DOMAIN17_PGFSM_PWR_STATUS, pwr_status,
393 1, 1000);
394 break;
395 case 2: /* DSC2 */
396 REG_UPDATE(DOMAIN18_PG_CONFIG,
397 DOMAIN18_POWER_GATE, power_gate);
398
399 REG_WAIT(DOMAIN18_PG_STATUS,
400 DOMAIN18_PGFSM_PWR_STATUS, pwr_status,
401 1, 1000);
402 break;
403 case 3: /* DSC3 */
404 REG_UPDATE(DOMAIN19_PG_CONFIG,
405 DOMAIN19_POWER_GATE, power_gate);
406
407 REG_WAIT(DOMAIN19_PG_STATUS,
408 DOMAIN19_PGFSM_PWR_STATUS, pwr_status,
409 1, 1000);
410 break;
411 case 4: /* DSC4 */
412 REG_UPDATE(DOMAIN20_PG_CONFIG,
413 DOMAIN20_POWER_GATE, power_gate);
414
415 REG_WAIT(DOMAIN20_PG_STATUS,
416 DOMAIN20_PGFSM_PWR_STATUS, pwr_status,
417 1, 1000);
418 break;
419 case 5: /* DSC5 */
420 REG_UPDATE(DOMAIN21_PG_CONFIG,
421 DOMAIN21_POWER_GATE, power_gate);
422
423 REG_WAIT(DOMAIN21_PG_STATUS,
424 DOMAIN21_PGFSM_PWR_STATUS, pwr_status,
425 1, 1000);
426 break;
427 default:
428 BREAK_TO_DEBUGGER();
429 break;
430 }
98ce8cc1
NC
431
432 if (org_ip_request_cntl == 0)
433 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
97bda032 434}
7ed4e635 435
78c77382 436void dcn20_dpp_pg_control(
7ed4e635
HW
437 struct dce_hwseq *hws,
438 unsigned int dpp_inst,
439 bool power_on)
440{
441 uint32_t power_gate = power_on ? 0 : 1;
442 uint32_t pwr_status = power_on ? 0 : 2;
443
444 if (hws->ctx->dc->debug.disable_dpp_power_gate)
445 return;
446 if (REG(DOMAIN1_PG_CONFIG) == 0)
447 return;
448
449 switch (dpp_inst) {
450 case 0: /* DPP0 */
451 REG_UPDATE(DOMAIN1_PG_CONFIG,
452 DOMAIN1_POWER_GATE, power_gate);
453
454 REG_WAIT(DOMAIN1_PG_STATUS,
455 DOMAIN1_PGFSM_PWR_STATUS, pwr_status,
456 1, 1000);
457 break;
458 case 1: /* DPP1 */
459 REG_UPDATE(DOMAIN3_PG_CONFIG,
460 DOMAIN3_POWER_GATE, power_gate);
461
462 REG_WAIT(DOMAIN3_PG_STATUS,
463 DOMAIN3_PGFSM_PWR_STATUS, pwr_status,
464 1, 1000);
465 break;
466 case 2: /* DPP2 */
467 REG_UPDATE(DOMAIN5_PG_CONFIG,
468 DOMAIN5_POWER_GATE, power_gate);
469
470 REG_WAIT(DOMAIN5_PG_STATUS,
471 DOMAIN5_PGFSM_PWR_STATUS, pwr_status,
472 1, 1000);
473 break;
474 case 3: /* DPP3 */
475 REG_UPDATE(DOMAIN7_PG_CONFIG,
476 DOMAIN7_POWER_GATE, power_gate);
477
478 REG_WAIT(DOMAIN7_PG_STATUS,
479 DOMAIN7_PGFSM_PWR_STATUS, pwr_status,
480 1, 1000);
481 break;
482 case 4: /* DPP4 */
483 REG_UPDATE(DOMAIN9_PG_CONFIG,
484 DOMAIN9_POWER_GATE, power_gate);
485
486 REG_WAIT(DOMAIN9_PG_STATUS,
487 DOMAIN9_PGFSM_PWR_STATUS, pwr_status,
488 1, 1000);
489 break;
490 case 5: /* DPP5 */
491 /*
492 * Do not power gate DPP5, should be left at HW default, power on permanently.
493 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard
494 * reset.
495 * REG_UPDATE(DOMAIN11_PG_CONFIG,
496 * DOMAIN11_POWER_GATE, power_gate);
497 *
498 * REG_WAIT(DOMAIN11_PG_STATUS,
499 * DOMAIN11_PGFSM_PWR_STATUS, pwr_status,
500 * 1, 1000);
501 */
502 break;
503 default:
504 BREAK_TO_DEBUGGER();
505 break;
506 }
507}
508
509
78c77382 510void dcn20_hubp_pg_control(
7ed4e635
HW
511 struct dce_hwseq *hws,
512 unsigned int hubp_inst,
513 bool power_on)
514{
515 uint32_t power_gate = power_on ? 0 : 1;
516 uint32_t pwr_status = power_on ? 0 : 2;
517
518 if (hws->ctx->dc->debug.disable_hubp_power_gate)
519 return;
520 if (REG(DOMAIN0_PG_CONFIG) == 0)
521 return;
522
523 switch (hubp_inst) {
524 case 0: /* DCHUBP0 */
525 REG_UPDATE(DOMAIN0_PG_CONFIG,
526 DOMAIN0_POWER_GATE, power_gate);
527
528 REG_WAIT(DOMAIN0_PG_STATUS,
529 DOMAIN0_PGFSM_PWR_STATUS, pwr_status,
530 1, 1000);
531 break;
532 case 1: /* DCHUBP1 */
533 REG_UPDATE(DOMAIN2_PG_CONFIG,
534 DOMAIN2_POWER_GATE, power_gate);
535
536 REG_WAIT(DOMAIN2_PG_STATUS,
537 DOMAIN2_PGFSM_PWR_STATUS, pwr_status,
538 1, 1000);
539 break;
540 case 2: /* DCHUBP2 */
541 REG_UPDATE(DOMAIN4_PG_CONFIG,
542 DOMAIN4_POWER_GATE, power_gate);
543
544 REG_WAIT(DOMAIN4_PG_STATUS,
545 DOMAIN4_PGFSM_PWR_STATUS, pwr_status,
546 1, 1000);
547 break;
548 case 3: /* DCHUBP3 */
549 REG_UPDATE(DOMAIN6_PG_CONFIG,
550 DOMAIN6_POWER_GATE, power_gate);
551
552 REG_WAIT(DOMAIN6_PG_STATUS,
553 DOMAIN6_PGFSM_PWR_STATUS, pwr_status,
554 1, 1000);
555 break;
556 case 4: /* DCHUBP4 */
557 REG_UPDATE(DOMAIN8_PG_CONFIG,
558 DOMAIN8_POWER_GATE, power_gate);
559
560 REG_WAIT(DOMAIN8_PG_STATUS,
561 DOMAIN8_PGFSM_PWR_STATUS, pwr_status,
562 1, 1000);
563 break;
564 case 5: /* DCHUBP5 */
565 /*
566 * Do not power gate DCHUB5, should be left at HW default, power on permanently.
567 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard
568 * reset.
569 * REG_UPDATE(DOMAIN10_PG_CONFIG,
570 * DOMAIN10_POWER_GATE, power_gate);
571 *
572 * REG_WAIT(DOMAIN10_PG_STATUS,
573 * DOMAIN10_PGFSM_PWR_STATUS, pwr_status,
574 * 1, 1000);
575 */
576 break;
577 default:
578 BREAK_TO_DEBUGGER();
579 break;
580 }
581}
582
583
7ed4e635
HW
584/* disable HW used by plane.
585 * note: cannot disable until disconnect is complete
586 */
78c77382 587void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
7ed4e635 588{
f42ea55b 589 struct dce_hwseq *hws = dc->hwseq;
7ed4e635
HW
590 struct hubp *hubp = pipe_ctx->plane_res.hubp;
591 struct dpp *dpp = pipe_ctx->plane_res.dpp;
7ed4e635
HW
592
593 dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);
594
6bd8d7d3
AC
595 /* In flip immediate with pipe splitting case GSL is used for
596 * synchronization so we must disable it when the plane is disabled.
597 */
598 if (pipe_ctx->stream_res.gsl_group != 0)
599 dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false);
600
a5b50a0c
AL
601 if (hubp->funcs->hubp_update_mall_sel)
602 hubp->funcs->hubp_update_mall_sel(hubp, 0, false);
603
6bd8d7d3
AC
604 dc->hwss.set_flip_control_gsl(pipe_ctx, false);
605
7ed4e635
HW
606 hubp->funcs->hubp_clk_cntl(hubp, false);
607
608 dpp->funcs->dpp_dppclk_control(dpp, false, false);
609
7ed4e635 610 hubp->power_gated = true;
7ed4e635 611
f42ea55b 612 hws->funcs.plane_atomic_power_down(dc,
8a31820b
ML
613 pipe_ctx->plane_res.dpp,
614 pipe_ctx->plane_res.hubp);
7ed4e635
HW
615
616 pipe_ctx->stream = NULL;
617 memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res));
618 memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res));
619 pipe_ctx->top_pipe = NULL;
620 pipe_ctx->bottom_pipe = NULL;
21741810
WL
621 pipe_ctx->prev_odm_pipe = NULL;
622 pipe_ctx->next_odm_pipe = NULL;
7ed4e635
HW
623 pipe_ctx->plane_state = NULL;
624}
625
626
012a04b1 627void dcn20_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx)
7ed4e635 628{
012a04b1 629 bool is_phantom = dc_state_get_pipe_subvp_type(state, pipe_ctx) == SUBVP_PHANTOM;
a5b50a0c
AL
630 struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL;
631
7ed4e635
HW
632 DC_LOGGER_INIT(dc->ctx->logger);
633
634 if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated)
635 return;
636
637 dcn20_plane_atomic_disable(dc, pipe_ctx);
638
a5b50a0c
AL
639 /* Turn back off the phantom OTG after the phantom plane is fully disabled
640 */
641 if (is_phantom)
642 if (tg && tg->funcs->disable_phantom_crtc)
643 tg->funcs->disable_phantom_crtc(tg);
644
7ed4e635
HW
645 DC_LOG_DC("Power down front end %d\n",
646 pipe_ctx->pipe_idx);
647}
648
4866b0bf
ML
649void dcn20_disable_pixel_data(struct dc *dc, struct pipe_ctx *pipe_ctx, bool blank)
650{
651 dcn20_blank_pixel_data(dc, pipe_ctx, blank);
652}
653
d99f1387
BL
654static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream,
655 int opp_cnt)
656{
657 bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing);
658 int flow_ctrl_cnt;
659
2665fded 660 if (opp_cnt >= 2)
d99f1387
BL
661 hblank_halved = true;
662
663 flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable -
664 stream->timing.h_border_left -
665 stream->timing.h_border_right;
666
667 if (hblank_halved)
668 flow_ctrl_cnt /= 2;
669
670 /* ODM combine 4:1 case */
671 if (opp_cnt == 4)
672 flow_ctrl_cnt /= 2;
673
674 return flow_ctrl_cnt;
675}
d99f1387 676
ce74bece
IB
677static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link)
678{
679 switch (link->link_enc->transmitter) {
680 case TRANSMITTER_UNIPHY_A:
681 return PHYD32CLKA;
682 case TRANSMITTER_UNIPHY_B:
683 return PHYD32CLKB;
684 case TRANSMITTER_UNIPHY_C:
685 return PHYD32CLKC;
686 case TRANSMITTER_UNIPHY_D:
687 return PHYD32CLKD;
688 case TRANSMITTER_UNIPHY_E:
689 return PHYD32CLKE;
690 default:
691 return PHYD32CLKA;
692 }
693}
694
695static int get_odm_segment_count(struct pipe_ctx *pipe_ctx)
696{
697 struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
698 int count = 1;
699
700 while (odm_pipe != NULL) {
701 count++;
702 odm_pipe = odm_pipe->next_odm_pipe;
703 }
704
705 return count;
706}
707
7ed4e635
HW
708enum dc_status dcn20_enable_stream_timing(
709 struct pipe_ctx *pipe_ctx,
710 struct dc_state *context,
711 struct dc *dc)
712{
f42ea55b 713 struct dce_hwseq *hws = dc->hwseq;
7ed4e635 714 struct dc_stream_state *stream = pipe_ctx->stream;
7ed4e635
HW
715 struct drr_params params = {0};
716 unsigned int event_triggers = 0;
b1f6d01c
DL
717 struct pipe_ctx *odm_pipe;
718 int opp_cnt = 1;
719 int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
d99f1387
BL
720 bool interlace = stream->timing.flags.INTERLACE;
721 int i;
d99f1387
BL
722 struct mpc_dwb_flow_control flow_control;
723 struct mpc *mpc = dc->res_pool->mpc;
724 bool rate_control_2x_pclk = (interlace || optc2_is_two_pixels_per_containter(&stream->timing));
49f59499
JL
725 unsigned int k1_div = PIXEL_RATE_DIV_NA;
726 unsigned int k2_div = PIXEL_RATE_DIV_NA;
d99f1387 727
49f59499
JL
728 if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) {
729 hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div);
730
731 dc->res_pool->dccg->funcs->set_pixel_rate_div(
732 dc->res_pool->dccg,
733 pipe_ctx->stream_res.tg->inst,
734 k1_div, k2_div);
735 }
7ed4e635
HW
736 /* by upper caller loop, pipe0 is parent pipe and be called first.
737 * back end is set up by for pipe0. Other children pipe share back end
738 * with pipe 0. No program is needed.
739 */
740 if (pipe_ctx->top_pipe != NULL)
741 return DC_OK;
742
743 /* TODO check if timing_changed, disable stream if timing changed */
744
b1f6d01c
DL
745 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
746 opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
747 opp_cnt++;
748 }
2b162fd3 749
b1f6d01c 750 if (opp_cnt > 1)
7ed4e635
HW
751 pipe_ctx->stream_res.tg->funcs->set_odm_combine(
752 pipe_ctx->stream_res.tg,
b1f6d01c 753 opp_inst, opp_cnt,
2b162fd3 754 &pipe_ctx->stream->timing);
b1f6d01c 755
7ed4e635
HW
756 /* HW program guide assume display already disable
757 * by unplug sequence. OTG assume stop.
758 */
759 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true);
760
761 if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
762 pipe_ctx->clock_source,
763 &pipe_ctx->stream_res.pix_clk_params,
98ce7d32 764 dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings),
7ed4e635
HW
765 &pipe_ctx->pll_settings)) {
766 BREAK_TO_DEBUGGER();
767 return DC_ERROR_UNEXPECTED;
768 }
769
9c75891f
WL
770 if (dc_is_hdmi_tmds_signal(stream->signal)) {
771 stream->link->phy_state.symclk_ref_cnts.otg = 1;
772 if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF)
773 stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
774 else
775 stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
776 }
777
1ef893e2
YS
778 if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal)))
779 dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx);
780
7ed4e635
HW
781 pipe_ctx->stream_res.tg->funcs->program_timing(
782 pipe_ctx->stream_res.tg,
783 &stream->timing,
784 pipe_ctx->pipe_dlg_param.vready_offset,
785 pipe_ctx->pipe_dlg_param.vstartup_start,
786 pipe_ctx->pipe_dlg_param.vupdate_offset,
787 pipe_ctx->pipe_dlg_param.vupdate_width,
788 pipe_ctx->stream->signal,
789 true);
790
d99f1387
BL
791 rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1;
792 flow_control.flow_ctrl_mode = 0;
793 flow_control.flow_ctrl_cnt0 = 0x80;
794 flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(stream, opp_cnt);
795 if (mpc->funcs->set_out_rate_control) {
796 for (i = 0; i < opp_cnt; ++i) {
797 mpc->funcs->set_out_rate_control(
798 mpc, opp_inst[i],
799 true,
800 rate_control_2x_pclk,
801 &flow_control);
802 }
803 }
20f2ffe5 804
b1f6d01c 805 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
7ed4e635
HW
806 odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
807 odm_pipe->stream_res.opp,
808 true);
809
7ed4e635
HW
810 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
811 pipe_ctx->stream_res.opp,
812 true);
813
f42ea55b 814 hws->funcs.blank_pixel_data(dc, pipe_ctx, true);
7ed4e635
HW
815
816 /* VTG is within DCHUB command block. DCFCLK is always on */
817 if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) {
818 BREAK_TO_DEBUGGER();
819 return DC_ERROR_UNEXPECTED;
820 }
821
f42ea55b 822 hws->funcs.wait_for_blank_complete(pipe_ctx->stream_res.opp);
7ed4e635
HW
823
824 params.vertical_total_min = stream->adjust.v_total_min;
825 params.vertical_total_max = stream->adjust.v_total_max;
470e2ca5
BZ
826 params.vertical_total_mid = stream->adjust.v_total_mid;
827 params.vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num;
7ed4e635
HW
828 if (pipe_ctx->stream_res.tg->funcs->set_drr)
829 pipe_ctx->stream_res.tg->funcs->set_drr(
830 pipe_ctx->stream_res.tg, &params);
831
832 // DRR should set trigger event to monitor surface update event
833 if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
834 event_triggers = 0x80;
5b5abe95
AK
835 /* Event triggers and num frames initialized for DRR, but can be
836 * later updated for PSR use. Note DRR trigger events are generated
837 * regardless of whether num frames met.
838 */
7ed4e635
HW
839 if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
840 pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
5b5abe95 841 pipe_ctx->stream_res.tg, event_triggers, 2);
7ed4e635
HW
842
843 /* TODO program crtc source select for non-virtual signal*/
844 /* TODO program FMT */
845 /* TODO setup link_enc */
846 /* TODO set stream attributes */
847 /* TODO program audio */
848 /* TODO enable stream if timing changed */
849 /* TODO unblank stream if DP */
850
09a4ec5d 851 if (pipe_ctx->stream && dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) {
d3dfceb5
AP
852 if (pipe_ctx->stream_res.tg && pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable)
853 pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable(pipe_ctx->stream_res.tg);
854 }
ce74bece
IB
855
856 if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
857 struct dccg *dccg = dc->res_pool->dccg;
858 struct timing_generator *tg = pipe_ctx->stream_res.tg;
859 struct dtbclk_dto_params dto_params = {0};
860
861 if (dccg->funcs->set_dtbclk_p_src)
862 dccg->funcs->set_dtbclk_p_src(dccg, DTBCLK0, tg->inst);
863
864 dto_params.otg_inst = tg->inst;
865 dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
866 dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx);
867 dto_params.timing = &pipe_ctx->stream->timing;
868 dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
869 dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
870 }
871
7ed4e635
HW
872 return DC_OK;
873}
874
875void dcn20_program_output_csc(struct dc *dc,
876 struct pipe_ctx *pipe_ctx,
877 enum dc_color_space colorspace,
878 uint16_t *matrix,
879 int opp_id)
880{
881 struct mpc *mpc = dc->res_pool->mpc;
882 enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A;
54461859
CL
883 int mpcc_id = pipe_ctx->plane_res.hubp->inst;
884
885 if (mpc->funcs->power_on_mpc_mem_pwr)
886 mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true);
7ed4e635
HW
887
888 if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) {
889 if (mpc->funcs->set_output_csc != NULL)
890 mpc->funcs->set_output_csc(mpc,
891 opp_id,
892 matrix,
893 ocsc_mode);
894 } else {
895 if (mpc->funcs->set_ocsc_default != NULL)
896 mpc->funcs->set_ocsc_default(mpc,
897 opp_id,
898 colorspace,
899 ocsc_mode);
900 }
901}
902
78c77382 903bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
7ed4e635
HW
904 const struct dc_stream_state *stream)
905{
906 int mpcc_id = pipe_ctx->plane_res.hubp->inst;
907 struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
908 struct pwl_params *params = NULL;
909 /*
910 * program OGAM only for the top pipe
911 * if there is a pipe split then fix diagnostic is required:
912 * how to pass OGAM parameter for stream.
913 * if programming for all pipes is required then remove condition
914 * pipe_ctx->top_pipe == NULL ,but then fix the diagnostic.
915 */
54461859
CL
916 if (mpc->funcs->power_on_mpc_mem_pwr)
917 mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true);
b1f6d01c 918 if (pipe_ctx->top_pipe == NULL
7ed4e635
HW
919 && mpc->funcs->set_output_gamma && stream->out_transfer_func) {
920 if (stream->out_transfer_func->type == TF_TYPE_HWPWL)
921 params = &stream->out_transfer_func->pwl;
922 else if (pipe_ctx->stream->out_transfer_func->type ==
923 TF_TYPE_DISTRIBUTED_POINTS &&
27fc10d1 924 cm_helper_translate_curve_to_hw_format(dc->ctx,
7ed4e635
HW
925 stream->out_transfer_func,
926 &mpc->blender_params, false))
927 params = &mpc->blender_params;
928 /*
929 * there is no ROM
930 */
931 if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED)
932 BREAK_TO_DEBUGGER();
933 }
934 /*
935 * if above if is not executed then 'params' equal to 0 and set in bypass
936 */
937 mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
938
939 return true;
940}
941
ff344c8d 942bool dcn20_set_blend_lut(
7ed4e635
HW
943 struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
944{
945 struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
946 bool result = true;
947 struct pwl_params *blend_lut = NULL;
948
949 if (plane_state->blend_tf) {
950 if (plane_state->blend_tf->type == TF_TYPE_HWPWL)
951 blend_lut = &plane_state->blend_tf->pwl;
952 else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
27fc10d1 953 cm_helper_translate_curve_to_hw_format(plane_state->ctx,
7ed4e635
HW
954 plane_state->blend_tf,
955 &dpp_base->regamma_params, false);
956 blend_lut = &dpp_base->regamma_params;
957 }
958 }
959 result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut);
960
961 return result;
962}
963
ff344c8d 964bool dcn20_set_shaper_3dlut(
7ed4e635
HW
965 struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
966{
967 struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
968 bool result = true;
969 struct pwl_params *shaper_lut = NULL;
970
971 if (plane_state->in_shaper_func) {
972 if (plane_state->in_shaper_func->type == TF_TYPE_HWPWL)
973 shaper_lut = &plane_state->in_shaper_func->pwl;
974 else if (plane_state->in_shaper_func->type == TF_TYPE_DISTRIBUTED_POINTS) {
27fc10d1 975 cm_helper_translate_curve_to_hw_format(plane_state->ctx,
7ed4e635
HW
976 plane_state->in_shaper_func,
977 &dpp_base->shaper_params, true);
978 shaper_lut = &dpp_base->shaper_params;
979 }
980 }
981
982 result = dpp_base->funcs->dpp_program_shaper_lut(dpp_base, shaper_lut);
983 if (plane_state->lut3d_func &&
a2080098 984 plane_state->lut3d_func->state.bits.initialized == 1)
7ed4e635
HW
985 result = dpp_base->funcs->dpp_program_3dlut(dpp_base,
986 &plane_state->lut3d_func->lut_3d);
987 else
988 result = dpp_base->funcs->dpp_program_3dlut(dpp_base, NULL);
989
7ed4e635
HW
990 return result;
991}
992
78c77382
AK
993bool dcn20_set_input_transfer_func(struct dc *dc,
994 struct pipe_ctx *pipe_ctx,
995 const struct dc_plane_state *plane_state)
7ed4e635 996{
f42ea55b 997 struct dce_hwseq *hws = dc->hwseq;
7ed4e635
HW
998 struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
999 const struct dc_transfer_func *tf = NULL;
1000 bool result = true;
1001 bool use_degamma_ram = false;
1002
1003 if (dpp_base == NULL || plane_state == NULL)
1004 return false;
1005
f42ea55b
AK
1006 hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state);
1007 hws->funcs.set_blend_lut(pipe_ctx, plane_state);
7ed4e635
HW
1008
1009 if (plane_state->in_transfer_func)
1010 tf = plane_state->in_transfer_func;
1011
1012
1013 if (tf == NULL) {
1014 dpp_base->funcs->dpp_set_degamma(dpp_base,
1015 IPP_DEGAMMA_MODE_BYPASS);
1016 return true;
1017 }
1018
1019 if (tf->type == TF_TYPE_HWPWL || tf->type == TF_TYPE_DISTRIBUTED_POINTS)
1020 use_degamma_ram = true;
1021
1022 if (use_degamma_ram == true) {
1023 if (tf->type == TF_TYPE_HWPWL)
1024 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base,
1025 &tf->pwl);
1026 else if (tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
1027 cm_helper_translate_curve_to_degamma_hw_format(tf,
1028 &dpp_base->degamma_params);
1029 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base,
1030 &dpp_base->degamma_params);
1031 }
1032 return true;
1033 }
1034 /* handle here the optimized cases when de-gamma ROM could be used.
1035 *
1036 */
1037 if (tf->type == TF_TYPE_PREDEFINED) {
1038 switch (tf->tf) {
1039 case TRANSFER_FUNCTION_SRGB:
1040 dpp_base->funcs->dpp_set_degamma(dpp_base,
1041 IPP_DEGAMMA_MODE_HW_sRGB);
1042 break;
1043 case TRANSFER_FUNCTION_BT709:
1044 dpp_base->funcs->dpp_set_degamma(dpp_base,
1045 IPP_DEGAMMA_MODE_HW_xvYCC);
1046 break;
1047 case TRANSFER_FUNCTION_LINEAR:
1048 dpp_base->funcs->dpp_set_degamma(dpp_base,
1049 IPP_DEGAMMA_MODE_BYPASS);
1050 break;
1051 case TRANSFER_FUNCTION_PQ:
e6616410
RA
1052 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL);
1053 cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params);
1054 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params);
1055 result = true;
1056 break;
7ed4e635
HW
1057 default:
1058 result = false;
1059 break;
1060 }
1061 } else if (tf->type == TF_TYPE_BYPASS)
1062 dpp_base->funcs->dpp_set_degamma(dpp_base,
1063 IPP_DEGAMMA_MODE_BYPASS);
1064 else {
1065 /*
1066 * if we are here, we did not handle correctly.
1067 * fix is required for this use case
1068 */
1069 BREAK_TO_DEBUGGER();
1070 dpp_base->funcs->dpp_set_degamma(dpp_base,
1071 IPP_DEGAMMA_MODE_BYPASS);
1072 }
1073
1074 return result;
1075}
1076
78c77382 1077void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx)
7ed4e635 1078{
b1f6d01c
DL
1079 struct pipe_ctx *odm_pipe;
1080 int opp_cnt = 1;
1081 int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
7ed4e635 1082
b1f6d01c
DL
1083 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
1084 opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
1085 opp_cnt++;
1086 }
2b162fd3 1087
b1f6d01c 1088 if (opp_cnt > 1)
7ed4e635
HW
1089 pipe_ctx->stream_res.tg->funcs->set_odm_combine(
1090 pipe_ctx->stream_res.tg,
b1f6d01c 1091 opp_inst, opp_cnt,
2b162fd3 1092 &pipe_ctx->stream->timing);
b1f6d01c 1093 else
7ed4e635
HW
1094 pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
1095 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
1096}
1097
1098void dcn20_blank_pixel_data(
1099 struct dc *dc,
1100 struct pipe_ctx *pipe_ctx,
1101 bool blank)
1102{
7ed4e635
HW
1103 struct tg_color black_color = {0};
1104 struct stream_resource *stream_res = &pipe_ctx->stream_res;
1105 struct dc_stream_state *stream = pipe_ctx->stream;
324707fd 1106 enum dc_color_space color_space = stream->output_color_space;
7ed4e635 1107 enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR;
2057b7e1 1108 enum controller_dp_color_space test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
b1f6d01c
DL
1109 struct pipe_ctx *odm_pipe;
1110 int odm_cnt = 1;
ad4455c6
WL
1111 int h_active = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
1112 int v_active = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top;
1113 int odm_slice_width, last_odm_slice_width, offset = 0;
7ed4e635 1114
31635887
WL
1115 if (stream->link->test_pattern_enabled)
1116 return;
1117
324707fd 1118 /* get opp dpg blank color */
7ed4e635
HW
1119 color_space_to_black_color(dc, color_space, &black_color);
1120
b1f6d01c
DL
1121 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
1122 odm_cnt++;
ad4455c6
WL
1123 odm_slice_width = h_active / odm_cnt;
1124 last_odm_slice_width = h_active - odm_slice_width * (odm_cnt - 1);
7ed4e635
HW
1125
1126 if (blank) {
3ba01817 1127 dc->hwss.set_abm_immediate_disable(pipe_ctx);
7ed4e635 1128
2057b7e1 1129 if (dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) {
324707fd 1130 test_pattern = CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
2057b7e1
WL
1131 test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
1132 }
324707fd
JA
1133 } else {
1134 test_pattern = CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
1135 }
7ed4e635 1136
ad4455c6 1137 odm_pipe = pipe_ctx;
7ed4e635 1138
ad4455c6 1139 while (odm_pipe->next_odm_pipe) {
dbf5256b 1140 dc->hwss.set_disp_pattern_generator(dc,
f77d1a49 1141 odm_pipe,
ad4455c6 1142 test_pattern,
2057b7e1 1143 test_pattern_color_space,
7ed4e635
HW
1144 stream->timing.display_color_depth,
1145 &black_color,
ad4455c6
WL
1146 odm_slice_width,
1147 v_active,
1148 offset);
1149 offset += odm_slice_width;
1150 odm_pipe = odm_pipe->next_odm_pipe;
7ed4e635
HW
1151 }
1152
ad4455c6
WL
1153 dc->hwss.set_disp_pattern_generator(dc,
1154 odm_pipe,
1155 test_pattern,
1156 test_pattern_color_space,
1157 stream->timing.display_color_depth,
1158 &black_color,
1159 last_odm_slice_width,
1160 v_active,
1161 offset);
1162
7ed4e635
HW
1163 if (!blank)
1164 if (stream_res->abm) {
474ac4a8 1165 dc->hwss.set_pipe(pipe_ctx);
7ed4e635
HW
1166 stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level);
1167 }
1168}
1169
1170
bf224e00 1171static void dcn20_power_on_plane_resources(
7ed4e635
HW
1172 struct dce_hwseq *hws,
1173 struct pipe_ctx *pipe_ctx)
1174{
1175 DC_LOGGER_INIT(hws->ctx->logger);
bf224e00
NK
1176
1177 if (hws->funcs.dpp_root_clock_control)
1178 hws->funcs.dpp_root_clock_control(hws, pipe_ctx->plane_res.dpp->inst, true);
1179
7ed4e635
HW
1180 if (REG(DC_IP_REQUEST_CNTL)) {
1181 REG_SET(DC_IP_REQUEST_CNTL, 0,
1182 IP_REQUEST_EN, 1);
c74f865f
NK
1183
1184 if (hws->funcs.dpp_pg_control)
1185 hws->funcs.dpp_pg_control(hws, pipe_ctx->plane_res.dpp->inst, true);
1186
1187 if (hws->funcs.hubp_pg_control)
1188 hws->funcs.hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, true);
1189
7ed4e635
HW
1190 REG_SET(DC_IP_REQUEST_CNTL, 0,
1191 IP_REQUEST_EN, 0);
1192 DC_LOG_DEBUG(
1193 "Un-gated front end for pipe %d\n", pipe_ctx->plane_res.hubp->inst);
1194 }
1195}
1196
240e6d25
IB
1197static void dcn20_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx,
1198 struct dc_state *context)
7ed4e635
HW
1199{
1200 //if (dc->debug.sanity_checks) {
1201 // dcn10_verify_allow_pstate_change_high(dc);
1202 //}
bf224e00 1203 dcn20_power_on_plane_resources(dc->hwseq, pipe_ctx);
7ed4e635
HW
1204
1205 /* enable DCFCLK current DCHUB */
1206 pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true);
1207
89cb5614
ZYL
1208 /* initialize HUBP on power up */
1209 pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp);
1210
7ed4e635
HW
1211 /* make sure OPP_PIPE_CLOCK_EN = 1 */
1212 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
1213 pipe_ctx->stream_res.opp,
1214 true);
1215
1216/* TODO: enable/disable in dm as per update type.
1217 if (plane_state) {
1218 DC_LOG_DC(dc->ctx->logger,
1219 "Pipe:%d 0x%x: addr hi:0x%x, "
1220 "addr low:0x%x, "
1221 "src: %d, %d, %d,"
1222 " %d; dst: %d, %d, %d, %d;\n",
1223 pipe_ctx->pipe_idx,
1224 plane_state,
1225 plane_state->address.grph.addr.high_part,
1226 plane_state->address.grph.addr.low_part,
1227 plane_state->src_rect.x,
1228 plane_state->src_rect.y,
1229 plane_state->src_rect.width,
1230 plane_state->src_rect.height,
1231 plane_state->dst_rect.x,
1232 plane_state->dst_rect.y,
1233 plane_state->dst_rect.width,
1234 plane_state->dst_rect.height);
1235
1236 DC_LOG_DC(dc->ctx->logger,
1237 "Pipe %d: width, height, x, y format:%d\n"
1238 "viewport:%d, %d, %d, %d\n"
1239 "recout: %d, %d, %d, %d\n",
1240 pipe_ctx->pipe_idx,
1241 plane_state->format,
1242 pipe_ctx->plane_res.scl_data.viewport.width,
1243 pipe_ctx->plane_res.scl_data.viewport.height,
1244 pipe_ctx->plane_res.scl_data.viewport.x,
1245 pipe_ctx->plane_res.scl_data.viewport.y,
1246 pipe_ctx->plane_res.scl_data.recout.width,
1247 pipe_ctx->plane_res.scl_data.recout.height,
1248 pipe_ctx->plane_res.scl_data.recout.x,
1249 pipe_ctx->plane_res.scl_data.recout.y);
1250 print_rq_dlg_ttu(dc, pipe_ctx);
1251 }
1252*/
bda9afda 1253 if (dc->vm_pa_config.valid) {
7ed4e635
HW
1254 struct vm_system_aperture_param apt;
1255
1256 apt.sys_default.quad_part = 0;
7ed4e635 1257
6d988a55
JL
1258 apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.start_addr;
1259 apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.end_addr;
7ed4e635
HW
1260
1261 // Program system aperture settings
1262 pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt);
1263 }
1264
0c66824b
QZ
1265 if (!pipe_ctx->top_pipe
1266 && pipe_ctx->plane_state
1267 && pipe_ctx->plane_state->flip_int_enabled
1268 && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int)
1269 pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp);
1270
7ed4e635
HW
1271// if (dc->debug.sanity_checks) {
1272// dcn10_verify_allow_pstate_change_high(dc);
1273// }
1274}
1275
ff344c8d 1276void dcn20_pipe_control_lock(
7ed4e635
HW
1277 struct dc *dc,
1278 struct pipe_ctx *pipe,
1279 bool lock)
1280{
6f2239cc 1281 struct pipe_ctx *temp_pipe;
7ed4e635
HW
1282 bool flip_immediate = false;
1283
1284 /* use TG master update lock to lock everything on the TG
1285 * therefore only top pipe need to lock
1286 */
009114f6 1287 if (!pipe || pipe->top_pipe)
7ed4e635
HW
1288 return;
1289
1290 if (pipe->plane_state != NULL)
1291 flip_immediate = pipe->plane_state->flip_immediate;
1292
4f6274b3
AL
1293 if (pipe->stream_res.gsl_group > 0) {
1294 temp_pipe = pipe->bottom_pipe;
1295 while (!flip_immediate && temp_pipe) {
1296 if (temp_pipe->plane_state != NULL)
1297 flip_immediate = temp_pipe->plane_state->flip_immediate;
1298 temp_pipe = temp_pipe->bottom_pipe;
1299 }
6f2239cc
AL
1300 }
1301
0e29be9e 1302 if (flip_immediate && lock) {
dbca8310
JA
1303 const int TIMEOUT_FOR_FLIP_PENDING_US = 100000;
1304 unsigned int polling_interval_us = 1;
0e29be9e
AD
1305 int i;
1306
e9917ef8
AC
1307 temp_pipe = pipe;
1308 while (temp_pipe) {
1309 if (temp_pipe->plane_state && temp_pipe->plane_state->flip_immediate) {
dbca8310 1310 for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING_US / polling_interval_us; ++i) {
e9917ef8
AC
1311 if (!temp_pipe->plane_res.hubp->funcs->hubp_is_flip_pending(temp_pipe->plane_res.hubp))
1312 break;
dbca8310 1313 udelay(polling_interval_us);
e9917ef8
AC
1314 }
1315
1316 /* no reason it should take this long for immediate flips */
dbca8310 1317 ASSERT(i != TIMEOUT_FOR_FLIP_PENDING_US);
0e29be9e 1318 }
e9917ef8 1319 temp_pipe = temp_pipe->bottom_pipe;
0e29be9e
AD
1320 }
1321 }
1322
7ed4e635
HW
1323 /* In flip immediate and pipe splitting case, we need to use GSL
1324 * for synchronization. Only do setup on locking and on flip type change.
1325 */
86c5a9e3 1326 if (lock && (pipe->bottom_pipe != NULL || !flip_immediate))
7ed4e635
HW
1327 if ((flip_immediate && pipe->stream_res.gsl_group == 0) ||
1328 (!flip_immediate && pipe->stream_res.gsl_group > 0))
2e2e73fc 1329 dcn20_setup_gsl_group_as_lock(dc, pipe, flip_immediate);
7ed4e635 1330
ec76bd6f
AL
1331 if (pipe->plane_state != NULL)
1332 flip_immediate = pipe->plane_state->flip_immediate;
1333
6f2239cc
AL
1334 temp_pipe = pipe->bottom_pipe;
1335 while (flip_immediate && temp_pipe) {
1336 if (temp_pipe->plane_state != NULL)
1337 flip_immediate = temp_pipe->plane_state->flip_immediate;
1338 temp_pipe = temp_pipe->bottom_pipe;
1339 }
1340
1341 if (!lock && pipe->stream_res.gsl_group > 0 && pipe->plane_state &&
1342 !flip_immediate)
1343 dcn20_setup_gsl_group_as_lock(dc, pipe, false);
1344
dc6e2448
WW
1345 if (pipe->stream && should_use_dmub_lock(pipe->stream->link)) {
1346 union dmub_hw_lock_flags hw_locks = { 0 };
1347 struct dmub_hw_lock_inst_flags inst_flags = { 0 };
1348
1349 hw_locks.bits.lock_pipe = 1;
1350 inst_flags.otg_inst = pipe->stream_res.tg->inst;
1351
1352 if (pipe->plane_state != NULL)
1353 hw_locks.bits.triple_buffer_lock = pipe->plane_state->triplebuffer_flips;
1354
1355 dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv,
1356 lock,
1357 &hw_locks,
1358 &inst_flags);
1359 } else if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {
7ed4e635
HW
1360 if (lock)
1361 pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);
1362 else
1363 pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
1364 } else {
1365 if (lock)
1366 pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
1367 else
1368 pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
1369 }
1370}
1371
012a04b1
DV
1372static void dcn20_detect_pipe_changes(struct dc_state *old_state,
1373 struct dc_state *new_state,
1374 struct pipe_ctx *old_pipe,
1375 struct pipe_ctx *new_pipe)
7ed4e635 1376{
012a04b1
DV
1377 bool old_is_phantom = dc_state_get_pipe_subvp_type(old_state, old_pipe) == SUBVP_PHANTOM;
1378 bool new_is_phantom = dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM;
09a4ec5d 1379
b6e881c9 1380 new_pipe->update_flags.raw = 0;
7ed4e635 1381
e267f5e6
AL
1382 /* If non-phantom pipe is being transitioned to a phantom pipe,
1383 * set disable and return immediately. This is because the pipe
1384 * that was previously in use must be fully disabled before we
1385 * can "enable" it as a phantom pipe (since the OTG will certainly
1386 * be different). The post_unlock sequence will set the correct
1387 * update flags to enable the phantom pipe.
1388 */
09a4ec5d
DV
1389 if (old_pipe->plane_state && !old_is_phantom &&
1390 new_pipe->plane_state && new_is_phantom) {
e267f5e6
AL
1391 new_pipe->update_flags.bits.disable = 1;
1392 return;
1393 }
1394
b6e881c9
DL
1395 /* Exit on unchanged, unused pipe */
1396 if (!old_pipe->plane_state && !new_pipe->plane_state)
7ed4e635 1397 return;
b6e881c9 1398 /* Detect pipe enable/disable */
c0838cbe 1399 if (!old_pipe->plane_state && new_pipe->plane_state) {
b6e881c9
DL
1400 new_pipe->update_flags.bits.enable = 1;
1401 new_pipe->update_flags.bits.mpcc = 1;
1402 new_pipe->update_flags.bits.dppclk = 1;
1403 new_pipe->update_flags.bits.hubp_interdependent = 1;
1404 new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
fe9fa385 1405 new_pipe->update_flags.bits.unbounded_req = 1;
b6e881c9
DL
1406 new_pipe->update_flags.bits.gamut_remap = 1;
1407 new_pipe->update_flags.bits.scaler = 1;
1408 new_pipe->update_flags.bits.viewport = 1;
ba5a5371 1409 new_pipe->update_flags.bits.det_size = 1;
b5882675
GS
1410 if (new_pipe->stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE &&
1411 new_pipe->stream_res.test_pattern_params.width != 0 &&
1412 new_pipe->stream_res.test_pattern_params.height != 0)
1413 new_pipe->update_flags.bits.test_pattern_changed = 1;
b6e881c9
DL
1414 if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) {
1415 new_pipe->update_flags.bits.odm = 1;
1416 new_pipe->update_flags.bits.global_sync = 1;
1417 }
1418 return;
1419 }
85f4bc0c
AL
1420
1421 /* For SubVP we need to unconditionally enable because any phantom pipes are
1422 * always removed then newly added for every full updates whenever SubVP is in use.
1423 * The remove-add sequence of the phantom pipe always results in the pipe
1424 * being blanked in enable_stream_timing (DPG).
1425 */
012a04b1 1426 if (new_pipe->stream && dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM)
85f4bc0c
AL
1427 new_pipe->update_flags.bits.enable = 1;
1428
14eb72ff
AL
1429 /* Phantom pipes are effectively disabled, if the pipe was previously phantom
1430 * we have to enable
1431 */
09a4ec5d
DV
1432 if (old_pipe->plane_state && old_is_phantom &&
1433 new_pipe->plane_state && !new_is_phantom)
14eb72ff
AL
1434 new_pipe->update_flags.bits.enable = 1;
1435
b6e881c9
DL
1436 if (old_pipe->plane_state && !new_pipe->plane_state) {
1437 new_pipe->update_flags.bits.disable = 1;
1438 return;
1439 }
7ed4e635 1440
498563cf
JX
1441 /* Detect plane change */
1442 if (old_pipe->plane_state != new_pipe->plane_state) {
1443 new_pipe->update_flags.bits.plane_changed = true;
1444 }
1445
b6e881c9 1446 /* Detect top pipe only changes */
d8494349 1447 if (resource_is_pipe_type(new_pipe, OTG_MASTER)) {
b6e881c9 1448 /* Detect odm changes */
d8494349 1449 if (resource_is_odm_topology_changed(new_pipe, old_pipe))
b6e881c9
DL
1450 new_pipe->update_flags.bits.odm = 1;
1451
1452 /* Detect global sync changes */
1453 if (old_pipe->pipe_dlg_param.vready_offset != new_pipe->pipe_dlg_param.vready_offset
1454 || old_pipe->pipe_dlg_param.vstartup_start != new_pipe->pipe_dlg_param.vstartup_start
1455 || old_pipe->pipe_dlg_param.vupdate_offset != new_pipe->pipe_dlg_param.vupdate_offset
1456 || old_pipe->pipe_dlg_param.vupdate_width != new_pipe->pipe_dlg_param.vupdate_width)
1457 new_pipe->update_flags.bits.global_sync = 1;
1458 }
21ffcc94 1459
ba5a5371
NK
1460 if (old_pipe->det_buffer_size_kb != new_pipe->det_buffer_size_kb)
1461 new_pipe->update_flags.bits.det_size = 1;
8fe44c08 1462
b6e881c9
DL
1463 /*
1464 * Detect opp / tg change, only set on change, not on enable
1465 * Assume mpcc inst = pipe index, if not this code needs to be updated
1466 * since mpcc is what is affected by these. In fact all of our sequence
1467 * makes this assumption at the moment with how hubp reset is matched to
1468 * same index mpcc reset.
1469 */
1470 if (old_pipe->stream_res.opp != new_pipe->stream_res.opp)
1471 new_pipe->update_flags.bits.opp_changed = 1;
1472 if (old_pipe->stream_res.tg != new_pipe->stream_res.tg)
1473 new_pipe->update_flags.bits.tg_changed = 1;
1474
ed8ec123
DL
1475 /*
1476 * Detect mpcc blending changes, only dpp inst and opp matter here,
1477 * mpccs getting removed/inserted update connected ones during their own
1478 * programming
1479 */
b6e881c9 1480 if (old_pipe->plane_res.dpp != new_pipe->plane_res.dpp
ed8ec123 1481 || old_pipe->stream_res.opp != new_pipe->stream_res.opp)
b6e881c9
DL
1482 new_pipe->update_flags.bits.mpcc = 1;
1483
1484 /* Detect dppclk change */
1485 if (old_pipe->plane_res.bw.dppclk_khz != new_pipe->plane_res.bw.dppclk_khz)
1486 new_pipe->update_flags.bits.dppclk = 1;
1487
1488 /* Check for scl update */
1489 if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data)))
1490 new_pipe->update_flags.bits.scaler = 1;
1491 /* Check for vp update */
1492 if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect))
1493 || memcmp(&old_pipe->plane_res.scl_data.viewport_c,
1494 &new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect)))
1495 new_pipe->update_flags.bits.viewport = 1;
1496
1497 /* Detect dlg/ttu/rq updates */
1498 {
1499 struct _vcs_dpi_display_dlg_regs_st old_dlg_attr = old_pipe->dlg_regs;
1500 struct _vcs_dpi_display_ttu_regs_st old_ttu_attr = old_pipe->ttu_regs;
1501 struct _vcs_dpi_display_dlg_regs_st *new_dlg_attr = &new_pipe->dlg_regs;
1502 struct _vcs_dpi_display_ttu_regs_st *new_ttu_attr = &new_pipe->ttu_regs;
1503
1504 /* Detect pipe interdependent updates */
1505 if (old_dlg_attr.dst_y_prefetch != new_dlg_attr->dst_y_prefetch ||
1506 old_dlg_attr.vratio_prefetch != new_dlg_attr->vratio_prefetch ||
1507 old_dlg_attr.vratio_prefetch_c != new_dlg_attr->vratio_prefetch_c ||
1508 old_dlg_attr.dst_y_per_vm_vblank != new_dlg_attr->dst_y_per_vm_vblank ||
1509 old_dlg_attr.dst_y_per_row_vblank != new_dlg_attr->dst_y_per_row_vblank ||
1510 old_dlg_attr.dst_y_per_vm_flip != new_dlg_attr->dst_y_per_vm_flip ||
1511 old_dlg_attr.dst_y_per_row_flip != new_dlg_attr->dst_y_per_row_flip ||
1512 old_dlg_attr.refcyc_per_meta_chunk_vblank_l != new_dlg_attr->refcyc_per_meta_chunk_vblank_l ||
1513 old_dlg_attr.refcyc_per_meta_chunk_vblank_c != new_dlg_attr->refcyc_per_meta_chunk_vblank_c ||
1514 old_dlg_attr.refcyc_per_meta_chunk_flip_l != new_dlg_attr->refcyc_per_meta_chunk_flip_l ||
1515 old_dlg_attr.refcyc_per_line_delivery_pre_l != new_dlg_attr->refcyc_per_line_delivery_pre_l ||
1516 old_dlg_attr.refcyc_per_line_delivery_pre_c != new_dlg_attr->refcyc_per_line_delivery_pre_c ||
1517 old_ttu_attr.refcyc_per_req_delivery_pre_l != new_ttu_attr->refcyc_per_req_delivery_pre_l ||
1518 old_ttu_attr.refcyc_per_req_delivery_pre_c != new_ttu_attr->refcyc_per_req_delivery_pre_c ||
1519 old_ttu_attr.refcyc_per_req_delivery_pre_cur0 != new_ttu_attr->refcyc_per_req_delivery_pre_cur0 ||
1520 old_ttu_attr.refcyc_per_req_delivery_pre_cur1 != new_ttu_attr->refcyc_per_req_delivery_pre_cur1 ||
1521 old_ttu_attr.min_ttu_vblank != new_ttu_attr->min_ttu_vblank ||
1522 old_ttu_attr.qos_level_flip != new_ttu_attr->qos_level_flip) {
1523 old_dlg_attr.dst_y_prefetch = new_dlg_attr->dst_y_prefetch;
1524 old_dlg_attr.vratio_prefetch = new_dlg_attr->vratio_prefetch;
1525 old_dlg_attr.vratio_prefetch_c = new_dlg_attr->vratio_prefetch_c;
1526 old_dlg_attr.dst_y_per_vm_vblank = new_dlg_attr->dst_y_per_vm_vblank;
1527 old_dlg_attr.dst_y_per_row_vblank = new_dlg_attr->dst_y_per_row_vblank;
1528 old_dlg_attr.dst_y_per_vm_flip = new_dlg_attr->dst_y_per_vm_flip;
1529 old_dlg_attr.dst_y_per_row_flip = new_dlg_attr->dst_y_per_row_flip;
1530 old_dlg_attr.refcyc_per_meta_chunk_vblank_l = new_dlg_attr->refcyc_per_meta_chunk_vblank_l;
1531 old_dlg_attr.refcyc_per_meta_chunk_vblank_c = new_dlg_attr->refcyc_per_meta_chunk_vblank_c;
1532 old_dlg_attr.refcyc_per_meta_chunk_flip_l = new_dlg_attr->refcyc_per_meta_chunk_flip_l;
1533 old_dlg_attr.refcyc_per_line_delivery_pre_l = new_dlg_attr->refcyc_per_line_delivery_pre_l;
1534 old_dlg_attr.refcyc_per_line_delivery_pre_c = new_dlg_attr->refcyc_per_line_delivery_pre_c;
1535 old_ttu_attr.refcyc_per_req_delivery_pre_l = new_ttu_attr->refcyc_per_req_delivery_pre_l;
1536 old_ttu_attr.refcyc_per_req_delivery_pre_c = new_ttu_attr->refcyc_per_req_delivery_pre_c;
1537 old_ttu_attr.refcyc_per_req_delivery_pre_cur0 = new_ttu_attr->refcyc_per_req_delivery_pre_cur0;
1538 old_ttu_attr.refcyc_per_req_delivery_pre_cur1 = new_ttu_attr->refcyc_per_req_delivery_pre_cur1;
1539 old_ttu_attr.min_ttu_vblank = new_ttu_attr->min_ttu_vblank;
1540 old_ttu_attr.qos_level_flip = new_ttu_attr->qos_level_flip;
1541 new_pipe->update_flags.bits.hubp_interdependent = 1;
1542 }
1543 /* Detect any other updates to ttu/rq/dlg */
1544 if (memcmp(&old_dlg_attr, &new_pipe->dlg_regs, sizeof(old_dlg_attr)) ||
1545 memcmp(&old_ttu_attr, &new_pipe->ttu_regs, sizeof(old_ttu_attr)) ||
1546 memcmp(&old_pipe->rq_regs, &new_pipe->rq_regs, sizeof(old_pipe->rq_regs)))
1547 new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
21ffcc94 1548 }
fe9fa385
AL
1549
1550 if (old_pipe->unbounded_req != new_pipe->unbounded_req)
1551 new_pipe->update_flags.bits.unbounded_req = 1;
051d9007
GS
1552
1553 if (memcmp(&old_pipe->stream_res.test_pattern_params,
1554 &new_pipe->stream_res.test_pattern_params, sizeof(struct test_pattern_params))) {
1555 new_pipe->update_flags.bits.test_pattern_changed = 1;
1556 }
b6e881c9 1557}
21ffcc94 1558
b6e881c9
DL
1559static void dcn20_update_dchubp_dpp(
1560 struct dc *dc,
1561 struct pipe_ctx *pipe_ctx,
1562 struct dc_state *context)
1563{
f42ea55b 1564 struct dce_hwseq *hws = dc->hwseq;
b6e881c9
DL
1565 struct hubp *hubp = pipe_ctx->plane_res.hubp;
1566 struct dpp *dpp = pipe_ctx->plane_res.dpp;
1567 struct dc_plane_state *plane_state = pipe_ctx->plane_state;
d4965c53 1568 struct dccg *dccg = dc->res_pool->dccg;
cf27a6d1 1569 bool viewport_changed = false;
09a4ec5d 1570 enum mall_stream_type pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe_ctx);
7ed4e635 1571
1ea8751b 1572 if (pipe_ctx->update_flags.bits.dppclk)
b6e881c9 1573 dpp->funcs->dpp_dppclk_control(dpp, false, true);
4e0cbbbf 1574
d4965c53
DM
1575 if (pipe_ctx->update_flags.bits.enable)
1576 dccg->funcs->update_dpp_dto(dccg, dpp->inst, pipe_ctx->plane_res.bw.dppclk_khz);
1577
b6e881c9
DL
1578 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
1579 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
1580 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
1581 */
1582 if (pipe_ctx->update_flags.bits.hubp_rq_dlg_ttu) {
1583 hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst);
1584
1585 hubp->funcs->hubp_setup(
1586 hubp,
1587 &pipe_ctx->dlg_regs,
1588 &pipe_ctx->ttu_regs,
1589 &pipe_ctx->rq_regs,
1590 &pipe_ctx->pipe_dlg_param);
1591 }
fe9fa385
AL
1592
1593 if (pipe_ctx->update_flags.bits.unbounded_req && hubp->funcs->set_unbounded_requesting)
1594 hubp->funcs->set_unbounded_requesting(hubp, pipe_ctx->unbounded_req);
1595
b6e881c9
DL
1596 if (pipe_ctx->update_flags.bits.hubp_interdependent)
1597 hubp->funcs->hubp_setup_interdependent(
1598 hubp,
1599 &pipe_ctx->dlg_regs,
1600 &pipe_ctx->ttu_regs);
1601
1602 if (pipe_ctx->update_flags.bits.enable ||
498563cf 1603 pipe_ctx->update_flags.bits.plane_changed ||
b6e881c9
DL
1604 plane_state->update_flags.bits.bpp_change ||
1605 plane_state->update_flags.bits.input_csc_change ||
1606 plane_state->update_flags.bits.color_space_change ||
1607 plane_state->update_flags.bits.coeff_reduction_change) {
1608 struct dc_bias_and_scale bns_params = {0};
1609
1610 // program the input csc
1611 dpp->funcs->dpp_setup(dpp,
1612 plane_state->format,
1613 EXPANSION_MODE_ZERO,
1614 plane_state->input_csc_color_matrix,
1615 plane_state->color_space,
1616 NULL);
1617
1618 if (dpp->funcs->dpp_program_bias_and_scale) {
1619 //TODO :for CNVC set scale and bias registers if necessary
78c77382 1620 build_prescale_params(&bns_params, plane_state);
b6e881c9
DL
1621 dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params);
1622 }
7ed4e635
HW
1623 }
1624
b6e881c9 1625 if (pipe_ctx->update_flags.bits.mpcc
498563cf 1626 || pipe_ctx->update_flags.bits.plane_changed
b6e881c9
DL
1627 || plane_state->update_flags.bits.global_alpha_change
1628 || plane_state->update_flags.bits.per_pixel_alpha_change) {
8b0fbb36 1629 // MPCC inst is equal to pipe index in practice
f42ea55b 1630 hws->funcs.update_mpcc(dc, pipe_ctx);
b6e881c9 1631 }
7ed4e635 1632
b6e881c9
DL
1633 if (pipe_ctx->update_flags.bits.scaler ||
1634 plane_state->update_flags.bits.scaling_change ||
1635 plane_state->update_flags.bits.position_change ||
1636 plane_state->update_flags.bits.per_pixel_alpha_change ||
1637 pipe_ctx->stream->update_flags.bits.scaling) {
1638 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha;
a316db72 1639 ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_36BPP);
b6e881c9
DL
1640 /* scaler configuration */
1641 pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler(
1642 pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data);
1643 }
7ed4e635 1644
b6e881c9 1645 if (pipe_ctx->update_flags.bits.viewport ||
b34659de 1646 (context == dc->current_state && plane_state->update_flags.bits.position_change) ||
b6e881c9 1647 (context == dc->current_state && plane_state->update_flags.bits.scaling_change) ||
cf27a6d1
EY
1648 (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) {
1649
b6e881c9
DL
1650 hubp->funcs->mem_program_viewport(
1651 hubp,
1652 &pipe_ctx->plane_res.scl_data.viewport,
cf27a6d1
EY
1653 &pipe_ctx->plane_res.scl_data.viewport_c);
1654 viewport_changed = true;
1655 }
b6e881c9
DL
1656
1657 /* Any updates are handled in dc interface, just need to apply existing for plane enable */
74cc5f02 1658 if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
8e80d482
PH
1659 pipe_ctx->update_flags.bits.scaler || viewport_changed == true) &&
1660 pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
b6e881c9
DL
1661 dc->hwss.set_cursor_position(pipe_ctx);
1662 dc->hwss.set_cursor_attribute(pipe_ctx);
1663
1664 if (dc->hwss.set_cursor_sdr_white_level)
1665 dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
1666 }
7ed4e635 1667
b6e881c9
DL
1668 /* Any updates are handled in dc interface, just need
1669 * to apply existing for plane enable / opp change */
1670 if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed
441595ba 1671 || pipe_ctx->update_flags.bits.plane_changed
b6e881c9 1672 || pipe_ctx->stream->update_flags.bits.gamut_remap
d288c871 1673 || plane_state->update_flags.bits.gamut_remap_change
b6e881c9 1674 || pipe_ctx->stream->update_flags.bits.out_csc) {
90d1a626
DV
1675 /* dpp/cm gamut remap*/
1676 dc->hwss.program_gamut_remap(pipe_ctx);
b6e881c9
DL
1677
1678 /*call the dcn2 method which uses mpc csc*/
1679 dc->hwss.program_output_csc(dc,
1680 pipe_ctx,
1681 pipe_ctx->stream->output_color_space,
1682 pipe_ctx->stream->csc_color_matrix.matrix,
1683 hubp->opp_id);
7ed4e635
HW
1684 }
1685
b6e881c9 1686 if (pipe_ctx->update_flags.bits.enable ||
498563cf 1687 pipe_ctx->update_flags.bits.plane_changed ||
b6e881c9
DL
1688 pipe_ctx->update_flags.bits.opp_changed ||
1689 plane_state->update_flags.bits.pixel_format_change ||
1690 plane_state->update_flags.bits.horizontal_mirror_change ||
1691 plane_state->update_flags.bits.rotation_change ||
1692 plane_state->update_flags.bits.swizzle_change ||
1693 plane_state->update_flags.bits.dcc_change ||
1694 plane_state->update_flags.bits.bpp_change ||
1695 plane_state->update_flags.bits.scaling_change ||
1696 plane_state->update_flags.bits.plane_size_change) {
1697 struct plane_size size = plane_state->plane_size;
1698
1699 size.surface_size = pipe_ctx->plane_res.scl_data.viewport;
1700 hubp->funcs->hubp_program_surface_config(
1701 hubp,
1702 plane_state->format,
1703 &plane_state->tiling_info,
1704 &size,
1705 plane_state->rotation,
1706 &plane_state->dcc,
1707 plane_state->horizontal_mirror,
1708 0);
1709 hubp->power_gated = false;
1710 }
1711
498563cf
JX
1712 if (pipe_ctx->update_flags.bits.enable ||
1713 pipe_ctx->update_flags.bits.plane_changed ||
0b9dc439
AL
1714 plane_state->update_flags.bits.addr_update) {
1715 if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) &&
09a4ec5d 1716 pipe_mall_type == SUBVP_MAIN) {
0b9dc439
AL
1717 union block_sequence_params params;
1718
1719 params.subvp_save_surf_addr.dc_dmub_srv = dc->ctx->dmub_srv;
1720 params.subvp_save_surf_addr.addr = &pipe_ctx->plane_state->address;
1721 params.subvp_save_surf_addr.subvp_index = pipe_ctx->subvp_index;
1722 hwss_subvp_save_surf_addr(&params);
1723 }
f42ea55b 1724 hws->funcs.update_plane_addr(dc, pipe_ctx);
0b9dc439 1725 }
b6e881c9 1726
e7a30ade 1727 if (pipe_ctx->update_flags.bits.enable)
0b7421f0 1728 hubp->funcs->set_blank(hubp, false);
d3dfceb5 1729 /* If the stream paired with this plane is phantom, the plane is also phantom */
09a4ec5d 1730 if (pipe_ctx->stream && pipe_mall_type == SUBVP_PHANTOM
d3dfceb5
AP
1731 && hubp->funcs->phantom_hubp_post_enable)
1732 hubp->funcs->phantom_hubp_post_enable(hubp);
b6e881c9
DL
1733}
1734
5842abd9
WC
1735static int calculate_vready_offset_for_group(struct pipe_ctx *pipe)
1736{
1737 struct pipe_ctx *other_pipe;
1738 int vready_offset = pipe->pipe_dlg_param.vready_offset;
1739
1740 /* Always use the largest vready_offset of all connected pipes */
1741 for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) {
1742 if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
1743 vready_offset = other_pipe->pipe_dlg_param.vready_offset;
1744 }
1745 for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) {
1746 if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
1747 vready_offset = other_pipe->pipe_dlg_param.vready_offset;
1748 }
1749 for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) {
1750 if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
1751 vready_offset = other_pipe->pipe_dlg_param.vready_offset;
1752 }
1753 for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) {
1754 if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
1755 vready_offset = other_pipe->pipe_dlg_param.vready_offset;
1756 }
1757
1758 return vready_offset;
1759}
b6e881c9
DL
1760
1761static void dcn20_program_pipe(
1762 struct dc *dc,
1763 struct pipe_ctx *pipe_ctx,
1764 struct dc_state *context)
1765{
f42ea55b 1766 struct dce_hwseq *hws = dc->hwseq;
d3dfceb5 1767
15e6b396
WL
1768 /* Only need to unblank on top pipe */
1769 if (resource_is_pipe_type(pipe_ctx, OTG_MASTER)) {
1770 if (pipe_ctx->update_flags.bits.enable ||
1771 pipe_ctx->update_flags.bits.odm ||
1772 pipe_ctx->stream->update_flags.bits.abm_level)
1773 hws->funcs.blank_pixel_data(dc, pipe_ctx,
1774 !pipe_ctx->plane_state ||
1775 !pipe_ctx->plane_state->visible);
1776 }
b6e881c9 1777
a71e5529
AC
1778 /* Only update TG on top pipe */
1779 if (pipe_ctx->update_flags.bits.global_sync && !pipe_ctx->top_pipe
1780 && !pipe_ctx->prev_odm_pipe) {
b6e881c9
DL
1781 pipe_ctx->stream_res.tg->funcs->program_global_sync(
1782 pipe_ctx->stream_res.tg,
5842abd9 1783 calculate_vready_offset_for_group(pipe_ctx),
b6e881c9
DL
1784 pipe_ctx->pipe_dlg_param.vstartup_start,
1785 pipe_ctx->pipe_dlg_param.vupdate_offset,
1786 pipe_ctx->pipe_dlg_param.vupdate_width);
1787
012a04b1 1788 if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM)
203ccaf5 1789 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
a71e5529 1790
a14e9e02 1791 pipe_ctx->stream_res.tg->funcs->set_vtg_params(
a71e5529 1792 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true);
1caba4e8 1793
f42ea55b
AK
1794 if (hws->funcs.setup_vupdate_interrupt)
1795 hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
a14e9e02
DL
1796 }
1797
b6e881c9 1798 if (pipe_ctx->update_flags.bits.odm)
f42ea55b 1799 hws->funcs.update_odm(dc, context, pipe_ctx);
b6e881c9 1800
868149c9 1801 if (pipe_ctx->update_flags.bits.enable) {
9fc64ead
QZ
1802 if (hws->funcs.enable_plane)
1803 hws->funcs.enable_plane(dc, pipe_ctx, context);
1804 else
1805 dcn20_enable_plane(dc, pipe_ctx, context);
1806
868149c9
JA
1807 if (dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes)
1808 dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes(dc->res_pool->hubbub);
1809 }
b6e881c9 1810
ba5a5371
NK
1811 if (dc->res_pool->hubbub->funcs->program_det_size && pipe_ctx->update_flags.bits.det_size)
1812 dc->res_pool->hubbub->funcs->program_det_size(
1813 dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb);
ba5a5371 1814
74701238 1815 if (pipe_ctx->update_flags.raw || pipe_ctx->plane_state->update_flags.raw || pipe_ctx->stream->update_flags.raw)
b6e881c9
DL
1816 dcn20_update_dchubp_dpp(dc, pipe_ctx, context);
1817
1818 if (pipe_ctx->update_flags.bits.enable
46250a0c 1819 || pipe_ctx->plane_state->update_flags.bits.hdr_mult)
f42ea55b 1820 hws->funcs.set_hdr_multiplier(pipe_ctx);
b6e881c9
DL
1821
1822 if (pipe_ctx->update_flags.bits.enable ||
2dc84508
MW
1823 pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
1824 pipe_ctx->plane_state->update_flags.bits.gamma_change ||
1825 pipe_ctx->plane_state->update_flags.bits.lut_3d)
f42ea55b 1826 hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
b6e881c9
DL
1827
1828 /* dcn10_translate_regamma_to_hw_format takes 750us to finish
1829 * only do gamma programming for powering on, internal memcmp to avoid
1830 * updating on slave planes
1831 */
bb622e0c
DV
1832 if (pipe_ctx->update_flags.bits.enable ||
1833 pipe_ctx->update_flags.bits.plane_changed ||
1834 pipe_ctx->stream->update_flags.bits.out_tf ||
1835 pipe_ctx->plane_state->update_flags.bits.output_tf_change)
f42ea55b 1836 hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
377c9d04
JP
1837
1838 /* If the pipe has been enabled or has a different opp, we
1839 * should reprogram the fmt. This deals with cases where
1840 * interation between mpc and odm combine on different streams
1841 * causes a different pipe to be chosen to odm combine with.
1842 */
1843 if (pipe_ctx->update_flags.bits.enable
1844 || pipe_ctx->update_flags.bits.opp_changed) {
1845
1846 pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
1847 pipe_ctx->stream_res.opp,
1848 COLOR_SPACE_YCBCR601,
1849 pipe_ctx->stream->timing.display_color_depth,
1850 pipe_ctx->stream->signal);
1851
1852 pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
1853 pipe_ctx->stream_res.opp,
1854 &pipe_ctx->stream->bit_depth_params,
1855 &pipe_ctx->stream->clamping);
1856 }
32e3da43
LH
1857
1858 /* Set ABM pipe after other pipe configurations done */
1859 if (pipe_ctx->plane_state->visible) {
1860 if (pipe_ctx->stream_res.abm) {
1861 dc->hwss.set_pipe(pipe_ctx);
1862 pipe_ctx->stream_res.abm->funcs->set_abm_level(pipe_ctx->stream_res.abm,
1863 pipe_ctx->stream->abm_level);
1864 }
1865 }
051d9007
GS
1866
1867 if (pipe_ctx->update_flags.bits.test_pattern_changed) {
1868 struct output_pixel_processor *odm_opp = pipe_ctx->stream_res.opp;
1869 struct bit_depth_reduction_params params;
1870
1871 memset(&params, 0, sizeof(params));
1872 odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
1873 dc->hwss.set_disp_pattern_generator(dc,
1874 pipe_ctx,
1875 pipe_ctx->stream_res.test_pattern_params.test_pattern,
1876 pipe_ctx->stream_res.test_pattern_params.color_space,
1877 pipe_ctx->stream_res.test_pattern_params.color_depth,
1878 NULL,
1879 pipe_ctx->stream_res.test_pattern_params.width,
1880 pipe_ctx->stream_res.test_pattern_params.height,
1881 pipe_ctx->stream_res.test_pattern_params.offset);
1882 }
b6e881c9
DL
1883}
1884
78c77382 1885void dcn20_program_front_end_for_ctx(
b6e881c9
DL
1886 struct dc *dc,
1887 struct dc_state *context)
1888{
b6e881c9 1889 int i;
f42ea55b 1890 struct dce_hwseq *hws = dc->hwseq;
b6e881c9 1891 DC_LOGGER_INIT(dc->ctx->logger);
9a902a90
AL
1892 unsigned int prev_hubp_count = 0;
1893 unsigned int hubp_count = 0;
b6e881c9 1894
d8bafc2b
WL
1895 if (resource_is_pipe_topology_changed(dc->current_state, context))
1896 resource_log_pipe_topology_update(dc, context);
d5c0af57 1897
091018a5
AC
1898 if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) {
1899 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1900 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
009114f6 1901
091018a5
AC
1902 if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe && pipe_ctx->plane_state) {
1903 ASSERT(!pipe_ctx->plane_state->triplebuffer_flips);
009114f6
AK
1904 /*turn off triple buffer for full update*/
1905 dc->hwss.program_triplebuffer(
091018a5 1906 dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips);
009114f6
AK
1907 }
1908 }
1909 }
1910
9a902a90
AL
1911 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1912 if (dc->current_state->res_ctx.pipe_ctx[i].plane_state)
1913 prev_hubp_count++;
1914 if (context->res_ctx.pipe_ctx[i].plane_state)
1915 hubp_count++;
1916 }
1917
1918 if (prev_hubp_count == 0 && hubp_count > 0) {
1919 if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
1920 dc->res_pool->hubbub->funcs->force_pstate_change_control(
1921 dc->res_pool->hubbub, true, false);
1922 udelay(500);
1923 }
1924
b6e881c9
DL
1925 /* Set pipe update flags and lock pipes */
1926 for (i = 0; i < dc->res_pool->pipe_count; i++)
012a04b1 1927 dcn20_detect_pipe_changes(dc->current_state, context, &dc->current_state->res_ctx.pipe_ctx[i],
b6e881c9 1928 &context->res_ctx.pipe_ctx[i]);
7ed4e635 1929
a5b50a0c
AL
1930 /* When disabling phantom pipes, turn on phantom OTG first (so we can get double
1931 * buffer updates properly)
1932 */
af23aee9
AP
1933 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1934 struct dc_stream_state *stream = dc->current_state->res_ctx.pipe_ctx[i].stream;
1935
1936 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && stream &&
09a4ec5d 1937 dc_state_get_pipe_subvp_type(dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]) == SUBVP_PHANTOM) {
a5b50a0c
AL
1938 struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg;
1939
e87a6c5b
AL
1940 if (tg->funcs->enable_crtc) {
1941 if (dc->hwss.blank_phantom) {
1942 int main_pipe_width, main_pipe_height;
09a4ec5d 1943 struct dc_stream_state *phantom_stream = dc_state_get_paired_subvp_stream(dc->current_state, dc->current_state->res_ctx.pipe_ctx[i].stream);
e87a6c5b 1944
09a4ec5d
DV
1945 main_pipe_width = phantom_stream->dst.width;
1946 main_pipe_height = phantom_stream->dst.height;
e87a6c5b
AL
1947 dc->hwss.blank_phantom(dc, tg, main_pipe_width, main_pipe_height);
1948 }
a5b50a0c 1949 tg->funcs->enable_crtc(tg);
e87a6c5b 1950 }
a5b50a0c 1951 }
af23aee9 1952 }
b6e881c9
DL
1953 /* OTG blank before disabling all front ends */
1954 for (i = 0; i < dc->res_pool->pipe_count; i++)
1955 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
1956 && !context->res_ctx.pipe_ctx[i].top_pipe
1957 && !context->res_ctx.pipe_ctx[i].prev_odm_pipe
1958 && context->res_ctx.pipe_ctx[i].stream)
f42ea55b 1959 hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true);
b6e881c9 1960
d4930b7a 1961
b6e881c9
DL
1962 /* Disconnect mpcc */
1963 for (i = 0; i < dc->res_pool->pipe_count; i++)
1964 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
1965 || context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) {
ba5a5371
NK
1966 struct hubbub *hubbub = dc->res_pool->hubbub;
1967
14eb72ff
AL
1968 /* Phantom pipe DET should be 0, but if a pipe in use is being transitioned to phantom
1969 * then we want to do the programming here (effectively it's being disabled). If we do
1970 * the programming later the DET won't be updated until the OTG for the phantom pipe is
1971 * turned on (i.e. in an MCLK switch) which can come in too late and cause issues with
1972 * DET allocation.
1973 */
1974 if (hubbub->funcs->program_det_size && (context->res_ctx.pipe_ctx[i].update_flags.bits.disable ||
09a4ec5d 1975 (context->res_ctx.pipe_ctx[i].plane_state && dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[i]) == SUBVP_PHANTOM)))
ba5a5371 1976 hubbub->funcs->program_det_size(hubbub, dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);
012a04b1 1977 hws->funcs.plane_atomic_disconnect(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]);
b6e881c9 1978 DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx);
7ed4e635
HW
1979 }
1980
b6e881c9
DL
1981 /*
1982 * Program all updated pipes, order matters for mpcc setup. Start with
1983 * top pipe and program all pipes that follow in order
1984 */
1985 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1986 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
7ed4e635 1987
b6e881c9
DL
1988 if (pipe->plane_state && !pipe->top_pipe) {
1989 while (pipe) {
7f63d8a1
PH
1990 if (hws->funcs.program_pipe)
1991 hws->funcs.program_pipe(dc, pipe, context);
14eb72ff
AL
1992 else {
1993 /* Don't program phantom pipes in the regular front end programming sequence.
1994 * There is an MPO transition case where a pipe being used by a video plane is
1995 * transitioned directly to be a phantom pipe when closing the MPO video. However
1996 * the phantom pipe will program a new HUBP_VTG_SEL (update takes place right away),
1997 * but the MPO still exists until the double buffered update of the main pipe so we
1998 * will get a frame of underflow if the phantom pipe is programmed here.
1999 */
09a4ec5d 2000 if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM)
14eb72ff
AL
2001 dcn20_program_pipe(dc, pipe, context);
2002 }
7f63d8a1 2003
b6e881c9
DL
2004 pipe = pipe->bottom_pipe;
2005 }
b6e881c9 2006 }
82367e7f
RC
2007 /* Program secondary blending tree and writeback pipes */
2008 pipe = &context->res_ctx.pipe_ctx[i];
2009 if (!pipe->top_pipe && !pipe->prev_odm_pipe
2010 && pipe->stream && pipe->stream->num_wb_info > 0
2011 && (pipe->update_flags.raw || (pipe->plane_state && pipe->plane_state->update_flags.raw)
2012 || pipe->stream->update_flags.raw)
2013 && hws->funcs.program_all_writeback_pipes_in_tree)
2014 hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context);
dd15640b
BL
2015
2016 /* Avoid underflow by check of pipe line read when adding 2nd plane. */
2017 if (hws->wa.wait_hubpret_read_start_during_mpo_transition &&
2018 !pipe->top_pipe &&
2019 pipe->stream &&
2020 pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start &&
2021 dc->current_state->stream_status[0].plane_count == 1 &&
2022 context->stream_status[0].plane_count > 1) {
2023 pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp);
2024 }
1cb69b43
DV
2025
2026 /* when dynamic ODM is active, pipes must be reconfigured when all planes are
2027 * disabled, as some transitions will leave software and hardware state
2028 * mismatched.
2029 */
2030 if (dc->debug.enable_single_display_2to1_odm_policy &&
2031 pipe->stream &&
2032 pipe->update_flags.bits.disable &&
2033 !pipe->prev_odm_pipe &&
2034 hws->funcs.update_odm)
2035 hws->funcs.update_odm(dc, context, pipe);
b6e881c9 2036 }
bbf5f6c3
AK
2037}
2038
2039void dcn20_post_unlock_program_front_end(
2040 struct dc *dc,
2041 struct dc_state *context)
2042{
2043 int i;
dbca8310
JA
2044 const unsigned int TIMEOUT_FOR_PIPE_ENABLE_US = 100000;
2045 unsigned int polling_interval_us = 1;
d9758768 2046 struct dce_hwseq *hwseq = dc->hwseq;
bbf5f6c3 2047
b6e881c9
DL
2048 for (i = 0; i < dc->res_pool->pipe_count; i++)
2049 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
012a04b1 2050 dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]);
986936d1
JL
2051
2052 /*
2053 * If we are enabling a pipe, we need to wait for pending clear as this is a critical
2054 * part of the enable operation otherwise, DM may request an immediate flip which
2055 * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which
2056 * is unsupported on DCN.
2057 */
b6e881c9
DL
2058 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2059 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
85f4bc0c
AL
2060 // Don't check flip pending on phantom pipes
2061 if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable &&
09a4ec5d 2062 dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {
b6e881c9
DL
2063 struct hubp *hubp = pipe->plane_res.hubp;
2064 int j = 0;
dbca8310 2065 for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_US / polling_interval_us
b6e881c9 2066 && hubp->funcs->hubp_is_flip_pending(hubp); j++)
dbca8310 2067 udelay(polling_interval_us);
986936d1
JL
2068 }
2069 }
f93e29f0 2070
9a902a90
AL
2071 if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
2072 dc->res_pool->hubbub->funcs->force_pstate_change_control(
2073 dc->res_pool->hubbub, false, false);
2074
14eb72ff
AL
2075 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2076 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
2077
2078 if (pipe->plane_state && !pipe->top_pipe) {
2079 /* Program phantom pipe here to prevent a frame of underflow in the MPO transition
2080 * case (if a pipe being used for a video plane transitions to a phantom pipe, it
2081 * can underflow due to HUBP_VTG_SEL programming if done in the regular front end
2082 * programming sequence).
2083 */
b0d6de32 2084 while (pipe) {
09a4ec5d 2085 if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
e267f5e6
AL
2086 /* When turning on the phantom pipe we want to run through the
2087 * entire enable sequence, so apply all the "enable" flags.
2088 */
2089 if (dc->hwss.apply_update_flags_for_phantom)
2090 dc->hwss.apply_update_flags_for_phantom(pipe);
b0d6de32
AL
2091 if (dc->hwss.update_phantom_vp_position)
2092 dc->hwss.update_phantom_vp_position(dc, context, pipe);
2093 dcn20_program_pipe(dc, pipe, context);
2094 }
2095 pipe = pipe->bottom_pipe;
43080c9b 2096 }
14eb72ff
AL
2097 }
2098 }
2099
4ed79308
AL
2100 /* P-State support transitions:
2101 * Natural -> FPO: P-State disabled in prepare, force disallow anytime is safe
2102 * FPO -> Natural: Unforce anytime after FW disable is safe (P-State will assert naturally)
2103 * Unsupported -> FPO: P-State enabled in optimize, force disallow anytime is safe
2104 * FPO -> Unsupported: P-State disabled in prepare, unforce disallow anytime is safe
2105 * FPO <-> SubVP: Force disallow is maintained on the FPO / SubVP pipes
2106 */
2107 if (hwseq && hwseq->funcs.update_force_pstate)
2108 dc->hwseq->funcs.update_force_pstate(dc, context);
2109
14eb72ff
AL
2110 /* Only program the MALL registers after all the main and phantom pipes
2111 * are done programming.
2112 */
2113 if (hwseq->funcs.program_mall_pipe_config)
2114 hwseq->funcs.program_mall_pipe_config(dc, context);
2115
f93e29f0 2116 /* WA to apply WM setting*/
d9758768 2117 if (hwseq->wa.DEGVIDCN21)
f93e29f0 2118 dc->res_pool->hubbub->funcs->apply_DEDCN21_147_wa(dc->res_pool->hubbub);
d9758768
GS
2119
2120
2121 /* WA for stutter underflow during MPO transitions when adding 2nd plane */
2122 if (hwseq->wa.disallow_self_refresh_during_multi_plane_transition) {
2123
2124 if (dc->current_state->stream_status[0].plane_count == 1 &&
2125 context->stream_status[0].plane_count > 1) {
2126
2127 struct timing_generator *tg = dc->res_pool->timing_generators[0];
2128
2129 dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, false);
2130
2131 hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = true;
2132 hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame = tg->funcs->get_frame_count(tg);
2133 }
2134 }
7ed4e635
HW
2135}
2136
7ed4e635
HW
2137void dcn20_prepare_bandwidth(
2138 struct dc *dc,
2139 struct dc_state *context)
2140{
2141 struct hubbub *hubbub = dc->res_pool->hubbub;
2e6e14c9 2142 unsigned int compbuf_size_kb = 0;
85f4bc0c
AL
2143 unsigned int cache_wm_a = context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns;
2144 unsigned int i;
7ed4e635 2145
057fc695
JL
2146 dc->clk_mgr->funcs->update_clocks(
2147 dc->clk_mgr,
2148 context,
2149 false);
2150
85f4bc0c
AL
2151 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2152 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
2153
2154 // At optimize don't restore the original watermark value
09a4ec5d 2155 if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_NONE) {
85f4bc0c
AL
2156 context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U;
2157 break;
2158 }
2159 }
2160
2710d6c1 2161 /* program dchubbub watermarks:
a465536e 2162 * For assigning wm_optimized_required, use |= operator since we don't want
2710d6c1
AL
2163 * to clear the value if the optimize has not happened yet
2164 */
a465536e 2165 dc->wm_optimized_required |= hubbub->funcs->program_watermarks(hubbub,
7ed4e635
HW
2166 &context->bw_ctx.bw.dcn.watermarks,
2167 dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
2168 false);
2e6e14c9 2169
85f4bc0c
AL
2170 // Restore the real watermark so we can commit the value to DMCUB
2171 // DMCUB uses the "original" watermark value in SubVP MCLK switch
2172 context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = cache_wm_a;
2173
ba5a5371 2174 /* decrease compbuf size */
2e6e14c9 2175 if (hubbub->funcs->program_compbuf_size) {
9a10c126 2176 if (context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes) {
2e6e14c9 2177 compbuf_size_kb = context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes;
a465536e 2178 dc->wm_optimized_required |= (compbuf_size_kb != dc->current_state->bw_ctx.dml.ip.min_comp_buffer_size_kbytes);
9a10c126 2179 } else {
2e6e14c9 2180 compbuf_size_kb = context->bw_ctx.bw.dcn.compbuf_size_kb;
a465536e 2181 dc->wm_optimized_required |= (compbuf_size_kb != dc->current_state->bw_ctx.bw.dcn.compbuf_size_kb);
9a10c126 2182 }
2e6e14c9
DM
2183
2184 hubbub->funcs->program_compbuf_size(hubbub, compbuf_size_kb, false);
2185 }
7ed4e635
HW
2186}
2187
2188void dcn20_optimize_bandwidth(
2189 struct dc *dc,
2190 struct dc_state *context)
2191{
2192 struct hubbub *hubbub = dc->res_pool->hubbub;
e5fc7825 2193 int i;
7ed4e635 2194
85f4bc0c
AL
2195 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2196 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
2197
2198 // At optimize don't need to restore the original watermark value
09a4ec5d 2199 if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_NONE) {
85f4bc0c
AL
2200 context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U;
2201 break;
2202 }
2203 }
2204
4c631826
YS
2205 /* program dchubbub watermarks */
2206 hubbub->funcs->program_watermarks(hubbub,
2207 &context->bw_ctx.bw.dcn.watermarks,
2208 dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
2209 true);
7ed4e635 2210
4866b0bf
ML
2211 if (dc->clk_mgr->dc_mode_softmax_enabled)
2212 if (dc->clk_mgr->clks.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
2213 context->bw_ctx.bw.dcn.clk.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
2214 dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->dc_mode_softmax_memclk);
2215
b808a7eb
DV
2216 /* increase compbuf size */
2217 if (hubbub->funcs->program_compbuf_size)
2218 hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, true);
2219
09c8cbed
WC
2220 if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) {
2221 dc_dmub_srv_p_state_delegate(dc,
2222 true, context);
2223 context->bw_ctx.bw.dcn.clk.p_state_change_support = true;
3b6df06f
WC
2224 dc->clk_mgr->clks.fw_based_mclk_switching = true;
2225 } else {
2226 dc->clk_mgr->clks.fw_based_mclk_switching = false;
09c8cbed
WC
2227 }
2228
4c631826
YS
2229 dc->clk_mgr->funcs->update_clocks(
2230 dc->clk_mgr,
2231 context,
2232 true);
ec39a6d0
MA
2233 if (context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW &&
2234 !dc->debug.disable_extblankadj) {
e5fc7825
GT
2235 for (i = 0; i < dc->res_pool->pipe_count; ++i) {
2236 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2237
2238 if (pipe_ctx->stream && pipe_ctx->plane_res.hubp->funcs->program_extended_blank
2239 && pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max
2240 && pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total)
2241 pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp,
469a6293 2242 pipe_ctx->dlg_regs.min_dst_y_next_start);
e5fc7825
GT
2243 }
2244 }
7ed4e635
HW
2245}
2246
2247bool dcn20_update_bandwidth(
2248 struct dc *dc,
2249 struct dc_state *context)
2250{
2251 int i;
f42ea55b 2252 struct dce_hwseq *hws = dc->hwseq;
7ed4e635
HW
2253
2254 /* recalculate DML parameters */
254eb07c 2255 if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false))
7ed4e635 2256 return false;
7ed4e635
HW
2257
2258 /* apply updated bandwidth parameters */
2259 dc->hwss.prepare_bandwidth(dc, context);
2260
2261 /* update hubp configs for all pipes */
2262 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2263 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2264
2265 if (pipe_ctx->plane_state == NULL)
2266 continue;
2267
2268 if (pipe_ctx->top_pipe == NULL) {
2269 bool blank = !is_pipe_tree_visible(pipe_ctx);
2270
2271 pipe_ctx->stream_res.tg->funcs->program_global_sync(
2272 pipe_ctx->stream_res.tg,
5842abd9 2273 calculate_vready_offset_for_group(pipe_ctx),
7ed4e635
HW
2274 pipe_ctx->pipe_dlg_param.vstartup_start,
2275 pipe_ctx->pipe_dlg_param.vupdate_offset,
2276 pipe_ctx->pipe_dlg_param.vupdate_width);
2277
3972c350 2278 pipe_ctx->stream_res.tg->funcs->set_vtg_params(
5200c401 2279 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, false);
1caba4e8 2280
b1f6d01c 2281 if (pipe_ctx->prev_odm_pipe == NULL)
f42ea55b 2282 hws->funcs.blank_pixel_data(dc, pipe_ctx, blank);
1caba4e8 2283
f42ea55b
AK
2284 if (hws->funcs.setup_vupdate_interrupt)
2285 hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
7ed4e635
HW
2286 }
2287
2288 pipe_ctx->plane_res.hubp->funcs->hubp_setup(
2289 pipe_ctx->plane_res.hubp,
2290 &pipe_ctx->dlg_regs,
2291 &pipe_ctx->ttu_regs,
2292 &pipe_ctx->rq_regs,
2293 &pipe_ctx->pipe_dlg_param);
2294 }
2295
2296 return true;
2297}
2298
78c77382 2299void dcn20_enable_writeback(
7ed4e635 2300 struct dc *dc,
edb922b0
JP
2301 struct dc_writeback_info *wb_info,
2302 struct dc_state *context)
7ed4e635
HW
2303{
2304 struct dwbc *dwb;
2305 struct mcif_wb *mcif_wb;
2306 struct timing_generator *optc;
2307
2308 ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES);
2309 ASSERT(wb_info->wb_enabled);
2310 dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
2311 mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
2312
2313 /* set the OPTC source mux */
6a652f6d 2314 optc = dc->res_pool->timing_generators[dwb->otg_inst];
7ed4e635
HW
2315 optc->funcs->set_dwb_source(optc, wb_info->dwb_pipe_inst);
2316 /* set MCIF_WB buffer and arbitration configuration */
2317 mcif_wb->funcs->config_mcif_buf(mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height);
edb922b0 2318 mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]);
7ed4e635
HW
2319 /* Enable MCIF_WB */
2320 mcif_wb->funcs->enable_mcif(mcif_wb);
2321 /* Enable DWB */
2322 dwb->funcs->enable(dwb, &wb_info->dwb_params);
2323 /* TODO: add sequence to enable/disable warmup */
2324}
2325
2326void dcn20_disable_writeback(
2327 struct dc *dc,
2328 unsigned int dwb_pipe_inst)
2329{
2330 struct dwbc *dwb;
2331 struct mcif_wb *mcif_wb;
2332
2333 ASSERT(dwb_pipe_inst < MAX_DWB_PIPES);
2334 dwb = dc->res_pool->dwbc[dwb_pipe_inst];
2335 mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst];
2336
2337 dwb->funcs->disable(dwb);
2338 mcif_wb->funcs->disable_mcif(mcif_wb);
2339}
2340
78c77382 2341bool dcn20_wait_for_blank_complete(
7ed4e635
HW
2342 struct output_pixel_processor *opp)
2343{
2344 int counter;
2345
2346 for (counter = 0; counter < 1000; counter++) {
2347 if (opp->funcs->dpg_is_blanked(opp))
2348 break;
2349
2350 udelay(100);
2351 }
2352
2353 if (counter == 1000) {
2354 dm_error("DC: failed to blank crtc!\n");
2355 return false;
2356 }
2357
2358 return true;
2359}
2360
2361bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx)
2362{
2363 struct hubp *hubp = pipe_ctx->plane_res.hubp;
2364
2365 if (!hubp)
2366 return false;
2367 return hubp->funcs->dmdata_status_done(hubp);
2368}
2369
78c77382 2370void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx)
7ed4e635 2371{
97bda032 2372 struct dce_hwseq *hws = dc->hwseq;
97bda032
HW
2373
2374 if (pipe_ctx->stream_res.dsc) {
b1f6d01c
DL
2375 struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
2376
20cc44c9 2377 hws->funcs.dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, true);
b1f6d01c 2378 while (odm_pipe) {
20cc44c9 2379 hws->funcs.dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, true);
b1f6d01c
DL
2380 odm_pipe = odm_pipe->next_odm_pipe;
2381 }
97bda032 2382 }
7ed4e635
HW
2383}
2384
78c77382 2385void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx)
7ed4e635 2386{
97bda032 2387 struct dce_hwseq *hws = dc->hwseq;
97bda032
HW
2388
2389 if (pipe_ctx->stream_res.dsc) {
b1f6d01c
DL
2390 struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
2391
20cc44c9 2392 hws->funcs.dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, false);
b1f6d01c 2393 while (odm_pipe) {
20cc44c9 2394 hws->funcs.dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, false);
b1f6d01c
DL
2395 odm_pipe = odm_pipe->next_odm_pipe;
2396 }
97bda032 2397 }
7ed4e635
HW
2398}
2399
2400void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx)
2401{
2402 struct dc_dmdata_attributes attr = { 0 };
2403 struct hubp *hubp = pipe_ctx->plane_res.hubp;
2404
2405 attr.dmdata_mode = DMDATA_HW_MODE;
2406 attr.dmdata_size =
2407 dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36;
2408 attr.address.quad_part =
2409 pipe_ctx->stream->dmdata_address.quad_part;
2410 attr.dmdata_dl_delta = 0;
2411 attr.dmdata_qos_mode = 0;
2412 attr.dmdata_qos_level = 0;
2413 attr.dmdata_repeat = 1; /* always repeat */
2414 attr.dmdata_updated = 1;
2415 attr.dmdata_sw_data = NULL;
2416
2417 hubp->funcs->dmdata_set_attributes(hubp, &attr);
2418}
2419
78c77382 2420void dcn20_init_vm_ctx(
bda9afda
DL
2421 struct dce_hwseq *hws,
2422 struct dc *dc,
2423 struct dc_virtual_addr_space_config *va_config,
2424 int vmid)
7ed4e635 2425{
bda9afda
DL
2426 struct dcn_hubbub_virt_addr_config config;
2427
2428 if (vmid == 0) {
2429 ASSERT(0); /* VMID cannot be 0 for vm context */
2430 return;
2431 }
2432
2433 config.page_table_start_addr = va_config->page_table_start_addr;
2434 config.page_table_end_addr = va_config->page_table_end_addr;
2435 config.page_table_block_size = va_config->page_table_block_size_in_bytes;
2436 config.page_table_depth = va_config->page_table_depth;
2437 config.page_table_base_addr = va_config->page_table_base_addr;
2438
2439 dc->res_pool->hubbub->funcs->init_vm_ctx(dc->res_pool->hubbub, &config, vmid);
2440}
2441
78c77382 2442int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config)
bda9afda
DL
2443{
2444 struct dcn_hubbub_phys_addr_config config;
2445
2446 config.system_aperture.fb_top = pa_config->system_aperture.fb_top;
2447 config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset;
2448 config.system_aperture.fb_base = pa_config->system_aperture.fb_base;
2449 config.system_aperture.agp_top = pa_config->system_aperture.agp_top;
2450 config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot;
2451 config.system_aperture.agp_base = pa_config->system_aperture.agp_base;
2452 config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr;
2453 config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr;
2454 config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr;
ee80de54 2455 config.page_table_default_page_addr = pa_config->page_table_default_page_addr;
bda9afda
DL
2456
2457 return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config);
7ed4e635
HW
2458}
2459
2460static bool patch_address_for_sbs_tb_stereo(
2461 struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
2462{
2463 struct dc_plane_state *plane_state = pipe_ctx->plane_state;
2464 bool sec_split = pipe_ctx->top_pipe &&
2465 pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
2466 if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
2467 (pipe_ctx->stream->timing.timing_3d_format ==
2468 TIMING_3D_FORMAT_SIDE_BY_SIDE ||
2469 pipe_ctx->stream->timing.timing_3d_format ==
2470 TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
2471 *addr = plane_state->address.grph_stereo.left_addr;
2472 plane_state->address.grph_stereo.left_addr =
2473 plane_state->address.grph_stereo.right_addr;
2474 return true;
2475 }
2476
2477 if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&
2478 plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
2479 plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
2480 plane_state->address.grph_stereo.right_addr =
2481 plane_state->address.grph_stereo.left_addr;
480c5b8f
AL
2482 plane_state->address.grph_stereo.right_meta_addr =
2483 plane_state->address.grph_stereo.left_meta_addr;
7ed4e635
HW
2484 }
2485 return false;
2486}
2487
78c77382 2488void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
7ed4e635
HW
2489{
2490 bool addr_patched = false;
2491 PHYSICAL_ADDRESS_LOC addr;
2492 struct dc_plane_state *plane_state = pipe_ctx->plane_state;
7ed4e635
HW
2493
2494 if (plane_state == NULL)
2495 return;
2496
2497 addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
2498
bda9afda
DL
2499 // Call Helper to track VMID use
2500 vm_helper_mark_vmid_used(dc->vm_helper, plane_state->address.vmid, pipe_ctx->plane_res.hubp->inst);
7ed4e635
HW
2501
2502 pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
2503 pipe_ctx->plane_res.hubp,
2504 &plane_state->address,
bda9afda 2505 plane_state->flip_immediate);
7ed4e635
HW
2506
2507 plane_state->status.requested_address = plane_state->address;
2508
2509 if (plane_state->flip_immediate)
2510 plane_state->status.current_address = plane_state->address;
2511
2512 if (addr_patched)
2513 pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
2514}
2515
2516void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
2517 struct dc_link_settings *link_settings)
2518{
c78abac9 2519 struct encoder_unblank_param params = {0};
7ed4e635
HW
2520 struct dc_stream_state *stream = pipe_ctx->stream;
2521 struct dc_link *link = stream->link;
f42ea55b 2522 struct dce_hwseq *hws = link->dc->hwseq;
b1f6d01c 2523 struct pipe_ctx *odm_pipe;
7ed4e635 2524
b1f6d01c
DL
2525 params.opp_cnt = 1;
2526 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
2527 params.opp_cnt++;
2528 }
7ed4e635
HW
2529 /* only 3 items below are used by unblank */
2530 params.timing = pipe_ctx->stream->timing;
2531
2532 params.link_settings.link_rate = link_settings->link_rate;
2533
98ce7d32 2534 if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
f01ee019
FZ
2535 /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
2536 pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank(
2537 pipe_ctx->stream_res.hpo_dp_stream_enc,
2538 pipe_ctx->stream_res.tg->inst);
2539 } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
78c77382 2540 if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1)
7ed4e635
HW
2541 params.timing.pix_clk_100hz /= 2;
2542 pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(
1f332460 2543 pipe_ctx->stream_res.stream_enc, params.opp_cnt > 1);
3550d622 2544 pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
7ed4e635
HW
2545 }
2546
2547 if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
f42ea55b 2548 hws->funcs.edp_backlight_control(link, true);
7ed4e635
HW
2549 }
2550}
2551
78c77382 2552void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx)
7ed4e635
HW
2553{
2554 struct timing_generator *tg = pipe_ctx->stream_res.tg;
78c77382 2555 int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx);
7ed4e635 2556
7fad39ca
EB
2557 if (start_line < 0)
2558 start_line = 0;
7ed4e635
HW
2559
2560 if (tg->funcs->setup_vertical_interrupt2)
2561 tg->funcs->setup_vertical_interrupt2(tg, start_line);
2562}
2563
ca8179ba 2564void dcn20_reset_back_end_for_pipe(
7ed4e635
HW
2565 struct dc *dc,
2566 struct pipe_ctx *pipe_ctx,
2567 struct dc_state *context)
2568{
2569 int i;
9c75891f
WL
2570 struct dc_link *link = pipe_ctx->stream->link;
2571 const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
2572
7ed4e635
HW
2573 DC_LOGGER_INIT(dc->ctx->logger);
2574 if (pipe_ctx->stream_res.stream_enc == NULL) {
2575 pipe_ctx->stream = NULL;
2576 return;
2577 }
2578
25879d7b
QZ
2579 /* DPMS may already disable or */
2580 /* dpms_off status is incorrect due to fastboot
2581 * feature. When system resume from S4 with second
2582 * screen only, the dpms_off would be true but
2583 * VBIOS lit up eDP, so check link status too.
2584 */
2585 if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
2586 dc->link_srv->set_dpms_off(pipe_ctx);
2587 else if (pipe_ctx->stream_res.audio)
2588 dc->hwss.disable_audio_stream(pipe_ctx);
2589
2590 /* free acquired resources */
2591 if (pipe_ctx->stream_res.audio) {
2592 /*disable az_endpoint*/
2593 pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
2594
2595 /*free audio*/
2596 if (dc->caps.dynamic_audio == true) {
2597 /*we have to dynamic arbitrate the audio endpoints*/
2598 /*we free the resource, need reset is_audio_acquired*/
2599 update_audio_usage(&dc->current_state->res_ctx, dc->res_pool,
2600 pipe_ctx->stream_res.audio, false);
2601 pipe_ctx->stream_res.audio = NULL;
7ed4e635 2602 }
7ed4e635
HW
2603 }
2604
2605 /* by upper caller loop, parent pipe: pipe0, will be reset last.
2606 * back end share by all pipes and will be disable only when disable
2607 * parent pipe.
2608 */
2609 if (pipe_ctx->top_pipe == NULL) {
9edf202d 2610
3ba01817 2611 dc->hwss.set_abm_immediate_disable(pipe_ctx);
9edf202d 2612
7ed4e635
HW
2613 pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
2614
2615 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
2616 if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
2617 pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
2618 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
38df0701
WL
2619
2620 if (pipe_ctx->stream_res.tg->funcs->set_drr)
2621 pipe_ctx->stream_res.tg->funcs->set_drr(
2622 pipe_ctx->stream_res.tg, NULL);
9c75891f
WL
2623 /* TODO - convert symclk_ref_cnts for otg to a bit map to solve
2624 * the case where the same symclk is shared across multiple otg
2625 * instances
2626 */
dff45f03
AL
2627 if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))
2628 link->phy_state.symclk_ref_cnts.otg = 0;
9c75891f
WL
2629 if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) {
2630 link_hwss->disable_link_output(link,
2631 &pipe_ctx->link_res, pipe_ctx->stream->signal);
2632 link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
2633 }
7ed4e635
HW
2634 }
2635
2636 for (i = 0; i < dc->res_pool->pipe_count; i++)
2637 if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx)
2638 break;
2639
2640 if (i == dc->res_pool->pipe_count)
2641 return;
2642
2643 pipe_ctx->stream = NULL;
2644 DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
2645 pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
2646}
2647
78c77382 2648void dcn20_reset_hw_ctx_wrap(
7ed4e635
HW
2649 struct dc *dc,
2650 struct dc_state *context)
2651{
2652 int i;
f42ea55b 2653 struct dce_hwseq *hws = dc->hwseq;
7ed4e635
HW
2654
2655 /* Reset Back End*/
2656 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
2657 struct pipe_ctx *pipe_ctx_old =
2658 &dc->current_state->res_ctx.pipe_ctx[i];
2659 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2660
2661 if (!pipe_ctx_old->stream)
2662 continue;
2663
b1f6d01c 2664 if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
7ed4e635
HW
2665 continue;
2666
2667 if (!pipe_ctx->stream ||
2668 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
2669 struct clock_source *old_clk = pipe_ctx_old->clock_source;
2670
2671 dcn20_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
f42ea55b 2672 if (hws->funcs.enable_stream_gating)
ae6c9601 2673 hws->funcs.enable_stream_gating(dc, pipe_ctx_old);
7ed4e635
HW
2674 if (old_clk)
2675 old_clk->funcs->cs_power_down(old_clk);
2676 }
2677 }
2678}
2679
3ca40237
WW
2680void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
2681{
7ed4e635 2682 struct hubp *hubp = pipe_ctx->plane_res.hubp;
c78abac9 2683 struct mpcc_blnd_cfg blnd_cfg = {0};
473e0ecb 2684 bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha;
7ed4e635
HW
2685 int mpcc_id;
2686 struct mpcc *new_mpcc;
2687 struct mpc *mpc = dc->res_pool->mpc;
2688 struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
2689
7ed4e635
HW
2690 blnd_cfg.overlap_only = false;
2691 blnd_cfg.global_gain = 0xff;
2692
76818cdd
SJK
2693 if (per_pixel_alpha) {
2694 blnd_cfg.pre_multiplied_alpha = pipe_ctx->plane_state->pre_multiplied_alpha;
2695 if (pipe_ctx->plane_state->global_alpha) {
2696 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
2697 blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
2698 } else {
2699 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
2700 }
67229b27 2701 } else {
76818cdd 2702 blnd_cfg.pre_multiplied_alpha = false;
67229b27
MW
2703 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
2704 }
2705
7ed4e635
HW
2706 if (pipe_ctx->plane_state->global_alpha)
2707 blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
2708 else
2709 blnd_cfg.global_alpha = 0xff;
2710
2711 blnd_cfg.background_color_bpc = 4;
2712 blnd_cfg.bottom_gain_mode = 0;
2713 blnd_cfg.top_gain = 0x1f000;
2714 blnd_cfg.bottom_inside_gain = 0x1f000;
2715 blnd_cfg.bottom_outside_gain = 0x1f000;
76818cdd 2716
d99f1387
BL
2717 if (pipe_ctx->plane_state->format
2718 == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA)
2719 blnd_cfg.pre_multiplied_alpha = false;
7ed4e635
HW
2720
2721 /*
2722 * TODO: remove hack
2723 * Note: currently there is a bug in init_hw such that
2724 * on resume from hibernate, BIOS sets up MPCC0, and
2725 * we do mpcc_remove but the mpcc cannot go to idle
2726 * after remove. This cause us to pick mpcc1 here,
2727 * which causes a pstate hang for yet unknown reason.
2728 */
2729 mpcc_id = hubp->inst;
2730
c97c8d77 2731 /* If there is no full update, don't need to touch MPC tree*/
68c10ac9
AC
2732 if (!pipe_ctx->plane_state->update_flags.bits.full_update &&
2733 !pipe_ctx->update_flags.bits.mpcc) {
c97c8d77 2734 mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
d205a800 2735 dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
c97c8d77
NK
2736 return;
2737 }
2738
7ed4e635
HW
2739 /* check if this MPCC is already being used */
2740 new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id);
2741 /* remove MPCC if being used */
2742 if (new_mpcc != NULL)
2743 mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc);
2744 else
2745 if (dc->debug.sanity_checks)
2746 mpc->funcs->assert_mpcc_idle_before_connect(
2747 dc->res_pool->mpc, mpcc_id);
2748
2749 /* Call MPC to insert new plane */
2750 new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
2751 mpc_tree_params,
2752 &blnd_cfg,
2753 NULL,
2754 NULL,
2755 hubp->inst,
2756 mpcc_id);
d205a800 2757 dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
7ed4e635
HW
2758
2759 ASSERT(new_mpcc != NULL);
2760 hubp->opp_id = pipe_ctx->stream_res.opp->inst;
2761 hubp->mpcc_id = mpcc_id;
2762}
2763
78c77382 2764void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
f591344e
JP
2765{
2766 enum dc_lane_count lane_count =
2767 pipe_ctx->stream->link->cur_link_settings.lane_count;
2768
2769 struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
2770 struct dc_link *link = pipe_ctx->stream->link;
2771
2772 uint32_t active_total_with_borders;
2773 uint32_t early_control = 0;
2774 struct timing_generator *tg = pipe_ctx->stream_res.tg;
9d8033d6
WL
2775 const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
2776 struct dc *dc = pipe_ctx->stream->ctx->dc;
7462475e
WL
2777 struct dtbclk_dto_params dto_params = {0};
2778 struct dccg *dccg = dc->res_pool->dccg;
2779 enum phyd32clk_clock_source phyd32clk;
2780 int dp_hpo_inst;
a10a22b0
WL
2781 struct dce_hwseq *hws = dc->hwseq;
2782 unsigned int k1_div = PIXEL_RATE_DIV_NA;
2783 unsigned int k2_div = PIXEL_RATE_DIV_NA;
543068f0
FZ
2784 struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
2785 struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
64d283cb 2786
98ce7d32 2787 if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
9d8033d6
WL
2788 if (dc->hwseq->funcs.setup_hpo_hw_control)
2789 dc->hwseq->funcs.setup_hpo_hw_control(dc->hwseq, true);
f01ee019
FZ
2790 }
2791
98ce7d32 2792 if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
7462475e
WL
2793 dto_params.otg_inst = tg->inst;
2794 dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
2795 dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx);
2796 dto_params.timing = &pipe_ctx->stream->timing;
2797 dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
2798 dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
31c2bf25
DL
2799 dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
2800 dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, dp_hpo_inst);
2801
2802 phyd32clk = get_phyd32clk_src(link);
2803 dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk);
543068f0
FZ
2804 } else {
2805 if (dccg->funcs->enable_symclk_se)
2806 dccg->funcs->enable_symclk_se(dccg, stream_enc->stream_enc_inst,
2807 link_enc->transmitter - TRANSMITTER_UNIPHY_A);
cac9f51d 2808 }
a10a22b0
WL
2809 if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) {
2810 hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div);
2811
2812 dc->res_pool->dccg->funcs->set_pixel_rate_div(
2813 dc->res_pool->dccg,
2814 pipe_ctx->stream_res.tg->inst,
2815 k1_div, k2_div);
2816 }
2817
9d8033d6 2818 link_hwss->setup_stream_encoder(pipe_ctx);
3550d622 2819
ce10a0f3 2820 if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) {
9d8033d6
WL
2821 if (dc->hwss.program_dmdata_engine)
2822 dc->hwss.program_dmdata_engine(pipe_ctx);
ce10a0f3 2823 }
f591344e 2824
9d8033d6 2825 dc->hwss.update_info_frame(pipe_ctx);
f591344e 2826
3550d622 2827 if (dc_is_dp_signal(pipe_ctx->stream->signal))
98ce7d32 2828 dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
3550d622 2829
f591344e
JP
2830 /* enable early control to avoid corruption on DP monitor*/
2831 active_total_with_borders =
2832 timing->h_addressable
2833 + timing->h_border_left
2834 + timing->h_border_right;
2835
2836 if (lane_count != 0)
2837 early_control = active_total_with_borders % lane_count;
2838
2839 if (early_control == 0)
2840 early_control = lane_count;
2841
2842 tg->funcs->set_early_control(tg, early_control);
2843
64a30aaf
EB
2844 if (dc->hwseq->funcs.set_pixels_per_cycle)
2845 dc->hwseq->funcs.set_pixels_per_cycle(pipe_ctx);
f591344e
JP
2846}
2847
78c77382 2848void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
f591344e
JP
2849{
2850 struct dc_stream_state *stream = pipe_ctx->stream;
2851 struct hubp *hubp = pipe_ctx->plane_res.hubp;
2852 bool enable = false;
2853 struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
2854 enum dynamic_metadata_mode mode = dc_is_dp_signal(stream->signal)
2855 ? dmdata_dp
2856 : dmdata_hdmi;
2857
2858 /* if using dynamic meta, don't set up generic infopackets */
2859 if (pipe_ctx->stream->dmdata_address.quad_part != 0) {
2860 pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false;
2861 enable = true;
2862 }
2863
2864 if (!hubp)
2865 return;
2866
2867 if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata)
2868 return;
2869
2870 stream_enc->funcs->set_dynamic_metadata(stream_enc, enable,
2871 hubp->inst, mode);
2872}
2873
78c77382 2874void dcn20_fpga_init_hw(struct dc *dc)
8a31820b
ML
2875{
2876 int i, j;
2877 struct dce_hwseq *hws = dc->hwseq;
2878 struct resource_pool *res_pool = dc->res_pool;
2879 struct dc_state *context = dc->current_state;
2880
2881 if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
2882 dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
2883
2884 // Initialize the dccg
2885 if (res_pool->dccg->funcs->dccg_init)
2886 res_pool->dccg->funcs->dccg_init(res_pool->dccg);
2887
2888 //Enable ability to power gate / don't force power on permanently
f42ea55b 2889 hws->funcs.enable_power_gating_plane(hws, true);
8a31820b
ML
2890
2891 // Specific to FPGA dccg and registers
2892 REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF);
2893 REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF);
2894
f42ea55b 2895 hws->funcs.dccg_init(hws);
8a31820b
ML
2896
2897 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2);
2898 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
3ebd17f5
DL
2899 if (REG(REFCLK_CNTL))
2900 REG_WRITE(REFCLK_CNTL, 0);
8a31820b
ML
2901 //
2902
2903
2904 /* Blank pixel data with OPP DPG */
2905 for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
2906 struct timing_generator *tg = dc->res_pool->timing_generators[i];
2907
2908 if (tg->funcs->is_tg_enabled(tg))
2909 dcn20_init_blank(dc, tg);
2910 }
2911
2912 for (i = 0; i < res_pool->timing_generator_count; i++) {
2913 struct timing_generator *tg = dc->res_pool->timing_generators[i];
2914
2915 if (tg->funcs->is_tg_enabled(tg))
2916 tg->funcs->lock(tg);
2917 }
2918
2919 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2920 struct dpp *dpp = res_pool->dpps[i];
2921
2922 dpp->funcs->dpp_reset(dpp);
2923 }
2924
2925 /* Reset all MPCC muxes */
2926 res_pool->mpc->funcs->mpc_init(res_pool->mpc);
2927
2928 /* initialize OPP mpc_tree parameter */
9aa75e3b 2929 for (i = 0; i < dc->res_pool->pipe_count; i++) {
8a31820b
ML
2930 res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
2931 res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
2932 for (j = 0; j < MAX_PIPES; j++)
2933 res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
2934 }
2935
2936 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2937 struct timing_generator *tg = dc->res_pool->timing_generators[i];
2938 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2939 struct hubp *hubp = dc->res_pool->hubps[i];
2940 struct dpp *dpp = dc->res_pool->dpps[i];
2941
2942 pipe_ctx->stream_res.tg = tg;
2943 pipe_ctx->pipe_idx = i;
2944
2945 pipe_ctx->plane_res.hubp = hubp;
2946 pipe_ctx->plane_res.dpp = dpp;
2947 pipe_ctx->plane_res.mpcc_inst = dpp->inst;
2948 hubp->mpcc_id = dpp->inst;
2949 hubp->opp_id = OPP_ID_INVALID;
2950 hubp->power_gated = false;
2951 pipe_ctx->stream_res.opp = NULL;
2952
2953 hubp->funcs->hubp_init(hubp);
2954
2955 //dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst;
2956 //dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
2957 dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
2958 pipe_ctx->stream_res.opp = dc->res_pool->opps[i];
2959 /*to do*/
012a04b1 2960 hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx);
8a31820b
ML
2961 }
2962
2963 /* initialize DWB pointer to MCIF_WB */
2964 for (i = 0; i < res_pool->res_cap->num_dwb; i++)
2965 res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];
2966
2967 for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
2968 struct timing_generator *tg = dc->res_pool->timing_generators[i];
2969
2970 if (tg->funcs->is_tg_enabled(tg))
2971 tg->funcs->unlock(tg);
2972 }
2973
2974 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2975 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2976
012a04b1 2977 dc->hwss.disable_plane(dc, context, pipe_ctx);
8a31820b
ML
2978
2979 pipe_ctx->stream_res.tg = NULL;
2980 pipe_ctx->plane_res.hubp = NULL;
2981 }
2982
2983 for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
2984 struct timing_generator *tg = dc->res_pool->timing_generators[i];
2985
2986 tg->funcs->tg_init(tg);
2987 }
8fe44c08 2988
ba5a5371
NK
2989 if (dc->res_pool->hubbub->funcs->init_crb)
2990 dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
8a31820b 2991}
dbf5256b
JA
2992
2993void dcn20_set_disp_pattern_generator(const struct dc *dc,
2994 struct pipe_ctx *pipe_ctx,
2995 enum controller_dp_test_pattern test_pattern,
2996 enum controller_dp_color_space color_space,
2997 enum dc_color_depth color_depth,
2998 const struct tg_color *solid_color,
2999 int width, int height, int offset)
3000{
3001 pipe_ctx->stream_res.opp->funcs->opp_set_disp_pattern_generator(pipe_ctx->stream_res.opp, test_pattern,
3002 color_space, color_depth, solid_color, width, height, offset);
a71e5529 3003}