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