Merge tag 'drm-intel-gt-next-2023-06-08' of git://anongit.freedesktop.org/drm/drm...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / display / dc / dcn201 / dcn201_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
26 #include "dm_services.h"
27 #include "basics/dc_common.h"
28 #include "core_types.h"
29 #include "resource.h"
30 #include "dcn201_hwseq.h"
31 #include "dcn201_optc.h"
32 #include "dce/dce_hwseq.h"
33 #include "hubp.h"
34 #include "dchubbub.h"
35 #include "timing_generator.h"
36 #include "opp.h"
37 #include "ipp.h"
38 #include "mpc.h"
39 #include "dccg.h"
40 #include "clk_mgr.h"
41 #include "reg_helper.h"
42
43 #define CTX \
44         hws->ctx
45
46 #define REG(reg)\
47         hws->regs->reg
48
49 #define DC_LOGGER \
50         dc->ctx->logger
51
52 #undef FN
53 #define FN(reg_name, field_name) \
54         hws->shifts->field_name, hws->masks->field_name
55
56 static bool patch_address_for_sbs_tb_stereo(
57                 struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
58 {
59         struct dc_plane_state *plane_state = pipe_ctx->plane_state;
60         bool sec_split = pipe_ctx->top_pipe &&
61                 pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
62
63         if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
64                 (pipe_ctx->stream->timing.timing_3d_format ==
65                         TIMING_3D_FORMAT_SIDE_BY_SIDE ||
66                 pipe_ctx->stream->timing.timing_3d_format ==
67                         TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
68                 *addr = plane_state->address.grph_stereo.left_addr;
69                 plane_state->address.grph_stereo.left_addr =
70                         plane_state->address.grph_stereo.right_addr;
71                 return true;
72         } else {
73                 if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&
74                         plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
75                         plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
76                         plane_state->address.grph_stereo.right_addr =
77                         plane_state->address.grph_stereo.left_addr;
78                         plane_state->address.grph_stereo.right_meta_addr =
79                         plane_state->address.grph_stereo.left_meta_addr;
80                 }
81         }
82         return false;
83 }
84
85 static bool gpu_addr_to_uma(struct dce_hwseq *hwseq,
86                 PHYSICAL_ADDRESS_LOC *addr)
87 {
88         bool is_in_uma;
89
90         if (hwseq->fb_base.quad_part <= addr->quad_part &&
91                         addr->quad_part < hwseq->fb_top.quad_part) {
92                 addr->quad_part -= hwseq->fb_base.quad_part;
93                 addr->quad_part += hwseq->fb_offset.quad_part;
94                 is_in_uma = true;
95         } else if (hwseq->fb_offset.quad_part <= addr->quad_part &&
96                         addr->quad_part <= hwseq->uma_top.quad_part) {
97                 is_in_uma = true;
98         } else {
99                 is_in_uma = false;
100         }
101         return is_in_uma;
102 }
103
104 static void plane_address_in_gpu_space_to_uma(struct dce_hwseq *hwseq,
105                 struct dc_plane_address *addr)
106 {
107         switch (addr->type) {
108         case PLN_ADDR_TYPE_GRAPHICS:
109                 gpu_addr_to_uma(hwseq, &addr->grph.addr);
110                 gpu_addr_to_uma(hwseq, &addr->grph.meta_addr);
111                 break;
112         case PLN_ADDR_TYPE_GRPH_STEREO:
113                 gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_addr);
114                 gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_meta_addr);
115                 gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_addr);
116                 gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_meta_addr);
117                 break;
118         case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE:
119                 gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_addr);
120                 gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_meta_addr);
121                 gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_addr);
122                 gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_meta_addr);
123                 break;
124         default:
125                 BREAK_TO_DEBUGGER();
126                 break;
127         }
128 }
129
130 void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
131 {
132         bool addr_patched = false;
133         PHYSICAL_ADDRESS_LOC addr;
134         struct dc_plane_state *plane_state = pipe_ctx->plane_state;
135         struct dce_hwseq *hws = dc->hwseq;
136         struct dc_plane_address uma;
137
138         if (plane_state == NULL)
139                 return;
140
141         uma = plane_state->address;
142         addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
143
144         plane_address_in_gpu_space_to_uma(hws, &uma);
145
146         pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
147                         pipe_ctx->plane_res.hubp,
148                         &uma,
149                         plane_state->flip_immediate);
150
151         plane_state->status.requested_address = plane_state->address;
152
153         if (plane_state->flip_immediate)
154                 plane_state->status.current_address = plane_state->address;
155
156         if (addr_patched)
157                 pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
158 }
159
160 /* Blank pixel data during initialization */
161 void dcn201_init_blank(
162                 struct dc *dc,
163                 struct timing_generator *tg)
164 {
165         struct dce_hwseq *hws = dc->hwseq;
166         enum dc_color_space color_space;
167         struct tg_color black_color = {0};
168         struct output_pixel_processor *opp = NULL;
169         uint32_t num_opps, opp_id_src0, opp_id_src1;
170         uint32_t otg_active_width, otg_active_height;
171
172         /* program opp dpg blank color */
173         color_space = COLOR_SPACE_SRGB;
174         color_space_to_black_color(dc, color_space, &black_color);
175
176         /* get the OTG active size */
177         tg->funcs->get_otg_active_size(tg,
178                         &otg_active_width,
179                         &otg_active_height);
180
181         /* get the OPTC source */
182         tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
183         ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp);
184         opp = dc->res_pool->opps[opp_id_src0];
185
186         opp->funcs->opp_set_disp_pattern_generator(
187                         opp,
188                         CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
189                         CONTROLLER_DP_COLOR_SPACE_UDEFINED,
190                         COLOR_DEPTH_UNDEFINED,
191                         &black_color,
192                         otg_active_width,
193                         otg_active_height,
194                         0);
195
196         hws->funcs.wait_for_blank_complete(opp);
197 }
198
199 static void read_mmhub_vm_setup(struct dce_hwseq *hws)
200 {
201         uint32_t fb_base = REG_READ(MC_VM_FB_LOCATION_BASE);
202         uint32_t fb_top = REG_READ(MC_VM_FB_LOCATION_TOP);
203         uint32_t fb_offset = REG_READ(MC_VM_FB_OFFSET);
204
205         /* MC_VM_FB_LOCATION_TOP is in pages, actual top should add 1 */
206         fb_top++;
207
208         /* bit 23:0 in register map to bit 47:24 in address */
209         hws->fb_base.low_part = fb_base;
210         hws->fb_base.quad_part <<= 24;
211
212         hws->fb_top.low_part  = fb_top;
213         hws->fb_top.quad_part <<= 24;
214         hws->fb_offset.low_part = fb_offset;
215         hws->fb_offset.quad_part <<= 24;
216
217         hws->uma_top.quad_part = hws->fb_top.quad_part
218                         - hws->fb_base.quad_part + hws->fb_offset.quad_part;
219 }
220
221 void dcn201_init_hw(struct dc *dc)
222 {
223         int i, j;
224         struct dce_hwseq *hws = dc->hwseq;
225         struct resource_pool *res_pool = dc->res_pool;
226         struct dc_state  *context = dc->current_state;
227
228         if (res_pool->dccg->funcs->dccg_init)
229                 res_pool->dccg->funcs->dccg_init(res_pool->dccg);
230
231         if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
232                 dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
233
234         if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
235                 REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF);
236                 REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF);
237
238                 hws->funcs.dccg_init(hws);
239
240                 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2);
241                 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
242                 REG_WRITE(REFCLK_CNTL, 0);
243         } else {
244                 hws->funcs.bios_golden_init(dc);
245
246                 if (dc->ctx->dc_bios->fw_info_valid) {
247                         res_pool->ref_clocks.xtalin_clock_inKhz =
248                                 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
249
250                         if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
251                                 if (res_pool->dccg && res_pool->hubbub) {
252                                         (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
253                                                         dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
254                                                         &res_pool->ref_clocks.dccg_ref_clock_inKhz);
255
256                                         (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
257                                                         res_pool->ref_clocks.dccg_ref_clock_inKhz,
258                                                         &res_pool->ref_clocks.dchub_ref_clock_inKhz);
259                                 } else {
260                                         res_pool->ref_clocks.dccg_ref_clock_inKhz =
261                                                         res_pool->ref_clocks.xtalin_clock_inKhz;
262                                         res_pool->ref_clocks.dchub_ref_clock_inKhz =
263                                                         res_pool->ref_clocks.xtalin_clock_inKhz;
264                                 }
265                         }
266                 } else
267                         ASSERT_CRITICAL(false);
268                 for (i = 0; i < dc->link_count; i++) {
269                         /* Power up AND update implementation according to the
270                          * required signal (which may be different from the
271                          * default signal on connector).
272                          */
273                         struct dc_link *link = dc->links[i];
274
275                         link->link_enc->funcs->hw_init(link->link_enc);
276                 }
277                 if (hws->fb_offset.quad_part == 0)
278                         read_mmhub_vm_setup(hws);
279         }
280
281         /* Blank pixel data with OPP DPG */
282         for (i = 0; i < res_pool->timing_generator_count; i++) {
283                 struct timing_generator *tg = res_pool->timing_generators[i];
284
285                 if (tg->funcs->is_tg_enabled(tg)) {
286                         dcn201_init_blank(dc, tg);
287                 }
288         }
289
290         for (i = 0; i < res_pool->timing_generator_count; i++) {
291                 struct timing_generator *tg = res_pool->timing_generators[i];
292
293                 if (tg->funcs->is_tg_enabled(tg))
294                         tg->funcs->lock(tg);
295         }
296
297         for (i = 0; i < res_pool->pipe_count; i++) {
298                 struct dpp *dpp = res_pool->dpps[i];
299
300                 dpp->funcs->dpp_reset(dpp);
301         }
302
303         /* Reset all MPCC muxes */
304         res_pool->mpc->funcs->mpc_init(res_pool->mpc);
305
306         /* initialize OPP mpc_tree parameter */
307         for (i = 0; i < res_pool->res_cap->num_opp; i++) {
308                 res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
309                 res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
310                 for (j = 0; j < MAX_PIPES; j++)
311                         res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
312         }
313
314         for (i = 0; i < res_pool->timing_generator_count; i++) {
315                 struct timing_generator *tg = res_pool->timing_generators[i];
316                 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
317                 struct hubp *hubp = res_pool->hubps[i];
318                 struct dpp *dpp = res_pool->dpps[i];
319
320                 pipe_ctx->stream_res.tg = tg;
321                 pipe_ctx->pipe_idx = i;
322
323                 pipe_ctx->plane_res.hubp = hubp;
324                 pipe_ctx->plane_res.dpp = dpp;
325                 pipe_ctx->plane_res.mpcc_inst = dpp->inst;
326                 hubp->mpcc_id = dpp->inst;
327                 hubp->opp_id = OPP_ID_INVALID;
328                 hubp->power_gated = false;
329                 pipe_ctx->stream_res.opp = NULL;
330
331                 hubp->funcs->hubp_init(hubp);
332
333                 res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
334                 pipe_ctx->stream_res.opp = res_pool->opps[i];
335                 /*To do: number of MPCC != number of opp*/
336                 hws->funcs.plane_atomic_disconnect(dc, pipe_ctx);
337         }
338
339         /* initialize DWB pointer to MCIF_WB */
340         for (i = 0; i < res_pool->res_cap->num_dwb; i++)
341                 res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];
342
343         for (i = 0; i < res_pool->timing_generator_count; i++) {
344                 struct timing_generator *tg = res_pool->timing_generators[i];
345
346                 if (tg->funcs->is_tg_enabled(tg))
347                         tg->funcs->unlock(tg);
348         }
349
350         for (i = 0; i < res_pool->pipe_count; i++) {
351                 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
352
353                 dc->hwss.disable_plane(dc, pipe_ctx);
354
355                 pipe_ctx->stream_res.tg = NULL;
356                 pipe_ctx->plane_res.hubp = NULL;
357         }
358
359         for (i = 0; i < res_pool->timing_generator_count; i++) {
360                 struct timing_generator *tg = res_pool->timing_generators[i];
361
362                 tg->funcs->tg_init(tg);
363         }
364
365         /* end of FPGA. Below if real ASIC */
366         if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
367                 return;
368
369         for (i = 0; i < res_pool->audio_count; i++) {
370                 struct audio *audio = res_pool->audios[i];
371
372                 audio->funcs->hw_init(audio);
373         }
374
375         /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
376         REG_WRITE(DIO_MEM_PWR_CTRL, 0);
377
378         if (!dc->debug.disable_clock_gate) {
379                 /* enable all DCN clock gating */
380                 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
381
382                 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
383
384                 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
385         }
386 }
387
388 /* trigger HW to start disconnect plane from stream on the next vsync */
389 void dcn201_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx)
390 {
391         struct dce_hwseq *hws = dc->hwseq;
392         struct hubp *hubp = pipe_ctx->plane_res.hubp;
393         int dpp_id = pipe_ctx->plane_res.dpp->inst;
394         struct mpc *mpc = dc->res_pool->mpc;
395         struct mpc_tree *mpc_tree_params;
396         struct mpcc *mpcc_to_remove = NULL;
397         struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
398         bool mpcc_removed = false;
399
400         mpc_tree_params = &(opp->mpc_tree_params);
401
402         /* check if this plane is being used by an MPCC in the secondary blending chain */
403         if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
404                 mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
405
406         /* remove MPCC from secondary if being used */
407         if (mpcc_to_remove != NULL && mpc->funcs->remove_mpcc_from_secondary) {
408                 mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, mpcc_to_remove);
409                 mpcc_removed = true;
410         }
411
412         /* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
413         mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
414         if (mpcc_to_remove != NULL) {
415                 mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove);
416                 mpcc_removed = true;
417         }
418
419         /*Already reset*/
420         if (mpcc_removed == false)
421                 return;
422
423         if (opp != NULL)
424                 opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
425
426         dc->optimized_required = true;
427
428         if (hubp->funcs->hubp_disconnect)
429                 hubp->funcs->hubp_disconnect(hubp);
430
431         if (dc->debug.sanity_checks)
432                 hws->funcs.verify_allow_pstate_change_high(dc);
433 }
434
435 void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
436 {
437         struct hubp *hubp = pipe_ctx->plane_res.hubp;
438         struct mpcc_blnd_cfg blnd_cfg;
439         bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
440         int mpcc_id, dpp_id;
441         struct mpcc *new_mpcc;
442         struct mpcc *remove_mpcc = NULL;
443         struct mpc *mpc = dc->res_pool->mpc;
444         struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
445
446         if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) {
447                 get_hdr_visual_confirm_color(
448                                 pipe_ctx, &blnd_cfg.black_color);
449         } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) {
450                 get_surface_visual_confirm_color(
451                                 pipe_ctx, &blnd_cfg.black_color);
452         } else {
453                 color_space_to_black_color(
454                                 dc, pipe_ctx->stream->output_color_space,
455                                 &blnd_cfg.black_color);
456         }
457
458         if (per_pixel_alpha)
459                 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
460         else
461                 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
462
463         blnd_cfg.overlap_only = false;
464
465         if (pipe_ctx->plane_state->global_alpha_value)
466                 blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
467         else
468                 blnd_cfg.global_alpha = 0xff;
469
470         blnd_cfg.global_gain = 0xff;
471         blnd_cfg.background_color_bpc = 4;
472         blnd_cfg.bottom_gain_mode = 0;
473         blnd_cfg.top_gain = 0x1f000;
474         blnd_cfg.bottom_inside_gain = 0x1f000;
475         blnd_cfg.bottom_outside_gain = 0x1f000;
476         /*the input to MPCC is RGB*/
477         blnd_cfg.black_color.color_b_cb = 0;
478         blnd_cfg.black_color.color_g_y = 0;
479         blnd_cfg.black_color.color_r_cr = 0;
480
481         /* DCN1.0 has output CM before MPC which seems to screw with
482          * pre-multiplied alpha. This is a w/a hopefully unnecessary for DCN2.
483          */
484         blnd_cfg.pre_multiplied_alpha = per_pixel_alpha;
485
486         /*
487          * TODO: remove hack
488          * Note: currently there is a bug in init_hw such that
489          * on resume from hibernate, BIOS sets up MPCC0, and
490          * we do mpcc_remove but the mpcc cannot go to idle
491          * after remove. This cause us to pick mpcc1 here,
492          * which causes a pstate hang for yet unknown reason.
493          */
494         dpp_id = hubp->inst;
495         mpcc_id = dpp_id;
496
497         /* If there is no full update, don't need to touch MPC tree*/
498         if (!pipe_ctx->plane_state->update_flags.bits.full_update) {
499                 dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id);
500                 mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
501                 return;
502         }
503
504         /* check if this plane is being used by an MPCC in the secondary blending chain */
505         if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
506                 remove_mpcc = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
507
508         /* remove MPCC from secondary if being used */
509         if (remove_mpcc != NULL && mpc->funcs->remove_mpcc_from_secondary)
510                 mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, remove_mpcc);
511
512         /* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
513         remove_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
514         /* remove MPCC if being used */
515
516         if (remove_mpcc != NULL)
517                 mpc->funcs->remove_mpcc(mpc, mpc_tree_params, remove_mpcc);
518         else
519                 if (dc->debug.sanity_checks)
520                         mpc->funcs->assert_mpcc_idle_before_connect(
521                                         dc->res_pool->mpc, mpcc_id);
522
523         /* Call MPC to insert new plane */
524         dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id);
525         new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
526                         mpc_tree_params,
527                         &blnd_cfg,
528                         NULL,
529                         NULL,
530                         dpp_id,
531                         mpcc_id);
532
533         ASSERT(new_mpcc != NULL);
534         hubp->opp_id = pipe_ctx->stream_res.opp->inst;
535         hubp->mpcc_id = mpcc_id;
536 }
537
538 void dcn201_pipe_control_lock(
539         struct dc *dc,
540         struct pipe_ctx *pipe,
541         bool lock)
542 {
543         struct dce_hwseq *hws = dc->hwseq;
544         /* use TG master update lock to lock everything on the TG
545          * therefore only top pipe need to lock
546          */
547         if (pipe->top_pipe)
548                 return;
549
550         if (dc->debug.sanity_checks)
551                 hws->funcs.verify_allow_pstate_change_high(dc);
552
553         if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {
554                 if (lock)
555                         pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);
556                 else
557                         pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
558         } else {
559                 if (lock)
560                         pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
561                 else
562                         pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
563         }
564
565         if (dc->debug.sanity_checks)
566                 hws->funcs.verify_allow_pstate_change_high(dc);
567 }
568
569 void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
570 {
571         struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
572
573         gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq, &attributes->address);
574
575         pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
576                         pipe_ctx->plane_res.hubp, attributes);
577         pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes(
578                 pipe_ctx->plane_res.dpp, attributes);
579 }
580
581 void dcn201_set_dmdata_attributes(struct pipe_ctx *pipe_ctx)
582 {
583         struct dc_dmdata_attributes attr = { 0 };
584         struct hubp *hubp = pipe_ctx->plane_res.hubp;
585
586         gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq,
587                         &pipe_ctx->stream->dmdata_address);
588
589         attr.dmdata_mode = DMDATA_HW_MODE;
590         attr.dmdata_size =
591                 dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36;
592         attr.address.quad_part =
593                         pipe_ctx->stream->dmdata_address.quad_part;
594         attr.dmdata_dl_delta = 0;
595         attr.dmdata_qos_mode = 0;
596         attr.dmdata_qos_level = 0;
597         attr.dmdata_repeat = 1; /* always repeat */
598         attr.dmdata_updated = 1;
599         attr.dmdata_sw_data = NULL;
600
601         hubp->funcs->dmdata_set_attributes(hubp, &attr);
602 }
603
604 void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx,
605                 struct dc_link_settings *link_settings)
606 {
607         struct encoder_unblank_param params = { { 0 } };
608         struct dc_stream_state *stream = pipe_ctx->stream;
609         struct dc_link *link = stream->link;
610         struct dce_hwseq *hws = link->dc->hwseq;
611
612         /* only 3 items below are used by unblank */
613         params.timing = pipe_ctx->stream->timing;
614
615         params.link_settings.link_rate = link_settings->link_rate;
616
617         if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
618                 /*check whether it is half the rate*/
619                 if (optc201_is_two_pixels_per_containter(&stream->timing))
620                         params.timing.pix_clk_100hz /= 2;
621
622                 pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
623         }
624
625         if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
626                 hws->funcs.edp_backlight_control(link, true);
627         }
628 }