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