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