1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2024 Advanced Micro Devices, Inc. 4 5 6 #include "os_types.h" 7 #include "dm_services.h" 8 #include "basics/dc_common.h" 9 #include "dm_helpers.h" 10 #include "core_types.h" 11 #include "resource.h" 12 #include "dccg.h" 13 #include "dce/dce_hwseq.h" 14 #include "reg_helper.h" 15 #include "abm.h" 16 #include "hubp.h" 17 #include "dchubbub.h" 18 #include "timing_generator.h" 19 #include "opp.h" 20 #include "ipp.h" 21 #include "mpc.h" 22 #include "mcif_wb.h" 23 #include "dc_dmub_srv.h" 24 #include "link_hwss.h" 25 #include "dpcd_defs.h" 26 #include "clk_mgr.h" 27 #include "dsc.h" 28 #include "link_service.h" 29 #include "custom_float.h" 30 31 #include "dce/dmub_hw_lock_mgr.h" 32 #include "dcn10/dcn10_cm_common.h" 33 #include "dcn10/dcn10_hubbub.h" 34 #include "dcn20/dcn20_optc.h" 35 #include "dcn30/dcn30_cm_common.h" 36 #include "dcn32/dcn32_hwseq.h" 37 #include "dcn401_hwseq.h" 38 #include "dcn401/dcn401_resource.h" 39 #include "dc_state_priv.h" 40 #include "link_enc_cfg.h" 41 #include "../hw_sequencer.h" 42 #include "dio/dcn10/dcn10_dio.h" 43 44 #define DC_LOGGER_INIT(logger) 45 46 #define CTX \ 47 hws->ctx 48 #define REG(reg)\ 49 hws->regs->reg 50 #define DC_LOGGER \ 51 dc->ctx->logger 52 53 54 #undef FN 55 #define FN(reg_name, field_name) \ 56 hws->shifts->field_name, hws->masks->field_name 57 58 void dcn401_initialize_min_clocks(struct dc *dc) 59 { 60 struct dc_clocks *clocks = &dc->current_state->bw_ctx.bw.dcn.clk; 61 62 clocks->dcfclk_deep_sleep_khz = DCN3_2_DCFCLK_DS_INIT_KHZ; 63 clocks->dcfclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz * 1000; 64 clocks->socclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].socclk_mhz * 1000; 65 clocks->dramclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].memclk_mhz * 1000; 66 clocks->dppclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dppclk_mhz * 1000; 67 if (dc->debug.disable_boot_optimizations) { 68 clocks->dispclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz * 1000; 69 } else { 70 /* Even though DPG_EN = 1 for the connected display, it still requires the 71 * correct timing so we cannot set DISPCLK to min freq or it could cause 72 * audio corruption. Read current DISPCLK from DENTIST and request the same 73 * freq to ensure that the timing is valid and unchanged. 74 */ 75 if (dc->clk_mgr->funcs->get_dispclk_from_dentist) { 76 clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr); 77 } else { 78 clocks->dispclk_khz = dc->clk_mgr->boot_snapshot.dispclk * 1000; 79 } 80 } 81 clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000; 82 clocks->fclk_p_state_change_support = true; 83 clocks->p_state_change_support = true; 84 85 dc->clk_mgr->funcs->update_clocks( 86 dc->clk_mgr, 87 dc->current_state, 88 true); 89 } 90 91 void dcn401_program_gamut_remap(struct pipe_ctx *pipe_ctx) 92 { 93 unsigned int i = 0; 94 struct mpc_grph_gamut_adjustment mpc_adjust; 95 unsigned int mpcc_id = pipe_ctx->plane_res.mpcc_inst; 96 struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; 97 98 // program MPCC_MCM_FIRST_GAMUT_REMAP 99 memset(&mpc_adjust, 0, sizeof(mpc_adjust)); 100 mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; 101 mpc_adjust.mpcc_gamut_remap_block_id = MPCC_MCM_FIRST_GAMUT_REMAP; 102 103 if (pipe_ctx->plane_state && 104 pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) { 105 mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; 106 for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) 107 mpc_adjust.temperature_matrix[i] = 108 pipe_ctx->plane_state->gamut_remap_matrix.matrix[i]; 109 } 110 111 mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust); 112 113 // program MPCC_MCM_SECOND_GAMUT_REMAP for Bypass / Disable for now 114 mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; 115 mpc_adjust.mpcc_gamut_remap_block_id = MPCC_MCM_SECOND_GAMUT_REMAP; 116 117 mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust); 118 119 // program MPCC_OGAM_GAMUT_REMAP same as is currently used on DCN3x 120 memset(&mpc_adjust, 0, sizeof(mpc_adjust)); 121 mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; 122 mpc_adjust.mpcc_gamut_remap_block_id = MPCC_OGAM_GAMUT_REMAP; 123 124 if (pipe_ctx->top_pipe == NULL) { 125 if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { 126 mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; 127 for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) 128 mpc_adjust.temperature_matrix[i] = 129 pipe_ctx->stream->gamut_remap_matrix.matrix[i]; 130 } 131 } 132 133 mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust); 134 } 135 136 void dcn401_init_hw(struct dc *dc) 137 { 138 struct abm **abms = dc->res_pool->multiple_abms; 139 struct dce_hwseq *hws = dc->hwseq; 140 struct dc_bios *dcb = dc->ctx->dc_bios; 141 struct resource_pool *res_pool = dc->res_pool; 142 int i; 143 unsigned int edp_num; 144 uint32_t backlight = MAX_BACKLIGHT_LEVEL; 145 uint32_t user_level = MAX_BACKLIGHT_LEVEL; 146 bool dchub_ref_freq_changed; 147 int current_dchub_ref_freq = 0; 148 149 if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) { 150 dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); 151 152 // mark dcmode limits present if any clock has distinct AC and DC values from SMU 153 dc->caps.dcmode_power_limits_present = dc->clk_mgr->funcs->is_dc_mode_present && 154 dc->clk_mgr->funcs->is_dc_mode_present(dc->clk_mgr); 155 } 156 157 // Initialize the dccg 158 if (res_pool->dccg->funcs->dccg_init) 159 res_pool->dccg->funcs->dccg_init(res_pool->dccg); 160 161 // Disable DMUB Initialization until IPS state programming is finalized 162 //if (!dcb->funcs->is_accelerated_mode(dcb)) { 163 // hws->funcs.bios_golden_init(dc); 164 //} 165 166 // Set default OPTC memory power states 167 if (dc->debug.enable_mem_low_power.bits.optc) { 168 // Shutdown when unassigned and light sleep in VBLANK 169 REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1); 170 } 171 172 if (dc->debug.enable_mem_low_power.bits.vga) { 173 // Power down VGA memory 174 REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); 175 } 176 177 if (dc->ctx->dc_bios->fw_info_valid) { 178 res_pool->ref_clocks.xtalin_clock_inKhz = 179 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; 180 181 if (res_pool->hubbub) { 182 (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, 183 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, 184 &res_pool->ref_clocks.dccg_ref_clock_inKhz); 185 186 current_dchub_ref_freq = res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000; 187 188 (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, 189 res_pool->ref_clocks.dccg_ref_clock_inKhz, 190 &res_pool->ref_clocks.dchub_ref_clock_inKhz); 191 } else { 192 // Not all ASICs have DCCG sw component 193 res_pool->ref_clocks.dccg_ref_clock_inKhz = 194 res_pool->ref_clocks.xtalin_clock_inKhz; 195 res_pool->ref_clocks.dchub_ref_clock_inKhz = 196 res_pool->ref_clocks.xtalin_clock_inKhz; 197 } 198 } else 199 ASSERT_CRITICAL(false); 200 201 for (i = 0; i < dc->link_count; i++) { 202 /* Power up AND update implementation according to the 203 * required signal (which may be different from the 204 * default signal on connector). 205 */ 206 struct dc_link *link = dc->links[i]; 207 208 if (link->ep_type != DISPLAY_ENDPOINT_PHY) 209 continue; 210 211 link->link_enc->funcs->hw_init(link->link_enc); 212 213 /* Check for enabled DIG to identify enabled display */ 214 if (link->link_enc->funcs->is_dig_enabled && 215 link->link_enc->funcs->is_dig_enabled(link->link_enc)) { 216 link->link_status.link_active = true; 217 link->phy_state.symclk_state = SYMCLK_ON_TX_ON; 218 if (link->link_enc->funcs->fec_is_active && 219 link->link_enc->funcs->fec_is_active(link->link_enc)) 220 link->fec_state = dc_link_fec_enabled; 221 } 222 } 223 224 /* enable_power_gating_plane before dsc_pg_control because 225 * FORCEON = 1 with hw default value on bootup, resume from s3 226 */ 227 if (hws->funcs.enable_power_gating_plane) 228 hws->funcs.enable_power_gating_plane(dc->hwseq, true); 229 230 /* we want to turn off all dp displays before doing detection */ 231 dc->link_srv->blank_all_dp_displays(dc); 232 233 /* If taking control over from VBIOS, we may want to optimize our first 234 * mode set, so we need to skip powering down pipes until we know which 235 * pipes we want to use. 236 * Otherwise, if taking control is not possible, we need to power 237 * everything down. 238 */ 239 if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { 240 /* Disable boot optimizations means power down everything including PHY, DIG, 241 * and OTG (i.e. the boot is not optimized because we do a full power down). 242 */ 243 if (dc->hwss.enable_accelerated_mode && dc->debug.disable_boot_optimizations) 244 dc->hwss.enable_accelerated_mode(dc, dc->current_state); 245 else 246 hws->funcs.init_pipes(dc, dc->current_state); 247 248 if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) 249 dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, 250 !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); 251 252 dcn401_initialize_min_clocks(dc); 253 254 /* On HW init, allow idle optimizations after pipes have been turned off. 255 * 256 * In certain D3 cases (i.e. BOCO / BOMACO) it's possible that hardware state 257 * is reset (i.e. not in idle at the time hw init is called), but software state 258 * still has idle_optimizations = true, so we must disable idle optimizations first 259 * (i.e. set false), then re-enable (set true). 260 */ 261 dc_allow_idle_optimizations(dc, false); 262 dc_allow_idle_optimizations(dc, true); 263 } 264 265 /* In headless boot cases, DIG may be turned 266 * on which causes HW/SW discrepancies. 267 * To avoid this, power down hardware on boot 268 * if DIG is turned on and seamless boot not enabled 269 */ 270 if (!dc->config.seamless_boot_edp_requested) { 271 struct dc_link *edp_links[MAX_NUM_EDP]; 272 struct dc_link *edp_link; 273 274 dc_get_edp_links(dc, edp_links, &edp_num); 275 if (edp_num) { 276 for (i = 0; i < edp_num; i++) { 277 edp_link = edp_links[i]; 278 if (edp_link->link_enc->funcs->is_dig_enabled && 279 edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && 280 dc->hwss.edp_backlight_control && 281 hws->funcs.power_down && 282 dc->hwss.edp_power_control) { 283 dc->hwss.edp_backlight_control(edp_link, false); 284 hws->funcs.power_down(dc); 285 dc->hwss.edp_power_control(edp_link, false); 286 } 287 } 288 } else { 289 for (i = 0; i < dc->link_count; i++) { 290 struct dc_link *link = dc->links[i]; 291 292 if (link->ep_type != DISPLAY_ENDPOINT_PHY) 293 continue; 294 if (link->link_enc->funcs->is_dig_enabled && 295 link->link_enc->funcs->is_dig_enabled(link->link_enc) && 296 hws->funcs.power_down) { 297 hws->funcs.power_down(dc); 298 break; 299 } 300 301 } 302 } 303 } 304 305 for (i = 0; i < res_pool->audio_count; i++) { 306 struct audio *audio = res_pool->audios[i]; 307 308 audio->funcs->hw_init(audio); 309 } 310 311 for (i = 0; i < dc->link_count; i++) { 312 struct dc_link *link = dc->links[i]; 313 314 if (link->panel_cntl) { 315 backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); 316 user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL; 317 } 318 } 319 320 for (i = 0; i < dc->res_pool->pipe_count; i++) { 321 if (abms[i] != NULL && abms[i]->funcs != NULL) 322 abms[i]->funcs->abm_init(abms[i], backlight, user_level); 323 } 324 325 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ 326 if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl) 327 dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false); 328 329 if (!dc->debug.disable_clock_gate) { 330 /* enable all DCN clock gating */ 331 if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->allow_clock_gating) 332 dc->res_pool->dccg->funcs->allow_clock_gating(dc->res_pool->dccg, true); 333 334 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); 335 } 336 337 dcn401_setup_hpo_hw_control(hws, true); 338 339 if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) 340 dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); 341 342 if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges) 343 dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); 344 345 if (dc->res_pool->hubbub->funcs->force_pstate_change_control) 346 dc->res_pool->hubbub->funcs->force_pstate_change_control( 347 dc->res_pool->hubbub, false, false); 348 349 if (dc->res_pool->hubbub->funcs->init_crb) 350 dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); 351 352 if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0) 353 dc->res_pool->hubbub->funcs->set_request_limit(dc->res_pool->hubbub, dc->ctx->dc_bios->vram_info.num_chans, dc->config.sdpif_request_limit_words_per_umc); 354 355 // Get DMCUB capabilities 356 if (dc->ctx->dmub_srv) { 357 dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv); 358 dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; 359 dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0; 360 dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver; 361 362 /* sw and fw FAMS versions must match for support */ 363 dc->debug.fams2_config.bits.enable &= 364 dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; 365 dchub_ref_freq_changed = 366 res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq; 367 if ((!dc->debug.fams2_config.bits.enable || dchub_ref_freq_changed) && 368 dc->res_pool->funcs->update_bw_bounding_box && 369 dc->clk_mgr && dc->clk_mgr->bw_params) { 370 /* update bounding box if FAMS2 disabled, or if dchub clk has changed */ 371 dc->res_pool->funcs->update_bw_bounding_box(dc, 372 dc->clk_mgr->bw_params); 373 } 374 } 375 } 376 377 void dcn401_trigger_3dlut_dma_load(struct dc *dc, struct pipe_ctx *pipe_ctx) 378 { 379 (void)dc; 380 struct hubp *hubp = pipe_ctx->plane_res.hubp; 381 382 if (hubp->funcs->hubp_enable_3dlut_fl) { 383 hubp->funcs->hubp_enable_3dlut_fl(hubp, true); 384 } 385 } 386 387 bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx, 388 const struct dc_plane_state *plane_state) 389 { 390 struct dc *dc = pipe_ctx->plane_res.hubp->ctx->dc; 391 struct dpp *dpp_base = pipe_ctx->plane_res.dpp; 392 struct hubp *hubp = pipe_ctx->plane_res.hubp; 393 const struct dc_plane_cm *cm = &plane_state->cm; 394 int mpcc_id = hubp->inst; 395 struct mpc *mpc = dc->res_pool->mpc; 396 union mcm_lut_params m_lut_params; 397 struct dc_3dlut_dma lut3d_dma; 398 bool lut_enable; 399 bool lut_bank_a; 400 bool rval; 401 bool result = true; 402 403 /* decide LUT bank based on current in use */ 404 mpc->funcs->get_lut_mode(mpc, MCM_LUT_1DLUT, mpcc_id, &lut_enable, &lut_bank_a); 405 if (!lut_enable) { 406 mpc->funcs->get_lut_mode(mpc, MCM_LUT_SHAPER, mpcc_id, &lut_enable, &lut_bank_a); 407 } 408 if (!lut_enable) { 409 mpc->funcs->get_lut_mode(mpc, MCM_LUT_3DLUT, mpcc_id, &lut_enable, &lut_bank_a); 410 } 411 412 /* switch to the next bank */ 413 if (lut_enable) { 414 lut_bank_a = !lut_bank_a; 415 } 416 417 /* MCM location fixed to pre-blend */ 418 mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id); 419 420 /* 1D LUT */ 421 lut_enable = cm->flags.bits.blend_enable; 422 memset(&m_lut_params, 0, sizeof(m_lut_params)); 423 if (lut_enable) { 424 if (cm->blend_func.type == TF_TYPE_HWPWL) 425 m_lut_params.pwl = &cm->blend_func.pwl; 426 else if (cm->blend_func.type == TF_TYPE_DISTRIBUTED_POINTS) { 427 rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, 428 &cm->blend_func, 429 &dpp_base->regamma_params, 430 false); 431 m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL; 432 } 433 434 if (!m_lut_params.pwl) { 435 lut_enable = false; 436 } 437 } else { 438 lut_enable = false; 439 } 440 441 if (mpc->funcs->program_lut_mode) 442 mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, lut_enable, lut_bank_a, CM_LUT_SIZE_NONE, mpcc_id); 443 if (lut_enable && mpc->funcs->populate_lut) 444 mpc->funcs->populate_lut(mpc, MCM_LUT_1DLUT, &m_lut_params, lut_bank_a, mpcc_id); 445 446 /* Shaper */ 447 lut_enable = cm->flags.bits.shaper_enable; 448 if (lut_enable) { 449 memset(&m_lut_params, 0, sizeof(m_lut_params)); 450 if (cm->shaper_func.type == TF_TYPE_HWPWL) 451 m_lut_params.pwl = &cm->shaper_func.pwl; 452 else if (cm->shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { 453 ASSERT(false); 454 rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, 455 &cm->shaper_func, 456 &dpp_base->shaper_params, 457 true); 458 m_lut_params.pwl = rval ? &dpp_base->shaper_params : NULL; 459 } 460 if (!m_lut_params.pwl) { 461 lut_enable = false; 462 } 463 } else { 464 lut_enable = false; 465 } 466 467 if (mpc->funcs->program_lut_mode) 468 mpc->funcs->program_lut_mode(mpc, MCM_LUT_SHAPER, lut_enable, lut_bank_a, CM_LUT_SIZE_NONE, mpcc_id); 469 if (lut_enable && mpc->funcs->populate_lut) 470 mpc->funcs->populate_lut(mpc, MCM_LUT_SHAPER, &m_lut_params, lut_bank_a, mpcc_id); 471 472 /* NOTE: Toggling from DMA->Host is not supported atomically as hardware 473 * blocks writes until 3DLUT FL mode is cleared from HUBP on VUpdate. 474 * Expectation is either option is used consistently. 475 */ 476 477 /* 3DLUT */ 478 lut_enable = cm->flags.bits.lut3d_enable; 479 if (lut_enable && cm->flags.bits.lut3d_dma_enable) { 480 /* Fast (DMA) Load Mode */ 481 /* MPC */ 482 if (mpc->funcs->program_lut_mode) 483 mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, lut_enable, lut_bank_a, cm->lut3d_dma.size, mpcc_id); 484 485 /* only supports 12 bit */ 486 if (mpc->funcs->program_lut_read_write_control) 487 mpc->funcs->program_lut_read_write_control(mpc, MCM_LUT_3DLUT, lut_bank_a, 12, mpcc_id); 488 489 if (mpc->funcs->update_3dlut_fast_load_select) 490 mpc->funcs->update_3dlut_fast_load_select(mpc, mpcc_id, hubp->inst); 491 492 /* HUBP */ 493 if (hubp->funcs->hubp_program_3dlut_fl_config) 494 hubp->funcs->hubp_program_3dlut_fl_config(hubp, &cm->lut3d_dma); 495 496 if (hubp->funcs->hubp_program_3dlut_fl_crossbar) 497 hubp->funcs->hubp_program_3dlut_fl_crossbar(hubp, cm->lut3d_dma.format); 498 499 if (hubp->funcs->hubp_program_3dlut_fl_addr) 500 hubp->funcs->hubp_program_3dlut_fl_addr(hubp, &cm->lut3d_dma.addr); 501 502 if (hubp->funcs->hubp_enable_3dlut_fl) { 503 hubp->funcs->hubp_enable_3dlut_fl(hubp, true); 504 } else { 505 /* GPU memory only supports fast load path */ 506 BREAK_TO_DEBUGGER(); 507 lut_enable = false; 508 result = false; 509 } 510 } else { 511 /* Legacy (Host) Load Mode */ 512 memset(&m_lut_params, 0, sizeof(m_lut_params)); 513 514 if (cm->flags.bits.lut3d_enable && cm->lut3d_func.state.bits.initialized) { 515 m_lut_params.lut3d = &cm->lut3d_func.lut_3d; 516 } else { 517 lut_enable = false; 518 } 519 520 /* MPC */ 521 if (mpc->funcs->program_lut_mode) 522 mpc->funcs->program_lut_mode(mpc, 523 MCM_LUT_3DLUT, 524 lut_enable, 525 lut_bank_a, 526 cm->lut3d_func.lut_3d.use_tetrahedral_9 ? CM_LUT_SIZE_999 : CM_LUT_SIZE_171717, 527 mpcc_id); 528 529 if (lut_enable) { 530 if (mpc->funcs->program_lut_read_write_control) 531 mpc->funcs->program_lut_read_write_control(mpc, 532 MCM_LUT_3DLUT, 533 lut_bank_a, 534 cm->lut3d_func.lut_3d.use_12bits ? 12 : 10, 535 mpcc_id); 536 537 if (mpc->funcs->update_3dlut_fast_load_select) 538 mpc->funcs->update_3dlut_fast_load_select(mpc, mpcc_id, 0xf); 539 540 if (mpc->funcs->populate_lut) 541 mpc->funcs->populate_lut(mpc, MCM_LUT_3DLUT, &m_lut_params, lut_bank_a, mpcc_id); 542 } 543 544 /* HUBP */ 545 memset(&lut3d_dma, 0, sizeof(lut3d_dma)); 546 if (hubp->funcs->hubp_program_3dlut_fl_config) 547 hubp->funcs->hubp_program_3dlut_fl_config(hubp, &lut3d_dma); 548 549 if (hubp->funcs->hubp_enable_3dlut_fl) 550 hubp->funcs->hubp_enable_3dlut_fl(hubp, false); 551 } 552 553 return result; 554 } 555 556 bool dcn401_set_output_transfer_func(struct dc *dc, 557 struct pipe_ctx *pipe_ctx, 558 const struct dc_stream_state *stream) 559 { 560 (void)dc; 561 int mpcc_id = pipe_ctx->plane_res.hubp->inst; 562 struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; 563 const struct pwl_params *params = NULL; 564 bool ret = false; 565 566 /* program OGAM or 3DLUT only for the top pipe*/ 567 if (resource_is_pipe_type(pipe_ctx, OPP_HEAD)) { 568 /*program shaper and 3dlut in MPC*/ 569 ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream); 570 if (ret == false && mpc->funcs->set_output_gamma) { 571 if (stream->out_transfer_func.type == TF_TYPE_HWPWL) 572 params = &stream->out_transfer_func.pwl; 573 else if (pipe_ctx->stream->out_transfer_func.type == 574 TF_TYPE_DISTRIBUTED_POINTS && 575 cm3_helper_translate_curve_to_hw_format(stream->ctx, 576 &stream->out_transfer_func, 577 &mpc->blender_params, false)) 578 params = &mpc->blender_params; 579 /* there are no ROM LUTs in OUTGAM */ 580 if (stream->out_transfer_func.type == TF_TYPE_PREDEFINED) 581 BREAK_TO_DEBUGGER(); 582 } 583 } 584 585 if (mpc->funcs->set_output_gamma) 586 mpc->funcs->set_output_gamma(mpc, mpcc_id, params); 587 588 return ret; 589 } 590 591 void dcn401_calculate_dccg_tmds_div_value(struct pipe_ctx *pipe_ctx, 592 unsigned int *tmds_div) 593 { 594 struct dc_stream_state *stream = pipe_ctx->stream; 595 596 if (dc_is_tmds_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) { 597 if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) 598 *tmds_div = PIXEL_RATE_DIV_BY_2; 599 else 600 *tmds_div = PIXEL_RATE_DIV_BY_4; 601 } else { 602 *tmds_div = PIXEL_RATE_DIV_BY_1; 603 } 604 605 if (*tmds_div == PIXEL_RATE_DIV_NA) 606 ASSERT(false); 607 608 } 609 610 static void enable_stream_timing_calc( 611 struct pipe_ctx *pipe_ctx, 612 struct dc_state *context, 613 struct dc *dc, 614 unsigned int *tmds_div, 615 int *opp_inst, 616 int *opp_cnt, 617 struct pipe_ctx *opp_heads[MAX_PIPES], 618 bool *manual_mode, 619 struct drr_params *params, 620 unsigned int *event_triggers) 621 { 622 (void)dc; 623 struct dc_stream_state *stream = pipe_ctx->stream; 624 int i; 625 626 if (dc_is_tmds_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) 627 dcn401_calculate_dccg_tmds_div_value(pipe_ctx, tmds_div); 628 629 *opp_cnt = resource_get_opp_heads_for_otg_master(pipe_ctx, &context->res_ctx, opp_heads); 630 for (i = 0; i < *opp_cnt; i++) 631 opp_inst[i] = opp_heads[i]->stream_res.opp->inst; 632 633 if (dc_is_tmds_signal(stream->signal)) { 634 stream->link->phy_state.symclk_ref_cnts.otg = 1; 635 if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) 636 stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; 637 else 638 stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON; 639 } 640 641 params->vertical_total_min = stream->adjust.v_total_min; 642 params->vertical_total_max = stream->adjust.v_total_max; 643 params->vertical_total_mid = stream->adjust.v_total_mid; 644 params->vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num; 645 646 // DRR should set trigger event to monitor surface update event 647 if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0) 648 *event_triggers = 0x80; 649 } 650 651 enum dc_status dcn401_enable_stream_timing( 652 struct pipe_ctx *pipe_ctx, 653 struct dc_state *context, 654 struct dc *dc) 655 { 656 struct dce_hwseq *hws = dc->hwseq; 657 struct dc_stream_state *stream = pipe_ctx->stream; 658 struct drr_params params = {0}; 659 unsigned int event_triggers = 0; 660 int opp_cnt = 1; 661 int opp_inst[MAX_PIPES] = {0}; 662 struct pipe_ctx *opp_heads[MAX_PIPES] = {0}; 663 struct dc_crtc_timing patched_crtc_timing = stream->timing; 664 bool manual_mode = false; 665 unsigned int tmds_div = PIXEL_RATE_DIV_NA; 666 unsigned int unused_div = PIXEL_RATE_DIV_NA; 667 int odm_slice_width; 668 int last_odm_slice_width; 669 int i; 670 671 if (!resource_is_pipe_type(pipe_ctx, OTG_MASTER)) 672 return DC_OK; 673 674 enable_stream_timing_calc(pipe_ctx, context, dc, &tmds_div, opp_inst, 675 &opp_cnt, opp_heads, &manual_mode, ¶ms, &event_triggers); 676 677 if (dc->res_pool->dccg->funcs->set_pixel_rate_div) { 678 dc->res_pool->dccg->funcs->set_pixel_rate_div( 679 dc->res_pool->dccg, pipe_ctx->stream_res.tg->inst, 680 tmds_div, unused_div); 681 } 682 683 /* TODO check if timing_changed, disable stream if timing changed */ 684 685 if (opp_cnt > 1) { 686 odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false); 687 last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true); 688 pipe_ctx->stream_res.tg->funcs->set_odm_combine( 689 pipe_ctx->stream_res.tg, 690 opp_inst, opp_cnt, 691 odm_slice_width, last_odm_slice_width); 692 } 693 694 /* set DTBCLK_P */ 695 if (dc->res_pool->dccg->funcs->set_dtbclk_p_src) { 696 if (dc_is_dp_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) { 697 dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, DPREFCLK, pipe_ctx->stream_res.tg->inst); 698 } 699 } 700 701 /* HW program guide assume display already disable 702 * by unplug sequence. OTG assume stop. 703 */ 704 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true); 705 706 if (false == pipe_ctx->clock_source->funcs->program_pix_clk( 707 pipe_ctx->clock_source, 708 &pipe_ctx->stream_res.pix_clk_params, 709 dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings), 710 &pipe_ctx->pll_settings)) { 711 BREAK_TO_DEBUGGER(); 712 return DC_ERROR_UNEXPECTED; 713 } 714 715 if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal))) 716 dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx); 717 718 /* if we are padding, h_addressable needs to be adjusted */ 719 if (dc->debug.enable_hblank_borrow) { 720 patched_crtc_timing.h_addressable = patched_crtc_timing.h_addressable + pipe_ctx->dsc_padding_params.dsc_hactive_padding; 721 patched_crtc_timing.h_total = patched_crtc_timing.h_total + pipe_ctx->dsc_padding_params.dsc_htotal_padding; 722 patched_crtc_timing.pix_clk_100hz = pipe_ctx->dsc_padding_params.dsc_pix_clk_100hz; 723 } 724 725 pipe_ctx->stream_res.tg->funcs->program_timing( 726 pipe_ctx->stream_res.tg, 727 &patched_crtc_timing, 728 (unsigned int)pipe_ctx->global_sync.dcn4x.vready_offset_pixels, 729 (unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines, 730 (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels, 731 (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels, 732 (unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines, 733 pipe_ctx->stream->signal, 734 true); 735 736 for (i = 0; i < opp_cnt; i++) { 737 opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control( 738 opp_heads[i]->stream_res.opp, 739 true); 740 opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel( 741 opp_heads[i]->stream_res.opp, 742 stream->timing.pixel_encoding, 743 resource_is_pipe_type(opp_heads[i], OTG_MASTER)); 744 } 745 746 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( 747 pipe_ctx->stream_res.opp, 748 true); 749 750 hws->funcs.blank_pixel_data(dc, pipe_ctx, true); 751 752 /* VTG is within DCHUB command block. DCFCLK is always on */ 753 if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { 754 BREAK_TO_DEBUGGER(); 755 return DC_ERROR_UNEXPECTED; 756 } 757 758 hws->funcs.wait_for_blank_complete(pipe_ctx->stream_res.opp); 759 set_drr_and_clear_adjust_pending(pipe_ctx, stream, ¶ms); 760 761 /* Event triggers and num frames initialized for DRR, but can be 762 * later updated for PSR use. Note DRR trigger events are generated 763 * regardless of whether num frames met. 764 */ 765 if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control) 766 pipe_ctx->stream_res.tg->funcs->set_static_screen_control( 767 pipe_ctx->stream_res.tg, event_triggers, 2); 768 769 /* TODO program crtc source select for non-virtual signal*/ 770 /* TODO program FMT */ 771 /* TODO setup link_enc */ 772 /* TODO set stream attributes */ 773 /* TODO program audio */ 774 /* TODO enable stream if timing changed */ 775 /* TODO unblank stream if DP */ 776 777 if (dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) { 778 if (pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable) 779 pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable(pipe_ctx->stream_res.tg); 780 } 781 782 return DC_OK; 783 } 784 785 static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link) 786 { 787 switch (link->link_enc->transmitter) { 788 case TRANSMITTER_UNIPHY_A: 789 return PHYD32CLKA; 790 case TRANSMITTER_UNIPHY_B: 791 return PHYD32CLKB; 792 case TRANSMITTER_UNIPHY_C: 793 return PHYD32CLKC; 794 case TRANSMITTER_UNIPHY_D: 795 return PHYD32CLKD; 796 case TRANSMITTER_UNIPHY_E: 797 return PHYD32CLKE; 798 default: 799 return PHYD32CLKA; 800 } 801 } 802 803 static void dcn401_enable_stream_calc( 804 struct pipe_ctx *pipe_ctx, 805 int *dp_hpo_inst, 806 enum phyd32clk_clock_source *phyd32clk, 807 unsigned int *tmds_div, 808 uint32_t *early_control) 809 { 810 811 struct dc *dc = pipe_ctx->stream->ctx->dc; 812 struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; 813 enum dc_lane_count lane_count = 814 pipe_ctx->stream->link->cur_link_settings.lane_count; 815 uint32_t active_total_with_borders; 816 817 if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { 818 *dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; 819 *phyd32clk = get_phyd32clk_src(pipe_ctx->stream->link); 820 } 821 822 if (dc_is_tmds_signal(pipe_ctx->stream->signal)) 823 dcn401_calculate_dccg_tmds_div_value(pipe_ctx, tmds_div); 824 else 825 *tmds_div = PIXEL_RATE_DIV_BY_1; 826 827 /* enable early control to avoid corruption on DP monitor*/ 828 active_total_with_borders = 829 timing->h_addressable 830 + timing->h_border_left 831 + timing->h_border_right; 832 833 if (lane_count != 0) 834 *early_control = active_total_with_borders % lane_count; 835 836 if (*early_control == 0) 837 *early_control = lane_count; 838 839 } 840 841 void dcn401_enable_stream(struct pipe_ctx *pipe_ctx) 842 { 843 uint32_t early_control = 0; 844 struct timing_generator *tg = pipe_ctx->stream_res.tg; 845 struct dc_link *link = pipe_ctx->stream->link; 846 const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); 847 struct dc *dc = pipe_ctx->stream->ctx->dc; 848 struct dccg *dccg = dc->res_pool->dccg; 849 enum phyd32clk_clock_source phyd32clk = PHYD32CLKA; 850 int dp_hpo_inst = 0; 851 unsigned int tmds_div = PIXEL_RATE_DIV_NA; 852 unsigned int unused_div = PIXEL_RATE_DIV_NA; 853 struct link_encoder *link_enc = pipe_ctx->link_res.dio_link_enc; 854 struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; 855 856 if (!dc->config.unify_link_enc_assignment) 857 link_enc = link_enc_cfg_get_link_enc(link); 858 859 dcn401_enable_stream_calc(pipe_ctx, &dp_hpo_inst, &phyd32clk, 860 &tmds_div, &early_control); 861 862 if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) { 863 if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { 864 dccg->funcs->set_dpstreamclk(dccg, DPREFCLK, tg->inst, dp_hpo_inst); 865 if (link->cur_link_settings.link_rate == LINK_RATE_UNKNOWN) { 866 dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst); 867 } else { 868 dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk); 869 } 870 } else { 871 dccg->funcs->enable_symclk_se(dccg, stream_enc->stream_enc_inst, 872 link_enc->transmitter - TRANSMITTER_UNIPHY_A); 873 } 874 } 875 876 link_hwss->setup_stream_attribute(pipe_ctx); 877 878 if (dc->res_pool->dccg->funcs->set_pixel_rate_div) { 879 dc->res_pool->dccg->funcs->set_pixel_rate_div( 880 dc->res_pool->dccg, 881 pipe_ctx->stream_res.tg->inst, 882 tmds_div, 883 unused_div); 884 } 885 886 link_hwss->setup_stream_encoder(pipe_ctx); 887 888 if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) { 889 if (dc->hwss.program_dmdata_engine) 890 dc->hwss.program_dmdata_engine(pipe_ctx); 891 } 892 893 dc->hwss.update_info_frame(pipe_ctx); 894 895 if (dc_is_dp_signal(pipe_ctx->stream->signal)) 896 dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME); 897 898 tg->funcs->set_early_control(tg, early_control); 899 } 900 901 void dcn401_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable) 902 { 903 REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, enable); 904 } 905 906 void adjust_hotspot_between_slices_for_2x_magnify(uint32_t cursor_width, struct dc_cursor_position *pos_cpy) 907 { 908 if (cursor_width <= 128) { 909 pos_cpy->x_hotspot /= 2; 910 pos_cpy->x_hotspot += 1; 911 } else { 912 pos_cpy->x_hotspot /= 2; 913 pos_cpy->x_hotspot += 2; 914 } 915 } 916 917 static void disable_link_output_symclk_on_tx_off(struct dc_link *link, enum dp_link_encoding link_encoding) 918 { 919 struct dc *dc = link->ctx->dc; 920 struct pipe_ctx *pipe_ctx = NULL; 921 uint8_t i; 922 923 for (i = 0; i < MAX_PIPES; i++) { 924 pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; 925 if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) { 926 pipe_ctx->clock_source->funcs->program_pix_clk( 927 pipe_ctx->clock_source, 928 &pipe_ctx->stream_res.pix_clk_params, 929 link_encoding, 930 &pipe_ctx->pll_settings); 931 break; 932 } 933 } 934 } 935 936 void dcn401_disable_link_output(struct dc_link *link, 937 const struct link_resource *link_res, 938 enum signal_type signal) 939 { 940 struct dc *dc = link->ctx->dc; 941 const struct link_hwss *link_hwss = get_link_hwss(link, link_res); 942 struct dmcu *dmcu = dc->res_pool->dmcu; 943 944 if (signal == SIGNAL_TYPE_EDP && 945 link->dc->hwss.edp_backlight_control && 946 !link->skip_implict_edp_power_control) 947 link->dc->hwss.edp_backlight_control(link, false); 948 else if (dmcu != NULL && dmcu->funcs->lock_phy) 949 dmcu->funcs->lock_phy(dmcu); 950 951 if (dc_is_tmds_signal(signal) && link->phy_state.symclk_ref_cnts.otg > 0) { 952 disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING); 953 link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; 954 } else { 955 link_hwss->disable_link_output(link, link_res, signal); 956 link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; 957 } 958 959 if (signal == SIGNAL_TYPE_EDP && 960 link->dc->hwss.edp_backlight_control && 961 !link->skip_implict_edp_power_control) 962 link->dc->hwss.edp_power_control(link, false); 963 else if (dmcu != NULL && dmcu->funcs->lock_phy) 964 dmcu->funcs->unlock_phy(dmcu); 965 966 dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); 967 } 968 969 void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx) 970 { 971 struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; 972 struct hubp *hubp = pipe_ctx->plane_res.hubp; 973 struct dpp *dpp = pipe_ctx->plane_res.dpp; 974 struct dc_cursor_mi_param param = { 975 .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10, 976 .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz, 977 .viewport = pipe_ctx->plane_res.scl_data.viewport, 978 .recout = pipe_ctx->plane_res.scl_data.recout, 979 .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, 980 .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, 981 .rotation = pipe_ctx->plane_state->rotation, 982 .mirror = pipe_ctx->plane_state->horizontal_mirror, 983 .stream = pipe_ctx->stream 984 }; 985 struct rect odm_slice_src = { 0 }; 986 bool odm_combine_on = (pipe_ctx->next_odm_pipe != NULL) || 987 (pipe_ctx->prev_odm_pipe != NULL); 988 int prev_odm_width = 0; 989 struct pipe_ctx *prev_odm_pipe = NULL; 990 bool mpc_combine_on = false; 991 int bottom_pipe_x_pos = 0; 992 993 int x_pos = pos_cpy.x; 994 int y_pos = pos_cpy.y; 995 int recout_x_pos = 0; 996 int recout_y_pos = 0; 997 998 if ((pipe_ctx->top_pipe != NULL) || (pipe_ctx->bottom_pipe != NULL)) { 999 if ((pipe_ctx->plane_state->src_rect.width != pipe_ctx->plane_res.scl_data.viewport.width) || 1000 (pipe_ctx->plane_state->src_rect.height != pipe_ctx->plane_res.scl_data.viewport.height)) { 1001 mpc_combine_on = true; 1002 } 1003 } 1004 1005 /* DCN4 moved cursor composition after Scaler, so in HW it is in 1006 * recout space and for HW Cursor position programming need to 1007 * translate to recout space. 1008 * 1009 * Cursor X and Y position programmed into HW can't be negative, 1010 * in fact it is X, Y coordinate shifted for the HW Cursor Hot spot 1011 * position that goes into HW X and Y coordinates while HW Hot spot 1012 * X and Y coordinates are length relative to the cursor top left 1013 * corner, hotspot must be smaller than the cursor size. 1014 * 1015 * DMs/DC interface for Cursor position is in stream->src space, and 1016 * DMs supposed to transform Cursor coordinates to stream->src space, 1017 * then here we need to translate Cursor coordinates to stream->dst 1018 * space, as now in HW, Cursor coordinates are in per pipe recout 1019 * space, and for the given pipe valid coordinates are only in range 1020 * from 0,0 - recout width, recout height space. 1021 * If certain pipe combining is in place, need to further adjust per 1022 * pipe to make sure each pipe enabling cursor on its part of the 1023 * screen. 1024 */ 1025 x_pos = pipe_ctx->stream->dst.x + x_pos * pipe_ctx->stream->dst.width / 1026 pipe_ctx->stream->src.width; 1027 y_pos = pipe_ctx->stream->dst.y + y_pos * pipe_ctx->stream->dst.height / 1028 pipe_ctx->stream->src.height; 1029 1030 /* If the cursor's source viewport is clipped then we need to 1031 * translate the cursor to appear in the correct position on 1032 * the screen. 1033 * 1034 * This translation isn't affected by scaling so it needs to be 1035 * done *after* we adjust the position for the scale factor. 1036 * 1037 * This is only done by opt-in for now since there are still 1038 * some usecases like tiled display that might enable the 1039 * cursor on both streams while expecting dc to clip it. 1040 */ 1041 if (pos_cpy.translate_by_source) { 1042 x_pos += pipe_ctx->plane_state->src_rect.x; 1043 y_pos += pipe_ctx->plane_state->src_rect.y; 1044 } 1045 1046 /* Adjust for ODM Combine 1047 * next/prev_odm_offset is to account for scaled modes that have underscan 1048 */ 1049 if (odm_combine_on) { 1050 prev_odm_pipe = pipe_ctx->prev_odm_pipe; 1051 1052 while (prev_odm_pipe != NULL) { 1053 odm_slice_src = resource_get_odm_slice_src_rect(prev_odm_pipe); 1054 prev_odm_width += odm_slice_src.width; 1055 prev_odm_pipe = prev_odm_pipe->prev_odm_pipe; 1056 } 1057 1058 x_pos -= (prev_odm_width); 1059 } 1060 1061 /* If the position is negative then we need to add to the hotspot 1062 * to fix cursor size between ODM slices 1063 */ 1064 1065 if (x_pos < 0) { 1066 pos_cpy.x_hotspot -= x_pos; 1067 if (hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION) 1068 adjust_hotspot_between_slices_for_2x_magnify(hubp->curs_attr.width, &pos_cpy); 1069 x_pos = 0; 1070 } 1071 1072 if (y_pos < 0) { 1073 pos_cpy.y_hotspot -= y_pos; 1074 y_pos = 0; 1075 } 1076 1077 /* If the position on bottom MPC pipe is negative then we need to add to the hotspot and 1078 * adjust x_pos on bottom pipe to make cursor visible when crossing between MPC slices. 1079 */ 1080 if (mpc_combine_on && 1081 pipe_ctx->top_pipe && 1082 (pipe_ctx == pipe_ctx->top_pipe->bottom_pipe)) { 1083 1084 bottom_pipe_x_pos = x_pos - pipe_ctx->plane_res.scl_data.recout.x; 1085 if (bottom_pipe_x_pos < 0) { 1086 x_pos = pipe_ctx->plane_res.scl_data.recout.x; 1087 pos_cpy.x_hotspot -= bottom_pipe_x_pos; 1088 if (hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION) 1089 adjust_hotspot_between_slices_for_2x_magnify(hubp->curs_attr.width, &pos_cpy); 1090 } 1091 } 1092 1093 pos_cpy.x = (uint32_t)x_pos; 1094 pos_cpy.y = (uint32_t)y_pos; 1095 1096 if (pos_cpy.enable && resource_can_pipe_disable_cursor(pipe_ctx)) 1097 pos_cpy.enable = false; 1098 1099 x_pos = pos_cpy.x - param.recout.x; 1100 y_pos = pos_cpy.y - param.recout.y; 1101 1102 /** 1103 * If the cursor position is negative after recout adjustment, we need 1104 * to shift the hotspot to compensate and clamp position to 0. This 1105 * handles the case where cursor straddles the left/top edge of an 1106 * overlay plane - the cursor is partially visible and needs correct 1107 * hotspot adjustment to render the visible portion. 1108 */ 1109 if (x_pos < 0) { 1110 pos_cpy.x_hotspot -= x_pos; 1111 if (hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION) 1112 adjust_hotspot_between_slices_for_2x_magnify(hubp->curs_attr.width, &pos_cpy); 1113 x_pos = 0; 1114 } 1115 1116 if (y_pos < 0) { 1117 pos_cpy.y_hotspot -= y_pos; 1118 y_pos = 0; 1119 } 1120 1121 recout_x_pos = x_pos - pos_cpy.x_hotspot; 1122 recout_y_pos = y_pos - pos_cpy.y_hotspot; 1123 1124 if (recout_x_pos >= (int)param.recout.width) 1125 pos_cpy.enable = false; /* not visible beyond right edge*/ 1126 1127 if (recout_y_pos >= (int)param.recout.height) 1128 pos_cpy.enable = false; /* not visible beyond bottom edge*/ 1129 1130 if (recout_x_pos + (int)hubp->curs_attr.width <= 0) 1131 pos_cpy.enable = false; /* not visible beyond left edge*/ 1132 1133 if (recout_y_pos + (int)hubp->curs_attr.height <= 0) 1134 pos_cpy.enable = false; /* not visible beyond top edge*/ 1135 1136 pos_cpy.x = x_pos; 1137 pos_cpy.y = y_pos; 1138 1139 hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); 1140 dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width, hubp->curs_attr.height); 1141 } 1142 1143 static bool dcn401_check_no_memory_request_for_cab(struct dc *dc) 1144 { 1145 int i; 1146 1147 /* First, check no-memory-request case */ 1148 for (i = 0; i < dc->current_state->stream_count; i++) { 1149 if ((dc->current_state->stream_status[i].plane_count) && 1150 (dc->current_state->streams[i]->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED)) 1151 /* Fail eligibility on a visible stream */ 1152 return false; 1153 } 1154 1155 return true; 1156 } 1157 1158 static uint32_t dcn401_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx) 1159 { 1160 int i; 1161 uint8_t num_ways = 0; 1162 uint32_t mall_ss_size_bytes = 0; 1163 1164 mall_ss_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_size_bytes; 1165 // TODO add additional logic for PSR active stream exclusion optimization 1166 // mall_ss_psr_active_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes; 1167 1168 // Include cursor size for CAB allocation 1169 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1170 struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[i]; 1171 1172 if (!pipe->stream || !pipe->plane_state) 1173 continue; 1174 1175 mall_ss_size_bytes += dcn32_helper_calculate_mall_bytes_for_cursor(dc, pipe, false); 1176 } 1177 1178 // Convert number of cache lines required to number of ways 1179 if (dc->debug.force_mall_ss_num_ways > 0) 1180 num_ways = dc->debug.force_mall_ss_num_ways; 1181 else if (dc->res_pool->funcs->calculate_mall_ways_from_bytes) 1182 num_ways = dc->res_pool->funcs->calculate_mall_ways_from_bytes(dc, mall_ss_size_bytes); 1183 else 1184 num_ways = 0; 1185 1186 return num_ways; 1187 } 1188 1189 bool dcn401_apply_idle_power_optimizations(struct dc *dc, bool enable) 1190 { 1191 union dmub_rb_cmd cmd; 1192 uint8_t ways, i; 1193 int j; 1194 bool mall_ss_unsupported = false; 1195 struct dc_plane_state *plane = NULL; 1196 1197 if (!dc->ctx->dmub_srv || !dc->current_state) 1198 return false; 1199 1200 for (i = 0; i < dc->current_state->stream_count; i++) { 1201 /* MALL SS messaging is not supported with PSR at this time */ 1202 if (dc->current_state->streams[i] != NULL && 1203 dc->current_state->streams[i]->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED) { 1204 DC_LOG_MALL("MALL SS not supported with PSR at this time\n"); 1205 return false; 1206 } 1207 } 1208 1209 memset(&cmd, 0, sizeof(cmd)); 1210 cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS; 1211 cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header); 1212 1213 if (enable) { 1214 if (dcn401_check_no_memory_request_for_cab(dc)) { 1215 /* 1. Check no memory request case for CAB. 1216 * If no memory request case, send CAB_ACTION NO_DCN_REQ DMUB message 1217 */ 1218 DC_LOG_MALL("sending CAB action NO_DCN_REQ\n"); 1219 cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_DCN_REQ; 1220 } else { 1221 /* 2. Check if all surfaces can fit in CAB. 1222 * If surfaces can fit into CAB, send CAB_ACTION_ALLOW DMUB message 1223 * and configure HUBP's to fetch from MALL 1224 */ 1225 ways = dcn401_calculate_cab_allocation(dc, dc->current_state); 1226 1227 /* MALL not supported with Stereo3D or TMZ surface. If any plane is using stereo, 1228 * or TMZ surface, don't try to enter MALL. 1229 */ 1230 for (i = 0; i < dc->current_state->stream_count; i++) { 1231 for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) { 1232 plane = dc->current_state->stream_status[i].plane_states[j]; 1233 1234 if (plane->address.type == PLN_ADDR_TYPE_GRPH_STEREO || 1235 plane->address.tmz_surface) { 1236 mall_ss_unsupported = true; 1237 break; 1238 } 1239 } 1240 if (mall_ss_unsupported) 1241 break; 1242 } 1243 if (ways <= dc->caps.cache_num_ways && !mall_ss_unsupported) { 1244 cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB; 1245 cmd.cab.cab_alloc_ways = ways; 1246 DC_LOG_MALL("cab allocation: %d ways. CAB action: DCN_SS_FIT_IN_CAB\n", ways); 1247 } else { 1248 cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_NOT_FIT_IN_CAB; 1249 DC_LOG_MALL("frame does not fit in CAB: %d ways required. CAB action: DCN_SS_NOT_FIT_IN_CAB\n", ways); 1250 } 1251 } 1252 } else { 1253 /* Disable CAB */ 1254 cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_IDLE_OPTIMIZATION; 1255 DC_LOG_MALL("idle optimization disabled\n"); 1256 } 1257 1258 dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 1259 1260 return true; 1261 } 1262 1263 void dcn401_wait_for_dcc_meta_propagation(const struct dc *dc, 1264 const struct pipe_ctx *top_pipe) 1265 { 1266 bool is_wait_needed = false; 1267 const struct pipe_ctx *pipe_ctx = top_pipe; 1268 1269 /* check if any surfaces are updating address while using flip immediate and dcc */ 1270 while (pipe_ctx != NULL) { 1271 if (pipe_ctx->plane_state && 1272 pipe_ctx->plane_state->dcc.enable && 1273 pipe_ctx->plane_state->flip_immediate && 1274 pipe_ctx->plane_state->update_flags.bits.addr_update) { 1275 is_wait_needed = true; 1276 break; 1277 } 1278 1279 /* check next pipe */ 1280 pipe_ctx = pipe_ctx->bottom_pipe; 1281 } 1282 1283 if (is_wait_needed && dc->debug.dcc_meta_propagation_delay_us > 0) { 1284 udelay(dc->debug.dcc_meta_propagation_delay_us); 1285 } 1286 } 1287 1288 void dcn401_prepare_bandwidth(struct dc *dc, 1289 struct dc_state *context) 1290 { 1291 struct hubbub *hubbub = dc->res_pool->hubbub; 1292 bool p_state_change_support = context->bw_ctx.bw.dcn.clk.p_state_change_support; 1293 unsigned int compbuf_size = 0; 1294 1295 /* Any transition into P-State support should disable MCLK switching first to avoid hangs */ 1296 if (p_state_change_support) { 1297 dc->optimized_required = true; 1298 context->bw_ctx.bw.dcn.clk.p_state_change_support = false; 1299 } 1300 1301 if (dc->clk_mgr->dc_mode_softmax_enabled) 1302 if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 && 1303 context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000) 1304 dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz); 1305 1306 /* Increase clocks */ 1307 dc->clk_mgr->funcs->update_clocks( 1308 dc->clk_mgr, 1309 context, 1310 false); 1311 1312 /* program dchubbub watermarks: 1313 * For assigning optimized_required, use |= operator since we don't want 1314 * to clear the value if the optimize has not happened yet 1315 */ 1316 dc->optimized_required |= hubbub->funcs->program_watermarks(hubbub, 1317 &context->bw_ctx.bw.dcn.watermarks, 1318 dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, 1319 false); 1320 /* update timeout thresholds */ 1321 if (hubbub->funcs->program_arbiter) { 1322 dc->optimized_required |= hubbub->funcs->program_arbiter(hubbub, &context->bw_ctx.bw.dcn.arb_regs, false); 1323 } 1324 1325 /* decrease compbuf size */ 1326 if (hubbub->funcs->program_compbuf_segments) { 1327 compbuf_size = context->bw_ctx.bw.dcn.arb_regs.compbuf_size; 1328 dc->optimized_required |= (compbuf_size != dc->current_state->bw_ctx.bw.dcn.arb_regs.compbuf_size); 1329 1330 hubbub->funcs->program_compbuf_segments(hubbub, compbuf_size, false); 1331 } 1332 1333 if (dc->debug.fams2_config.bits.enable) { 1334 dcn401_dmub_hw_control_lock(dc, context, true); 1335 dcn401_fams2_update_config(dc, context, false); 1336 dcn401_dmub_hw_control_lock(dc, context, false); 1337 } 1338 1339 if (p_state_change_support != context->bw_ctx.bw.dcn.clk.p_state_change_support) { 1340 /* After disabling P-State, restore the original value to ensure we get the correct P-State 1341 * on the next optimize. */ 1342 context->bw_ctx.bw.dcn.clk.p_state_change_support = p_state_change_support; 1343 } 1344 } 1345 1346 void dcn401_optimize_bandwidth( 1347 struct dc *dc, 1348 struct dc_state *context) 1349 { 1350 int i; 1351 struct hubbub *hubbub = dc->res_pool->hubbub; 1352 1353 /* enable fams2 if needed */ 1354 if (dc->debug.fams2_config.bits.enable) { 1355 dcn401_dmub_hw_control_lock(dc, context, true); 1356 dcn401_fams2_update_config(dc, context, true); 1357 dcn401_dmub_hw_control_lock(dc, context, false); 1358 } 1359 1360 /* program dchubbub watermarks */ 1361 hubbub->funcs->program_watermarks(hubbub, 1362 &context->bw_ctx.bw.dcn.watermarks, 1363 dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, 1364 true); 1365 /* update timeout thresholds */ 1366 if (hubbub->funcs->program_arbiter) { 1367 hubbub->funcs->program_arbiter(hubbub, &context->bw_ctx.bw.dcn.arb_regs, true); 1368 } 1369 1370 if (dc->clk_mgr->dc_mode_softmax_enabled) 1371 if (dc->clk_mgr->clks.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 && 1372 context->bw_ctx.bw.dcn.clk.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000) 1373 dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->dc_mode_softmax_memclk); 1374 1375 /* increase compbuf size */ 1376 if (hubbub->funcs->program_compbuf_segments) 1377 hubbub->funcs->program_compbuf_segments(hubbub, context->bw_ctx.bw.dcn.arb_regs.compbuf_size, true); 1378 1379 dc->clk_mgr->funcs->update_clocks( 1380 dc->clk_mgr, 1381 context, 1382 true); 1383 if (context->bw_ctx.bw.dcn.clk.zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW) { 1384 for (i = 0; i < dc->res_pool->pipe_count; ++i) { 1385 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1386 1387 if (pipe_ctx->stream && pipe_ctx->plane_res.hubp->funcs->program_extended_blank 1388 && pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max 1389 && pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total) 1390 pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp, 1391 pipe_ctx->hubp_regs.dlg_regs.min_dst_y_next_start); 1392 } 1393 } 1394 } 1395 1396 void dcn401_dmub_hw_control_lock(struct dc *dc, 1397 struct dc_state *context, 1398 bool lock) 1399 { 1400 (void)context; 1401 /* use always for now */ 1402 union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 }; 1403 1404 if (!dc->ctx || !dc->ctx->dmub_srv) 1405 return; 1406 1407 if (!dc->debug.fams2_config.bits.enable && !dc_dmub_srv_is_cursor_offload_enabled(dc)) 1408 return; 1409 1410 hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK; 1411 hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER; 1412 hw_lock_cmd.bits.lock = lock; 1413 hw_lock_cmd.bits.should_release = !lock; 1414 dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd); 1415 } 1416 1417 void dcn401_dmub_hw_control_lock_fast(union block_sequence_params *params) 1418 { 1419 struct dc *dc = params->dmub_hw_control_lock_fast_params.dc; 1420 bool lock = params->dmub_hw_control_lock_fast_params.lock; 1421 1422 if (params->dmub_hw_control_lock_fast_params.is_required) { 1423 union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 }; 1424 1425 hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK; 1426 hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER; 1427 hw_lock_cmd.bits.lock = lock; 1428 hw_lock_cmd.bits.should_release = !lock; 1429 dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd); 1430 } 1431 } 1432 1433 void dcn401_fams2_update_config(struct dc *dc, struct dc_state *context, bool enable) 1434 { 1435 bool fams2_info_required; 1436 1437 if (!dc->ctx || !dc->ctx->dmub_srv || !dc->debug.fams2_config.bits.enable) 1438 return; 1439 1440 fams2_info_required = context->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable; 1441 fams2_info_required |= context->bw_ctx.bw.dcn.fams2_global_config.features.bits.legacy_method_no_fams2; 1442 1443 dc_dmub_srv_fams2_update_config(dc, context, enable && fams2_info_required); 1444 } 1445 1446 static void update_dsc_for_odm_change(struct dc *dc, struct dc_state *context, 1447 struct pipe_ctx *otg_master) 1448 { 1449 int i; 1450 struct pipe_ctx *old_pipe; 1451 struct pipe_ctx *new_pipe; 1452 struct pipe_ctx *old_opp_heads[MAX_PIPES]; 1453 struct pipe_ctx *old_otg_master; 1454 int old_opp_head_count = 0; 1455 1456 old_otg_master = &dc->current_state->res_ctx.pipe_ctx[otg_master->pipe_idx]; 1457 1458 if (resource_is_pipe_type(old_otg_master, OTG_MASTER)) { 1459 old_opp_head_count = resource_get_opp_heads_for_otg_master(old_otg_master, 1460 &dc->current_state->res_ctx, 1461 old_opp_heads); 1462 } else { 1463 // DC cannot assume that the current state and the new state 1464 // share the same OTG pipe since this is not true when called 1465 // in the context of a commit stream not checked. Hence, set 1466 // old_otg_master to NULL to skip the DSC configuration. 1467 old_otg_master = NULL; 1468 } 1469 1470 1471 if (otg_master->stream_res.dsc) 1472 dcn32_update_dsc_on_stream(otg_master, 1473 otg_master->stream->timing.flags.DSC); 1474 if (old_otg_master && old_otg_master->stream_res.dsc) { 1475 for (i = 0; i < old_opp_head_count; i++) { 1476 old_pipe = old_opp_heads[i]; 1477 new_pipe = &context->res_ctx.pipe_ctx[old_pipe->pipe_idx]; 1478 if (old_pipe->stream_res.dsc && !new_pipe->stream_res.dsc) 1479 old_pipe->stream_res.dsc->funcs->dsc_disconnect( 1480 old_pipe->stream_res.dsc); 1481 } 1482 } 1483 } 1484 1485 void dcn401_update_odm(struct dc *dc, struct dc_state *context, 1486 struct pipe_ctx *otg_master) 1487 { 1488 struct pipe_ctx *opp_heads[MAX_PIPES]; 1489 int opp_inst[MAX_PIPES] = {0}; 1490 int opp_head_count; 1491 int odm_slice_width = resource_get_odm_slice_dst_width(otg_master, false); 1492 int last_odm_slice_width = resource_get_odm_slice_dst_width(otg_master, true); 1493 int i; 1494 1495 opp_head_count = resource_get_opp_heads_for_otg_master( 1496 otg_master, &context->res_ctx, opp_heads); 1497 1498 for (i = 0; i < opp_head_count; i++) 1499 opp_inst[i] = opp_heads[i]->stream_res.opp->inst; 1500 if (opp_head_count > 1) 1501 otg_master->stream_res.tg->funcs->set_odm_combine( 1502 otg_master->stream_res.tg, 1503 opp_inst, opp_head_count, 1504 odm_slice_width, last_odm_slice_width); 1505 else 1506 otg_master->stream_res.tg->funcs->set_odm_bypass( 1507 otg_master->stream_res.tg, 1508 &otg_master->stream->timing); 1509 1510 for (i = 0; i < opp_head_count; i++) { 1511 opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control( 1512 opp_heads[i]->stream_res.opp, 1513 true); 1514 opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel( 1515 opp_heads[i]->stream_res.opp, 1516 opp_heads[i]->stream->timing.pixel_encoding, 1517 resource_is_pipe_type(opp_heads[i], OTG_MASTER)); 1518 } 1519 1520 update_dsc_for_odm_change(dc, context, otg_master); 1521 1522 if (!resource_is_pipe_type(otg_master, DPP_PIPE)) 1523 /* 1524 * blank pattern is generated by OPP, reprogram blank pattern 1525 * due to OPP count change 1526 */ 1527 dc->hwseq->funcs.blank_pixel_data(dc, otg_master, true); 1528 } 1529 1530 static void dcn401_add_dsc_sequence_for_odm_change(struct dc *dc, struct dc_state *context, 1531 struct pipe_ctx *otg_master, struct block_sequence_state *seq_state) 1532 { 1533 struct pipe_ctx *old_pipe; 1534 struct pipe_ctx *new_pipe; 1535 struct pipe_ctx *old_opp_heads[MAX_PIPES]; 1536 struct pipe_ctx *old_otg_master; 1537 int old_opp_head_count = 0; 1538 int i; 1539 1540 old_otg_master = &dc->current_state->res_ctx.pipe_ctx[otg_master->pipe_idx]; 1541 1542 if (resource_is_pipe_type(old_otg_master, OTG_MASTER)) { 1543 old_opp_head_count = resource_get_opp_heads_for_otg_master(old_otg_master, 1544 &dc->current_state->res_ctx, 1545 old_opp_heads); 1546 } else { 1547 old_otg_master = NULL; 1548 } 1549 1550 /* Process new DSC configuration if DSC is enabled */ 1551 if (otg_master->stream_res.dsc && otg_master->stream->timing.flags.DSC) { 1552 struct dc_stream_state *stream = otg_master->stream; 1553 struct pipe_ctx *odm_pipe; 1554 int opp_cnt = 1; 1555 int last_dsc_calc = 0; 1556 bool should_use_dto_dscclk = (dc->res_pool->dccg->funcs->set_dto_dscclk != NULL) && 1557 stream->timing.pix_clk_100hz > 480000; 1558 1559 /* Count ODM pipes */ 1560 for (odm_pipe = otg_master->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) 1561 opp_cnt++; 1562 1563 int num_slices_h = stream->timing.dsc_cfg.num_slices_h / opp_cnt; 1564 1565 /* Step 1: Set DTO DSCCLK for main DSC if needed */ 1566 if (should_use_dto_dscclk) { 1567 hwss_add_dccg_set_dto_dscclk(seq_state, dc->res_pool->dccg, 1568 otg_master->stream_res.dsc->inst, num_slices_h); 1569 } 1570 1571 /* Step 2: Calculate and set DSC config for main DSC */ 1572 last_dsc_calc = *seq_state->num_steps; 1573 hwss_add_dsc_calculate_and_set_config(seq_state, otg_master, true, opp_cnt); 1574 1575 /* Step 3: Enable main DSC block */ 1576 hwss_add_dsc_enable_with_opp(seq_state, otg_master); 1577 1578 /* Step 4: Configure and enable ODM DSC blocks */ 1579 for (odm_pipe = otg_master->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { 1580 if (!odm_pipe->stream_res.dsc) 1581 continue; 1582 1583 /* Set DTO DSCCLK for ODM DSC if needed */ 1584 if (should_use_dto_dscclk) { 1585 hwss_add_dccg_set_dto_dscclk(seq_state, dc->res_pool->dccg, 1586 odm_pipe->stream_res.dsc->inst, num_slices_h); 1587 } 1588 1589 /* Calculate and set DSC config for ODM DSC */ 1590 last_dsc_calc = *seq_state->num_steps; 1591 hwss_add_dsc_calculate_and_set_config(seq_state, odm_pipe, true, opp_cnt); 1592 1593 /* Enable ODM DSC block */ 1594 hwss_add_dsc_enable_with_opp(seq_state, odm_pipe); 1595 } 1596 1597 /* Step 5: Configure DSC in timing generator */ 1598 hwss_add_tg_set_dsc_config(seq_state, otg_master->stream_res.tg, 1599 &seq_state->steps[last_dsc_calc].params.dsc_calculate_and_set_config_params.dsc_optc_cfg, true); 1600 } else if (otg_master->stream_res.dsc && !otg_master->stream->timing.flags.DSC) { 1601 /* Disable DSC in OPTC */ 1602 hwss_add_tg_set_dsc_config(seq_state, otg_master->stream_res.tg, NULL, false); 1603 1604 hwss_add_dsc_disconnect(seq_state, otg_master->stream_res.dsc); 1605 } 1606 1607 /* Disable DSC for old pipes that no longer need it */ 1608 if (old_otg_master && old_otg_master->stream_res.dsc) { 1609 for (i = 0; i < old_opp_head_count; i++) { 1610 old_pipe = old_opp_heads[i]; 1611 new_pipe = &context->res_ctx.pipe_ctx[old_pipe->pipe_idx]; 1612 1613 /* If old pipe had DSC but new pipe doesn't, disable the old DSC */ 1614 if (old_pipe->stream_res.dsc && !new_pipe->stream_res.dsc) { 1615 /* Then disconnect DSC block */ 1616 hwss_add_dsc_disconnect(seq_state, old_pipe->stream_res.dsc); 1617 } 1618 } 1619 } 1620 } 1621 1622 void dcn401_update_odm_sequence(struct dc *dc, struct dc_state *context, 1623 struct pipe_ctx *otg_master, struct block_sequence_state *seq_state) 1624 { 1625 struct pipe_ctx *opp_heads[MAX_PIPES]; 1626 int opp_inst[MAX_PIPES] = {0}; 1627 int opp_head_count; 1628 int odm_slice_width = resource_get_odm_slice_dst_width(otg_master, false); 1629 int last_odm_slice_width = resource_get_odm_slice_dst_width(otg_master, true); 1630 int i; 1631 1632 opp_head_count = resource_get_opp_heads_for_otg_master( 1633 otg_master, &context->res_ctx, opp_heads); 1634 1635 for (i = 0; i < opp_head_count; i++) 1636 opp_inst[i] = opp_heads[i]->stream_res.opp->inst; 1637 1638 /* Add ODM combine/bypass operation to sequence */ 1639 if (opp_head_count > 1) { 1640 hwss_add_optc_set_odm_combine(seq_state, otg_master->stream_res.tg, opp_inst, 1641 opp_head_count, odm_slice_width, last_odm_slice_width); 1642 } else { 1643 hwss_add_optc_set_odm_bypass(seq_state, otg_master->stream_res.tg, &otg_master->stream->timing); 1644 } 1645 1646 /* Add OPP operations to sequence */ 1647 for (i = 0; i < opp_head_count; i++) { 1648 /* Add OPP pipe clock control operation */ 1649 hwss_add_opp_pipe_clock_control(seq_state, opp_heads[i]->stream_res.opp, true); 1650 1651 /* Add OPP program left edge extra pixel operation */ 1652 hwss_add_opp_program_left_edge_extra_pixel(seq_state, opp_heads[i]->stream_res.opp, 1653 opp_heads[i]->stream->timing.pixel_encoding, resource_is_pipe_type(opp_heads[i], OTG_MASTER)); 1654 } 1655 1656 /* Add DSC update operations to sequence */ 1657 dcn401_add_dsc_sequence_for_odm_change(dc, context, otg_master, seq_state); 1658 1659 /* Add blank pixel data operation if needed */ 1660 if (!resource_is_pipe_type(otg_master, DPP_PIPE)) { 1661 if (dc->hwseq->funcs.blank_pixel_data_sequence) 1662 dc->hwseq->funcs.blank_pixel_data_sequence( 1663 dc, otg_master, true, seq_state); 1664 } 1665 } 1666 1667 void dcn401_unblank_stream(struct pipe_ctx *pipe_ctx, 1668 struct dc_link_settings *link_settings) 1669 { 1670 struct encoder_unblank_param params = {0}; 1671 struct dc_stream_state *stream = pipe_ctx->stream; 1672 struct dc_link *link = stream->link; 1673 struct dce_hwseq *hws = link->dc->hwseq; 1674 1675 /* calculate parameters for unblank */ 1676 params.opp_cnt = resource_get_odm_slice_count(pipe_ctx); 1677 1678 params.timing = pipe_ctx->stream->timing; 1679 params.link_settings.link_rate = link_settings->link_rate; 1680 params.pix_per_cycle = pipe_ctx->stream_res.pix_clk_params.dio_se_pix_per_cycle; 1681 1682 if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { 1683 pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank( 1684 pipe_ctx->stream_res.hpo_dp_stream_enc, 1685 pipe_ctx->stream_res.tg->inst); 1686 } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) { 1687 pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); 1688 } 1689 1690 if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) 1691 hws->funcs.edp_backlight_control(link, true); 1692 } 1693 1694 void dcn401_hardware_release(struct dc *dc) 1695 { 1696 if (!dc->debug.disable_force_pstate_allow_on_hw_release) { 1697 if (dc->ctx->dmub_srv && dc->debug.fams2_config.bits.enable) 1698 dc_dmub_srv_fams2_update_config(dc, dc->current_state, false); 1699 1700 /* If pstate unsupported, or still supported 1701 * by firmware, force it supported by dcn 1702 */ 1703 if (dc->current_state) { 1704 if ((!dc->clk_mgr->clks.p_state_change_support || 1705 dc->current_state->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable) && 1706 dc->res_pool->hubbub->funcs->force_pstate_change_control) 1707 dc->res_pool->hubbub->funcs->force_pstate_change_control( 1708 dc->res_pool->hubbub, true, true); 1709 1710 dc->current_state->bw_ctx.bw.dcn.clk.p_state_change_support = true; 1711 dc->clk_mgr->funcs->update_clocks(dc->clk_mgr, dc->current_state, true); 1712 } 1713 } else { 1714 if (dc->current_state) { 1715 dc->clk_mgr->clks.p_state_change_support = false; 1716 dc->clk_mgr->funcs->update_clocks(dc->clk_mgr, dc->current_state, true); 1717 } 1718 1719 if (dc->ctx->dmub_srv && dc->debug.fams2_config.bits.enable) 1720 dc_dmub_srv_fams2_update_config(dc, dc->current_state, false); 1721 } 1722 } 1723 1724 void dcn401_wait_for_det_buffer_update_under_otg_master(struct dc *dc, struct dc_state *context, struct pipe_ctx *otg_master) 1725 { 1726 struct pipe_ctx *opp_heads[MAX_PIPES]; 1727 struct pipe_ctx *dpp_pipes[MAX_PIPES]; 1728 struct hubbub *hubbub = dc->res_pool->hubbub; 1729 int dpp_count = 0; 1730 1731 if (!otg_master->stream) 1732 return; 1733 1734 int slice_count = resource_get_opp_heads_for_otg_master(otg_master, 1735 &context->res_ctx, opp_heads); 1736 1737 for (int slice_idx = 0; slice_idx < slice_count; slice_idx++) { 1738 if (opp_heads[slice_idx]->plane_state) { 1739 dpp_count = resource_get_dpp_pipes_for_opp_head( 1740 opp_heads[slice_idx], 1741 &context->res_ctx, 1742 dpp_pipes); 1743 for (int dpp_idx = 0; dpp_idx < dpp_count; dpp_idx++) { 1744 struct pipe_ctx *dpp_pipe = dpp_pipes[dpp_idx]; 1745 if (dpp_pipe && hubbub && 1746 dpp_pipe->plane_res.hubp && 1747 hubbub->funcs->wait_for_det_update) 1748 hubbub->funcs->wait_for_det_update(hubbub, dpp_pipe->plane_res.hubp->inst); 1749 } 1750 } else { 1751 if (hubbub && opp_heads[slice_idx]->plane_res.hubp && hubbub->funcs->wait_for_det_update) 1752 hubbub->funcs->wait_for_det_update(hubbub, opp_heads[slice_idx]->plane_res.hubp->inst); 1753 } 1754 } 1755 } 1756 1757 void dcn401_interdependent_update_lock(struct dc *dc, 1758 struct dc_state *context, bool lock) 1759 { 1760 unsigned int i = 0; 1761 struct pipe_ctx *pipe = NULL; 1762 struct timing_generator *tg = NULL; 1763 1764 if (lock) { 1765 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1766 pipe = &context->res_ctx.pipe_ctx[i]; 1767 tg = pipe->stream_res.tg; 1768 1769 if (!resource_is_pipe_type(pipe, OTG_MASTER) || 1770 !tg->funcs->is_tg_enabled(tg) || 1771 dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) 1772 continue; 1773 dc->hwss.pipe_control_lock(dc, pipe, true); 1774 } 1775 } else { 1776 /* Need to free DET being used first and have pipe update, then unlock the remaining pipes*/ 1777 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1778 pipe = &context->res_ctx.pipe_ctx[i]; 1779 tg = pipe->stream_res.tg; 1780 1781 if (!resource_is_pipe_type(pipe, OTG_MASTER) || 1782 !tg->funcs->is_tg_enabled(tg) || 1783 dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { 1784 continue; 1785 } 1786 1787 if (dc->scratch.pipes_to_unlock_first[i]) { 1788 struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; 1789 dc->hwss.pipe_control_lock(dc, pipe, false); 1790 /* Assumes pipe of the same index in current_state is also an OTG_MASTER pipe*/ 1791 dcn401_wait_for_det_buffer_update_under_otg_master(dc, dc->current_state, old_pipe); 1792 } 1793 } 1794 1795 /* Unlocking the rest of the pipes */ 1796 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1797 if (dc->scratch.pipes_to_unlock_first[i]) 1798 continue; 1799 1800 pipe = &context->res_ctx.pipe_ctx[i]; 1801 tg = pipe->stream_res.tg; 1802 if (!resource_is_pipe_type(pipe, OTG_MASTER) || 1803 !tg->funcs->is_tg_enabled(tg) || 1804 dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { 1805 continue; 1806 } 1807 1808 dc->hwss.pipe_control_lock(dc, pipe, false); 1809 } 1810 } 1811 } 1812 1813 void dcn401_perform_3dlut_wa_unlock(struct pipe_ctx *pipe_ctx) 1814 { 1815 /* If 3DLUT FL is enabled and 3DLUT is in use, follow the workaround sequence for pipe unlock to make sure that 1816 * HUBP will properly fetch 3DLUT contents after unlock. 1817 * 1818 * This is meant to work around a known HW issue where VREADY will cancel the pending 3DLUT_ENABLE signal regardless 1819 * of whether OTG lock is currently being held or not. 1820 */ 1821 struct pipe_ctx *wa_pipes[MAX_PIPES] = { NULL }; 1822 struct pipe_ctx *odm_pipe, *mpc_pipe; 1823 int i, wa_pipe_ct = 0; 1824 1825 for (odm_pipe = pipe_ctx; odm_pipe != NULL; odm_pipe = odm_pipe->next_odm_pipe) { 1826 for (mpc_pipe = odm_pipe; mpc_pipe != NULL; mpc_pipe = mpc_pipe->bottom_pipe) { 1827 if (mpc_pipe->plane_state && 1828 mpc_pipe->plane_state->cm.flags.bits.lut3d_enable && 1829 mpc_pipe->plane_state->cm.flags.bits.lut3d_dma_enable) { 1830 wa_pipes[wa_pipe_ct++] = mpc_pipe; 1831 } 1832 } 1833 } 1834 1835 if (wa_pipe_ct > 0) { 1836 if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout) 1837 pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, true); 1838 1839 for (i = 0; i < wa_pipe_ct; ++i) { 1840 if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl) 1841 wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true); 1842 } 1843 1844 pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg); 1845 if (pipe_ctx->stream_res.tg->funcs->wait_update_lock_status) 1846 pipe_ctx->stream_res.tg->funcs->wait_update_lock_status(pipe_ctx->stream_res.tg, false); 1847 1848 for (i = 0; i < wa_pipe_ct; ++i) { 1849 if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl) 1850 wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true); 1851 } 1852 1853 if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout) 1854 pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, false); 1855 } else { 1856 pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg); 1857 } 1858 } 1859 1860 void dcn401_program_outstanding_updates(struct dc *dc, 1861 struct dc_state *context) 1862 { 1863 struct hubbub *hubbub = dc->res_pool->hubbub; 1864 1865 /* update compbuf if required */ 1866 if (hubbub->funcs->program_compbuf_segments) 1867 hubbub->funcs->program_compbuf_segments(hubbub, context->bw_ctx.bw.dcn.arb_regs.compbuf_size, true); 1868 } 1869 1870 void dcn401_reset_back_end_for_pipe( 1871 struct dc *dc, 1872 struct pipe_ctx *pipe_ctx, 1873 struct dc_state *context) 1874 { 1875 (void)context; 1876 struct dc_link *link = pipe_ctx->stream->link; 1877 const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); 1878 1879 if (pipe_ctx->stream_res.stream_enc == NULL) { 1880 pipe_ctx->stream = NULL; 1881 return; 1882 } 1883 1884 /* DPMS may already disable or */ 1885 /* dpms_off status is incorrect due to fastboot 1886 * feature. When system resume from S4 with second 1887 * screen only, the dpms_off would be true but 1888 * VBIOS lit up eDP, so check link status too. 1889 */ 1890 if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) 1891 dc->link_srv->set_dpms_off(pipe_ctx); 1892 else if (pipe_ctx->stream_res.audio) 1893 dc->hwss.disable_audio_stream(pipe_ctx); 1894 1895 /* free acquired resources */ 1896 if (pipe_ctx->stream_res.audio) { 1897 /*disable az_endpoint*/ 1898 pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); 1899 1900 /*free audio*/ 1901 if (dc->caps.dynamic_audio == true) { 1902 /*we have to dynamic arbitrate the audio endpoints*/ 1903 /*we free the resource, need reset is_audio_acquired*/ 1904 update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, 1905 pipe_ctx->stream_res.audio, false); 1906 pipe_ctx->stream_res.audio = NULL; 1907 } 1908 } 1909 1910 /* by upper caller loop, parent pipe: pipe0, will be reset last. 1911 * back end share by all pipes and will be disable only when disable 1912 * parent pipe. 1913 */ 1914 if (pipe_ctx->top_pipe == NULL) { 1915 1916 dc->hwss.set_abm_immediate_disable(pipe_ctx); 1917 1918 pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); 1919 1920 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); 1921 if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) 1922 pipe_ctx->stream_res.tg->funcs->set_odm_bypass( 1923 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); 1924 1925 set_drr_and_clear_adjust_pending(pipe_ctx, pipe_ctx->stream, NULL); 1926 1927 /* TODO - convert symclk_ref_cnts for otg to a bit map to solve 1928 * the case where the same symclk is shared across multiple otg 1929 * instances 1930 */ 1931 if (dc_is_tmds_signal(pipe_ctx->stream->signal)) 1932 link->phy_state.symclk_ref_cnts.otg = 0; 1933 if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) { 1934 link_hwss->disable_link_output(link, 1935 &pipe_ctx->link_res, pipe_ctx->stream->signal); 1936 link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; 1937 } 1938 1939 /* reset DTBCLK_P */ 1940 if (dc->res_pool->dccg->funcs->set_dtbclk_p_src) 1941 dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, REFCLK, pipe_ctx->stream_res.tg->inst); 1942 } 1943 1944 /* 1945 * In case of a dangling plane, setting this to NULL unconditionally 1946 * causes failures during reset hw ctx where, if stream is NULL, 1947 * it is expected that the pipe_ctx pointers to pipes and plane are NULL. 1948 */ 1949 pipe_ctx->stream = NULL; 1950 pipe_ctx->top_pipe = NULL; 1951 pipe_ctx->bottom_pipe = NULL; 1952 pipe_ctx->next_odm_pipe = NULL; 1953 pipe_ctx->prev_odm_pipe = NULL; 1954 DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", 1955 pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); 1956 } 1957 static void dc_hwss_disable_otg_pwa(struct dc *dc) 1958 { 1959 if (dc->debug.enable_otg_frame_sync_pwa) { 1960 int i; 1961 1962 /*reset all the otg*/ 1963 for (i = dc->res_pool->timing_generator_count - 1; i >= 0 ; i--) { 1964 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 1965 1966 if (tg->funcs->disable_otg_pwa) { 1967 tg->funcs->disable_otg_pwa(tg); 1968 DC_LOG_DC("otg frame sync pwa disabled on otg%d\n", tg->inst); 1969 } 1970 } 1971 } 1972 } 1973 1974 void dcn401_reset_hw_ctx_wrap( 1975 struct dc *dc, 1976 struct dc_state *context) 1977 { 1978 int i; 1979 struct dce_hwseq *hws = dc->hwseq; 1980 1981 dc_hwss_disable_otg_pwa(dc); 1982 /* Reset Back End*/ 1983 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { 1984 struct pipe_ctx *pipe_ctx_old = 1985 &dc->current_state->res_ctx.pipe_ctx[i]; 1986 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1987 1988 if (!pipe_ctx_old->stream) 1989 continue; 1990 1991 if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) 1992 continue; 1993 1994 if (!pipe_ctx->stream || 1995 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { 1996 struct clock_source *old_clk = pipe_ctx_old->clock_source; 1997 1998 if (hws->funcs.reset_back_end_for_pipe) 1999 hws->funcs.reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); 2000 if (hws->funcs.enable_stream_gating) 2001 hws->funcs.enable_stream_gating(dc, pipe_ctx_old); 2002 if (old_clk) 2003 old_clk->funcs->cs_power_down(old_clk); 2004 } 2005 } 2006 } 2007 2008 static unsigned int dcn401_calculate_vready_offset_for_group(struct pipe_ctx *pipe) 2009 { 2010 struct pipe_ctx *other_pipe; 2011 unsigned int vready_offset = pipe->global_sync.dcn4x.vready_offset_pixels; 2012 2013 /* Always use the largest vready_offset of all connected pipes */ 2014 for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) { 2015 if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset) 2016 vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels; 2017 } 2018 for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) { 2019 if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset) 2020 vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels; 2021 } 2022 for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) { 2023 if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset) 2024 vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels; 2025 } 2026 for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) { 2027 if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset) 2028 vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels; 2029 } 2030 2031 return vready_offset; 2032 } 2033 2034 static void dcn401_program_tg( 2035 struct dc *dc, 2036 struct pipe_ctx *pipe_ctx, 2037 struct dc_state *context, 2038 struct dce_hwseq *hws) 2039 { 2040 pipe_ctx->stream_res.tg->funcs->program_global_sync( 2041 pipe_ctx->stream_res.tg, 2042 dcn401_calculate_vready_offset_for_group(pipe_ctx), 2043 (unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines, 2044 (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels, 2045 (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels, 2046 (unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines); 2047 2048 if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) 2049 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); 2050 2051 pipe_ctx->stream_res.tg->funcs->set_vtg_params( 2052 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true); 2053 2054 if (hws->funcs.setup_vupdate_interrupt) 2055 hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); 2056 } 2057 2058 void dcn401_program_pipe( 2059 struct dc *dc, 2060 struct pipe_ctx *pipe_ctx, 2061 struct dc_state *context) 2062 { 2063 struct dce_hwseq *hws = dc->hwseq; 2064 2065 /* Only need to unblank on top pipe */ 2066 if (resource_is_pipe_type(pipe_ctx, OTG_MASTER)) { 2067 if (pipe_ctx->update_flags.bits.enable || 2068 pipe_ctx->update_flags.bits.odm || 2069 pipe_ctx->stream->update_flags.bits.abm_level) 2070 hws->funcs.blank_pixel_data(dc, pipe_ctx, 2071 !pipe_ctx->plane_state || 2072 !pipe_ctx->plane_state->visible); 2073 } 2074 2075 /* Only update TG on top pipe */ 2076 if (pipe_ctx->update_flags.bits.global_sync && !pipe_ctx->top_pipe 2077 && !pipe_ctx->prev_odm_pipe) 2078 dcn401_program_tg(dc, pipe_ctx, context, hws); 2079 2080 if (pipe_ctx->update_flags.bits.odm) 2081 hws->funcs.update_odm(dc, context, pipe_ctx); 2082 2083 if (pipe_ctx->update_flags.bits.enable) { 2084 if (hws->funcs.enable_plane) 2085 hws->funcs.enable_plane(dc, pipe_ctx, context); 2086 else 2087 dc->hwss.enable_plane(dc, pipe_ctx, context); 2088 2089 if (dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes) 2090 dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes(dc->res_pool->hubbub); 2091 } 2092 2093 if (pipe_ctx->update_flags.bits.det_size) { 2094 if (dc->res_pool->hubbub->funcs->program_det_size) 2095 dc->res_pool->hubbub->funcs->program_det_size( 2096 dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb); 2097 if (dc->res_pool->hubbub->funcs->program_det_segments) 2098 dc->res_pool->hubbub->funcs->program_det_segments( 2099 dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->hubp_regs.det_size); 2100 } 2101 2102 if (pipe_ctx->plane_state && (pipe_ctx->update_flags.raw || 2103 pipe_ctx->plane_state->update_flags.raw || 2104 pipe_ctx->stream->update_flags.raw)) 2105 dc->hwss.update_dchubp_dpp(dc, pipe_ctx, context); 2106 2107 if (pipe_ctx->plane_state && (pipe_ctx->update_flags.bits.enable || 2108 pipe_ctx->plane_state->update_flags.bits.hdr_mult)) 2109 hws->funcs.set_hdr_multiplier(pipe_ctx); 2110 2111 if (pipe_ctx->plane_state && 2112 (pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || 2113 pipe_ctx->plane_state->update_flags.bits.gamma_change || 2114 pipe_ctx->plane_state->update_flags.bits.lut_3d || 2115 pipe_ctx->update_flags.bits.enable)) 2116 hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); 2117 2118 /* dcn10_translate_regamma_to_hw_format takes 750us to finish 2119 * only do gamma programming for powering on, internal memcmp to avoid 2120 * updating on slave planes 2121 */ 2122 if (pipe_ctx->update_flags.bits.enable || 2123 pipe_ctx->update_flags.bits.plane_changed || 2124 pipe_ctx->stream->update_flags.bits.out_tf) 2125 hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); 2126 2127 /* If the pipe has been enabled or has a different opp, we 2128 * should reprogram the fmt. This deals with cases where 2129 * interation between mpc and odm combine on different streams 2130 * causes a different pipe to be chosen to odm combine with. 2131 */ 2132 if (pipe_ctx->update_flags.bits.enable 2133 || pipe_ctx->update_flags.bits.opp_changed) { 2134 2135 pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion( 2136 pipe_ctx->stream_res.opp, 2137 COLOR_SPACE_YCBCR601, 2138 pipe_ctx->stream->timing.display_color_depth, 2139 pipe_ctx->stream->signal); 2140 2141 pipe_ctx->stream_res.opp->funcs->opp_program_fmt( 2142 pipe_ctx->stream_res.opp, 2143 &pipe_ctx->stream->bit_depth_params, 2144 &pipe_ctx->stream->clamping); 2145 } 2146 2147 /* Set ABM pipe after other pipe configurations done */ 2148 if ((pipe_ctx->plane_state && pipe_ctx->plane_state->visible)) { 2149 if (pipe_ctx->stream_res.abm) { 2150 dc->hwss.set_pipe(pipe_ctx); 2151 pipe_ctx->stream_res.abm->funcs->set_abm_level(pipe_ctx->stream_res.abm, 2152 pipe_ctx->stream->abm_level); 2153 } 2154 } 2155 2156 if (pipe_ctx->update_flags.bits.test_pattern_changed) { 2157 struct output_pixel_processor *odm_opp = pipe_ctx->stream_res.opp; 2158 struct bit_depth_reduction_params params; 2159 2160 memset(¶ms, 0, sizeof(params)); 2161 odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, ¶ms); 2162 dc->hwss.set_disp_pattern_generator(dc, 2163 pipe_ctx, 2164 pipe_ctx->stream_res.test_pattern_params.test_pattern, 2165 pipe_ctx->stream_res.test_pattern_params.color_space, 2166 pipe_ctx->stream_res.test_pattern_params.color_depth, 2167 NULL, 2168 pipe_ctx->stream_res.test_pattern_params.width, 2169 pipe_ctx->stream_res.test_pattern_params.height, 2170 pipe_ctx->stream_res.test_pattern_params.offset); 2171 } 2172 if (pipe_ctx->plane_state 2173 && pipe_ctx->plane_state->update_flags.bits.cm_hist_change 2174 && hws->funcs.program_cm_hist) 2175 hws->funcs.program_cm_hist(dc, pipe_ctx, pipe_ctx->plane_state); 2176 } 2177 2178 /* 2179 * dcn401_program_pipe_sequence - Sequence-based version of dcn401_program_pipe 2180 * 2181 * This function creates a sequence-based version of the original dcn401_program_pipe 2182 * function. Instead of directly calling hardware programming functions, it appends 2183 * sequence steps to the provided block_sequence array that can later be executed 2184 * as part of hwss_execute_sequence. 2185 * 2186 */ 2187 void dcn401_program_pipe_sequence( 2188 struct dc *dc, 2189 struct pipe_ctx *pipe_ctx, 2190 struct dc_state *context, 2191 struct block_sequence_state *seq_state) 2192 { 2193 struct dce_hwseq *hws = dc->hwseq; 2194 2195 /* Only need to unblank on top pipe */ 2196 if (resource_is_pipe_type(pipe_ctx, OTG_MASTER)) { 2197 if (pipe_ctx->update_flags.bits.enable || 2198 pipe_ctx->update_flags.bits.odm || 2199 pipe_ctx->stream->update_flags.bits.abm_level) { 2200 if (dc->hwseq->funcs.blank_pixel_data_sequence) 2201 dc->hwseq->funcs.blank_pixel_data_sequence(dc, pipe_ctx, 2202 !pipe_ctx->plane_state || !pipe_ctx->plane_state->visible, 2203 seq_state); 2204 } 2205 } 2206 2207 /* Only update TG on top pipe */ 2208 if (pipe_ctx->update_flags.bits.global_sync && !pipe_ctx->top_pipe 2209 && !pipe_ctx->prev_odm_pipe) { 2210 2211 /* Step 1: Program global sync */ 2212 hwss_add_tg_program_global_sync(seq_state, pipe_ctx->stream_res.tg, 2213 dcn401_calculate_vready_offset_for_group(pipe_ctx), 2214 (unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines, 2215 (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels, 2216 (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels, 2217 (unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines); 2218 2219 /* Step 2: Wait for VACTIVE state (if not phantom pipe) */ 2220 if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) 2221 hwss_add_tg_wait_for_state(seq_state, pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); 2222 2223 /* Step 3: Set VTG params */ 2224 hwss_add_tg_set_vtg_params(seq_state, pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true); 2225 2226 /* Step 4: Setup vupdate interrupt (if available) */ 2227 if (hws->funcs.setup_vupdate_interrupt) 2228 dcn401_setup_vupdate_interrupt_sequence(dc, pipe_ctx, seq_state); 2229 } 2230 2231 if (pipe_ctx->update_flags.bits.odm) { 2232 if (hws->funcs.update_odm_sequence) 2233 hws->funcs.update_odm_sequence(dc, context, pipe_ctx, seq_state); 2234 } 2235 2236 if (pipe_ctx->update_flags.bits.enable) { 2237 if (dc->hwss.enable_plane_sequence) 2238 dc->hwss.enable_plane_sequence(dc, pipe_ctx, context, seq_state); 2239 } 2240 2241 if (pipe_ctx->update_flags.bits.det_size) { 2242 if (dc->res_pool->hubbub->funcs->program_det_size) { 2243 hwss_add_hubp_program_det_size(seq_state, dc->res_pool->hubbub, 2244 pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb); 2245 } 2246 2247 if (dc->res_pool->hubbub->funcs->program_det_segments) { 2248 hwss_add_hubp_program_det_segments(seq_state, dc->res_pool->hubbub, 2249 pipe_ctx->plane_res.hubp->inst, pipe_ctx->hubp_regs.det_size); 2250 } 2251 } 2252 2253 if (pipe_ctx->plane_state && (pipe_ctx->update_flags.raw || 2254 pipe_ctx->plane_state->update_flags.raw || 2255 pipe_ctx->stream->update_flags.raw)) { 2256 2257 if (dc->hwss.update_dchubp_dpp_sequence) 2258 dc->hwss.update_dchubp_dpp_sequence(dc, pipe_ctx, context, seq_state); 2259 } 2260 2261 if (pipe_ctx->plane_state && (pipe_ctx->update_flags.bits.enable || 2262 pipe_ctx->plane_state->update_flags.bits.hdr_mult)) { 2263 2264 hws->funcs.set_hdr_multiplier_sequence(pipe_ctx, seq_state); 2265 } 2266 2267 if (pipe_ctx->plane_state && 2268 (pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || 2269 pipe_ctx->plane_state->update_flags.bits.gamma_change || 2270 pipe_ctx->plane_state->update_flags.bits.lut_3d || 2271 pipe_ctx->update_flags.bits.enable)) { 2272 2273 hwss_add_dpp_set_input_transfer_func(seq_state, dc, pipe_ctx, pipe_ctx->plane_state); 2274 } 2275 2276 /* dcn10_translate_regamma_to_hw_format takes 750us to finish 2277 * only do gamma programming for powering on, internal memcmp to avoid 2278 * updating on slave planes 2279 */ 2280 if (pipe_ctx->update_flags.bits.enable || 2281 pipe_ctx->update_flags.bits.plane_changed || 2282 pipe_ctx->stream->update_flags.bits.out_tf) { 2283 hwss_add_dpp_set_output_transfer_func(seq_state, dc, pipe_ctx, pipe_ctx->stream); 2284 } 2285 2286 /* If the pipe has been enabled or has a different opp, we 2287 * should reprogram the fmt. This deals with cases where 2288 * interation between mpc and odm combine on different streams 2289 * causes a different pipe to be chosen to odm combine with. 2290 */ 2291 if (pipe_ctx->update_flags.bits.enable 2292 || pipe_ctx->update_flags.bits.opp_changed) { 2293 2294 hwss_add_opp_set_dyn_expansion(seq_state, pipe_ctx->stream_res.opp, COLOR_SPACE_YCBCR601, 2295 pipe_ctx->stream->timing.display_color_depth, pipe_ctx->stream->signal); 2296 2297 hwss_add_opp_program_fmt(seq_state, pipe_ctx->stream_res.opp, 2298 &pipe_ctx->stream->bit_depth_params, &pipe_ctx->stream->clamping); 2299 } 2300 2301 /* Set ABM pipe after other pipe configurations done */ 2302 if ((pipe_ctx->plane_state && pipe_ctx->plane_state->visible)) { 2303 if (pipe_ctx->stream_res.abm) { 2304 hwss_add_abm_set_pipe(seq_state, dc, pipe_ctx); 2305 2306 hwss_add_abm_set_level(seq_state, pipe_ctx->stream_res.abm, pipe_ctx->stream->abm_level); 2307 } 2308 } 2309 2310 if (pipe_ctx->update_flags.bits.test_pattern_changed) { 2311 struct output_pixel_processor *odm_opp = pipe_ctx->stream_res.opp; 2312 2313 hwss_add_opp_program_bit_depth_reduction(seq_state, odm_opp, true, pipe_ctx); 2314 2315 hwss_add_opp_set_disp_pattern_generator(seq_state, 2316 odm_opp, 2317 pipe_ctx->stream_res.test_pattern_params.test_pattern, 2318 pipe_ctx->stream_res.test_pattern_params.color_space, 2319 pipe_ctx->stream_res.test_pattern_params.color_depth, 2320 (struct tg_color){0}, 2321 false, 2322 pipe_ctx->stream_res.test_pattern_params.width, 2323 pipe_ctx->stream_res.test_pattern_params.height, 2324 pipe_ctx->stream_res.test_pattern_params.offset); 2325 } 2326 2327 if (pipe_ctx->plane_state 2328 && pipe_ctx->plane_state->update_flags.bits.cm_hist_change 2329 && hws->funcs.program_cm_hist) { 2330 2331 hwss_add_dpp_program_cm_hist(seq_state, pipe_ctx->plane_res.dpp, 2332 pipe_ctx->plane_state->cm_hist_control, pipe_ctx->plane_state->color_space); 2333 } 2334 } 2335 2336 void dcn401_program_front_end_for_ctx( 2337 struct dc *dc, 2338 struct dc_state *context) 2339 { 2340 int i; 2341 unsigned int prev_hubp_count = 0; 2342 unsigned int hubp_count = 0; 2343 struct dce_hwseq *hws = dc->hwseq; 2344 struct pipe_ctx *pipe = NULL; 2345 2346 if (resource_is_pipe_topology_changed(dc->current_state, context)) 2347 resource_log_pipe_topology_update(dc, context); 2348 2349 if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) { 2350 for (i = 0; i < dc->res_pool->pipe_count; i++) { 2351 pipe = &context->res_ctx.pipe_ctx[i]; 2352 2353 if (pipe->plane_state) { 2354 if (pipe->plane_state->triplebuffer_flips) 2355 BREAK_TO_DEBUGGER(); 2356 2357 /*turn off triple buffer for full update*/ 2358 dc->hwss.program_triplebuffer( 2359 dc, pipe, pipe->plane_state->triplebuffer_flips); 2360 } 2361 } 2362 } 2363 2364 for (i = 0; i < dc->res_pool->pipe_count; i++) { 2365 if (dc->current_state->res_ctx.pipe_ctx[i].plane_state) 2366 prev_hubp_count++; 2367 if (context->res_ctx.pipe_ctx[i].plane_state) 2368 hubp_count++; 2369 } 2370 2371 if (prev_hubp_count == 0 && hubp_count > 0) { 2372 if (dc->res_pool->hubbub->funcs->force_pstate_change_control) 2373 dc->res_pool->hubbub->funcs->force_pstate_change_control( 2374 dc->res_pool->hubbub, true, false); 2375 udelay(500); 2376 } 2377 2378 /* Set pipe update flags and lock pipes */ 2379 for (i = 0; i < dc->res_pool->pipe_count; i++) 2380 dc->hwss.detect_pipe_changes(dc->current_state, context, &dc->current_state->res_ctx.pipe_ctx[i], 2381 &context->res_ctx.pipe_ctx[i]); 2382 2383 /* When disabling phantom pipes, turn on phantom OTG first (so we can get double 2384 * buffer updates properly) 2385 */ 2386 for (i = 0; i < dc->res_pool->pipe_count; i++) { 2387 struct dc_stream_state *stream = dc->current_state->res_ctx.pipe_ctx[i].stream; 2388 2389 pipe = &dc->current_state->res_ctx.pipe_ctx[i]; 2390 2391 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && stream && 2392 dc_state_get_pipe_subvp_type(dc->current_state, pipe) == SUBVP_PHANTOM) { 2393 struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg; 2394 2395 if (tg->funcs->enable_crtc) { 2396 if (dc->hwseq->funcs.blank_pixel_data) 2397 dc->hwseq->funcs.blank_pixel_data(dc, pipe, true); 2398 2399 tg->funcs->enable_crtc(tg); 2400 } 2401 } 2402 } 2403 /* OTG blank before disabling all front ends */ 2404 for (i = 0; i < dc->res_pool->pipe_count; i++) 2405 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable 2406 && !context->res_ctx.pipe_ctx[i].top_pipe 2407 && !context->res_ctx.pipe_ctx[i].prev_odm_pipe 2408 && context->res_ctx.pipe_ctx[i].stream) 2409 hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true); 2410 2411 /* Disconnect mpcc */ 2412 for (i = 0; i < dc->res_pool->pipe_count; i++) 2413 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable 2414 || context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) { 2415 struct hubbub *hubbub = dc->res_pool->hubbub; 2416 2417 /* Phantom pipe DET should be 0, but if a pipe in use is being transitioned to phantom 2418 * then we want to do the programming here (effectively it's being disabled). If we do 2419 * the programming later the DET won't be updated until the OTG for the phantom pipe is 2420 * turned on (i.e. in an MCLK switch) which can come in too late and cause issues with 2421 * DET allocation. 2422 */ 2423 if ((context->res_ctx.pipe_ctx[i].update_flags.bits.disable || 2424 (context->res_ctx.pipe_ctx[i].plane_state && 2425 dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[i]) == 2426 SUBVP_PHANTOM))) { 2427 if (hubbub->funcs->program_det_size) 2428 hubbub->funcs->program_det_size(hubbub, 2429 dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0); 2430 if (dc->res_pool->hubbub->funcs->program_det_segments) 2431 dc->res_pool->hubbub->funcs->program_det_segments( 2432 hubbub, dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0); 2433 } 2434 hws->funcs.plane_atomic_disconnect(dc, dc->current_state, 2435 &dc->current_state->res_ctx.pipe_ctx[i]); 2436 DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx); 2437 } 2438 2439 /* update ODM for blanked OTG master pipes */ 2440 for (i = 0; i < dc->res_pool->pipe_count; i++) { 2441 pipe = &context->res_ctx.pipe_ctx[i]; 2442 if (resource_is_pipe_type(pipe, OTG_MASTER) && 2443 !resource_is_pipe_type(pipe, DPP_PIPE) && 2444 pipe->update_flags.bits.odm && 2445 hws->funcs.update_odm) 2446 hws->funcs.update_odm(dc, context, pipe); 2447 } 2448 2449 /* 2450 * Program all updated pipes, order matters for mpcc setup. Start with 2451 * top pipe and program all pipes that follow in order 2452 */ 2453 for (i = 0; i < dc->res_pool->pipe_count; i++) { 2454 pipe = &context->res_ctx.pipe_ctx[i]; 2455 2456 if (pipe->plane_state && !pipe->top_pipe) { 2457 while (pipe) { 2458 if (hws->funcs.program_pipe) 2459 hws->funcs.program_pipe(dc, pipe, context); 2460 else { 2461 /* Don't program phantom pipes in the regular front end programming sequence. 2462 * There is an MPO transition case where a pipe being used by a video plane is 2463 * transitioned directly to be a phantom pipe when closing the MPO video. 2464 * However the phantom pipe will program a new HUBP_VTG_SEL (update takes place 2465 * right away) but the MPO still exists until the double buffered update of the 2466 * main pipe so we will get a frame of underflow if the phantom pipe is 2467 * programmed here. 2468 */ 2469 if (pipe->stream && 2470 dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) 2471 dcn401_program_pipe(dc, pipe, context); 2472 } 2473 2474 pipe = pipe->bottom_pipe; 2475 } 2476 } 2477 2478 /* Program secondary blending tree and writeback pipes */ 2479 pipe = &context->res_ctx.pipe_ctx[i]; 2480 if (!pipe->top_pipe && !pipe->prev_odm_pipe 2481 && pipe->stream && pipe->stream->num_wb_info > 0 2482 && (pipe->update_flags.raw || (pipe->plane_state && pipe->plane_state->update_flags.raw) 2483 || pipe->stream->update_flags.raw) 2484 && hws->funcs.program_all_writeback_pipes_in_tree) 2485 hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context); 2486 2487 /* Avoid underflow by check of pipe line read when adding 2nd plane. */ 2488 if (hws->wa.wait_hubpret_read_start_during_mpo_transition && 2489 !pipe->top_pipe && 2490 pipe->stream && 2491 pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start && 2492 dc->current_state->stream_status[0].plane_count == 1 && 2493 context->stream_status[0].plane_count > 1) { 2494 pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp); 2495 } 2496 } 2497 } 2498 2499 void dcn401_post_unlock_program_front_end( 2500 struct dc *dc, 2501 struct dc_state *context) 2502 { 2503 // Timeout for pipe enable 2504 unsigned int timeout_us = 100000; 2505 unsigned int polling_interval_us = 1; 2506 struct dce_hwseq *hwseq = dc->hwseq; 2507 int i; 2508 2509 for (i = 0; i < dc->res_pool->pipe_count; i++) 2510 if (resource_is_pipe_type(&dc->current_state->res_ctx.pipe_ctx[i], OPP_HEAD) && 2511 !resource_is_pipe_type(&context->res_ctx.pipe_ctx[i], OPP_HEAD)) 2512 dc->hwss.post_unlock_reset_opp(dc, 2513 &dc->current_state->res_ctx.pipe_ctx[i]); 2514 2515 for (i = 0; i < dc->res_pool->pipe_count; i++) 2516 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) 2517 dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]); 2518 2519 /* 2520 * If we are enabling a pipe, we need to wait for pending clear as this is a critical 2521 * part of the enable operation otherwise, DM may request an immediate flip which 2522 * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which 2523 * is unsupported on DCN. 2524 */ 2525 for (i = 0; i < dc->res_pool->pipe_count; i++) { 2526 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 2527 // Don't check flip pending on phantom pipes 2528 if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable && 2529 dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) { 2530 struct hubp *hubp = pipe->plane_res.hubp; 2531 int j = 0; 2532 2533 for (j = 0; j < timeout_us / polling_interval_us 2534 && hubp->funcs->hubp_is_flip_pending(hubp); j++) 2535 udelay(polling_interval_us); 2536 } 2537 } 2538 2539 for (i = 0; i < dc->res_pool->pipe_count; i++) { 2540 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 2541 struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; 2542 2543 /* When going from a smaller ODM slice count to larger, we must ensure double 2544 * buffer update completes before we return to ensure we don't reduce DISPCLK 2545 * before we've transitioned to 2:1 or 4:1 2546 */ 2547 if (resource_is_pipe_type(old_pipe, OTG_MASTER) && resource_is_pipe_type(pipe, OTG_MASTER) && 2548 resource_get_odm_slice_count(old_pipe) < resource_get_odm_slice_count(pipe) && 2549 dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) { 2550 int j = 0; 2551 struct timing_generator *tg = pipe->stream_res.tg; 2552 2553 if (tg->funcs->get_optc_double_buffer_pending) { 2554 for (j = 0; j < timeout_us / polling_interval_us 2555 && tg->funcs->get_optc_double_buffer_pending(tg); j++) 2556 udelay(polling_interval_us); 2557 } 2558 } 2559 } 2560 2561 if (dc->res_pool->hubbub->funcs->force_pstate_change_control) 2562 dc->res_pool->hubbub->funcs->force_pstate_change_control( 2563 dc->res_pool->hubbub, false, false); 2564 2565 2566 for (i = 0; i < dc->res_pool->pipe_count; i++) { 2567 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 2568 2569 if (pipe->plane_state && !pipe->top_pipe) { 2570 /* Program phantom pipe here to prevent a frame of underflow in the MPO transition 2571 * case (if a pipe being used for a video plane transitions to a phantom pipe, it 2572 * can underflow due to HUBP_VTG_SEL programming if done in the regular front end 2573 * programming sequence). 2574 */ 2575 while (pipe) { 2576 if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { 2577 /* When turning on the phantom pipe we want to run through the 2578 * entire enable sequence, so apply all the "enable" flags. 2579 */ 2580 if (dc->hwss.apply_update_flags_for_phantom) 2581 dc->hwss.apply_update_flags_for_phantom(pipe); 2582 if (dc->hwss.update_phantom_vp_position) 2583 dc->hwss.update_phantom_vp_position(dc, context, pipe); 2584 dcn401_program_pipe(dc, pipe, context); 2585 } 2586 pipe = pipe->bottom_pipe; 2587 } 2588 } 2589 } 2590 2591 if (!hwseq) 2592 return; 2593 2594 /* P-State support transitions: 2595 * Natural -> FPO: P-State disabled in prepare, force disallow anytime is safe 2596 * FPO -> Natural: Unforce anytime after FW disable is safe (P-State will assert naturally) 2597 * Unsupported -> FPO: P-State enabled in optimize, force disallow anytime is safe 2598 * FPO -> Unsupported: P-State disabled in prepare, unforce disallow anytime is safe 2599 * FPO <-> SubVP: Force disallow is maintained on the FPO / SubVP pipes 2600 */ 2601 if (hwseq->funcs.update_force_pstate) 2602 dc->hwseq->funcs.update_force_pstate(dc, context); 2603 /* Only program the MALL registers after all the main and phantom pipes 2604 * are done programming. 2605 */ 2606 if (hwseq->funcs.program_mall_pipe_config) 2607 hwseq->funcs.program_mall_pipe_config(dc, context); 2608 2609 /* WA to apply WM setting*/ 2610 if (hwseq->wa.DEGVIDCN21) 2611 dc->res_pool->hubbub->funcs->apply_DEDCN21_147_wa(dc->res_pool->hubbub); 2612 2613 2614 /* WA for stutter underflow during MPO transitions when adding 2nd plane */ 2615 if (hwseq->wa.disallow_self_refresh_during_multi_plane_transition) { 2616 2617 if (dc->current_state->stream_status[0].plane_count == 1 && 2618 context->stream_status[0].plane_count > 1) { 2619 2620 struct timing_generator *tg = dc->res_pool->timing_generators[0]; 2621 2622 dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, false); 2623 2624 hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = true; 2625 hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame = 2626 tg->funcs->get_frame_count(tg); 2627 } 2628 } 2629 } 2630 2631 bool dcn401_update_bandwidth( 2632 struct dc *dc, 2633 struct dc_state *context) 2634 { 2635 int i; 2636 struct dce_hwseq *hws = dc->hwseq; 2637 2638 /* recalculate DML parameters */ 2639 if (dc->res_pool->funcs->validate_bandwidth(dc, context, DC_VALIDATE_MODE_AND_PROGRAMMING) != DC_OK) 2640 return false; 2641 2642 /* apply updated bandwidth parameters */ 2643 dc->hwss.prepare_bandwidth(dc, context); 2644 2645 /* update hubp configs for all pipes */ 2646 for (i = 0; i < dc->res_pool->pipe_count; i++) { 2647 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 2648 2649 if (pipe_ctx->plane_state == NULL) 2650 continue; 2651 2652 if (pipe_ctx->top_pipe == NULL) { 2653 bool blank = !is_pipe_tree_visible(pipe_ctx); 2654 2655 pipe_ctx->stream_res.tg->funcs->program_global_sync( 2656 pipe_ctx->stream_res.tg, 2657 dcn401_calculate_vready_offset_for_group(pipe_ctx), 2658 (unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines, 2659 (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels, 2660 (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels, 2661 (unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines); 2662 2663 pipe_ctx->stream_res.tg->funcs->set_vtg_params( 2664 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, false); 2665 2666 if (pipe_ctx->prev_odm_pipe == NULL) 2667 hws->funcs.blank_pixel_data(dc, pipe_ctx, blank); 2668 2669 if (hws->funcs.setup_vupdate_interrupt) 2670 hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); 2671 } 2672 2673 if (pipe_ctx->plane_res.hubp->funcs->hubp_setup2) 2674 pipe_ctx->plane_res.hubp->funcs->hubp_setup2( 2675 pipe_ctx->plane_res.hubp, 2676 &pipe_ctx->hubp_regs, 2677 &pipe_ctx->global_sync, 2678 &pipe_ctx->stream->timing); 2679 } 2680 2681 return true; 2682 } 2683 2684 void dcn401_detect_pipe_changes(struct dc_state *old_state, 2685 struct dc_state *new_state, 2686 struct pipe_ctx *old_pipe, 2687 struct pipe_ctx *new_pipe) 2688 { 2689 bool old_is_phantom = dc_state_get_pipe_subvp_type(old_state, old_pipe) == SUBVP_PHANTOM; 2690 bool new_is_phantom = dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM; 2691 2692 unsigned int old_pipe_vready_offset_pixels = old_pipe->global_sync.dcn4x.vready_offset_pixels; 2693 unsigned int new_pipe_vready_offset_pixels = new_pipe->global_sync.dcn4x.vready_offset_pixels; 2694 unsigned int old_pipe_vstartup_lines = old_pipe->global_sync.dcn4x.vstartup_lines; 2695 unsigned int new_pipe_vstartup_lines = new_pipe->global_sync.dcn4x.vstartup_lines; 2696 unsigned int old_pipe_vupdate_offset_pixels = old_pipe->global_sync.dcn4x.vupdate_offset_pixels; 2697 unsigned int new_pipe_vupdate_offset_pixels = new_pipe->global_sync.dcn4x.vupdate_offset_pixels; 2698 unsigned int old_pipe_vupdate_width_pixels = old_pipe->global_sync.dcn4x.vupdate_vupdate_width_pixels; 2699 unsigned int new_pipe_vupdate_width_pixels = new_pipe->global_sync.dcn4x.vupdate_vupdate_width_pixels; 2700 2701 new_pipe->update_flags.raw = 0; 2702 2703 /* If non-phantom pipe is being transitioned to a phantom pipe, 2704 * set disable and return immediately. This is because the pipe 2705 * that was previously in use must be fully disabled before we 2706 * can "enable" it as a phantom pipe (since the OTG will certainly 2707 * be different). The post_unlock sequence will set the correct 2708 * update flags to enable the phantom pipe. 2709 */ 2710 if (old_pipe->plane_state && !old_is_phantom && 2711 new_pipe->plane_state && new_is_phantom) { 2712 new_pipe->update_flags.bits.disable = 1; 2713 return; 2714 } 2715 2716 if (resource_is_pipe_type(new_pipe, OTG_MASTER) && 2717 resource_is_odm_topology_changed(new_pipe, old_pipe)) 2718 /* Detect odm changes */ 2719 new_pipe->update_flags.bits.odm = 1; 2720 2721 /* Exit on unchanged, unused pipe */ 2722 if (!old_pipe->plane_state && !new_pipe->plane_state) 2723 return; 2724 /* Detect pipe enable/disable */ 2725 if (!old_pipe->plane_state && new_pipe->plane_state) { 2726 new_pipe->update_flags.bits.enable = 1; 2727 new_pipe->update_flags.bits.mpcc = 1; 2728 new_pipe->update_flags.bits.dppclk = 1; 2729 new_pipe->update_flags.bits.hubp_interdependent = 1; 2730 new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1; 2731 new_pipe->update_flags.bits.unbounded_req = 1; 2732 new_pipe->update_flags.bits.gamut_remap = 1; 2733 new_pipe->update_flags.bits.scaler = 1; 2734 new_pipe->update_flags.bits.viewport = 1; 2735 new_pipe->update_flags.bits.det_size = 1; 2736 if (new_pipe->stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE && 2737 new_pipe->stream_res.test_pattern_params.width != 0 && 2738 new_pipe->stream_res.test_pattern_params.height != 0) 2739 new_pipe->update_flags.bits.test_pattern_changed = 1; 2740 if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) { 2741 new_pipe->update_flags.bits.odm = 1; 2742 new_pipe->update_flags.bits.global_sync = 1; 2743 } 2744 return; 2745 } 2746 2747 /* For SubVP we need to unconditionally enable because any phantom pipes are 2748 * always removed then newly added for every full updates whenever SubVP is in use. 2749 * The remove-add sequence of the phantom pipe always results in the pipe 2750 * being blanked in enable_stream_timing (DPG). 2751 */ 2752 if (new_pipe->stream && dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM) 2753 new_pipe->update_flags.bits.enable = 1; 2754 2755 /* Phantom pipes are effectively disabled, if the pipe was previously phantom 2756 * we have to enable 2757 */ 2758 if (old_pipe->plane_state && old_is_phantom && 2759 new_pipe->plane_state && !new_is_phantom) 2760 new_pipe->update_flags.bits.enable = 1; 2761 2762 if (old_pipe->plane_state && !new_pipe->plane_state) { 2763 new_pipe->update_flags.bits.disable = 1; 2764 return; 2765 } 2766 2767 /* Detect plane change */ 2768 if (old_pipe->plane_state != new_pipe->plane_state) 2769 new_pipe->update_flags.bits.plane_changed = true; 2770 2771 /* Detect top pipe only changes */ 2772 if (resource_is_pipe_type(new_pipe, OTG_MASTER)) { 2773 /* Detect global sync changes */ 2774 if ((old_pipe_vready_offset_pixels != new_pipe_vready_offset_pixels) 2775 || (old_pipe_vstartup_lines != new_pipe_vstartup_lines) 2776 || (old_pipe_vupdate_offset_pixels != new_pipe_vupdate_offset_pixels) 2777 || (old_pipe_vupdate_width_pixels != new_pipe_vupdate_width_pixels)) 2778 new_pipe->update_flags.bits.global_sync = 1; 2779 } 2780 2781 if (old_pipe->det_buffer_size_kb != new_pipe->det_buffer_size_kb) 2782 new_pipe->update_flags.bits.det_size = 1; 2783 2784 /* 2785 * Detect opp / tg change, only set on change, not on enable 2786 * Assume mpcc inst = pipe index, if not this code needs to be updated 2787 * since mpcc is what is affected by these. In fact all of our sequence 2788 * makes this assumption at the moment with how hubp reset is matched to 2789 * same index mpcc reset. 2790 */ 2791 if (old_pipe->stream_res.opp != new_pipe->stream_res.opp) 2792 new_pipe->update_flags.bits.opp_changed = 1; 2793 if (old_pipe->stream_res.tg != new_pipe->stream_res.tg) 2794 new_pipe->update_flags.bits.tg_changed = 1; 2795 2796 /* 2797 * Detect mpcc blending changes, only dpp inst and opp matter here, 2798 * mpccs getting removed/inserted update connected ones during their own 2799 * programming 2800 */ 2801 if (old_pipe->plane_res.dpp != new_pipe->plane_res.dpp 2802 || old_pipe->stream_res.opp != new_pipe->stream_res.opp) 2803 new_pipe->update_flags.bits.mpcc = 1; 2804 2805 /* Detect dppclk change */ 2806 if (old_pipe->plane_res.bw.dppclk_khz != new_pipe->plane_res.bw.dppclk_khz) 2807 new_pipe->update_flags.bits.dppclk = 1; 2808 2809 /* Check for scl update */ 2810 if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data))) 2811 new_pipe->update_flags.bits.scaler = 1; 2812 /* Check for vp update */ 2813 if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect)) 2814 || memcmp(&old_pipe->plane_res.scl_data.viewport_c, 2815 &new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect))) 2816 new_pipe->update_flags.bits.viewport = 1; 2817 2818 /* Detect dlg/ttu/rq updates */ 2819 { 2820 struct dml2_display_dlg_regs old_dlg_regs = old_pipe->hubp_regs.dlg_regs; 2821 struct dml2_display_ttu_regs old_ttu_regs = old_pipe->hubp_regs.ttu_regs; 2822 struct dml2_display_rq_regs old_rq_regs = old_pipe->hubp_regs.rq_regs; 2823 struct dml2_display_dlg_regs *new_dlg_regs = &new_pipe->hubp_regs.dlg_regs; 2824 struct dml2_display_ttu_regs *new_ttu_regs = &new_pipe->hubp_regs.ttu_regs; 2825 struct dml2_display_rq_regs *new_rq_regs = &new_pipe->hubp_regs.rq_regs; 2826 2827 /* Detect pipe interdependent updates */ 2828 if ((old_dlg_regs.dst_y_prefetch != new_dlg_regs->dst_y_prefetch) 2829 || (old_dlg_regs.vratio_prefetch != new_dlg_regs->vratio_prefetch) 2830 || (old_dlg_regs.vratio_prefetch_c != new_dlg_regs->vratio_prefetch_c) 2831 || (old_dlg_regs.dst_y_per_vm_vblank != new_dlg_regs->dst_y_per_vm_vblank) 2832 || (old_dlg_regs.dst_y_per_row_vblank != new_dlg_regs->dst_y_per_row_vblank) 2833 || (old_dlg_regs.dst_y_per_vm_flip != new_dlg_regs->dst_y_per_vm_flip) 2834 || (old_dlg_regs.dst_y_per_row_flip != new_dlg_regs->dst_y_per_row_flip) 2835 || (old_dlg_regs.refcyc_per_meta_chunk_vblank_l != new_dlg_regs->refcyc_per_meta_chunk_vblank_l) 2836 || (old_dlg_regs.refcyc_per_meta_chunk_vblank_c != new_dlg_regs->refcyc_per_meta_chunk_vblank_c) 2837 || (old_dlg_regs.refcyc_per_meta_chunk_flip_l != new_dlg_regs->refcyc_per_meta_chunk_flip_l) 2838 || (old_dlg_regs.refcyc_per_line_delivery_pre_l != new_dlg_regs->refcyc_per_line_delivery_pre_l) 2839 || (old_dlg_regs.refcyc_per_line_delivery_pre_c != new_dlg_regs->refcyc_per_line_delivery_pre_c) 2840 || (old_ttu_regs.refcyc_per_req_delivery_pre_l != new_ttu_regs->refcyc_per_req_delivery_pre_l) 2841 || (old_ttu_regs.refcyc_per_req_delivery_pre_c != new_ttu_regs->refcyc_per_req_delivery_pre_c) 2842 || (old_ttu_regs.refcyc_per_req_delivery_pre_cur0 != 2843 new_ttu_regs->refcyc_per_req_delivery_pre_cur0) 2844 || (old_ttu_regs.min_ttu_vblank != new_ttu_regs->min_ttu_vblank) 2845 || (old_ttu_regs.qos_level_flip != new_ttu_regs->qos_level_flip)) { 2846 old_dlg_regs.dst_y_prefetch = new_dlg_regs->dst_y_prefetch; 2847 old_dlg_regs.vratio_prefetch = new_dlg_regs->vratio_prefetch; 2848 old_dlg_regs.vratio_prefetch_c = new_dlg_regs->vratio_prefetch_c; 2849 old_dlg_regs.dst_y_per_vm_vblank = new_dlg_regs->dst_y_per_vm_vblank; 2850 old_dlg_regs.dst_y_per_row_vblank = new_dlg_regs->dst_y_per_row_vblank; 2851 old_dlg_regs.dst_y_per_vm_flip = new_dlg_regs->dst_y_per_vm_flip; 2852 old_dlg_regs.dst_y_per_row_flip = new_dlg_regs->dst_y_per_row_flip; 2853 old_dlg_regs.refcyc_per_meta_chunk_vblank_l = new_dlg_regs->refcyc_per_meta_chunk_vblank_l; 2854 old_dlg_regs.refcyc_per_meta_chunk_vblank_c = new_dlg_regs->refcyc_per_meta_chunk_vblank_c; 2855 old_dlg_regs.refcyc_per_meta_chunk_flip_l = new_dlg_regs->refcyc_per_meta_chunk_flip_l; 2856 old_dlg_regs.refcyc_per_line_delivery_pre_l = new_dlg_regs->refcyc_per_line_delivery_pre_l; 2857 old_dlg_regs.refcyc_per_line_delivery_pre_c = new_dlg_regs->refcyc_per_line_delivery_pre_c; 2858 old_ttu_regs.refcyc_per_req_delivery_pre_l = new_ttu_regs->refcyc_per_req_delivery_pre_l; 2859 old_ttu_regs.refcyc_per_req_delivery_pre_c = new_ttu_regs->refcyc_per_req_delivery_pre_c; 2860 old_ttu_regs.refcyc_per_req_delivery_pre_cur0 = new_ttu_regs->refcyc_per_req_delivery_pre_cur0; 2861 old_ttu_regs.min_ttu_vblank = new_ttu_regs->min_ttu_vblank; 2862 old_ttu_regs.qos_level_flip = new_ttu_regs->qos_level_flip; 2863 new_pipe->update_flags.bits.hubp_interdependent = 1; 2864 } 2865 /* Detect any other updates to ttu/rq/dlg */ 2866 if (memcmp(&old_dlg_regs, new_dlg_regs, sizeof(old_dlg_regs)) || 2867 memcmp(&old_ttu_regs, new_ttu_regs, sizeof(old_ttu_regs)) || 2868 memcmp(&old_rq_regs, new_rq_regs, sizeof(old_rq_regs))) 2869 new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1; 2870 } 2871 2872 if (old_pipe->unbounded_req != new_pipe->unbounded_req) 2873 new_pipe->update_flags.bits.unbounded_req = 1; 2874 2875 if (memcmp(&old_pipe->stream_res.test_pattern_params, 2876 &new_pipe->stream_res.test_pattern_params, sizeof(struct test_pattern_params))) { 2877 new_pipe->update_flags.bits.test_pattern_changed = 1; 2878 } 2879 } 2880 2881 void dcn401_plane_atomic_power_down(struct dc *dc, 2882 struct dpp *dpp, 2883 struct hubp *hubp) 2884 { 2885 struct dce_hwseq *hws = dc->hwseq; 2886 uint32_t org_ip_request_cntl = 0; 2887 2888 if (REG(DC_IP_REQUEST_CNTL)) { 2889 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); 2890 if (org_ip_request_cntl == 0) 2891 REG_SET(DC_IP_REQUEST_CNTL, 0, 2892 IP_REQUEST_EN, 1); 2893 } 2894 2895 if (hws->funcs.dpp_pg_control) 2896 hws->funcs.dpp_pg_control(hws, dpp->inst, false); 2897 2898 if (hws->funcs.hubp_pg_control) 2899 hws->funcs.hubp_pg_control(hws, hubp->inst, false); 2900 2901 hubp->funcs->hubp_reset(hubp); 2902 dpp->funcs->dpp_reset(dpp); 2903 2904 if (org_ip_request_cntl == 0 && REG(DC_IP_REQUEST_CNTL)) 2905 REG_SET(DC_IP_REQUEST_CNTL, 0, 2906 IP_REQUEST_EN, 0); 2907 2908 DC_LOG_DEBUG( 2909 "Power gated front end %d\n", hubp->inst); 2910 2911 if (hws->funcs.dpp_root_clock_control) 2912 hws->funcs.dpp_root_clock_control(hws, dpp->inst, false); 2913 } 2914 2915 void dcn401_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe) 2916 { 2917 volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1; 2918 const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe); 2919 const struct hubp *hubp = pipe->plane_res.hubp; 2920 const struct dpp *dpp = pipe->plane_res.dpp; 2921 volatile struct dmub_cursor_offload_pipe_data_dcn401_v1 *p; 2922 uint32_t stream_idx, write_idx, payload_idx; 2923 2924 if (!top_pipe || !hubp || !dpp) 2925 return; 2926 2927 stream_idx = top_pipe->pipe_idx; 2928 write_idx = cs->offload_streams[stream_idx].write_idx + 1; /* new payload (+1) */ 2929 payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads); 2930 2931 p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe->pipe_idx].dcn401; 2932 2933 p->CURSOR0_0_CURSOR_SURFACE_ADDRESS = hubp->att.SURFACE_ADDR; 2934 p->CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH = hubp->att.SURFACE_ADDR_HIGH; 2935 p->CURSOR0_0_CURSOR_SIZE__CURSOR_WIDTH = hubp->att.size.bits.width; 2936 p->CURSOR0_0_CURSOR_SIZE__CURSOR_HEIGHT = hubp->att.size.bits.height; 2937 p->CURSOR0_0_CURSOR_POSITION__CURSOR_X_POSITION = hubp->pos.position.bits.x_pos; 2938 p->CURSOR0_0_CURSOR_POSITION__CURSOR_Y_POSITION = hubp->pos.position.bits.y_pos; 2939 p->CURSOR0_0_CURSOR_HOT_SPOT__CURSOR_HOT_SPOT_X = hubp->pos.hot_spot.bits.x_hot; 2940 p->CURSOR0_0_CURSOR_HOT_SPOT__CURSOR_HOT_SPOT_Y = hubp->pos.hot_spot.bits.y_hot; 2941 p->CURSOR0_0_CURSOR_DST_OFFSET__CURSOR_DST_X_OFFSET = hubp->pos.dst_offset.bits.dst_x_offset; 2942 p->CURSOR0_0_CURSOR_CONTROL__CURSOR_ENABLE = hubp->pos.cur_ctl.bits.cur_enable; 2943 p->CURSOR0_0_CURSOR_CONTROL__CURSOR_MODE = hubp->att.cur_ctl.bits.mode; 2944 p->CURSOR0_0_CURSOR_CONTROL__CURSOR_2X_MAGNIFY = hubp->pos.cur_ctl.bits.cur_2x_magnify; 2945 p->CURSOR0_0_CURSOR_CONTROL__CURSOR_PITCH = hubp->att.cur_ctl.bits.pitch; 2946 p->CURSOR0_0_CURSOR_CONTROL__CURSOR_LINES_PER_CHUNK = hubp->att.cur_ctl.bits.line_per_chunk; 2947 2948 p->CM_CUR0_CURSOR0_CONTROL__CUR0_ENABLE = dpp->att.cur0_ctl.bits.cur0_enable; 2949 p->CM_CUR0_CURSOR0_CONTROL__CUR0_MODE = dpp->att.cur0_ctl.bits.mode; 2950 p->CM_CUR0_CURSOR0_CONTROL__CUR0_EXPANSION_MODE = dpp->att.cur0_ctl.bits.expansion_mode; 2951 p->CM_CUR0_CURSOR0_CONTROL__CUR0_ROM_EN = dpp->att.cur0_ctl.bits.cur0_rom_en; 2952 p->CM_CUR0_CURSOR0_COLOR0__CUR0_COLOR0 = 0x000000; 2953 p->CM_CUR0_CURSOR0_COLOR1__CUR0_COLOR1 = 0xFFFFFF; 2954 2955 p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_G_Y__CUR0_FP_BIAS_G_Y = 2956 dpp->att.fp_scale_bias_g_y.bits.fp_bias_g_y; 2957 p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_G_Y__CUR0_FP_SCALE_G_Y = 2958 dpp->att.fp_scale_bias_g_y.bits.fp_scale_g_y; 2959 p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_RB_CRCB__CUR0_FP_BIAS_RB_CRCB = 2960 dpp->att.fp_scale_bias_rb_crcb.bits.fp_bias_rb_crcb; 2961 p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_RB_CRCB__CUR0_FP_SCALE_RB_CRCB = 2962 dpp->att.fp_scale_bias_rb_crcb.bits.fp_scale_rb_crcb; 2963 2964 p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_DST_Y_OFFSET = hubp->att.settings.bits.dst_y_offset; 2965 p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_CHUNK_HDL_ADJUST = hubp->att.settings.bits.chunk_hdl_adjust; 2966 p->HUBP0_DCHUBP_MALL_CONFIG__USE_MALL_FOR_CURSOR = hubp->use_mall_for_cursor; 2967 2968 cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe->pipe_idx); 2969 } 2970 2971 void dcn401_plane_atomic_power_down_sequence(struct dc *dc, 2972 struct dpp *dpp, 2973 struct hubp *hubp, 2974 struct block_sequence_state *seq_state) 2975 { 2976 struct dce_hwseq *hws = dc->hwseq; 2977 uint32_t org_ip_request_cntl = 0; 2978 2979 /* Check and set DC_IP_REQUEST_CNTL if needed */ 2980 if (REG(DC_IP_REQUEST_CNTL)) { 2981 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); 2982 if (org_ip_request_cntl == 0) 2983 hwss_add_dc_ip_request_cntl(seq_state, dc, true); 2984 } 2985 2986 /* DPP power gating control */ 2987 hwss_add_dpp_pg_control(seq_state, hws, dpp->inst, false); 2988 2989 /* HUBP power gating control */ 2990 hwss_add_hubp_pg_control(seq_state, hws, hubp->inst, false); 2991 2992 /* HUBP reset */ 2993 hwss_add_hubp_reset(seq_state, hubp); 2994 2995 /* DPP reset */ 2996 hwss_add_dpp_reset(seq_state, dpp); 2997 2998 /* Restore DC_IP_REQUEST_CNTL if it was originally 0 */ 2999 if (org_ip_request_cntl == 0 && REG(DC_IP_REQUEST_CNTL)) 3000 hwss_add_dc_ip_request_cntl(seq_state, dc, false); 3001 3002 DC_LOG_DEBUG("Power gated front end %d\n", hubp->inst); 3003 3004 /* DPP root clock control */ 3005 hwss_add_dpp_root_clock_control(seq_state, hws, dpp->inst, false); 3006 } 3007 3008 /* trigger HW to start disconnect plane from stream on the next vsync using block sequence */ 3009 void dcn401_plane_atomic_disconnect_sequence(struct dc *dc, 3010 struct dc_state *state, 3011 struct pipe_ctx *pipe_ctx, 3012 struct block_sequence_state *seq_state) 3013 { 3014 struct hubp *hubp = pipe_ctx->plane_res.hubp; 3015 int dpp_id = pipe_ctx->plane_res.dpp->inst; 3016 struct mpc *mpc = dc->res_pool->mpc; 3017 struct mpc_tree *mpc_tree_params; 3018 struct mpcc *mpcc_to_remove = NULL; 3019 struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; 3020 3021 mpc_tree_params = &(opp->mpc_tree_params); 3022 mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); 3023 3024 /*Already reset*/ 3025 if (mpcc_to_remove == NULL) 3026 return; 3027 3028 /* Step 1: Remove MPCC from MPC tree */ 3029 hwss_add_mpc_remove_mpcc(seq_state, mpc, mpc_tree_params, mpcc_to_remove); 3030 3031 // Phantom pipes have OTG disabled by default, so MPCC_STATUS will never assert idle, 3032 // so don't wait for MPCC_IDLE in the programming sequence 3033 if (dc_state_get_pipe_subvp_type(state, pipe_ctx) != SUBVP_PHANTOM) { 3034 /* Step 2: Set MPCC disconnect pending flag */ 3035 hwss_add_opp_set_mpcc_disconnect_pending(seq_state, opp, pipe_ctx->plane_res.mpcc_inst, true); 3036 } 3037 3038 /* Step 3: Set optimized required flag */ 3039 hwss_add_dc_set_optimized_required(seq_state, dc, true); 3040 3041 /* Step 4: Disconnect HUBP if function exists */ 3042 if (hubp->funcs->hubp_disconnect) 3043 hwss_add_hubp_disconnect(seq_state, hubp); 3044 3045 /* Step 5: Verify pstate change high if debug sanity checks are enabled */ 3046 if (dc->debug.sanity_checks) 3047 dc->hwseq->funcs.verify_allow_pstate_change_high_sequence(dc, seq_state); 3048 } 3049 3050 void dcn401_blank_pixel_data_sequence( 3051 struct dc *dc, 3052 struct pipe_ctx *pipe_ctx, 3053 bool blank, 3054 struct block_sequence_state *seq_state) 3055 { 3056 struct tg_color black_color = {0}; 3057 struct stream_resource *stream_res = &pipe_ctx->stream_res; 3058 struct dc_stream_state *stream = pipe_ctx->stream; 3059 enum dc_color_space color_space = stream->output_color_space; 3060 enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR; 3061 enum controller_dp_color_space test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED; 3062 struct pipe_ctx *odm_pipe; 3063 struct rect odm_slice_src; 3064 3065 if (stream->link->test_pattern_enabled) 3066 return; 3067 3068 /* get opp dpg blank color */ 3069 color_space_to_black_color(dc, color_space, &black_color); 3070 3071 if (blank) { 3072 /* Set ABM immediate disable */ 3073 hwss_add_abm_set_immediate_disable(seq_state, dc, pipe_ctx); 3074 3075 if (dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) { 3076 test_pattern = CONTROLLER_DP_TEST_PATTERN_COLORSQUARES; 3077 test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_RGB; 3078 } 3079 } else { 3080 test_pattern = CONTROLLER_DP_TEST_PATTERN_VIDEOMODE; 3081 } 3082 3083 odm_pipe = pipe_ctx; 3084 3085 /* Set display pattern generator for all ODM pipes */ 3086 while (odm_pipe->next_odm_pipe) { 3087 odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe); 3088 3089 hwss_add_opp_set_disp_pattern_generator(seq_state, 3090 odm_pipe->stream_res.opp, 3091 test_pattern, 3092 test_pattern_color_space, 3093 stream->timing.display_color_depth, 3094 black_color, 3095 true, 3096 odm_slice_src.width, 3097 odm_slice_src.height, 3098 odm_slice_src.x); 3099 3100 odm_pipe = odm_pipe->next_odm_pipe; 3101 } 3102 3103 /* Set display pattern generator for final ODM pipe */ 3104 odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe); 3105 3106 hwss_add_opp_set_disp_pattern_generator(seq_state, 3107 odm_pipe->stream_res.opp, 3108 test_pattern, 3109 test_pattern_color_space, 3110 stream->timing.display_color_depth, 3111 black_color, 3112 true, 3113 odm_slice_src.width, 3114 odm_slice_src.height, 3115 odm_slice_src.x); 3116 3117 /* Handle ABM level setting when not blanking */ 3118 if (!blank) { 3119 if (stream_res->abm) { 3120 /* Set pipe for ABM */ 3121 hwss_add_abm_set_pipe(seq_state, dc, pipe_ctx); 3122 3123 /* Set ABM level */ 3124 hwss_add_abm_set_level(seq_state, stream_res->abm, stream->abm_level); 3125 } 3126 } 3127 } 3128 3129 void dcn401_program_all_writeback_pipes_in_tree_sequence( 3130 struct dc *dc, 3131 const struct dc_stream_state *stream, 3132 struct dc_state *context, 3133 struct block_sequence_state *seq_state) 3134 { 3135 struct dwbc *dwb; 3136 int i_wb, i_pipe; 3137 3138 if (!stream || stream->num_wb_info > dc->res_pool->res_cap->num_dwb) 3139 return; 3140 3141 /* For each writeback pipe */ 3142 for (i_wb = 0; i_wb < stream->num_wb_info; i_wb++) { 3143 /* Get direct pointer to writeback info */ 3144 struct dc_writeback_info *wb_info = (struct dc_writeback_info *)&stream->writeback_info[i_wb]; 3145 int mpcc_inst = -1; 3146 3147 if (wb_info->wb_enabled) { 3148 /* Get the MPCC instance for writeback_source_plane */ 3149 for (i_pipe = 0; i_pipe < dc->res_pool->pipe_count; i_pipe++) { 3150 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i_pipe]; 3151 3152 if (!pipe_ctx->plane_state) 3153 continue; 3154 3155 if (pipe_ctx->plane_state == wb_info->writeback_source_plane) { 3156 mpcc_inst = pipe_ctx->plane_res.mpcc_inst; 3157 break; 3158 } 3159 } 3160 3161 if (mpcc_inst == -1) { 3162 /* Disable writeback pipe and disconnect from MPCC 3163 * if source plane has been removed 3164 */ 3165 dcn401_disable_writeback_sequence(dc, wb_info, seq_state); 3166 continue; 3167 } 3168 3169 ASSERT(wb_info->dwb_pipe_inst < dc->res_pool->res_cap->num_dwb); 3170 dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; 3171 3172 if (dwb->funcs->is_enabled(dwb)) { 3173 /* Writeback pipe already enabled, only need to update */ 3174 dcn401_update_writeback_sequence(dc, wb_info, context, seq_state); 3175 } else { 3176 /* Enable writeback pipe and connect to MPCC */ 3177 dcn401_enable_writeback_sequence(dc, wb_info, context, mpcc_inst, seq_state); 3178 } 3179 } else { 3180 /* Disable writeback pipe and disconnect from MPCC */ 3181 dcn401_disable_writeback_sequence(dc, wb_info, seq_state); 3182 } 3183 } 3184 } 3185 3186 void dcn401_enable_writeback_sequence( 3187 struct dc *dc, 3188 struct dc_writeback_info *wb_info, 3189 struct dc_state *context, 3190 int mpcc_inst, 3191 struct block_sequence_state *seq_state) 3192 { 3193 struct dwbc *dwb; 3194 struct mcif_wb *mcif_wb; 3195 3196 if (!wb_info->wb_enabled || wb_info->dwb_pipe_inst >= dc->res_pool->res_cap->num_dwb) 3197 return; 3198 3199 dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; 3200 mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst]; 3201 3202 /* Update DWBC with new parameters */ 3203 hwss_add_dwbc_update(seq_state, dwb, &wb_info->dwb_params); 3204 3205 /* Configure MCIF_WB buffer settings */ 3206 hwss_add_mcif_wb_config_buf(seq_state, mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height); 3207 3208 /* Configure MCIF_WB arbitration */ 3209 hwss_add_mcif_wb_config_arb(seq_state, mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]); 3210 3211 /* Enable MCIF_WB */ 3212 hwss_add_mcif_wb_enable(seq_state, mcif_wb); 3213 3214 /* Set DWB MUX to connect writeback to MPCC */ 3215 hwss_add_mpc_set_dwb_mux(seq_state, dc->res_pool->mpc, wb_info->dwb_pipe_inst, mpcc_inst); 3216 3217 /* Enable DWBC */ 3218 hwss_add_dwbc_enable(seq_state, dwb, &wb_info->dwb_params); 3219 } 3220 3221 void dcn401_disable_writeback_sequence( 3222 struct dc *dc, 3223 struct dc_writeback_info *wb_info, 3224 struct block_sequence_state *seq_state) 3225 { 3226 struct dwbc *dwb; 3227 struct mcif_wb *mcif_wb; 3228 3229 if (wb_info->dwb_pipe_inst >= dc->res_pool->res_cap->num_dwb) 3230 return; 3231 3232 dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; 3233 mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst]; 3234 3235 /* Disable DWBC */ 3236 hwss_add_dwbc_disable(seq_state, dwb); 3237 3238 /* Disable DWB MUX */ 3239 hwss_add_mpc_disable_dwb_mux(seq_state, dc->res_pool->mpc, wb_info->dwb_pipe_inst); 3240 3241 /* Disable MCIF_WB */ 3242 hwss_add_mcif_wb_disable(seq_state, mcif_wb); 3243 } 3244 3245 void dcn401_update_writeback_sequence( 3246 struct dc *dc, 3247 struct dc_writeback_info *wb_info, 3248 struct dc_state *context, 3249 struct block_sequence_state *seq_state) 3250 { 3251 (void)context; 3252 struct dwbc *dwb; 3253 struct mcif_wb *mcif_wb; 3254 3255 if (!wb_info->wb_enabled || wb_info->dwb_pipe_inst >= dc->res_pool->res_cap->num_dwb) 3256 return; 3257 3258 dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; 3259 mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst]; 3260 3261 /* Update writeback pipe */ 3262 hwss_add_dwbc_update(seq_state, dwb, &wb_info->dwb_params); 3263 3264 /* Update MCIF_WB buffer settings if needed */ 3265 hwss_add_mcif_wb_config_buf(seq_state, mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height); 3266 } 3267 3268 static int find_free_gsl_group(const struct dc *dc) 3269 { 3270 if (dc->res_pool->gsl_groups.gsl_0 == 0) 3271 return 1; 3272 if (dc->res_pool->gsl_groups.gsl_1 == 0) 3273 return 2; 3274 if (dc->res_pool->gsl_groups.gsl_2 == 0) 3275 return 3; 3276 3277 return 0; 3278 } 3279 3280 void dcn401_setup_gsl_group_as_lock_sequence( 3281 const struct dc *dc, 3282 struct pipe_ctx *pipe_ctx, 3283 bool enable, 3284 struct block_sequence_state *seq_state) 3285 { 3286 struct gsl_params gsl; 3287 int group_idx; 3288 3289 memset(&gsl, 0, sizeof(struct gsl_params)); 3290 3291 if (enable) { 3292 /* return if group already assigned since GSL was set up 3293 * for vsync flip, we would unassign so it can't be "left over" 3294 */ 3295 if (pipe_ctx->stream_res.gsl_group > 0) 3296 return; 3297 3298 group_idx = find_free_gsl_group(dc); 3299 ASSERT(group_idx != 0); 3300 pipe_ctx->stream_res.gsl_group = group_idx; 3301 3302 /* set gsl group reg field and mark resource used */ 3303 switch (group_idx) { 3304 case 1: 3305 gsl.gsl0_en = 1; 3306 dc->res_pool->gsl_groups.gsl_0 = 1; 3307 break; 3308 case 2: 3309 gsl.gsl1_en = 1; 3310 dc->res_pool->gsl_groups.gsl_1 = 1; 3311 break; 3312 case 3: 3313 gsl.gsl2_en = 1; 3314 dc->res_pool->gsl_groups.gsl_2 = 1; 3315 break; 3316 default: 3317 BREAK_TO_DEBUGGER(); 3318 return; // invalid case 3319 } 3320 gsl.gsl_master_en = 1; 3321 } else { 3322 group_idx = pipe_ctx->stream_res.gsl_group; 3323 if (group_idx == 0) 3324 return; // if not in use, just return 3325 3326 pipe_ctx->stream_res.gsl_group = 0; 3327 3328 /* unset gsl group reg field and mark resource free */ 3329 switch (group_idx) { 3330 case 1: 3331 gsl.gsl0_en = 0; 3332 dc->res_pool->gsl_groups.gsl_0 = 0; 3333 break; 3334 case 2: 3335 gsl.gsl1_en = 0; 3336 dc->res_pool->gsl_groups.gsl_1 = 0; 3337 break; 3338 case 3: 3339 gsl.gsl2_en = 0; 3340 dc->res_pool->gsl_groups.gsl_2 = 0; 3341 break; 3342 default: 3343 BREAK_TO_DEBUGGER(); 3344 return; 3345 } 3346 gsl.gsl_master_en = 0; 3347 } 3348 3349 hwss_add_tg_set_gsl(seq_state, pipe_ctx->stream_res.tg, gsl); 3350 hwss_add_tg_set_gsl_source_select(seq_state, pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0); 3351 } 3352 3353 void dcn401_disable_plane_sequence( 3354 struct dc *dc, 3355 struct dc_state *state, 3356 struct pipe_ctx *pipe_ctx, 3357 struct block_sequence_state *seq_state) 3358 { 3359 bool is_phantom = dc_state_get_pipe_subvp_type(state, pipe_ctx) == SUBVP_PHANTOM; 3360 struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL; 3361 3362 if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) 3363 return; 3364 3365 /* Wait for MPCC disconnect */ 3366 if (dc->hwss.wait_for_mpcc_disconnect_sequence) 3367 dc->hwss.wait_for_mpcc_disconnect_sequence(dc, dc->res_pool, pipe_ctx, seq_state); 3368 3369 /* In flip immediate with pipe splitting case GSL is used for synchronization 3370 * so we must disable it when the plane is disabled. 3371 */ 3372 if (pipe_ctx->stream_res.gsl_group != 0) 3373 dcn401_setup_gsl_group_as_lock_sequence(dc, pipe_ctx, false, seq_state); 3374 3375 /* Update HUBP mall sel */ 3376 if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs->hubp_update_mall_sel) 3377 hwss_add_hubp_update_mall_sel(seq_state, pipe_ctx->plane_res.hubp, 0, false); 3378 3379 /* Set flip control GSL */ 3380 hwss_add_hubp_set_flip_control_gsl(seq_state, pipe_ctx->plane_res.hubp, false); 3381 3382 /* HUBP clock control */ 3383 hwss_add_hubp_clk_cntl(seq_state, pipe_ctx->plane_res.hubp, false); 3384 3385 /* DPP clock control */ 3386 hwss_add_dpp_dppclk_control(seq_state, pipe_ctx->plane_res.dpp, false, false); 3387 3388 /* Plane atomic power down */ 3389 if (dc->hwseq->funcs.plane_atomic_power_down_sequence) 3390 dc->hwseq->funcs.plane_atomic_power_down_sequence(dc, pipe_ctx->plane_res.dpp, 3391 pipe_ctx->plane_res.hubp, seq_state); 3392 3393 pipe_ctx->stream = NULL; 3394 memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); 3395 memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); 3396 pipe_ctx->top_pipe = NULL; 3397 pipe_ctx->bottom_pipe = NULL; 3398 pipe_ctx->prev_odm_pipe = NULL; 3399 pipe_ctx->next_odm_pipe = NULL; 3400 pipe_ctx->plane_state = NULL; 3401 3402 /* Turn back off the phantom OTG after the phantom plane is fully disabled */ 3403 if (is_phantom && tg && tg->funcs->disable_phantom_crtc) 3404 hwss_add_disable_phantom_crtc(seq_state, tg); 3405 } 3406 3407 void dcn401_post_unlock_reset_opp_sequence( 3408 struct dc *dc, 3409 struct pipe_ctx *opp_head, 3410 struct block_sequence_state *seq_state) 3411 { 3412 struct display_stream_compressor *dsc = opp_head->stream_res.dsc; 3413 struct dccg *dccg = dc->res_pool->dccg; 3414 3415 /* Wait for all DPP pipes in current mpc blending tree completes double 3416 * buffered disconnection before resetting OPP 3417 */ 3418 if (dc->hwss.wait_for_mpcc_disconnect_sequence) 3419 dc->hwss.wait_for_mpcc_disconnect_sequence(dc, dc->res_pool, opp_head, seq_state); 3420 3421 if (dsc) { 3422 bool *is_ungated = NULL; 3423 /* Check DSC power gate status */ 3424 if (dc->hwseq && dc->hwseq->funcs.dsc_pg_status) 3425 hwss_add_dsc_pg_status(seq_state, dc->hwseq, dsc->inst, false); 3426 3427 /* Seamless update specific where we will postpone non 3428 * double buffered DSCCLK disable logic in post unlock 3429 * sequence after DSC is disconnected from OPP but not 3430 * yet power gated. 3431 */ 3432 3433 /* DSC wait disconnect pending clear */ 3434 hwss_add_dsc_wait_disconnect_pending_clear(seq_state, dsc, is_ungated); 3435 3436 /* DSC disable */ 3437 hwss_add_dsc_disable(seq_state, dsc, is_ungated); 3438 3439 /* Set reference DSCCLK */ 3440 if (dccg && dccg->funcs->set_ref_dscclk) 3441 hwss_add_dccg_set_ref_dscclk(seq_state, dccg, dsc->inst, 0); 3442 } 3443 } 3444 3445 void dcn401_dc_ip_request_cntl(struct dc *dc, bool enable) 3446 { 3447 struct dce_hwseq *hws = dc->hwseq; 3448 3449 if (REG(DC_IP_REQUEST_CNTL)) 3450 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, enable ? 1 : 0); 3451 } 3452 3453 void dcn401_enable_plane_sequence(struct dc *dc, struct pipe_ctx *pipe_ctx, 3454 struct dc_state *context, 3455 struct block_sequence_state *seq_state) 3456 { 3457 (void)context; 3458 struct dce_hwseq *hws = dc->hwseq; 3459 uint32_t org_ip_request_cntl = 0; 3460 3461 if (!pipe_ctx->plane_res.dpp || !pipe_ctx->plane_res.hubp || !pipe_ctx->stream_res.opp) 3462 return; 3463 3464 if (REG(DC_IP_REQUEST_CNTL)) 3465 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); 3466 3467 /* Step 1: DPP root clock control - enable clock */ 3468 if (hws->funcs.dpp_root_clock_control) 3469 hwss_add_dpp_root_clock_control(seq_state, hws, pipe_ctx->plane_res.dpp->inst, true); 3470 3471 /* Step 2: Enable DC IP request (if needed) */ 3472 if (hws->funcs.dc_ip_request_cntl) 3473 hwss_add_dc_ip_request_cntl(seq_state, dc, true); 3474 3475 /* Step 3: DPP power gating control - power on */ 3476 if (REG(DC_IP_REQUEST_CNTL) && hws->funcs.dpp_pg_control) 3477 hwss_add_dpp_pg_control(seq_state, hws, pipe_ctx->plane_res.dpp->inst, true); 3478 3479 /* Step 4: HUBP power gating control - power on */ 3480 if (REG(DC_IP_REQUEST_CNTL) && hws->funcs.hubp_pg_control) 3481 hwss_add_hubp_pg_control(seq_state, hws, pipe_ctx->plane_res.hubp->inst, true); 3482 3483 /* Step 5: Disable DC IP request (restore state) */ 3484 if (org_ip_request_cntl == 0 && hws->funcs.dc_ip_request_cntl) 3485 hwss_add_dc_ip_request_cntl(seq_state, dc, false); 3486 3487 /* Step 6: HUBP clock control - enable DCFCLK */ 3488 if (pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl) 3489 hwss_add_hubp_clk_cntl(seq_state, pipe_ctx->plane_res.hubp, true); 3490 3491 /* Step 7: HUBP initialization */ 3492 if (pipe_ctx->plane_res.hubp->funcs->hubp_init) 3493 hwss_add_hubp_init(seq_state, pipe_ctx->plane_res.hubp); 3494 3495 /* Step 8: OPP pipe clock control - enable */ 3496 if (pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control) 3497 hwss_add_opp_pipe_clock_control(seq_state, pipe_ctx->stream_res.opp, true); 3498 3499 /* Step 9: VM system aperture settings */ 3500 if (dc->vm_pa_config.valid && pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings) { 3501 hwss_add_hubp_set_vm_system_aperture_settings(seq_state, pipe_ctx->plane_res.hubp, 0, 3502 dc->vm_pa_config.system_aperture.start_addr, dc->vm_pa_config.system_aperture.end_addr); 3503 } 3504 3505 /* Step 10: Flip interrupt setup */ 3506 if (!pipe_ctx->top_pipe 3507 && pipe_ctx->plane_state 3508 && pipe_ctx->plane_state->flip_int_enabled 3509 && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int) { 3510 hwss_add_hubp_set_flip_int(seq_state, pipe_ctx->plane_res.hubp); 3511 } 3512 } 3513 3514 void dcn401_update_dchubp_dpp_sequence(struct dc *dc, 3515 struct pipe_ctx *pipe_ctx, 3516 struct dc_state *context, 3517 struct block_sequence_state *seq_state) 3518 { 3519 struct dce_hwseq *hws = dc->hwseq; 3520 struct hubp *hubp = pipe_ctx->plane_res.hubp; 3521 struct dpp *dpp = pipe_ctx->plane_res.dpp; 3522 struct dc_plane_state *plane_state = pipe_ctx->plane_state; 3523 struct dccg *dccg = dc->res_pool->dccg; 3524 bool viewport_changed = false; 3525 enum mall_stream_type pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe_ctx); 3526 3527 if (!hubp || !dpp || !plane_state) 3528 return; 3529 3530 /* Step 1: DPP DPPCLK control */ 3531 if (pipe_ctx->update_flags.bits.dppclk) 3532 hwss_add_dpp_dppclk_control(seq_state, dpp, false, true); 3533 3534 /* Step 2: DCCG update DPP DTO */ 3535 if (pipe_ctx->update_flags.bits.enable) 3536 hwss_add_dccg_update_dpp_dto(seq_state, dccg, dpp->inst, pipe_ctx->plane_res.bw.dppclk_khz); 3537 3538 /* Step 3: HUBP VTG selection */ 3539 if (pipe_ctx->update_flags.bits.hubp_rq_dlg_ttu) { 3540 hwss_add_hubp_vtg_sel(seq_state, hubp, pipe_ctx->stream_res.tg->inst); 3541 3542 /* Step 4: HUBP setup (choose setup2 or setup) */ 3543 if (hubp->funcs->hubp_setup2) { 3544 hwss_add_hubp_setup2(seq_state, hubp, &pipe_ctx->hubp_regs, 3545 &pipe_ctx->global_sync, &pipe_ctx->stream->timing); 3546 } else if (hubp->funcs->hubp_setup) { 3547 hwss_add_hubp_setup(seq_state, hubp, &pipe_ctx->dlg_regs, 3548 &pipe_ctx->ttu_regs, &pipe_ctx->rq_regs, &pipe_ctx->pipe_dlg_param); 3549 } 3550 } 3551 3552 /* Step 5: Set unbounded requesting */ 3553 if (pipe_ctx->update_flags.bits.unbounded_req && hubp->funcs->set_unbounded_requesting) 3554 hwss_add_hubp_set_unbounded_requesting(seq_state, hubp, pipe_ctx->unbounded_req); 3555 3556 /* Step 6: HUBP interdependent setup */ 3557 if (pipe_ctx->update_flags.bits.hubp_interdependent) { 3558 if (hubp->funcs->hubp_setup_interdependent2) 3559 hwss_add_hubp_setup_interdependent2(seq_state, hubp, &pipe_ctx->hubp_regs); 3560 else if (hubp->funcs->hubp_setup_interdependent) 3561 hwss_add_hubp_setup_interdependent(seq_state, hubp, &pipe_ctx->dlg_regs, &pipe_ctx->ttu_regs); 3562 } 3563 3564 /* Step 7: DPP setup - input CSC and format setup */ 3565 if (pipe_ctx->update_flags.bits.enable || 3566 pipe_ctx->update_flags.bits.plane_changed || 3567 plane_state->update_flags.bits.bpp_change || 3568 plane_state->update_flags.bits.input_csc_change || 3569 plane_state->update_flags.bits.color_space_change || 3570 plane_state->update_flags.bits.coeff_reduction_change) { 3571 hwss_add_dpp_setup_dpp(seq_state, pipe_ctx); 3572 3573 /* Step 8: DPP cursor matrix setup */ 3574 if (dpp->funcs->set_cursor_matrix) { 3575 hwss_add_dpp_set_cursor_matrix(seq_state, dpp, plane_state->color_space, 3576 &plane_state->cursor_csc_color_matrix); 3577 } 3578 3579 /* Step 9: DPP program bias and scale */ 3580 if (dpp->funcs->dpp_program_bias_and_scale) 3581 hwss_add_dpp_program_bias_and_scale(seq_state, pipe_ctx); 3582 } 3583 3584 /* Step 10: MPCC updates */ 3585 if (pipe_ctx->update_flags.bits.mpcc || 3586 pipe_ctx->update_flags.bits.plane_changed || 3587 plane_state->update_flags.bits.global_alpha_change || 3588 plane_state->update_flags.bits.per_pixel_alpha_change) { 3589 3590 /* Check if update_mpcc_sequence is implemented and prefer it over single MPC_UPDATE_MPCC step */ 3591 if (hws->funcs.update_mpcc_sequence) 3592 hws->funcs.update_mpcc_sequence(dc, pipe_ctx, seq_state); 3593 } 3594 3595 /* Step 11: DPP scaler setup */ 3596 if (pipe_ctx->update_flags.bits.scaler || 3597 plane_state->update_flags.bits.scaling_change || 3598 plane_state->update_flags.bits.position_change || 3599 plane_state->update_flags.bits.per_pixel_alpha_change || 3600 pipe_ctx->stream->update_flags.bits.scaling) { 3601 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha; 3602 ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_36BPP); 3603 hwss_add_dpp_set_scaler(seq_state, pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); 3604 } 3605 3606 /* Step 12: HUBP viewport programming */ 3607 if (pipe_ctx->update_flags.bits.viewport || 3608 (context == dc->current_state && plane_state->update_flags.bits.position_change) || 3609 (context == dc->current_state && plane_state->update_flags.bits.scaling_change) || 3610 (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) { 3611 hwss_add_hubp_mem_program_viewport(seq_state, hubp, 3612 &pipe_ctx->plane_res.scl_data.viewport, &pipe_ctx->plane_res.scl_data.viewport_c); 3613 viewport_changed = true; 3614 } 3615 3616 /* Step 13: HUBP program mcache if available */ 3617 if (hubp->funcs->hubp_program_mcache_id_and_split_coordinate) 3618 hwss_add_hubp_program_mcache_id(seq_state, hubp, &pipe_ctx->mcache_regs); 3619 3620 /* Step 14: Cursor attribute setup */ 3621 if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed || 3622 pipe_ctx->update_flags.bits.scaler || viewport_changed == true) && 3623 pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { 3624 3625 hwss_add_abort_cursor_offload_update(seq_state, dc, pipe_ctx); 3626 3627 hwss_add_set_cursor_attribute(seq_state, dc, pipe_ctx); 3628 3629 /* Step 15: Cursor position setup */ 3630 hwss_add_set_cursor_position(seq_state, dc, pipe_ctx); 3631 3632 /* Step 16: Cursor SDR white level */ 3633 if (dc->hwss.set_cursor_sdr_white_level) 3634 hwss_add_set_cursor_sdr_white_level(seq_state, dc, pipe_ctx); 3635 } 3636 3637 /* Step 17: Gamut remap and output CSC */ 3638 if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed || 3639 pipe_ctx->update_flags.bits.plane_changed || 3640 pipe_ctx->stream->update_flags.bits.gamut_remap || 3641 plane_state->update_flags.bits.gamut_remap_change || 3642 pipe_ctx->stream->update_flags.bits.out_csc) { 3643 3644 /* Gamut remap */ 3645 hwss_add_dpp_program_gamut_remap(seq_state, pipe_ctx); 3646 3647 /* Output CSC */ 3648 hwss_add_program_output_csc(seq_state, dc, pipe_ctx, pipe_ctx->stream->output_color_space, 3649 pipe_ctx->stream->csc_color_matrix.matrix, hubp->opp_id); 3650 } 3651 3652 /* Step 18: HUBP surface configuration */ 3653 if (pipe_ctx->update_flags.bits.enable || 3654 pipe_ctx->update_flags.bits.plane_changed || 3655 pipe_ctx->update_flags.bits.opp_changed || 3656 plane_state->update_flags.bits.pixel_format_change || 3657 plane_state->update_flags.bits.horizontal_mirror_change || 3658 plane_state->update_flags.bits.rotation_change || 3659 plane_state->update_flags.bits.swizzle_change || 3660 plane_state->update_flags.bits.dcc_change || 3661 plane_state->update_flags.bits.bpp_change || 3662 plane_state->update_flags.bits.scaling_change || 3663 plane_state->update_flags.bits.plane_size_change) { 3664 struct plane_size size = plane_state->plane_size; 3665 3666 size.surface_size = pipe_ctx->plane_res.scl_data.viewport; 3667 hwss_add_hubp_program_surface_config(seq_state, hubp, 3668 plane_state->format, &plane_state->tiling_info, size, 3669 plane_state->rotation, &plane_state->dcc, 3670 plane_state->horizontal_mirror, 0); 3671 hubp->power_gated = false; 3672 } 3673 3674 /* Step 19: Update plane address (with SubVP support) */ 3675 if (pipe_ctx->update_flags.bits.enable || 3676 pipe_ctx->update_flags.bits.plane_changed || 3677 plane_state->update_flags.bits.addr_update) { 3678 3679 /* SubVP save surface address if needed */ 3680 if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && pipe_mall_type == SUBVP_MAIN) { 3681 hwss_add_dmub_subvp_save_surf_addr(seq_state, dc->ctx->dmub_srv, 3682 &pipe_ctx->plane_state->address, pipe_ctx->subvp_index); 3683 } 3684 3685 /* Update plane address */ 3686 hwss_add_hubp_update_plane_addr(seq_state, dc, pipe_ctx); 3687 } 3688 3689 /* Step 20: HUBP set blank - enable plane */ 3690 if (pipe_ctx->update_flags.bits.enable) 3691 hwss_add_hubp_set_blank(seq_state, hubp, false); 3692 3693 /* Step 21: Phantom HUBP post enable */ 3694 if (pipe_mall_type == SUBVP_PHANTOM && hubp->funcs->phantom_hubp_post_enable) 3695 hwss_add_phantom_hubp_post_enable(seq_state, hubp); 3696 } 3697 3698 void dcn401_update_mpcc_sequence(struct dc *dc, 3699 struct pipe_ctx *pipe_ctx, 3700 struct block_sequence_state *seq_state) 3701 { 3702 struct hubp *hubp = pipe_ctx->plane_res.hubp; 3703 struct mpcc_blnd_cfg blnd_cfg = {0}; 3704 bool per_pixel_alpha; 3705 int mpcc_id; 3706 struct mpcc *new_mpcc; 3707 struct mpc *mpc = dc->res_pool->mpc; 3708 struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); 3709 3710 if (!hubp || !pipe_ctx->plane_state) 3711 return; 3712 3713 per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha; 3714 3715 /* Initialize blend configuration */ 3716 blnd_cfg.overlap_only = false; 3717 blnd_cfg.global_gain = 0xff; 3718 3719 if (per_pixel_alpha) { 3720 blnd_cfg.pre_multiplied_alpha = pipe_ctx->plane_state->pre_multiplied_alpha; 3721 if (pipe_ctx->plane_state->global_alpha) { 3722 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN; 3723 blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value; 3724 } else { 3725 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; 3726 } 3727 } else { 3728 blnd_cfg.pre_multiplied_alpha = false; 3729 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; 3730 } 3731 3732 if (pipe_ctx->plane_state->global_alpha) 3733 blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value; 3734 else 3735 blnd_cfg.global_alpha = 0xff; 3736 3737 blnd_cfg.background_color_bpc = 4; 3738 blnd_cfg.bottom_gain_mode = 0; 3739 blnd_cfg.top_gain = 0x1f000; 3740 blnd_cfg.bottom_inside_gain = 0x1f000; 3741 blnd_cfg.bottom_outside_gain = 0x1f000; 3742 3743 if (pipe_ctx->plane_state->format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA) 3744 blnd_cfg.pre_multiplied_alpha = false; 3745 3746 /* MPCC instance is equal to HUBP instance */ 3747 mpcc_id = hubp->inst; 3748 3749 /* Step 1: Update blending if no full update needed */ 3750 if (!pipe_ctx->plane_state->update_flags.bits.full_update && 3751 !pipe_ctx->update_flags.bits.mpcc) { 3752 3753 /* Update blending configuration */ 3754 hwss_add_mpc_update_blending(seq_state, mpc, blnd_cfg, mpcc_id); 3755 3756 /* Update visual confirm color */ 3757 hwss_add_mpc_update_visual_confirm(seq_state, dc, pipe_ctx, mpcc_id); 3758 return; 3759 } 3760 3761 /* Step 2: Get existing MPCC for DPP */ 3762 new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id); 3763 3764 /* Step 3: Remove MPCC if being used */ 3765 if (new_mpcc != NULL) { 3766 hwss_add_mpc_remove_mpcc(seq_state, mpc, mpc_tree_params, new_mpcc); 3767 } else { 3768 /* Step 4: Assert MPCC idle (debug only) */ 3769 if (dc->debug.sanity_checks) 3770 hwss_add_mpc_assert_idle_mpcc(seq_state, mpc, mpcc_id); 3771 } 3772 3773 /* Step 5: Insert new plane into MPC tree */ 3774 hwss_add_mpc_insert_plane(seq_state, mpc, mpc_tree_params, blnd_cfg, NULL, NULL, hubp->inst, mpcc_id); 3775 3776 /* Step 6: Update visual confirm color */ 3777 hwss_add_mpc_update_visual_confirm(seq_state, dc, pipe_ctx, mpcc_id); 3778 3779 /* Step 7: Set HUBP OPP and MPCC IDs */ 3780 hubp->opp_id = pipe_ctx->stream_res.opp->inst; 3781 hubp->mpcc_id = mpcc_id; 3782 } 3783 3784 static struct hubp *get_hubp_by_inst(struct resource_pool *res_pool, int mpcc_inst) 3785 { 3786 int i; 3787 3788 for (i = 0; i < res_pool->pipe_count; i++) { 3789 if (res_pool->hubps[i]->inst == mpcc_inst) 3790 return res_pool->hubps[i]; 3791 } 3792 ASSERT(false); 3793 return NULL; 3794 } 3795 3796 void dcn401_wait_for_mpcc_disconnect_sequence( 3797 struct dc *dc, 3798 struct resource_pool *res_pool, 3799 struct pipe_ctx *pipe_ctx, 3800 struct block_sequence_state *seq_state) 3801 { 3802 int mpcc_inst; 3803 3804 if (dc->debug.sanity_checks) 3805 dc->hwseq->funcs.verify_allow_pstate_change_high_sequence(dc, seq_state); 3806 3807 if (!pipe_ctx->stream_res.opp) 3808 return; 3809 3810 for (mpcc_inst = 0; mpcc_inst < MAX_PIPES; mpcc_inst++) { 3811 if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) { 3812 struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst); 3813 3814 if (pipe_ctx->stream_res.tg && 3815 pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) { 3816 hwss_add_mpc_assert_idle_mpcc(seq_state, res_pool->mpc, mpcc_inst); 3817 } 3818 pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false; 3819 if (hubp) 3820 hwss_add_hubp_set_blank(seq_state, hubp, true); 3821 } 3822 } 3823 3824 if (dc->debug.sanity_checks) 3825 dc->hwseq->funcs.verify_allow_pstate_change_high_sequence(dc, seq_state); 3826 } 3827 3828 void dcn401_setup_vupdate_interrupt_sequence(struct dc *dc, struct pipe_ctx *pipe_ctx, 3829 struct block_sequence_state *seq_state) 3830 { 3831 struct timing_generator *tg = pipe_ctx->stream_res.tg; 3832 int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); 3833 3834 if (start_line < 0) 3835 start_line = 0; 3836 3837 if (tg->funcs->setup_vertical_interrupt2) 3838 hwss_add_tg_setup_vertical_interrupt2(seq_state, tg, start_line); 3839 } 3840 3841 void dcn401_set_hdr_multiplier_sequence(struct pipe_ctx *pipe_ctx, 3842 struct block_sequence_state *seq_state) 3843 { 3844 struct fixed31_32 multiplier = pipe_ctx->plane_state->hdr_mult; 3845 uint32_t hw_mult = 0x1f000; // 1.0 default multiplier 3846 struct custom_float_format fmt; 3847 3848 fmt.exponenta_bits = 6; 3849 fmt.mantissa_bits = 12; 3850 fmt.sign = true; 3851 3852 if (!dc_fixpt_eq(multiplier, dc_fixpt_from_int(0))) // check != 0 3853 convert_to_custom_float_format(multiplier, &fmt, &hw_mult); 3854 3855 hwss_add_dpp_set_hdr_multiplier(seq_state, pipe_ctx->plane_res.dpp, hw_mult); 3856 } 3857 3858 void dcn401_program_mall_pipe_config_sequence(struct dc *dc, struct dc_state *context, 3859 struct block_sequence_state *seq_state) 3860 { 3861 int i; 3862 unsigned int num_ways = dcn401_calculate_cab_allocation(dc, context); 3863 bool cache_cursor = false; 3864 3865 // Don't force p-state disallow -- can't block dummy p-state 3866 3867 // Update MALL_SEL register for each pipe (break down update_mall_sel call) 3868 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3869 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 3870 struct hubp *hubp = pipe->plane_res.hubp; 3871 3872 if (pipe->stream && pipe->plane_state && hubp && hubp->funcs->hubp_update_mall_sel) { 3873 int cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height; 3874 3875 switch (hubp->curs_attr.color_format) { 3876 case CURSOR_MODE_MONO: 3877 cursor_size /= 2; 3878 break; 3879 case CURSOR_MODE_COLOR_1BIT_AND: 3880 case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: 3881 case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: 3882 cursor_size *= 4; 3883 break; 3884 3885 case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: 3886 case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: 3887 default: 3888 cursor_size *= 8; 3889 break; 3890 } 3891 3892 if (cursor_size > 16384) 3893 cache_cursor = true; 3894 3895 if (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { 3896 hwss_add_hubp_update_mall_sel(seq_state, hubp, 1, false); 3897 } else { 3898 // MALL not supported with Stereo3D 3899 uint32_t mall_sel = (num_ways <= dc->caps.cache_num_ways && 3900 pipe->stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED && 3901 pipe->plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO && 3902 !pipe->plane_state->address.tmz_surface) ? 2 : 0; 3903 hwss_add_hubp_update_mall_sel(seq_state, hubp, mall_sel, cache_cursor); 3904 } 3905 } 3906 } 3907 3908 // Program FORCE_ONE_ROW_FOR_FRAME and CURSOR_REQ_MODE for main subvp pipes 3909 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3910 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 3911 struct hubp *hubp = pipe->plane_res.hubp; 3912 3913 if (pipe->stream && hubp && hubp->funcs->hubp_prepare_subvp_buffering) { 3914 if (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) 3915 hwss_add_hubp_prepare_subvp_buffering(seq_state, hubp, true); 3916 } 3917 } 3918 } 3919 3920 void dcn401_verify_allow_pstate_change_high_sequence(struct dc *dc, 3921 struct block_sequence_state *seq_state) 3922 { 3923 struct hubbub *hubbub = dc->res_pool->hubbub; 3924 3925 if (!hubbub->funcs->verify_allow_pstate_change_high) 3926 return; 3927 3928 if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) { 3929 /* Attempt hardware workaround force recovery */ 3930 dcn401_hw_wa_force_recovery_sequence(dc, seq_state); 3931 } 3932 } 3933 3934 bool dcn401_hw_wa_force_recovery_sequence(struct dc *dc, 3935 struct block_sequence_state *seq_state) 3936 { 3937 struct hubp *hubp; 3938 unsigned int i; 3939 3940 if (!dc->debug.recovery_enabled) 3941 return false; 3942 3943 /* Step 1: Set HUBP_BLANK_EN=1 for all active pipes */ 3944 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3945 struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; 3946 3947 if (pipe_ctx != NULL) { 3948 hubp = pipe_ctx->plane_res.hubp; 3949 if (hubp != NULL && hubp->funcs->set_hubp_blank_en) 3950 hwss_add_hubp_set_blank_en(seq_state, hubp, true); 3951 } 3952 } 3953 3954 /* Step 2: DCHUBBUB_GLOBAL_SOFT_RESET=1 */ 3955 hwss_add_hubbub_soft_reset(seq_state, dc->res_pool->hubbub, hubbub1_soft_reset, true); 3956 3957 /* Step 3: Set HUBP_DISABLE=1 for all active pipes */ 3958 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3959 struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; 3960 3961 if (pipe_ctx != NULL) { 3962 hubp = pipe_ctx->plane_res.hubp; 3963 if (hubp != NULL && hubp->funcs->hubp_disable_control) 3964 hwss_add_hubp_disable_control(seq_state, hubp, true); 3965 } 3966 } 3967 3968 /* Step 4: Set HUBP_DISABLE=0 for all active pipes */ 3969 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3970 struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; 3971 3972 if (pipe_ctx != NULL) { 3973 hubp = pipe_ctx->plane_res.hubp; 3974 if (hubp != NULL && hubp->funcs->hubp_disable_control) 3975 hwss_add_hubp_disable_control(seq_state, hubp, false); 3976 } 3977 } 3978 3979 /* Step 5: DCHUBBUB_GLOBAL_SOFT_RESET=0 */ 3980 hwss_add_hubbub_soft_reset(seq_state, dc->res_pool->hubbub, hubbub1_soft_reset, false); 3981 3982 /* Step 6: Set HUBP_BLANK_EN=0 for all active pipes */ 3983 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3984 struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; 3985 3986 if (pipe_ctx != NULL) { 3987 hubp = pipe_ctx->plane_res.hubp; 3988 if (hubp != NULL && hubp->funcs->set_hubp_blank_en) 3989 hwss_add_hubp_set_blank_en(seq_state, hubp, false); 3990 } 3991 } 3992 3993 return true; 3994 } 3995