1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2024 Advanced Micro Devices, Inc. 4 5 6 #include "dml2_internal_shared_types.h" 7 #include "dml21_translation_helper.h" 8 #include "dml2_internal_types.h" 9 #include "dml21_utils.h" 10 #include "dml2_dc_resource_mgmt.h" 11 12 #include "dml2_core_dcn4_calcs.h" 13 14 int dml21_helper_find_dml_pipe_idx_by_stream_id(struct dml2_context *ctx, unsigned int stream_id) 15 { 16 int i; 17 for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) { 18 if (ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id_valid[i] && ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id[i] == stream_id) 19 return i; 20 } 21 22 return -1; 23 } 24 25 int dml21_find_dml_pipe_idx_by_plane_id(struct dml2_context *ctx, unsigned int plane_id) 26 { 27 int i; 28 for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) { 29 if (ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id_valid[i] && ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id[i] == plane_id) 30 return i; 31 } 32 33 return -1; 34 } 35 36 bool dml21_get_plane_id(const struct dc_state *state, const struct dc_plane_state *plane, unsigned int *plane_id) 37 { 38 int i, j; 39 40 if (!plane_id) 41 return false; 42 43 for (i = 0; i < state->stream_count; i++) { 44 for (j = 0; j < state->stream_status[i].plane_count; j++) { 45 if (state->stream_status[i].plane_states[j] == plane) { 46 *plane_id = (i << 16) | j; 47 return true; 48 } 49 } 50 } 51 52 return false; 53 } 54 55 unsigned int dml21_get_dc_plane_idx_from_plane_id(unsigned int plane_id) 56 { 57 return 0xffff & plane_id; 58 } 59 60 void find_valid_pipe_idx_for_stream_index(const struct dml2_context *dml_ctx, unsigned int *dml_pipe_idx, unsigned int stream_index) 61 { 62 unsigned int i = 0; 63 64 for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) { 65 if (dml_ctx->v21.mode_programming.programming->plane_programming[i].plane_descriptor->stream_index == stream_index) { 66 *dml_pipe_idx = i; 67 return; 68 } 69 } 70 } 71 72 void find_pipe_regs_idx(const struct dml2_context *dml_ctx, 73 struct pipe_ctx *pipe, unsigned int *pipe_regs_idx) 74 { 75 struct pipe_ctx *opp_head = dml_ctx->config.callbacks.get_opp_head(pipe); 76 77 *pipe_regs_idx = dml_ctx->config.callbacks.get_odm_slice_index(opp_head); 78 79 if (pipe->plane_state) 80 *pipe_regs_idx += dml_ctx->config.callbacks.get_mpc_slice_index(pipe); 81 } 82 83 /* places pipe references into pipes arrays and returns number of pipes */ 84 int dml21_find_dc_pipes_for_plane(const struct dc *in_dc, 85 struct dc_state *context, 86 struct dml2_context *dml_ctx, 87 struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__], 88 struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__], 89 int dml_plane_idx) 90 { 91 (void)in_dc; 92 unsigned int dml_stream_index; 93 unsigned int main_stream_id; 94 unsigned int dc_plane_index; 95 struct dc_stream_state *dc_main_stream; 96 struct dc_stream_status *dc_main_stream_status; 97 struct dc_plane_state *dc_main_plane; 98 struct dc_stream_state *dc_phantom_stream; 99 struct dc_stream_status *dc_phantom_stream_status; 100 struct dc_plane_state *dc_phantom_plane; 101 int num_pipes = 0; 102 103 memset(dc_main_pipes, 0, sizeof(struct pipe_ctx *) * __DML2_WRAPPER_MAX_STREAMS_PLANES__); 104 memset(dc_phantom_pipes, 0, sizeof(struct pipe_ctx *) * __DML2_WRAPPER_MAX_STREAMS_PLANES__); 105 106 dml_stream_index = dml_ctx->v21.mode_programming.programming->plane_programming[dml_plane_idx].plane_descriptor->stream_index; 107 main_stream_id = dml_ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id[dml_stream_index]; 108 109 dc_main_stream = dml_ctx->config.callbacks.get_stream_from_id(context, main_stream_id); 110 dc_main_stream_status = dml_ctx->config.callbacks.get_stream_status(context, dc_main_stream); 111 if (!dc_main_stream_status) 112 return num_pipes; 113 114 /* find main plane based on id */ 115 dc_plane_index = dml21_get_dc_plane_idx_from_plane_id(dml_ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id[dml_plane_idx]); 116 dc_main_plane = dc_main_stream_status->plane_states[dc_plane_index]; 117 118 if (dc_main_plane) { 119 num_pipes = dml_ctx->config.callbacks.get_dpp_pipes_for_plane(dc_main_plane, &context->res_ctx, dc_main_pipes); 120 } else { 121 /* stream was configured with dummy plane, so get pipes from opp head */ 122 struct pipe_ctx *otg_master_pipe = dml_ctx->config.callbacks.get_otg_master_for_stream(&context->res_ctx, dc_main_stream); 123 if (otg_master_pipe != NULL) 124 num_pipes = dml_ctx->config.callbacks.get_opp_heads_for_otg_master(otg_master_pipe, &context->res_ctx, dc_main_pipes); 125 } 126 127 /* if phantom exists, find associated pipes */ 128 dc_phantom_stream = dml_ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, dc_main_stream); 129 if (dc_phantom_stream && num_pipes > 0) { 130 dc_phantom_stream_status = dml_ctx->config.callbacks.get_stream_status(context, dc_phantom_stream); 131 132 if (dc_phantom_stream_status) { 133 /* phantom plane will have same index as main */ 134 dc_phantom_plane = dc_phantom_stream_status->plane_states[dc_plane_index]; 135 136 if (dc_phantom_plane) { 137 /* only care about phantom pipes if they contain the phantom plane */ 138 dml_ctx->config.callbacks.get_dpp_pipes_for_plane(dc_phantom_plane, &context->res_ctx, dc_phantom_pipes); 139 } 140 } 141 } 142 143 return num_pipes; 144 } 145 146 void dml21_pipe_populate_global_sync(struct dml2_context *dml_ctx, 147 struct dc_state *context, 148 struct pipe_ctx *pipe_ctx, 149 struct dml2_per_stream_programming *stream_programming) 150 { 151 union dml2_global_sync_programming *global_sync = &stream_programming->global_sync; 152 153 if (dml_ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) { 154 /* phantom has its own global sync */ 155 global_sync = &stream_programming->phantom_stream.global_sync; 156 } 157 158 memcpy(&pipe_ctx->global_sync, 159 global_sync, 160 sizeof(union dml2_global_sync_programming)); 161 } 162 163 void dml21_populate_mall_allocation_size(struct dc_state *context, 164 struct dml2_context *in_ctx, 165 struct dml2_per_plane_programming *pln_prog, 166 struct pipe_ctx *dc_pipe) 167 { 168 169 /* Reuse MALL Allocation Sizes logic from dcn32_fpu.c */ 170 /* Count from active, top pipes per plane only. Only add mall_ss_size_bytes for each unique plane. */ 171 if (dc_pipe->stream && dc_pipe->plane_state && 172 (dc_pipe->top_pipe == NULL || 173 dc_pipe->plane_state != dc_pipe->top_pipe->plane_state) && 174 dc_pipe->prev_odm_pipe == NULL) { 175 /* SS: all active surfaces stored in MALL */ 176 if (in_ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, dc_pipe) != SUBVP_PHANTOM) { 177 dc_pipe->surface_size_in_mall_bytes = pln_prog->surface_size_mall_bytes; 178 context->bw_ctx.bw.dcn.mall_ss_size_bytes += dc_pipe->surface_size_in_mall_bytes; 179 } else { 180 /* SUBVP: phantom surfaces only stored in MALL */ 181 dc_pipe->surface_size_in_mall_bytes = pln_prog->svp_size_mall_bytes; 182 context->bw_ctx.bw.dcn.mall_subvp_size_bytes += dc_pipe->surface_size_in_mall_bytes; 183 } 184 } 185 } 186 187 bool check_dp2p0_output_encoder(const struct pipe_ctx *pipe_ctx) 188 { 189 /* If this assert is hit then we have a link encoder dynamic management issue */ 190 ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true); 191 return (pipe_ctx->stream_res.hpo_dp_stream_enc && 192 pipe_ctx->link_res.hpo_dp_link_enc && 193 dc_is_dp_signal(pipe_ctx->stream->signal)); 194 } 195 196 197 static bool is_sub_vp_enabled(struct dc *dc, struct dc_state *context) 198 { 199 int i; 200 201 for (i = 0; i < dc->res_pool->pipe_count; i++) { 202 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 203 204 if (pipe_ctx->stream && dc_state_get_paired_subvp_stream(context, pipe_ctx->stream) && 205 dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_MAIN) { 206 return true; 207 } 208 } 209 return false; 210 } 211 212 213 void dml21_program_dc_pipe(struct dml2_context *dml_ctx, struct dc_state *context, struct pipe_ctx *pipe_ctx, struct dml2_per_plane_programming *pln_prog, 214 struct dml2_per_stream_programming *stream_prog) 215 { 216 unsigned int pipe_reg_index = 0; 217 218 dml21_pipe_populate_global_sync(dml_ctx, context, pipe_ctx, stream_prog); 219 find_pipe_regs_idx(dml_ctx, pipe_ctx, &pipe_reg_index); 220 221 if (dml_ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) { 222 memcpy(&pipe_ctx->hubp_regs, pln_prog->phantom_plane.pipe_regs[pipe_reg_index], sizeof(struct dml2_dchub_per_pipe_register_set)); 223 pipe_ctx->unbounded_req = false; 224 pipe_ctx->det_buffer_size_kb = 0; 225 } else { 226 memcpy(&pipe_ctx->hubp_regs, pln_prog->pipe_regs[pipe_reg_index], sizeof(struct dml2_dchub_per_pipe_register_set)); 227 pipe_ctx->unbounded_req = pln_prog->pipe_regs[pipe_reg_index]->rq_regs.unbounded_request_enabled; 228 pipe_ctx->det_buffer_size_kb = pln_prog->pipe_regs[pipe_reg_index]->det_size * 64; 229 } 230 231 pipe_ctx->plane_res.bw.dppclk_khz = pln_prog->min_clocks.dcn4x.dppclk_khz; 232 if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipe_ctx->plane_res.bw.dppclk_khz) 233 context->bw_ctx.bw.dcn.clk.dppclk_khz = pipe_ctx->plane_res.bw.dppclk_khz; 234 235 dml21_populate_mall_allocation_size(context, dml_ctx, pln_prog, pipe_ctx); 236 237 bool sub_vp_enabled = is_sub_vp_enabled(pipe_ctx->stream->ctx->dc, context); 238 239 dml21_set_dc_p_state_type(pipe_ctx, stream_prog, sub_vp_enabled); 240 } 241 242 static struct dc_stream_state *dml21_add_phantom_stream(struct dml2_context *dml_ctx, 243 const struct dc *dc, 244 struct dc_state *context, 245 struct dc_stream_state *main_stream, 246 struct dml2_per_stream_programming *stream_programming) 247 { 248 struct dc_stream_state *phantom_stream; 249 struct dml2_stream_parameters *phantom_stream_descriptor = &stream_programming->phantom_stream.descriptor; 250 251 phantom_stream = dml_ctx->config.svp_pstate.callbacks.create_phantom_stream(dc, context, main_stream); 252 if (!phantom_stream) 253 return NULL; 254 255 /* copy details of phantom stream from main */ 256 memcpy(&phantom_stream->timing, &main_stream->timing, sizeof(phantom_stream->timing)); 257 memcpy(&phantom_stream->src, &main_stream->src, sizeof(phantom_stream->src)); 258 memcpy(&phantom_stream->dst, &main_stream->dst, sizeof(phantom_stream->dst)); 259 260 /* modify timing for phantom */ 261 phantom_stream->timing.v_front_porch = phantom_stream_descriptor->timing.v_front_porch; 262 phantom_stream->timing.v_addressable = phantom_stream_descriptor->timing.v_active; 263 phantom_stream->timing.v_total = phantom_stream_descriptor->timing.v_total; 264 phantom_stream->timing.flags.DSC = 0; // phantom always has DSC disabled 265 266 phantom_stream->dst.y = 0; 267 phantom_stream->dst.height = stream_programming->phantom_stream.descriptor.timing.v_active; 268 269 phantom_stream->src.y = 0; 270 phantom_stream->src.height = (int)((double)phantom_stream_descriptor->timing.v_active * (double)main_stream->src.height / (double)main_stream->dst.height); 271 272 phantom_stream->use_dynamic_meta = false; 273 274 dml_ctx->config.svp_pstate.callbacks.add_phantom_stream(dc, context, phantom_stream, main_stream); 275 276 return phantom_stream; 277 } 278 279 static struct dc_plane_state *dml21_add_phantom_plane(struct dml2_context *dml_ctx, 280 const struct dc *dc, 281 struct dc_state *context, 282 struct dc_stream_state *phantom_stream, 283 struct dc_plane_state *main_plane, 284 struct dml2_per_plane_programming *plane_programming) 285 { 286 (void)plane_programming; 287 struct dc_plane_state *phantom_plane; 288 289 phantom_plane = dml_ctx->config.svp_pstate.callbacks.create_phantom_plane(dc, context, main_plane); 290 if (!phantom_plane) 291 return NULL; 292 293 phantom_plane->format = main_plane->format; 294 phantom_plane->rotation = main_plane->rotation; 295 phantom_plane->visible = main_plane->visible; 296 297 memcpy(&phantom_plane->address, &main_plane->address, sizeof(phantom_plane->address)); 298 memcpy(&phantom_plane->scaling_quality, &main_plane->scaling_quality, 299 sizeof(phantom_plane->scaling_quality)); 300 memcpy(&phantom_plane->src_rect, &main_plane->src_rect, sizeof(phantom_plane->src_rect)); 301 memcpy(&phantom_plane->dst_rect, &main_plane->dst_rect, sizeof(phantom_plane->dst_rect)); 302 memcpy(&phantom_plane->clip_rect, &main_plane->clip_rect, sizeof(phantom_plane->clip_rect)); 303 memcpy(&phantom_plane->plane_size, &main_plane->plane_size, 304 sizeof(phantom_plane->plane_size)); 305 memcpy(&phantom_plane->tiling_info, &main_plane->tiling_info, 306 sizeof(phantom_plane->tiling_info)); 307 memcpy(&phantom_plane->dcc, &main_plane->dcc, sizeof(phantom_plane->dcc)); 308 309 phantom_plane->format = main_plane->format; 310 phantom_plane->rotation = main_plane->rotation; 311 phantom_plane->visible = main_plane->visible; 312 313 /* Shadow pipe has small viewport. */ 314 phantom_plane->clip_rect.y = 0; 315 phantom_plane->clip_rect.height = phantom_stream->src.height; 316 317 dml_ctx->config.svp_pstate.callbacks.add_phantom_plane(dc, phantom_stream, phantom_plane, context); 318 319 return phantom_plane; 320 } 321 322 void dml21_handle_phantom_streams_planes(const struct dc *dc, struct dc_state *context, struct dml2_context *dml_ctx) 323 { 324 unsigned int dml_stream_index, dml_plane_index, dc_plane_index; 325 struct dc_stream_state *main_stream; 326 struct dc_stream_status *main_stream_status; 327 struct dc_stream_state *phantom_stream; 328 struct dc_plane_state *main_plane; 329 bool phantoms_added = false; 330 331 /* create phantom streams and planes and add to context */ 332 for (dml_stream_index = 0; dml_stream_index < dml_ctx->v21.mode_programming.programming->display_config.num_streams; dml_stream_index++) { 333 /* iterate through DML streams looking for phantoms */ 334 if (dml_ctx->v21.mode_programming.programming->stream_programming[dml_stream_index].phantom_stream.enabled) { 335 /* find associated dc stream */ 336 main_stream = dml_ctx->config.callbacks.get_stream_from_id(context, 337 dml_ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id[dml_stream_index]); 338 339 main_stream_status = dml_ctx->config.callbacks.get_stream_status(context, main_stream); 340 341 if (!main_stream_status || main_stream_status->plane_count == 0) 342 continue; 343 344 /* create phantom stream for subvp enabled stream */ 345 phantom_stream = dml21_add_phantom_stream(dml_ctx, 346 dc, 347 context, 348 main_stream, 349 &dml_ctx->v21.mode_programming.programming->stream_programming[dml_stream_index]); 350 351 if (!phantom_stream) 352 continue; 353 354 /* iterate through DML planes associated with this stream */ 355 for (dml_plane_index = 0; dml_plane_index < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_plane_index++) { 356 if (dml_ctx->v21.mode_programming.programming->plane_programming[dml_plane_index].plane_descriptor->stream_index == dml_stream_index) { 357 /* find associated dc plane */ 358 dc_plane_index = dml21_get_dc_plane_idx_from_plane_id(dml_ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id[dml_plane_index]); 359 main_plane = main_stream_status->plane_states[dc_plane_index]; 360 361 /* create phantom planes for subvp enabled plane */ 362 dml21_add_phantom_plane(dml_ctx, 363 dc, 364 context, 365 phantom_stream, 366 main_plane, 367 &dml_ctx->v21.mode_programming.programming->plane_programming[dml_plane_index]); 368 369 phantoms_added = true; 370 } 371 } 372 } 373 } 374 375 if (phantoms_added) 376 dml2_map_dc_pipes(dml_ctx, context, NULL, &dml_ctx->v21.dml_to_dc_pipe_mapping, dc->current_state); 377 } 378 379 380 static unsigned int dml21_build_fams2_stream_programming_v2(const struct dc *dc, 381 struct dc_state *context, 382 struct dml2_context *dml_ctx) 383 { 384 int dc_stream_idx, dc_plane_idx, dc_pipe_idx; 385 unsigned int num_fams2_streams = 0; 386 387 for (dc_stream_idx = 0; dc_stream_idx < context->stream_count; dc_stream_idx++) { 388 int dml_stream_idx; 389 struct dc_stream_state *phantom_stream; 390 struct dc_stream_status *phantom_status; 391 enum fams2_stream_type type = 0; 392 393 union dmub_cmd_fams2_config *static_base_state = &context->bw_ctx.bw.dcn.fams2_stream_base_params[num_fams2_streams]; 394 union dmub_cmd_fams2_config *static_sub_state = &context->bw_ctx.bw.dcn.fams2_stream_sub_params[num_fams2_streams]; 395 396 struct dc_stream_state *stream = context->streams[dc_stream_idx]; 397 398 if (context->stream_status[dc_stream_idx].plane_count == 0 || 399 dml_ctx->config.svp_pstate.callbacks.get_stream_subvp_type(context, stream) == SUBVP_PHANTOM) { 400 /* can ignore blanked or phantom streams */ 401 continue; 402 } 403 404 dml_stream_idx = dml21_helper_find_dml_pipe_idx_by_stream_id(dml_ctx, stream->stream_id); 405 if (dml_stream_idx < 0) { 406 ASSERT(dml_stream_idx >= 0); 407 continue; 408 } 409 410 /* copy static state from PMO */ 411 memcpy(static_base_state, 412 &dml_ctx->v21.mode_programming.programming->stream_programming[dml_stream_idx].fams2_base_params, 413 sizeof(union dmub_cmd_fams2_config)); 414 415 memcpy(static_sub_state, 416 &dml_ctx->v21.mode_programming.programming->stream_programming[dml_stream_idx].fams2_sub_params, 417 sizeof(union dmub_cmd_fams2_config)); 418 419 switch (dc->debug.fams_version.minor) { 420 case 1: 421 default: 422 type = static_base_state->stream_v1.base.type; 423 424 /* get information from context */ 425 ASSERT(context->stream_status[dc_stream_idx].plane_count >= 0 && 426 context->stream_status[dc_stream_idx].plane_count <= 0xFF); 427 ASSERT(context->stream_status[dc_stream_idx].primary_otg_inst >= 0 && 428 context->stream_status[dc_stream_idx].primary_otg_inst <= 0xFF); 429 static_base_state->stream_v1.base.num_planes = (uint8_t)context->stream_status[dc_stream_idx].plane_count; 430 static_base_state->stream_v1.base.otg_inst = (uint8_t)context->stream_status[dc_stream_idx].primary_otg_inst; 431 432 /* populate pipe masks for planes */ 433 for (dc_plane_idx = 0; dc_plane_idx < context->stream_status[dc_stream_idx].plane_count; dc_plane_idx++) { 434 for (dc_pipe_idx = 0; dc_pipe_idx < dc->res_pool->pipe_count; dc_pipe_idx++) { 435 if (context->res_ctx.pipe_ctx[dc_pipe_idx].stream && 436 context->res_ctx.pipe_ctx[dc_pipe_idx].stream->stream_id == stream->stream_id && 437 context->res_ctx.pipe_ctx[dc_pipe_idx].plane_state == context->stream_status[dc_stream_idx].plane_states[dc_plane_idx]) { 438 static_base_state->stream_v1.base.pipe_mask |= (1 << dc_pipe_idx); 439 static_base_state->stream_v1.base.plane_pipe_masks[dc_plane_idx] |= (1 << dc_pipe_idx); 440 } 441 } 442 } 443 } 444 445 446 /* get per method programming */ 447 switch (type) { 448 case FAMS2_STREAM_TYPE_VBLANK: 449 case FAMS2_STREAM_TYPE_VACTIVE: 450 case FAMS2_STREAM_TYPE_DRR: 451 break; 452 case FAMS2_STREAM_TYPE_SUBVP: 453 phantom_stream = dml_ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, stream); 454 if (!phantom_stream) 455 break; 456 457 phantom_status = dml_ctx->config.callbacks.get_stream_status(context, phantom_stream); 458 459 /* phantom status should always be present */ 460 ASSERT(phantom_status); 461 if (!phantom_status) 462 break; 463 464 switch (dc->debug.fams_version.minor) { 465 case 1: 466 default: 467 ASSERT(phantom_status->primary_otg_inst >= 0 && 468 phantom_status->primary_otg_inst <= 0xFF); 469 static_sub_state->stream_v1.sub_state.subvp.phantom_otg_inst = (uint8_t)phantom_status->primary_otg_inst; 470 471 /* populate pipe masks for phantom planes */ 472 for (dc_plane_idx = 0; dc_plane_idx < phantom_status->plane_count; dc_plane_idx++) { 473 for (dc_pipe_idx = 0; dc_pipe_idx < dc->res_pool->pipe_count; dc_pipe_idx++) { 474 if (context->res_ctx.pipe_ctx[dc_pipe_idx].stream && 475 context->res_ctx.pipe_ctx[dc_pipe_idx].stream->stream_id == phantom_stream->stream_id && 476 context->res_ctx.pipe_ctx[dc_pipe_idx].plane_state == phantom_status->plane_states[dc_plane_idx]) { 477 switch (dc->debug.fams_version.minor) { 478 case 1: 479 default: 480 static_sub_state->stream_v1.sub_state.subvp.phantom_pipe_mask |= (1 << dc_pipe_idx); 481 static_sub_state->stream_v1.sub_state.subvp.phantom_plane_pipe_masks[dc_plane_idx] |= (1 << dc_pipe_idx); 482 } 483 } 484 } 485 } 486 } 487 break; 488 default: 489 ASSERT(false); 490 break; 491 } 492 493 num_fams2_streams++; 494 } 495 496 return num_fams2_streams; 497 } 498 499 void dml21_build_fams2_programming(const struct dc *dc, 500 struct dc_state *context, 501 struct dml2_context *dml_ctx) 502 { 503 unsigned int num_fams2_streams = 0; 504 505 /* reset fams2 data */ 506 memset(&context->bw_ctx.bw.dcn.fams2_stream_base_params, 0, sizeof(union dmub_cmd_fams2_config) * DML2_MAX_PLANES); 507 memset(&context->bw_ctx.bw.dcn.fams2_stream_sub_params, 0, sizeof(union dmub_cmd_fams2_config) * DML2_MAX_PLANES); 508 memset(&context->bw_ctx.bw.dcn.fams2_stream_sub_params_v2, 0, sizeof(union dmub_fams2_stream_static_sub_state_v2) * DML2_MAX_PLANES); 509 memset(&context->bw_ctx.bw.dcn.fams2_global_config, 0, sizeof(struct dmub_cmd_fams2_global_config)); 510 511 if (dml_ctx->v21.mode_programming.programming->fams2_required || 512 dml_ctx->v21.mode_programming.programming->legacy_pstate_info_for_dmu) { 513 if (dc->debug.fams_version.major == 2) { 514 num_fams2_streams = dml21_build_fams2_stream_programming_v2(dc, context, dml_ctx); 515 } 516 } 517 518 if (num_fams2_streams > 0) { 519 /* copy FAMS2 configuration */ 520 memcpy(&context->bw_ctx.bw.dcn.fams2_global_config, 521 &dml_ctx->v21.mode_programming.programming->fams2_global_config, 522 sizeof(struct dmub_cmd_fams2_global_config)); 523 524 context->bw_ctx.bw.dcn.fams2_global_config.num_streams = num_fams2_streams; 525 } 526 527 context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = 528 (context->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable != 0); 529 } 530 531 bool dml21_is_plane1_enabled(enum dml2_source_format_class source_format) 532 { 533 return source_format >= dml2_420_8 && source_format <= dml2_rgbe_alpha; 534 } 535