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