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