FILE
dcn30_hwseq.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
1/* 2 * Copyright 2020 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 27#include "dm_services.h" 28#include "dm_helpers.h" 29#include "core_types.h" 30#include "resource.h" 31#include "dcn30_hwseq.h" 32#include "dccg.h" 33#include "dce/dce_hwseq.h" 34#include "dcn30/dcn30_mpc.h" 35#include "dcn30/dcn30_dpp.h" 36#include "dcn10/dcn10_cm_common.h" 37#include "dcn30/dcn30_cm_common.h" 38#include "reg_helper.h" 39#include "abm.h" 40#include "clk_mgr.h" 41#include "hubp.h" 42#include "dchubbub.h" 43#include "timing_generator.h" 44#include "opp.h" 45#include "ipp.h" 46#include "mpc.h" 47#include "mcif_wb.h" 48#include "dc_dmub_srv.h" 49#include "link_hwss.h" 50#include "dpcd_defs.h" 51#include "dcn20/dcn20_hwseq.h" 52#include "dcn30/dcn30_resource.h" 53#include "link_service.h" 54#include "dc_state_priv.h" 55 56#define TO_DCN_DCCG(dccg)\ 57 container_of(dccg, struct dcn_dccg, base) 58 59#define DC_LOGGER_INIT(logger) 60 61#define CTX \ 62 hws->ctx 63#define REG(reg)\ 64 hws->regs->reg 65#define DC_LOGGER \ 66 dc->ctx->logger 67 68 69#undef FN 70#define FN(reg_name, field_name) \ 71 hws->shifts->field_name, hws->masks->field_name 72 73void dcn30_log_color_state(struct dc *dc, 74 struct dc_log_buffer_ctx *log_ctx) 75{ 76 struct dc_context *dc_ctx = dc->ctx; 77 struct resource_pool *pool = dc->res_pool; 78 bool is_gamut_remap_available = false; 79 int i; 80 81 DTN_INFO("DPP: DGAM ROM DGAM ROM type DGAM LUT SHAPER mode" 82 " 3DLUT mode 3DLUT bit depth 3DLUT size RGAM mode" 83 " GAMUT adjust " 84 "C11 C12 C13 C14 " 85 "C21 C22 C23 C24 " 86 "C31 C32 C33 C34 \n"); 87 88 for (i = 0; i < pool->pipe_count; i++) { 89 struct dpp *dpp = pool->dpps[i]; 90 struct dcn_dpp_state s = {0}; 91 92 dpp->funcs->dpp_read_state(dpp, &s); 93 94 if (dpp->funcs->dpp_get_gamut_remap) { 95 dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap); 96 is_gamut_remap_available = true; 97 } 98 99 if (!s.is_enabled) 100 continue; 101 102 DTN_INFO("[%2d]: %7x %13s %8s %11s %10s %15s %10s %9s", 103 dpp->inst, 104 s.pre_dgam_mode, 105 (s.pre_dgam_select == 0) ? "sRGB" : 106 ((s.pre_dgam_select == 1) ? "Gamma 2.2" : 107 ((s.pre_dgam_select == 2) ? "Gamma 2.4" : 108 ((s.pre_dgam_select == 3) ? "Gamma 2.6" : 109 ((s.pre_dgam_select == 4) ? "BT.709" : 110 ((s.pre_dgam_select == 5) ? "PQ" : 111 ((s.pre_dgam_select == 6) ? "HLG" : 112 "Unknown")))))), 113 (s.gamcor_mode == 0) ? "Bypass" : 114 ((s.gamcor_mode == 1) ? "RAM A" : 115 "RAM B"), 116 (s.shaper_lut_mode == 1) ? "RAM A" : 117 ((s.shaper_lut_mode == 2) ? "RAM B" : 118 "Bypass"), 119 (s.lut3d_mode == 1) ? "RAM A" : 120 ((s.lut3d_mode == 2) ? "RAM B" : 121 "Bypass"), 122 (s.lut3d_bit_depth <= 0) ? "12-bit" : "10-bit", 123 (s.lut3d_size == 0) ? "17x17x17" : "9x9x9", 124 (s.rgam_lut_mode == 0) ? "Bypass" : 125 ((s.rgam_lut_mode == 1) ? "RAM A" : 126 "RAM B")); 127 128 if (is_gamut_remap_available) { 129 DTN_INFO(" %12s " 130 "%010lld %010lld %010lld %010lld " 131 "%010lld %010lld %010lld %010lld " 132 "%010lld %010lld %010lld %010lld", 133 134 (s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" : 135 ((s.gamut_remap.gamut_adjust_type == 1) ? "HW" : 136 "SW"), 137 s.gamut_remap.temperature_matrix[0].value, 138 s.gamut_remap.temperature_matrix[1].value, 139 s.gamut_remap.temperature_matrix[2].value, 140 s.gamut_remap.temperature_matrix[3].value, 141 s.gamut_remap.temperature_matrix[4].value, 142 s.gamut_remap.temperature_matrix[5].value, 143 s.gamut_remap.temperature_matrix[6].value, 144 s.gamut_remap.temperature_matrix[7].value, 145 s.gamut_remap.temperature_matrix[8].value, 146 s.gamut_remap.temperature_matrix[9].value, 147 s.gamut_remap.temperature_matrix[10].value, 148 s.gamut_remap.temperature_matrix[11].value); 149 } 150 151 DTN_INFO("\n"); 152 } 153 DTN_INFO("\n"); 154 DTN_INFO("DPP Color Caps: input_lut_shared:%d icsc:%d" 155 " dgam_ram:%d dgam_rom: srgb:%d,bt2020:%d,gamma2_2:%d,pq:%d,hlg:%d" 156 " post_csc:%d gamcor:%d dgam_rom_for_yuv:%d 3d_lut:%d" 157 " blnd_lut:%d oscs:%d\n\n", 158 dc->caps.color.dpp.input_lut_shared, 159 dc->caps.color.dpp.icsc, 160 dc->caps.color.dpp.dgam_ram, 161 dc->caps.color.dpp.dgam_rom_caps.srgb, 162 dc->caps.color.dpp.dgam_rom_caps.bt2020, 163 dc->caps.color.dpp.dgam_rom_caps.gamma2_2, 164 dc->caps.color.dpp.dgam_rom_caps.pq, 165 dc->caps.color.dpp.dgam_rom_caps.hlg, 166 dc->caps.color.dpp.post_csc, 167 dc->caps.color.dpp.gamma_corr, 168 dc->caps.color.dpp.dgam_rom_for_yuv, 169 dc->caps.color.dpp.hw_3d_lut, 170 dc->caps.color.dpp.ogam_ram, 171 dc->caps.color.dpp.ocsc); 172 173 DTN_INFO("MPCC: OPP DPP MPCCBOT MODE ALPHA_MODE PREMULT OVERLAP_ONLY IDLE" 174 " SHAPER mode 3DLUT mode 3DLUT bit-depth 3DLUT size OGAM mode OGAM LUT" 175 " GAMUT adjust " 176 "C11 C12 C13 C14 " 177 "C21 C22 C23 C24 " 178 "C31 C32 C33 C34 \n"); 179 180 for (i = 0; i < pool->mpcc_count; i++) { 181 struct mpcc_state s = {0}; 182 183 pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s); 184 mpc3_get_gamut_remap(pool->mpc, i, &s.gamut_remap); 185 186 if (s.opp_id != 0xf) 187 DTN_INFO("[%2d]: %2xh %2xh %6xh %4d %10d %7d %12d %4d %11s %11s %16s %11s %10s %9s" 188 " %-12s " 189 "%010lld %010lld %010lld %010lld " 190 "%010lld %010lld %010lld %010lld " 191 "%010lld %010lld %010lld %010lld\n", 192 i, s.opp_id, s.dpp_id, s.bot_mpcc_id, 193 s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only, 194 s.idle, 195 (s.shaper_lut_mode == 1) ? "RAM A" : 196 ((s.shaper_lut_mode == 2) ? "RAM B" : 197 "Bypass"), 198 (s.lut3d_mode == 1) ? "RAM A" : 199 ((s.lut3d_mode == 2) ? "RAM B" : 200 "Bypass"), 201 (s.lut3d_bit_depth <= 0) ? "12-bit" : "10-bit", 202 (s.lut3d_size == 0) ? "17x17x17" : "9x9x9", 203 (s.rgam_mode == 0) ? "Bypass" : 204 ((s.rgam_mode == 2) ? "RAM" : 205 "Unknown"), 206 (s.rgam_mode == 1) ? "B" : "A", 207 (s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" : 208 ((s.gamut_remap.gamut_adjust_type == 1) ? "HW" : 209 "SW"), 210 s.gamut_remap.temperature_matrix[0].value, 211 s.gamut_remap.temperature_matrix[1].value, 212 s.gamut_remap.temperature_matrix[2].value, 213 s.gamut_remap.temperature_matrix[3].value, 214 s.gamut_remap.temperature_matrix[4].value, 215 s.gamut_remap.temperature_matrix[5].value, 216 s.gamut_remap.temperature_matrix[6].value, 217 s.gamut_remap.temperature_matrix[7].value, 218 s.gamut_remap.temperature_matrix[8].value, 219 s.gamut_remap.temperature_matrix[9].value, 220 s.gamut_remap.temperature_matrix[10].value, 221 s.gamut_remap.temperature_matrix[11].value); 222 223 } 224 DTN_INFO("\n"); 225 DTN_INFO("MPC Color Caps: gamut_remap:%d, 3dlut:%d, ogam_ram:%d, ocsc:%d\n\n", 226 dc->caps.color.mpc.gamut_remap, 227 dc->caps.color.mpc.num_3dluts, 228 dc->caps.color.mpc.ogam_ram, 229 dc->caps.color.mpc.ocsc); 230} 231 232bool dcn30_set_blend_lut( 233 struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) 234{ 235 struct dpp *dpp_base = pipe_ctx->plane_res.dpp; 236 bool result = true; 237 const struct pwl_params *blend_lut = NULL; 238 239 if (plane_state->blend_tf.type == TF_TYPE_HWPWL) 240 blend_lut = &plane_state->blend_tf.pwl; 241 else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) { 242 result = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, 243 &plane_state->blend_tf, &dpp_base->regamma_params, false); 244 if (!result) 245 return result; 246 247 blend_lut = &dpp_base->regamma_params; 248 } 249 result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut); 250 251 return result; 252} 253 254static bool dcn30_set_mpc_shaper_3dlut(struct pipe_ctx *pipe_ctx, 255 const struct dc_stream_state *stream) 256{ 257 struct dpp *dpp_base = pipe_ctx->plane_res.dpp; 258 int mpcc_id = pipe_ctx->plane_res.hubp->inst; 259 struct dc *dc = pipe_ctx->stream->ctx->dc; 260 struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; 261 bool result = false; 262 int acquired_rmu = 0; 263 int mpcc_id_projected = 0; 264 265 const struct pwl_params *shaper_lut = NULL; 266 //get the shaper lut params 267 if (stream->func_shaper) { 268 if (stream->func_shaper->type == TF_TYPE_HWPWL) { 269 shaper_lut = &stream->func_shaper->pwl; 270 } else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) { 271 cm_helper_translate_curve_to_hw_format(stream->ctx, stream->func_shaper, 272 &dpp_base->shaper_params, true); 273 shaper_lut = &dpp_base->shaper_params; 274 } 275 } 276 277 if (stream->lut3d_func && 278 stream->lut3d_func->state.bits.initialized == 1 && 279 stream->lut3d_func->state.bits.rmu_idx_valid == 1) { 280 if (stream->lut3d_func->state.bits.rmu_mux_num == 0) 281 mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu0_mux; 282 else if (stream->lut3d_func->state.bits.rmu_mux_num == 1) 283 mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu1_mux; 284 else if (stream->lut3d_func->state.bits.rmu_mux_num == 2) 285 mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu2_mux; 286 if (mpcc_id_projected != mpcc_id) 287 BREAK_TO_DEBUGGER(); 288 /* find the reason why logical layer assigned a different 289 * mpcc_id into acquire_post_bldn_3dlut 290 */ 291 acquired_rmu = mpc->funcs->acquire_rmu(mpc, mpcc_id, 292 stream->lut3d_func->state.bits.rmu_mux_num); 293 if (acquired_rmu != stream->lut3d_func->state.bits.rmu_mux_num) 294 BREAK_TO_DEBUGGER(); 295 296 result = mpc->funcs->program_3dlut(mpc, &stream->lut3d_func->lut_3d, 297 stream->lut3d_func->state.bits.rmu_mux_num); 298 if (!result) 299 DC_LOG_ERROR("%s: program_3dlut failed\n", __func__); 300 301 result = mpc->funcs->program_shaper(mpc, shaper_lut, 302 stream->lut3d_func->state.bits.rmu_mux_num); 303 if (!result) 304 DC_LOG_ERROR("%s: program_shaper failed\n", __func__); 305 306 } else { 307 // loop through the available mux and release the requested mpcc_id 308 mpc->funcs->release_rmu(mpc, mpcc_id); 309 } 310 311 return result; 312} 313 314bool dcn30_set_input_transfer_func(struct dc *dc, 315 struct pipe_ctx *pipe_ctx, 316 const struct dc_plane_state *plane_state) 317{ 318 struct dce_hwseq *hws = dc->hwseq; 319 struct dpp *dpp_base = pipe_ctx->plane_res.dpp; 320 enum dc_transfer_func_predefined tf; 321 bool result = true; 322 const struct pwl_params *params = NULL; 323 324 if (dpp_base == NULL || plane_state == NULL) 325 return false; 326 327 tf = TRANSFER_FUNCTION_UNITY; 328 329 if (plane_state->in_transfer_func.type == TF_TYPE_PREDEFINED) 330 tf = plane_state->in_transfer_func.tf; 331 332 dpp_base->funcs->dpp_set_pre_degam(dpp_base, tf); 333 334 if (plane_state->in_transfer_func.type == TF_TYPE_HWPWL) 335 params = &plane_state->in_transfer_func.pwl; 336 else if (plane_state->in_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS && 337 cm3_helper_translate_curve_to_hw_format(plane_state->ctx, 338 &plane_state->in_transfer_func, 339 &dpp_base->degamma_params, false)) 340 params = &dpp_base->degamma_params; 341 342 result = dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params); 343 344 if (pipe_ctx->stream_res.opp && pipe_ctx->stream_res.opp->ctx) { 345 if (dpp_base->funcs->dpp_program_blnd_lut) 346 hws->funcs.set_blend_lut(pipe_ctx, plane_state); 347 if (dpp_base->funcs->dpp_program_shaper_lut && 348 dpp_base->funcs->dpp_program_3dlut) 349 hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state); 350 } 351 352 return result; 353} 354 355void dcn30_program_gamut_remap(struct pipe_ctx *pipe_ctx) 356{ 357 int i = 0; 358 struct dpp_grph_csc_adjustment dpp_adjust; 359 struct mpc_grph_gamut_adjustment mpc_adjust; 360 int mpcc_id = pipe_ctx->plane_res.hubp->inst; 361 struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; 362 363 memset(&dpp_adjust, 0, sizeof(dpp_adjust)); 364 dpp_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; 365 366 if (pipe_ctx->plane_state && 367 pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) { 368 dpp_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; 369 for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) 370 dpp_adjust.temperature_matrix[i] = 371 pipe_ctx->plane_state->gamut_remap_matrix.matrix[i]; 372 } 373 374 pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, 375 &dpp_adjust); 376 377 memset(&mpc_adjust, 0, sizeof(mpc_adjust)); 378 mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; 379 380 if (pipe_ctx->top_pipe == NULL) { 381 if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { 382 mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; 383 for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) 384 mpc_adjust.temperature_matrix[i] = 385 pipe_ctx->stream->gamut_remap_matrix.matrix[i]; 386 } 387 } 388 389 mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust); 390} 391 392bool dcn30_set_output_transfer_func(struct dc *dc, 393 struct pipe_ctx *pipe_ctx, 394 const struct dc_stream_state *stream) 395{ 396 int mpcc_id = pipe_ctx->plane_res.hubp->inst; 397 struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; 398 const struct pwl_params *params = NULL; 399 bool ret = false; 400 401 /* program OGAM or 3DLUT only for the top pipe*/ 402 if (pipe_ctx->top_pipe == NULL) { 403 /*program rmu shaper and 3dlut in MPC*/ 404 ret = dcn30_set_mpc_shaper_3dlut(pipe_ctx, stream); 405 if (ret == false && mpc->funcs->set_output_gamma) { 406 if (stream->out_transfer_func.type == TF_TYPE_HWPWL) 407 params = &stream->out_transfer_func.pwl; 408 else if (pipe_ctx->stream->out_transfer_func.type == 409 TF_TYPE_DISTRIBUTED_POINTS && 410 cm3_helper_translate_curve_to_hw_format(stream->ctx, 411 &stream->out_transfer_func, 412 &mpc->blender_params, false)) 413 params = &mpc->blender_params; 414 /* there are no ROM LUTs in OUTGAM */ 415 if (stream->out_transfer_func.type == TF_TYPE_PREDEFINED) 416 BREAK_TO_DEBUGGER(); 417 } 418 } 419 420 if (mpc->funcs->set_output_gamma) 421 mpc->funcs->set_output_gamma(mpc, mpcc_id, params); 422 else 423 DC_LOG_ERROR("%s: set_output_gamma function pointer is NULL.\n", __func__); 424 425 return ret; 426} 427 428static void dcn30_set_writeback( 429 struct dc *dc, 430 struct dc_writeback_info *wb_info, 431 struct dc_state *context) 432{ 433 struct mcif_wb *mcif_wb; 434 struct mcif_buf_params *mcif_buf_params; 435 436 ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES); 437 ASSERT(wb_info->wb_enabled); 438 ASSERT(wb_info->mpcc_inst >= 0); 439 ASSERT(wb_info->mpcc_inst < dc->res_pool->mpcc_count); 440 mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst]; 441 mcif_buf_params = &wb_info->mcif_buf_params; 442 443 /* set DWB MPC mux */ 444 dc->res_pool->mpc->funcs->set_dwb_mux(dc->res_pool->mpc, 445 wb_info->dwb_pipe_inst, wb_info->mpcc_inst); 446 /* set MCIF_WB buffer and arbitration configuration */ 447 mcif_wb->funcs->config_mcif_buf(mcif_wb, mcif_buf_params, wb_info->dwb_params.dest_height); 448 mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]); 449} 450 451void dcn30_update_writeback( 452 struct dc *dc, 453 struct dc_writeback_info *wb_info, 454 struct dc_state *context) 455{ 456 struct dwbc *dwb; 457 dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; 458 DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\ 459 __func__, wb_info->dwb_pipe_inst,\ 460 wb_info->mpcc_inst); 461 462 dcn30_set_writeback(dc, wb_info, context); 463 464 /* update DWB */ 465 dwb->funcs->update(dwb, &wb_info->dwb_params); 466} 467 468bool dcn30_mmhubbub_warmup( 469 struct dc *dc, 470 unsigned int num_dwb, 471 struct dc_writeback_info *wb_info) 472{ 473 struct dwbc *dwb; 474 struct mcif_wb *mcif_wb; 475 struct mcif_warmup_params warmup_params = {0}; 476 unsigned int i, i_buf; 477 /* make sure there is no active DWB enabled */ 478 for (i = 0; i < num_dwb; i++) { 479 dwb = dc->res_pool->dwbc[wb_info[i].dwb_pipe_inst]; 480 if (dwb->dwb_is_efc_transition || dwb->dwb_is_drc) { 481 /*can not do warmup while any dwb enabled*/ 482 return false; 483 } 484 } 485 486 if (wb_info->mcif_warmup_params.p_vmid == 0) 487 return false; 488 489 /*check whether this is new interface: warmup big buffer once*/ 490 if (wb_info->mcif_warmup_params.start_address.quad_part != 0 && 491 wb_info->mcif_warmup_params.region_size != 0) { 492 /*mmhubbub is shared, so it does not matter which MCIF*/ 493 mcif_wb = dc->res_pool->mcif_wb[0]; 494 /*warmup a big chunk of VM buffer at once*/ 495 warmup_params.start_address.quad_part = wb_info->mcif_warmup_params.start_address.quad_part; 496 warmup_params.address_increment = wb_info->mcif_warmup_params.region_size; 497 warmup_params.region_size = wb_info->mcif_warmup_params.region_size; 498 warmup_params.p_vmid = wb_info->mcif_warmup_params.p_vmid; 499 500 if (warmup_params.address_increment == 0) 501 warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes; 502 503 mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params); 504 return true; 505 } 506 /*following is the original: warmup each DWB's mcif buffer*/ 507 for (i = 0; i < num_dwb; i++) { 508 mcif_wb = dc->res_pool->mcif_wb[wb_info[i].dwb_pipe_inst]; 509 /*warmup is for VM mode only*/ 510 if (wb_info[i].mcif_buf_params.p_vmid == 0) 511 return false; 512 513 /* Warmup MCIF_WB */ 514 for (i_buf = 0; i_buf < MCIF_BUF_COUNT; i_buf++) { 515 warmup_params.start_address.quad_part = wb_info[i].mcif_buf_params.luma_address[i_buf]; 516 warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes; 517 warmup_params.region_size = wb_info[i].mcif_buf_params.luma_pitch * wb_info[i].dwb_params.dest_height; 518 warmup_params.p_vmid = wb_info[i].mcif_buf_params.p_vmid; 519 mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params); 520 } 521 } 522 return true; 523} 524 525void dcn30_enable_writeback( 526 struct dc *dc, 527 struct dc_writeback_info *wb_info, 528 struct dc_state *context) 529{ 530 struct dwbc *dwb; 531 struct mcif_wb *mcif_wb; 532 533 dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; 534 mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst]; 535 536 DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\ 537 __func__, wb_info->dwb_pipe_inst,\ 538 wb_info->mpcc_inst); 539 540 /* Warmup interface */ 541 dcn30_mmhubbub_warmup(dc, 1, wb_info); 542 543 /* Update writeback pipe */ 544 dcn30_set_writeback(dc, wb_info, context); 545 546 /* Enable MCIF_WB */ 547 mcif_wb->funcs->enable_mcif(mcif_wb); 548 /* Enable DWB */ 549 dwb->funcs->enable(dwb, &wb_info->dwb_params); 550} 551 552void dcn30_disable_writeback( 553 struct dc *dc, 554 unsigned int dwb_pipe_inst) 555{ 556 struct dwbc *dwb; 557 struct mcif_wb *mcif_wb; 558 559 ASSERT(dwb_pipe_inst < MAX_DWB_PIPES); 560 dwb = dc->res_pool->dwbc[dwb_pipe_inst]; 561 mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst]; 562 DC_LOG_DWB("%s dwb_pipe_inst = %d",\ 563 __func__, dwb_pipe_inst); 564 565 /* disable DWB */ 566 dwb->funcs->disable(dwb); 567 /* disable MCIF */ 568 mcif_wb->funcs->disable_mcif(mcif_wb); 569 /* disable MPC DWB mux */ 570 dc->res_pool->mpc->funcs->disable_dwb_mux(dc->res_pool->mpc, dwb_pipe_inst); 571} 572 573void dcn30_program_all_writeback_pipes_in_tree( 574 struct dc *dc, 575 const struct dc_stream_state *stream, 576 struct dc_state *context) 577{ 578 struct dc_writeback_info wb_info; 579 struct dwbc *dwb; 580 struct dc_stream_status *stream_status = NULL; 581 int i_wb, i_pipe, i_stream; 582 DC_LOG_DWB("%s", __func__); 583 584 ASSERT(stream); 585 for (i_stream = 0; i_stream < context->stream_count; i_stream++) { 586 if (context->streams[i_stream] == stream) { 587 stream_status = &context->stream_status[i_stream]; 588 break; 589 } 590 } 591 ASSERT(stream_status); 592 593 ASSERT(stream->num_wb_info <= dc->res_pool->res_cap->num_dwb); 594 /* For each writeback pipe */ 595 for (i_wb = 0; i_wb < stream->num_wb_info; i_wb++) { 596 597 /* copy writeback info to local non-const so mpcc_inst can be set */ 598 wb_info = stream->writeback_info[i_wb]; 599 if (wb_info.wb_enabled) { 600 601 /* get the MPCC instance for writeback_source_plane */ 602 wb_info.mpcc_inst = -1; 603 for (i_pipe = 0; i_pipe < dc->res_pool->pipe_count; i_pipe++) { 604 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i_pipe]; 605 606 if (!pipe_ctx->plane_state) 607 continue; 608 609 if (pipe_ctx->plane_state == wb_info.writeback_source_plane) { 610 wb_info.mpcc_inst = pipe_ctx->plane_res.mpcc_inst; 611 break; 612 } 613 } 614 615 if (wb_info.mpcc_inst == -1) { 616 /* Disable writeback pipe and disconnect from MPCC 617 * if source plane has been removed 618 */ 619 dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst); 620 continue; 621 } 622 623 ASSERT(wb_info.dwb_pipe_inst < dc->res_pool->res_cap->num_dwb); 624 dwb = dc->res_pool->dwbc[wb_info.dwb_pipe_inst]; 625 if (dwb->funcs->is_enabled(dwb)) { 626 /* writeback pipe already enabled, only need to update */ 627 dc->hwss.update_writeback(dc, &wb_info, context); 628 } else { 629 /* Enable writeback pipe and connect to MPCC */ 630 dc->hwss.enable_writeback(dc, &wb_info, context); 631 } 632 } else { 633 /* Disable writeback pipe and disconnect from MPCC */ 634 dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst); 635 } 636 } 637} 638 639void dcn30_init_hw(struct dc *dc) 640{ 641 struct abm **abms = dc->res_pool->multiple_abms; 642 struct dce_hwseq *hws = dc->hwseq; 643 struct dc_bios *dcb = dc->ctx->dc_bios; 644 struct resource_pool *res_pool = dc->res_pool; 645 int i; 646 int edp_num; 647 uint32_t backlight = MAX_BACKLIGHT_LEVEL; 648 uint32_t user_level = MAX_BACKLIGHT_LEVEL; 649 650 if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) 651 dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); 652 653 // Initialize the dccg 654 if (res_pool->dccg->funcs->dccg_init) 655 res_pool->dccg->funcs->dccg_init(res_pool->dccg); 656 657 if (!dcb->funcs->is_accelerated_mode(dcb)) { 658 hws->funcs.bios_golden_init(dc); 659 hws->funcs.disable_vga(dc->hwseq); 660 } 661 662 if (dc->debug.enable_mem_low_power.bits.dmcu) { 663 // Force ERAM to shutdown if DMCU is not enabled 664 if (dc->debug.disable_dmcu || dc->config.disable_dmcu) { 665 REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3); 666 } 667 } 668 669 // Set default OPTC memory power states 670 if (dc->debug.enable_mem_low_power.bits.optc) { 671 // Shutdown when unassigned and light sleep in VBLANK 672 REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1); 673 } 674 675 if (dc->debug.enable_mem_low_power.bits.vga) { 676 // Power down VGA memory 677 REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); 678 } 679 680 if (dc->ctx->dc_bios->fw_info_valid) { 681 res_pool->ref_clocks.xtalin_clock_inKhz = 682 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; 683 684 if (res_pool->hubbub) { 685 686 (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, 687 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, 688 &res_pool->ref_clocks.dccg_ref_clock_inKhz); 689 690 (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, 691 res_pool->ref_clocks.dccg_ref_clock_inKhz, 692 &res_pool->ref_clocks.dchub_ref_clock_inKhz); 693 } else { 694 // Not all ASICs have DCCG sw component 695 res_pool->ref_clocks.dccg_ref_clock_inKhz = 696 res_pool->ref_clocks.xtalin_clock_inKhz; 697 res_pool->ref_clocks.dchub_ref_clock_inKhz = 698 res_pool->ref_clocks.xtalin_clock_inKhz; 699 } 700 } else 701 ASSERT_CRITICAL(false); 702 703 for (i = 0; i < dc->link_count; i++) { 704 /* Power up AND update implementation according to the 705 * required signal (which may be different from the 706 * default signal on connector). 707 */ 708 struct dc_link *link = dc->links[i]; 709 710 link->link_enc->funcs->hw_init(link->link_enc); 711 712 /* Check for enabled DIG to identify enabled display */ 713 if (link->link_enc->funcs->is_dig_enabled && 714 link->link_enc->funcs->is_dig_enabled(link->link_enc)) { 715 link->link_status.link_active = true; 716 if (link->link_enc->funcs->fec_is_active && 717 link->link_enc->funcs->fec_is_active(link->link_enc)) 718 link->fec_state = dc_link_fec_enabled; 719 } 720 } 721 722 /* we want to turn off all dp displays before doing detection */ 723 dc->link_srv->blank_all_dp_displays(dc); 724 725 if (hws->funcs.enable_power_gating_plane) 726 hws->funcs.enable_power_gating_plane(dc->hwseq, true); 727 728 /* If taking control over from VBIOS, we may want to optimize our first 729 * mode set, so we need to skip powering down pipes until we know which 730 * pipes we want to use. 731 * Otherwise, if taking control is not possible, we need to power 732 * everything down. 733 */ 734 if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { 735 hws->funcs.init_pipes(dc, dc->current_state); 736 if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) 737 dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, 738 !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); 739 } 740 741 /* In headless boot cases, DIG may be turned 742 * on which causes HW/SW discrepancies. 743 * To avoid this, power down hardware on boot 744 * if DIG is turned on and seamless boot not enabled 745 */ 746 if (!dc->config.seamless_boot_edp_requested) { 747 struct dc_link *edp_links[MAX_NUM_EDP]; 748 struct dc_link *edp_link = NULL; 749 750 dc_get_edp_links(dc, edp_links, &edp_num); 751 if (edp_num) 752 edp_link = edp_links[0]; 753 if (edp_link && edp_link->link_enc->funcs->is_dig_enabled && 754 edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && 755 dc->hwss.edp_backlight_control && 756 hws->funcs.power_down && 757 dc->hwss.edp_power_control) { 758 dc->hwss.edp_backlight_control(edp_link, false); 759 hws->funcs.power_down(dc); 760 dc->hwss.edp_power_control(edp_link, false); 761 } else { 762 for (i = 0; i < dc->link_count; i++) { 763 struct dc_link *link = dc->links[i]; 764 765 if (link->link_enc->funcs->is_dig_enabled && 766 link->link_enc->funcs->is_dig_enabled(link->link_enc) && 767 hws->funcs.power_down) { 768 hws->funcs.power_down(dc); 769 break; 770 } 771 772 } 773 } 774 } 775 776 for (i = 0; i < res_pool->audio_count; i++) { 777 struct audio *audio = res_pool->audios[i]; 778 779 audio->funcs->hw_init(audio); 780 } 781 782 for (i = 0; i < dc->link_count; i++) { 783 struct dc_link *link = dc->links[i]; 784 785 if (link->panel_cntl) { 786 backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); 787 user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL; 788 } 789 } 790 791 for (i = 0; i < dc->res_pool->pipe_count; i++) { 792 if (abms[i] != NULL) 793 abms[i]->funcs->abm_init(abms[i], backlight, user_level); 794 } 795 796 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ 797 REG_WRITE(DIO_MEM_PWR_CTRL, 0); 798 799 if (!dc->debug.disable_clock_gate) { 800 /* enable all DCN clock gating */ 801 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); 802 803 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); 804 805 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); 806 } 807 808 if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) 809 dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); 810 811 if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges) 812 dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); 813 814 //if softmax is enabled then hardmax will be set by a different call 815 if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->set_hard_max_memclk && 816 !dc->clk_mgr->dc_mode_softmax_enabled) 817 dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); 818 819 if (dc->res_pool->hubbub->funcs->force_pstate_change_control) 820 dc->res_pool->hubbub->funcs->force_pstate_change_control( 821 dc->res_pool->hubbub, false, false); 822 if (dc->res_pool->hubbub->funcs->init_crb) 823 dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); 824 825 // Get DMCUB capabilities 826 dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv); 827 dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; 828 dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver; 829} 830 831void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) 832{ 833 if (pipe_ctx == NULL) 834 return; 835 836 if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.stream_enc != NULL) { 837 pipe_ctx->stream_res.stream_enc->funcs->set_avmute( 838 pipe_ctx->stream_res.stream_enc, 839 enable); 840 841 /* Wait for two frame to make sure AV mute is sent out */ 842 if (enable && pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) { 843 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); 844 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); 845 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); 846 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); 847 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); 848 } 849 } 850} 851 852void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx) 853{ 854 bool is_hdmi_tmds; 855 bool is_dp; 856 857 ASSERT(pipe_ctx->stream); 858 859 if (pipe_ctx->stream_res.stream_enc == NULL) 860 return; /* this is not root pipe */ 861 862 is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal); 863 is_dp = dc_is_dp_signal(pipe_ctx->stream->signal); 864 865 if (!is_hdmi_tmds && !is_dp) 866 return; 867 868 if (is_hdmi_tmds) 869 pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets( 870 pipe_ctx->stream_res.stream_enc, 871 &pipe_ctx->stream_res.encoder_info_frame); 872 else { 873 if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num) 874 pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num( 875 pipe_ctx->stream_res.stream_enc, 876 &pipe_ctx->stream_res.encoder_info_frame); 877 878 pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets( 879 pipe_ctx->stream_res.stream_enc, 880 &pipe_ctx->stream_res.encoder_info_frame); 881 } 882} 883 884void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx) 885{ 886 struct dc_stream_state *stream = pipe_ctx->stream; 887 struct hubp *hubp = pipe_ctx->plane_res.hubp; 888 bool enable = false; 889 struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; 890 enum dynamic_metadata_mode mode = dc_is_dp_signal(stream->signal) 891 ? dmdata_dp 892 : dmdata_hdmi; 893 894 /* if using dynamic meta, don't set up generic infopackets */ 895 if (pipe_ctx->stream->dmdata_address.quad_part != 0) { 896 pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false; 897 enable = true; 898 } 899 900 if (!hubp) 901 return; 902 903 if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata) 904 return; 905 906 stream_enc->funcs->set_dynamic_metadata(stream_enc, enable, 907 hubp->inst, mode); 908} 909 910bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable) 911{ 912 union dmub_rb_cmd cmd; 913 uint32_t tmr_delay = 0, tmr_scale = 0; 914 struct dc_cursor_attributes cursor_attr = {0}; 915 bool cursor_cache_enable = false; 916 struct dc_stream_state *stream = NULL; 917 struct dc_plane_state *plane = NULL; 918 919 if (!dc->ctx->dmub_srv) 920 return false; 921 922 if (enable) { 923 if (dc->current_state) { 924 int i; 925 926 /* First, check no-memory-requests case */ 927 for (i = 0; i < dc->current_state->stream_count; i++) { 928 if (dc->current_state->stream_status[i].plane_count) 929 /* Fail eligibility on a visible stream */ 930 break; 931 } 932 933 if (i == dc->current_state->stream_count) { 934 /* Enable no-memory-requests case */ 935 memset(&cmd, 0, sizeof(cmd)); 936 cmd.mall.header.type = DMUB_CMD__MALL; 937 cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_NO_DF_REQ; 938 cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header); 939 940 dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); 941 942 return true; 943 } 944 945 stream = dc->current_state->streams[0]; 946 plane = (stream ? dc->current_state->stream_status[0].plane_states[0] : NULL); 947 948 if (!stream || !plane) 949 return false; 950 951 if (stream && plane) { 952 cursor_cache_enable = stream->cursor_position.enable && 953 plane->address.grph.cursor_cache_addr.quad_part; 954 cursor_attr = stream->cursor_attributes; 955 } 956 957 /* 958 * Second, check MALL eligibility 959 * 960 * single display only, single surface only, 8 and 16 bit formats only, no VM, 961 * do not use MALL for displays that support PSR as they use D0i3.2 in DMCUB FW 962 * 963 * TODO: When we implement multi-display, PSR displays will be allowed if there is 964 * a non-PSR display present, since in that case we can't do D0i3.2 965 */ 966 if (dc->current_state->stream_count == 1 && 967 stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED && 968 dc->current_state->stream_status[0].plane_count == 1 && 969 plane->format <= SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F && 970 plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB8888 && 971 plane->address.page_table_base.quad_part == 0 && 972 dc->hwss.does_plane_fit_in_mall && 973 dc->hwss.does_plane_fit_in_mall(dc, plane->plane_size.surface_pitch, 974 plane->plane_size.surface_size.height, plane->format, 975 cursor_cache_enable ? &cursor_attr : NULL)) { 976 unsigned int v_total = stream->adjust.v_total_max ? 977 stream->adjust.v_total_max : stream->timing.v_total; 978 unsigned int refresh_hz = div_u64((unsigned long long) stream->timing.pix_clk_100hz * 979 100LL, (v_total * stream->timing.h_total)); 980 981 /* 982 * one frame time in microsec: 983 * Delay_Us = 1000000 / refresh 984 * dynamic_delay_us = 1000000 / refresh + 2 * stutter_period 985 * 986 * one frame time modified by 'additional timer percent' (p): 987 * Delay_Us_modified = dynamic_delay_us + dynamic_delay_us * p / 100 988 * = dynamic_delay_us * (1 + p / 100) 989 * = (1000000 / refresh + 2 * stutter_period) * (100 + p) / 100 990 * = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh) 991 * 992 * formula for timer duration based on parameters, from regspec: 993 * dynamic_delay_us = 65.28 * (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale 994 * 995 * dynamic_delay_us / 65.28 = (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale 996 * (dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale = 64 + MallFrameCacheTmrDly 997 * MallFrameCacheTmrDly = ((dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale) - 64 998 * = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh) / 65.28 / 2^MallFrameCacheTmrScale - 64 999 * = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (refresh * 6528 * 2^MallFrameCacheTmrScale) - 64 1000 * 1001 * need to round up the result of the division before the subtraction 1002 */ 1003 unsigned int denom = refresh_hz * 6528; 1004 unsigned int stutter_period = dc->current_state->perf_params.stutter_period_us; 1005 1006 tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) * 1007 (100LL + dc->debug.mall_additional_timer_percent) + denom - 1), 1008 denom) - 64LL; 1009 1010 /* In some cases the stutter period is really big (tiny modes) in these 1011 * cases MALL cant be enabled, So skip these cases to avoid a ASSERT() 1012 * 1013 * We can check if stutter_period is more than 1/10th the frame time to 1014 * consider if we can actually meet the range of hysteresis timer 1015 */ 1016 if (stutter_period > 100000/refresh_hz) 1017 return false; 1018 1019 /* scale should be increased until it fits into 6 bits */ 1020 while (tmr_delay & ~0x3F) { 1021 tmr_scale++; 1022 1023 if (tmr_scale > 3) { 1024 /* Delay exceeds range of hysteresis timer */ 1025 ASSERT(false); 1026 return false; 1027 } 1028 1029 denom *= 2; 1030 tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) * 1031 (100LL + dc->debug.mall_additional_timer_percent) + denom - 1), 1032 denom) - 64LL; 1033 } 1034 1035 /* Copy HW cursor */ 1036 if (cursor_cache_enable) { 1037 memset(&cmd, 0, sizeof(cmd)); 1038 cmd.mall.header.type = DMUB_CMD__MALL; 1039 cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_COPY_CURSOR; 1040 cmd.mall.header.payload_bytes = 1041 sizeof(cmd.mall) - sizeof(cmd.mall.header); 1042 1043 switch (cursor_attr.color_format) { 1044 case CURSOR_MODE_MONO: 1045 cmd.mall.cursor_bpp = 2; 1046 break; 1047 case CURSOR_MODE_COLOR_1BIT_AND: 1048 case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: 1049 case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: 1050 cmd.mall.cursor_bpp = 32; 1051 break; 1052 1053 case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: 1054 case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: 1055 cmd.mall.cursor_bpp = 64; 1056 break; 1057 } 1058 1059 cmd.mall.cursor_copy_src.quad_part = cursor_attr.address.quad_part; 1060 cmd.mall.cursor_copy_dst.quad_part = 1061 (plane->address.grph.cursor_cache_addr.quad_part + 2047) & ~2047; 1062 cmd.mall.cursor_width = cursor_attr.width; 1063 cmd.mall.cursor_height = cursor_attr.height; 1064 cmd.mall.cursor_pitch = cursor_attr.pitch; 1065 1066 dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 1067 1068 /* Use copied cursor, and it's okay to not switch back */ 1069 cursor_attr.address.quad_part = cmd.mall.cursor_copy_dst.quad_part; 1070 dc_stream_program_cursor_attributes(stream, &cursor_attr); 1071 } 1072 1073 /* Enable MALL */ 1074 memset(&cmd, 0, sizeof(cmd)); 1075 cmd.mall.header.type = DMUB_CMD__MALL; 1076 cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_ALLOW; 1077 cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header); 1078 cmd.mall.tmr_delay = tmr_delay; 1079 cmd.mall.tmr_scale = tmr_scale; 1080 cmd.mall.debug_bits = dc->debug.mall_error_as_fatal; 1081 1082 dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); 1083 1084 return true; 1085 } 1086 } 1087 1088 /* No applicable optimizations */ 1089 return false; 1090 } 1091 1092 /* Disable MALL */ 1093 memset(&cmd, 0, sizeof(cmd)); 1094 cmd.mall.header.type = DMUB_CMD__MALL; 1095 cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_DISALLOW; 1096 cmd.mall.header.payload_bytes = 1097 sizeof(cmd.mall) - sizeof(cmd.mall.header); 1098 1099 dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 1100 1101 return true; 1102} 1103 1104bool dcn30_does_plane_fit_in_mall(struct dc *dc, 1105 unsigned int pitch, 1106 unsigned int height, 1107 enum surface_pixel_format format, 1108 struct dc_cursor_attributes *cursor_attr) 1109{ 1110 // add meta size? 1111 unsigned int surface_size = pitch * height * 1112 (format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4); 1113 unsigned int mall_size = dc->caps.mall_size_total; 1114 unsigned int cursor_size = 0; 1115 1116 if (dc->debug.mall_size_override) 1117 mall_size = 1024 * 1024 * dc->debug.mall_size_override; 1118 1119 if (cursor_attr) { 1120 cursor_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size; 1121 1122 switch (cursor_attr->color_format) { 1123 case CURSOR_MODE_MONO: 1124 cursor_size /= 2; 1125 break; 1126 case CURSOR_MODE_COLOR_1BIT_AND: 1127 case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: 1128 case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: 1129 cursor_size *= 4; 1130 break; 1131 1132 case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: 1133 case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: 1134 cursor_size *= 8; 1135 break; 1136 } 1137 } 1138 1139 return (surface_size + cursor_size) < mall_size; 1140} 1141 1142void dcn30_hardware_release(struct dc *dc) 1143{ 1144 bool subvp_in_use = false; 1145 uint32_t i; 1146 1147 dc_dmub_srv_p_state_delegate(dc, false, NULL); 1148 dc_dmub_setup_subvp_dmub_command(dc, dc->current_state, false); 1149 1150 /* SubVP treated the same way as FPO. If driver disable and 1151 * we are using a SubVP config, disable and force on DCN side 1152 * to prevent P-State hang on driver enable. 1153 */ 1154 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1155 struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; 1156 1157 if (!pipe->stream) 1158 continue; 1159 1160 if (dc_state_get_pipe_subvp_type(dc->current_state, pipe) == SUBVP_MAIN) { 1161 subvp_in_use = true; 1162 break; 1163 } 1164 } 1165 /* If pstate unsupported, or still supported 1166 * by firmware, force it supported by dcn 1167 */ 1168 if (dc->current_state) 1169 if ((!dc->clk_mgr->clks.p_state_change_support || subvp_in_use || 1170 dc->current_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) && 1171 dc->res_pool->hubbub->funcs->force_pstate_change_control) 1172 dc->res_pool->hubbub->funcs->force_pstate_change_control( 1173 dc->res_pool->hubbub, true, true); 1174} 1175 1176void dcn30_set_disp_pattern_generator(const struct dc *dc, 1177 struct pipe_ctx *pipe_ctx, 1178 enum controller_dp_test_pattern test_pattern, 1179 enum controller_dp_color_space color_space, 1180 enum dc_color_depth color_depth, 1181 const struct tg_color *solid_color, 1182 int width, int height, int offset) 1183{ 1184 pipe_ctx->stream_res.opp->funcs->opp_set_disp_pattern_generator(pipe_ctx->stream_res.opp, test_pattern, 1185 color_space, color_depth, solid_color, width, height, offset); 1186} 1187 1188void dcn30_prepare_bandwidth(struct dc *dc, 1189 struct dc_state *context) 1190{ 1191 if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching && !dc->clk_mgr->clks.fw_based_mclk_switching) { 1192 dc->optimized_required = true; 1193 context->bw_ctx.bw.dcn.clk.p_state_change_support = false; 1194 } 1195 1196 if (dc->clk_mgr->dc_mode_softmax_enabled) 1197 if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 && 1198 context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000) 1199 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); 1200 1201 dcn20_prepare_bandwidth(dc, context); 1202 1203 if (!dc->clk_mgr->clks.fw_based_mclk_switching) 1204 dc_dmub_srv_p_state_delegate(dc, false, context); 1205} 1206 1207void dcn30_wait_for_all_pending_updates(const struct pipe_ctx *pipe_ctx) 1208{ 1209 struct timing_generator *tg = pipe_ctx->stream_res.tg; 1210 bool pending_updates = false; 1211 unsigned int i; 1212 1213 if (tg && tg->funcs->is_tg_enabled(tg)) { 1214 // Poll for 100ms maximum 1215 for (i = 0; i < 100000; i++) { 1216 pending_updates = false; 1217 if (tg->funcs->get_optc_double_buffer_pending) 1218 pending_updates |= tg->funcs->get_optc_double_buffer_pending(tg); 1219 1220 if (tg->funcs->get_otg_double_buffer_pending) 1221 pending_updates |= tg->funcs->get_otg_double_buffer_pending(tg); 1222 1223 if (tg->funcs->get_pipe_update_pending && pipe_ctx->plane_state) 1224 pending_updates |= tg->funcs->get_pipe_update_pending(tg); 1225 1226 if (!pending_updates) 1227 break; 1228 1229 udelay(1); 1230 } 1231 } 1232} 1233 1234void dcn30_get_underflow_debug_data(const struct dc *dc, 1235 struct timing_generator *tg, 1236 struct dc_underflow_debug_data *out_data) 1237{ 1238 struct hubbub *hubbub = dc->res_pool->hubbub; 1239 1240 if (hubbub) { 1241 if (hubbub->funcs->hubbub_read_reg_state) { 1242 hubbub->funcs->hubbub_read_reg_state(hubbub, out_data->hubbub_reg_state); 1243 } 1244 } 1245 1246 for (int i = 0; i < MAX_PIPES; i++) { 1247 struct hubp *hubp = dc->res_pool->hubps[i]; 1248 struct dpp *dpp = dc->res_pool->dpps[i]; 1249 struct output_pixel_processor *opp = dc->res_pool->opps[i]; 1250 struct display_stream_compressor *dsc = dc->res_pool->dscs[i]; 1251 struct mpc *mpc = dc->res_pool->mpc; 1252 struct timing_generator *optc = dc->res_pool->timing_generators[i]; 1253 struct dccg *dccg = dc->res_pool->dccg; 1254 1255 if (hubp) 1256 if (hubp->funcs->hubp_read_reg_state) 1257 hubp->funcs->hubp_read_reg_state(hubp, out_data->hubp_reg_state[i]); 1258 1259 if (dpp) 1260 if (dpp->funcs->dpp_read_reg_state) 1261 dpp->funcs->dpp_read_reg_state(dpp, out_data->dpp_reg_state[i]); 1262 1263 if (opp) 1264 if (opp->funcs->opp_read_reg_state) 1265 opp->funcs->opp_read_reg_state(opp, out_data->opp_reg_state[i]); 1266 1267 if (dsc) 1268 if (dsc->funcs->dsc_read_reg_state) 1269 dsc->funcs->dsc_read_reg_state(dsc, out_data->dsc_reg_state[i]); 1270 1271 if (mpc) 1272 if (mpc->funcs->mpc_read_reg_state) 1273 mpc->funcs->mpc_read_reg_state(mpc, i, out_data->mpc_reg_state[i]); 1274 1275 if (optc) 1276 if (optc->funcs->optc_read_reg_state) 1277 optc->funcs->optc_read_reg_state(optc, out_data->optc_reg_state[i]); 1278 1279 if (dccg) 1280 if (dccg->funcs->dccg_read_reg_state) 1281 dccg->funcs->dccg_read_reg_state(dccg, out_data->dccg_reg_state[i]); 1282 } 1283}
~/
Read-only file preview.