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