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