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