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