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, ¶ms); 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 } 629