FILE
dml2_dc_resource_mgmt.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_dc_resource_mgmt.c
1/* SPDX-License-Identifier: MIT */ 2/* 3 * Copyright 2023 Advanced Micro Devices, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 * OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: AMD 24 * 25 */ 26 27#include "dml2_mall_phantom.h" 28 29#include "dml2_dc_types.h" 30#include "dml2_internal_types.h" 31#include "dml2_utils.h" 32#include "dml2_dc_resource_mgmt.h" 33 34#define MAX_ODM_FACTOR 4 35#define MAX_MPCC_FACTOR 4 36 37struct dc_plane_pipe_pool { 38 int pipes_assigned_to_plane[MAX_ODM_FACTOR][MAX_MPCC_FACTOR]; 39 bool pipe_used[MAX_ODM_FACTOR][MAX_MPCC_FACTOR]; 40 int num_pipes_assigned_to_plane_for_mpcc_combine; 41 int num_pipes_assigned_to_plane_for_odm_combine; 42}; 43 44struct dc_pipe_mapping_scratch { 45 struct { 46 unsigned int odm_factor; 47 unsigned int odm_slice_end_x[MAX_PIPES]; 48 struct pipe_ctx *next_higher_pipe_for_odm_slice[MAX_PIPES]; 49 } odm_info; 50 struct { 51 unsigned int mpc_factor; 52 struct pipe_ctx *prev_odm_pipe; 53 } mpc_info; 54 55 struct dc_plane_pipe_pool pipe_pool; 56}; 57 58static bool get_plane_id(struct dml2_context *dml2, const struct dc_state *state, const struct dc_plane_state *plane, 59 unsigned int stream_id, unsigned int plane_index, unsigned int *plane_id) 60{ 61 int i, j; 62 bool is_plane_duplicate = dml2->v20.scratch.plane_duplicate_exists; 63 64 if (!plane_id) 65 return false; 66 67 for (i = 0; i < state->stream_count; i++) { 68 if (state->streams[i]->stream_id == stream_id) { 69 for (j = 0; j < state->stream_status[i].plane_count; j++) { 70 if (state->stream_status[i].plane_states[j] == plane && 71 (!is_plane_duplicate || (j == plane_index))) { 72 *plane_id = (i << 16) | j; 73 return true; 74 } 75 } 76 } 77 } 78 79 return false; 80} 81 82static int find_disp_cfg_idx_by_plane_id(struct dml2_dml_to_dc_pipe_mapping *mapping, unsigned int plane_id) 83{ 84 int i; 85 86 for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) { 87 if (mapping->disp_cfg_to_plane_id_valid[i] && mapping->disp_cfg_to_plane_id[i] == plane_id) 88 return i; 89 } 90 91 ASSERT(false); 92 return __DML2_WRAPPER_MAX_STREAMS_PLANES__; 93} 94 95static int find_disp_cfg_idx_by_stream_id(struct dml2_dml_to_dc_pipe_mapping *mapping, unsigned int stream_id) 96{ 97 int i; 98 99 for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) { 100 if (mapping->disp_cfg_to_stream_id_valid[i] && mapping->disp_cfg_to_stream_id[i] == stream_id) 101 return i; 102 } 103 104 ASSERT(false); 105 return __DML2_WRAPPER_MAX_STREAMS_PLANES__; 106} 107 108// The master pipe of a stream is defined as the top pipe in odm slice 0 109static struct pipe_ctx *find_master_pipe_of_stream(struct dml2_context *ctx, struct dc_state *state, unsigned int stream_id) 110{ 111 int i; 112 113 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 114 if (state->res_ctx.pipe_ctx[i].stream && state->res_ctx.pipe_ctx[i].stream->stream_id == stream_id) { 115 if (!state->res_ctx.pipe_ctx[i].prev_odm_pipe && !state->res_ctx.pipe_ctx[i].top_pipe) 116 return &state->res_ctx.pipe_ctx[i]; 117 } 118 } 119 120 return NULL; 121} 122 123static struct pipe_ctx *find_master_pipe_of_plane(struct dml2_context *ctx, 124 struct dc_state *state, unsigned int plane_id) 125{ 126 int i; 127 unsigned int plane_id_assigned_to_pipe; 128 129 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 130 if (state->res_ctx.pipe_ctx[i].plane_state && get_plane_id(ctx, state, state->res_ctx.pipe_ctx[i].plane_state, 131 state->res_ctx.pipe_ctx[i].stream->stream_id, 132 ctx->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_index[state->res_ctx.pipe_ctx[i].pipe_idx], &plane_id_assigned_to_pipe)) { 133 if (plane_id_assigned_to_pipe == plane_id) 134 return &state->res_ctx.pipe_ctx[i]; 135 } 136 } 137 138 return NULL; 139} 140 141static unsigned int find_pipes_assigned_to_plane(struct dml2_context *ctx, 142 struct dc_state *state, unsigned int plane_id, unsigned int *pipes) 143{ 144 int i; 145 unsigned int num_found = 0; 146 unsigned int plane_id_assigned_to_pipe = -1; 147 148 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 149 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; 150 151 if (!pipe->plane_state || !pipe->stream) 152 continue; 153 154 get_plane_id(ctx, state, pipe->plane_state, pipe->stream->stream_id, 155 ctx->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_index[pipe->pipe_idx], 156 &plane_id_assigned_to_pipe); 157 if (plane_id_assigned_to_pipe == plane_id && !pipe->prev_odm_pipe 158 && (!pipe->top_pipe || pipe->top_pipe->plane_state != pipe->plane_state)) { 159 while (pipe) { 160 struct pipe_ctx *mpc_pipe = pipe; 161 162 while (mpc_pipe) { 163 pipes[num_found++] = mpc_pipe->pipe_idx; 164 mpc_pipe = mpc_pipe->bottom_pipe; 165 if (!mpc_pipe) 166 break; 167 if (mpc_pipe->plane_state != pipe->plane_state) 168 mpc_pipe = NULL; 169 } 170 pipe = pipe->next_odm_pipe; 171 } 172 break; 173 } 174 } 175 176 return num_found; 177} 178 179static bool validate_pipe_assignment(const struct dml2_context *ctx, const struct dc_state *state, const struct dml_display_cfg_st *disp_cfg, const struct dml2_dml_to_dc_pipe_mapping *mapping) 180{ 181// int i, j, k; 182// 183// unsigned int plane_id; 184// 185// unsigned int disp_cfg_index; 186// 187// unsigned int pipes_assigned_to_plane[MAX_PIPES]; 188// unsigned int num_pipes_assigned_to_plane; 189// 190// struct pipe_ctx *top_pipe; 191// 192// for (i = 0; i < state->stream_count; i++) { 193// for (j = 0; j < state->stream_status[i]->plane_count; j++) { 194// if (get_plane_id(state, state->stream_status.plane_states[j], &plane_id)) { 195// disp_cfg_index = find_disp_cfg_idx_by_plane_id(mapping, plane_id); 196// num_pipes_assigned_to_plane = find_pipes_assigned_to_plane(ctx, state, plane_id, pipes_assigned_to_plane); 197// 198// if (disp_cfg_index >= 0 && num_pipes_assigned_to_plane > 0) { 199// // Verify the number of pipes assigned matches 200// if (disp_cfg->hw.DPPPerSurface != num_pipes_assigned_to_plane) 201// return false; 202// 203// top_pipe = find_top_pipe_in_tree(state->res_ctx.pipe_ctx[pipes_assigned_to_plane[0]]); 204// 205// // Verify MPC and ODM combine 206// if (disp_cfg->hw.ODMMode == dml_odm_mode_bypass) { 207// verify_combine_tree(top_pipe, state->streams[i]->stream_id, plane_id, state, false); 208// } else { 209// verify_combine_tree(top_pipe, state->streams[i]->stream_id, plane_id, state, true); 210// } 211// 212// // TODO: could also do additional verification that the pipes in tree are the same as 213// // pipes_assigned_to_plane 214// } else { 215// ASSERT(false); 216// return false; 217// } 218// } else { 219// ASSERT(false); 220// return false; 221// } 222// } 223// } 224 return true; 225} 226 227static bool is_plane_using_pipe(const struct pipe_ctx *pipe) 228{ 229 if (pipe->plane_state) 230 return true; 231 232 return false; 233} 234 235static bool is_pipe_free(const struct pipe_ctx *pipe) 236{ 237 if (!pipe->plane_state && !pipe->stream) 238 return true; 239 240 return false; 241} 242 243static unsigned int find_preferred_pipe_candidates(const struct dc_state *existing_state, 244 const int pipe_count, 245 const unsigned int stream_id, 246 unsigned int *preferred_pipe_candidates) 247{ 248 unsigned int num_preferred_candidates = 0; 249 int i; 250 251 /* There is only one case which we consider for adding a pipe to the preferred 252 * pipe candidate array: 253 * 254 * 1. If the existing stream id of the pipe is equivalent to the stream id 255 * of the stream we are trying to achieve MPC/ODM combine for. This allows 256 * us to minimize the changes in pipe topology during the transition. 257 * 258 * However this condition comes with a caveat. We need to ignore pipes that will 259 * require a change in OPP but still have the same stream id. For example during 260 * an MPC to ODM transiton. 261 * 262 * Adding check to avoid pipe select on the head pipe by utilizing dc resource 263 * helper function resource_get_primary_dpp_pipe and comparing the pipe index. 264 */ 265 if (existing_state) { 266 for (i = 0; i < pipe_count; i++) { 267 if (existing_state->res_ctx.pipe_ctx[i].stream && existing_state->res_ctx.pipe_ctx[i].stream->stream_id == stream_id) { 268 struct pipe_ctx *head_pipe = 269 resource_is_pipe_type(&existing_state->res_ctx.pipe_ctx[i], DPP_PIPE) ? 270 resource_get_primary_dpp_pipe(&existing_state->res_ctx.pipe_ctx[i]) : 271 NULL; 272 273 // we should always respect the head pipe from selection 274 if (head_pipe && head_pipe->pipe_idx == i) 275 continue; 276 if (existing_state->res_ctx.pipe_ctx[i].plane_res.hubp && 277 existing_state->res_ctx.pipe_ctx[i].plane_res.hubp->opp_id != i && 278 (existing_state->res_ctx.pipe_ctx[i].prev_odm_pipe || 279 existing_state->res_ctx.pipe_ctx[i].next_odm_pipe)) 280 continue; 281 282 preferred_pipe_candidates[num_preferred_candidates++] = i; 283 } 284 } 285 } 286 287 return num_preferred_candidates; 288} 289 290static unsigned int find_last_resort_pipe_candidates(const struct dc_state *existing_state, 291 const int pipe_count, 292 const unsigned int stream_id, 293 unsigned int *last_resort_pipe_candidates) 294{ 295 unsigned int num_last_resort_candidates = 0; 296 int i; 297 298 /* There are two cases where we would like to add a given pipe into the last 299 * candidate array: 300 * 301 * 1. If the pipe requires a change in OPP, for example during an MPC 302 * to ODM transiton. 303 * 304 * 2. If the pipe already has an enabled OTG. 305 */ 306 if (existing_state) { 307 for (i = 0; i < pipe_count; i++) { 308 struct pipe_ctx *head_pipe = 309 resource_is_pipe_type(&existing_state->res_ctx.pipe_ctx[i], DPP_PIPE) ? 310 resource_get_primary_dpp_pipe(&existing_state->res_ctx.pipe_ctx[i]) : 311 NULL; 312 313 // we should always respect the head pipe from selection 314 if (head_pipe && head_pipe->pipe_idx == i) 315 continue; 316 if ((existing_state->res_ctx.pipe_ctx[i].plane_res.hubp && 317 existing_state->res_ctx.pipe_ctx[i].plane_res.hubp->opp_id != i) || 318 existing_state->res_ctx.pipe_ctx[i].stream_res.tg) 319 last_resort_pipe_candidates[num_last_resort_candidates++] = i; 320 } 321 } 322 323 return num_last_resort_candidates; 324} 325 326static bool is_pipe_in_candidate_array(const unsigned int pipe_idx, 327 const unsigned int *candidate_array, 328 const unsigned int candidate_array_size) 329{ 330 int i; 331 332 for (i = 0; i < candidate_array_size; i++) { 333 if (candidate_array[i] == pipe_idx) 334 return true; 335 } 336 337 return false; 338} 339 340static bool find_more_pipes_for_stream(struct dml2_context *ctx, 341 struct dc_state *state, // The state we want to find a free mapping in 342 unsigned int stream_id, // The stream we want this pipe to drive 343 int *assigned_pipes, 344 int *assigned_pipe_count, 345 int pipes_needed, 346 const struct dc_state *existing_state) // The state (optional) that we want to minimize remapping relative to 347{ 348 struct pipe_ctx *pipe = NULL; 349 unsigned int preferred_pipe_candidates[MAX_PIPES] = {0}; 350 unsigned int last_resort_pipe_candidates[MAX_PIPES] = {0}; 351 unsigned int num_preferred_candidates = 0; 352 unsigned int num_last_resort_candidates = 0; 353 int i; 354 355 if (existing_state) { 356 num_preferred_candidates = 357 find_preferred_pipe_candidates(existing_state, ctx->config.dcn_pipe_count, stream_id, preferred_pipe_candidates); 358 359 num_last_resort_candidates = 360 find_last_resort_pipe_candidates(existing_state, ctx->config.dcn_pipe_count, stream_id, last_resort_pipe_candidates); 361 } 362 363 // First see if any of the preferred are unmapped, and choose those instead 364 for (i = 0; pipes_needed > 0 && i < num_preferred_candidates; i++) { 365 pipe = &state->res_ctx.pipe_ctx[preferred_pipe_candidates[i]]; 366 if (!is_plane_using_pipe(pipe)) { 367 pipes_needed--; 368 // TODO: This doens't make sense really, pipe_idx should always be valid 369 pipe->pipe_idx = preferred_pipe_candidates[i]; 370 assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; 371 } 372 } 373 374 // We like to pair pipes starting from the higher order indicies for combining 375 for (i = ctx->config.dcn_pipe_count - 1; pipes_needed > 0 && i >= 0; i--) { 376 // Ignore any pipes that are the preferred or last resort candidate 377 if (is_pipe_in_candidate_array(i, preferred_pipe_candidates, num_preferred_candidates) || 378 is_pipe_in_candidate_array(i, last_resort_pipe_candidates, num_last_resort_candidates)) 379 continue; 380 381 pipe = &state->res_ctx.pipe_ctx[i]; 382 if (!is_plane_using_pipe(pipe)) { 383 pipes_needed--; 384 // TODO: This doens't make sense really, pipe_idx should always be valid 385 pipe->pipe_idx = i; 386 assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; 387 } 388 } 389 390 // Only use the last resort pipe candidates as a last resort 391 for (i = 0; pipes_needed > 0 && i < num_last_resort_candidates; i++) { 392 pipe = &state->res_ctx.pipe_ctx[last_resort_pipe_candidates[i]]; 393 if (!is_plane_using_pipe(pipe)) { 394 pipes_needed--; 395 // TODO: This doens't make sense really, pipe_idx should always be valid 396 pipe->pipe_idx = last_resort_pipe_candidates[i]; 397 assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; 398 } 399 } 400 401 ASSERT(pipes_needed <= 0); // Validation should prevent us from building a pipe context that exceeds the number of HW resoruces available 402 403 return pipes_needed <= 0; 404} 405 406static bool find_more_free_pipes(struct dml2_context *ctx, 407 struct dc_state *state, // The state we want to find a free mapping in 408 unsigned int stream_id, // The stream we want this pipe to drive 409 int *assigned_pipes, 410 int *assigned_pipe_count, 411 int pipes_needed, 412 const struct dc_state *existing_state) // The state (optional) that we want to minimize remapping relative to 413{ 414 struct pipe_ctx *pipe = NULL; 415 unsigned int preferred_pipe_candidates[MAX_PIPES] = {0}; 416 unsigned int last_resort_pipe_candidates[MAX_PIPES] = {0}; 417 unsigned int num_preferred_candidates = 0; 418 unsigned int num_last_resort_candidates = 0; 419 int i; 420 421 if (existing_state) { 422 num_preferred_candidates = 423 find_preferred_pipe_candidates(existing_state, ctx->config.dcn_pipe_count, stream_id, preferred_pipe_candidates); 424 425 num_last_resort_candidates = 426 find_last_resort_pipe_candidates(existing_state, ctx->config.dcn_pipe_count, stream_id, last_resort_pipe_candidates); 427 } 428 429 // First see if any of the preferred are unmapped, and choose those instead 430 for (i = 0; pipes_needed > 0 && i < num_preferred_candidates; i++) { 431 pipe = &state->res_ctx.pipe_ctx[preferred_pipe_candidates[i]]; 432 if (is_pipe_free(pipe)) { 433 pipes_needed--; 434 // TODO: This doens't make sense really, pipe_idx should always be valid 435 pipe->pipe_idx = preferred_pipe_candidates[i]; 436 assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; 437 } 438 } 439 440 // We like to pair pipes starting from the higher order indicies for combining 441 for (i = ctx->config.dcn_pipe_count - 1; pipes_needed > 0 && i >= 0; i--) { 442 // Ignore any pipes that are the preferred or last resort candidate 443 if (is_pipe_in_candidate_array(i, preferred_pipe_candidates, num_preferred_candidates) || 444 is_pipe_in_candidate_array(i, last_resort_pipe_candidates, num_last_resort_candidates)) 445 continue; 446 447 pipe = &state->res_ctx.pipe_ctx[i]; 448 if (is_pipe_free(pipe)) { 449 pipes_needed--; 450 // TODO: This doens't make sense really, pipe_idx should always be valid 451 pipe->pipe_idx = i; 452 assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; 453 } 454 } 455 456 // Only use the last resort pipe candidates as a last resort 457 for (i = 0; pipes_needed > 0 && i < num_last_resort_candidates; i++) { 458 pipe = &state->res_ctx.pipe_ctx[last_resort_pipe_candidates[i]]; 459 if (is_pipe_free(pipe)) { 460 pipes_needed--; 461 // TODO: This doens't make sense really, pipe_idx should always be valid 462 pipe->pipe_idx = last_resort_pipe_candidates[i]; 463 assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; 464 } 465 } 466 467 ASSERT(pipes_needed == 0); // Validation should prevent us from building a pipe context that exceeds the number of HW resoruces available 468 469 return pipes_needed == 0; 470} 471 472static void sort_pipes_for_splitting(struct dc_plane_pipe_pool *pipes) 473{ 474 bool sorted, swapped; 475 unsigned int cur_index; 476 int odm_slice_index; 477 478 for (odm_slice_index = 0; odm_slice_index < pipes->num_pipes_assigned_to_plane_for_odm_combine; odm_slice_index++) { 479 // Sort each MPCC set 480 //Un-optimized bubble sort, but that's okay for array sizes <= 6 481 482 if (pipes->num_pipes_assigned_to_plane_for_mpcc_combine <= 1) 483 sorted = true; 484 else 485 sorted = false; 486 487 cur_index = 0; 488 swapped = false; 489 while (!sorted) { 490 if (pipes->pipes_assigned_to_plane[odm_slice_index][cur_index] > pipes->pipes_assigned_to_plane[odm_slice_index][cur_index + 1]) { 491 swap(pipes->pipes_assigned_to_plane[odm_slice_index][cur_index + 1], 492 pipes->pipes_assigned_to_plane[odm_slice_index][cur_index]); 493 494 swapped = true; 495 } 496 497 cur_index++; 498 499 if (cur_index == pipes->num_pipes_assigned_to_plane_for_mpcc_combine - 1) { 500 cur_index = 0; 501 502 if (swapped) 503 sorted = false; 504 else 505 sorted = true; 506 507 swapped = false; 508 } 509 510 } 511 } 512} 513 514// For example, 3840 x 2160, ODM2:1 has a slice array of [1919, 3839], meaning, slice0 spans h_pixels 0->1919, and slice1 spans 1920->3840 515static void calculate_odm_slices(const struct dc_stream_state *stream, unsigned int odm_factor, unsigned int *odm_slice_end_x) 516{ 517 unsigned int slice_size = 0; 518 int i; 519 520 if (odm_factor < 1 || odm_factor > 4) { 521 ASSERT(false); 522 return; 523 } 524 525 slice_size = stream->src.width / odm_factor; 526 527 for (i = 0; i < odm_factor; i++) 528 odm_slice_end_x[i] = (slice_size * (i + 1)) - 1; 529 530 odm_slice_end_x[odm_factor - 1] = stream->src.width - 1; 531} 532 533static void add_odm_slice_to_odm_tree(struct dml2_context *ctx, 534 struct dc_state *state, 535 struct dc_pipe_mapping_scratch *scratch, 536 unsigned int odm_slice_index) 537{ 538 struct pipe_ctx *pipe = NULL; 539 int i; 540 541 // MPCC Combine + ODM Combine is not supported, so there should never be a case where the current plane 542 // has more than 1 pipe mapped to it for a given slice. 543 ASSERT(scratch->pipe_pool.num_pipes_assigned_to_plane_for_mpcc_combine == 1 || scratch->pipe_pool.num_pipes_assigned_to_plane_for_odm_combine == 1); 544 545 for (i = 0; i < scratch->pipe_pool.num_pipes_assigned_to_plane_for_mpcc_combine; i++) { 546 pipe = &state->res_ctx.pipe_ctx[scratch->pipe_pool.pipes_assigned_to_plane[odm_slice_index][i]]; 547 548 if (scratch->mpc_info.prev_odm_pipe) 549 scratch->mpc_info.prev_odm_pipe->next_odm_pipe = pipe; 550 551 pipe->prev_odm_pipe = scratch->mpc_info.prev_odm_pipe; 552 pipe->next_odm_pipe = NULL; 553 } 554 scratch->mpc_info.prev_odm_pipe = pipe; 555} 556 557static struct pipe_ctx *add_plane_to_blend_tree(struct dml2_context *ctx, 558 struct dc_state *state, 559 const struct dc_plane_state *plane, 560 struct dc_plane_pipe_pool *pipe_pool, 561 unsigned int odm_slice, 562 struct pipe_ctx *top_pipe) 563{ 564 int i; 565 566 for (i = 0; i < pipe_pool->num_pipes_assigned_to_plane_for_mpcc_combine; i++) { 567 if (top_pipe) 568 top_pipe->bottom_pipe = &state->res_ctx.pipe_ctx[pipe_pool->pipes_assigned_to_plane[odm_slice][i]]; 569 570 pipe_pool->pipe_used[odm_slice][i] = true; 571 572 state->res_ctx.pipe_ctx[pipe_pool->pipes_assigned_to_plane[odm_slice][i]].top_pipe = top_pipe; 573 state->res_ctx.pipe_ctx[pipe_pool->pipes_assigned_to_plane[odm_slice][i]].bottom_pipe = NULL; 574 575 top_pipe = &state->res_ctx.pipe_ctx[pipe_pool->pipes_assigned_to_plane[odm_slice][i]]; 576 } 577 578 // After running the above loop, the top pipe actually ends up pointing to the bottom of this MPCC combine tree, so we are actually 579 // returning the bottom pipe here 580 return top_pipe; 581} 582 583static unsigned int find_pipes_assigned_to_stream(struct dml2_context *ctx, struct dc_state *state, unsigned int stream_id, unsigned int *pipes) 584{ 585 int i; 586 unsigned int num_found = 0; 587 588 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 589 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; 590 591 if (pipe->stream && pipe->stream->stream_id == stream_id && !pipe->top_pipe && !pipe->prev_odm_pipe) { 592 while (pipe) { 593 pipes[num_found++] = pipe->pipe_idx; 594 pipe = pipe->next_odm_pipe; 595 } 596 break; 597 } 598 } 599 600 return num_found; 601} 602 603static struct pipe_ctx *assign_pipes_to_stream(struct dml2_context *ctx, struct dc_state *state, 604 const struct dc_stream_state *stream, 605 int odm_factor, 606 struct dc_plane_pipe_pool *pipe_pool, 607 const struct dc_state *existing_state) 608{ 609 struct pipe_ctx *master_pipe; 610 unsigned int pipes_needed; 611 unsigned int pipes_assigned; 612 unsigned int pipes[MAX_PIPES] = {0}; 613 unsigned int next_pipe_to_assign; 614 int odm_slice; 615 616 pipes_needed = odm_factor; 617 618 master_pipe = find_master_pipe_of_stream(ctx, state, stream->stream_id); 619 ASSERT(master_pipe); 620 621 pipes_assigned = find_pipes_assigned_to_stream(ctx, state, stream->stream_id, pipes); 622 623 find_more_free_pipes(ctx, state, stream->stream_id, pipes, &pipes_assigned, pipes_needed - pipes_assigned, existing_state); 624 625 ASSERT(pipes_assigned == pipes_needed); 626 627 next_pipe_to_assign = 0; 628 for (odm_slice = 0; odm_slice < odm_factor; odm_slice++) 629 pipe_pool->pipes_assigned_to_plane[odm_slice][0] = pipes[next_pipe_to_assign++]; 630 631 pipe_pool->num_pipes_assigned_to_plane_for_mpcc_combine = 1; 632 pipe_pool->num_pipes_assigned_to_plane_for_odm_combine = odm_factor; 633 634 return master_pipe; 635} 636 637static struct pipe_ctx *assign_pipes_to_plane(struct dml2_context *ctx, struct dc_state *state, 638 const struct dc_stream_state *stream, 639 const struct dc_plane_state *plane, 640 int odm_factor, 641 int mpc_factor, 642 int plane_index, 643 struct dc_plane_pipe_pool *pipe_pool, 644 const struct dc_state *existing_state) 645{ 646 struct pipe_ctx *master_pipe = NULL; 647 unsigned int plane_id; 648 unsigned int pipes_needed; 649 unsigned int pipes_assigned; 650 unsigned int pipes[MAX_PIPES] = {0}; 651 unsigned int next_pipe_to_assign; 652 int odm_slice, mpc_slice; 653 654 if (!get_plane_id(ctx, state, plane, stream->stream_id, plane_index, &plane_id)) { 655 ASSERT(false); 656 return master_pipe; 657 } 658 659 pipes_needed = mpc_factor * odm_factor; 660 661 master_pipe = find_master_pipe_of_plane(ctx, state, plane_id); 662 ASSERT(master_pipe); 663 664 pipes_assigned = find_pipes_assigned_to_plane(ctx, state, plane_id, pipes); 665 666 find_more_pipes_for_stream(ctx, state, stream->stream_id, pipes, &pipes_assigned, pipes_needed - pipes_assigned, existing_state); 667 668 ASSERT(pipes_assigned >= pipes_needed); 669 670 next_pipe_to_assign = 0; 671 for (odm_slice = 0; odm_slice < odm_factor; odm_slice++) 672 for (mpc_slice = 0; mpc_slice < mpc_factor; mpc_slice++) 673 pipe_pool->pipes_assigned_to_plane[odm_slice][mpc_slice] = pipes[next_pipe_to_assign++]; 674 675 pipe_pool->num_pipes_assigned_to_plane_for_mpcc_combine = mpc_factor; 676 pipe_pool->num_pipes_assigned_to_plane_for_odm_combine = odm_factor; 677 678 return master_pipe; 679} 680 681static bool is_pipe_used(const struct dc_plane_pipe_pool *pool, unsigned int pipe_idx) 682{ 683 int i, j; 684 685 for (i = 0; i < pool->num_pipes_assigned_to_plane_for_odm_combine; i++) { 686 for (j = 0; j < pool->num_pipes_assigned_to_plane_for_mpcc_combine; j++) { 687 if (pool->pipes_assigned_to_plane[i][j] == pipe_idx && pool->pipe_used[i][j]) 688 return true; 689 } 690 } 691 692 return false; 693} 694 695static void free_pipe(struct pipe_ctx *pipe) 696{ 697 memset(pipe, 0, sizeof(struct pipe_ctx)); 698} 699 700static void free_unused_pipes_for_plane(struct dml2_context *ctx, struct dc_state *state, 701 const struct dc_plane_state *plane, const struct dc_plane_pipe_pool *pool, unsigned int stream_id, int plane_index) 702{ 703 int i; 704 bool is_plane_duplicate = ctx->v20.scratch.plane_duplicate_exists; 705 706 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 707 if (state->res_ctx.pipe_ctx[i].plane_state == plane && 708 state->res_ctx.pipe_ctx[i].stream->stream_id == stream_id && 709 (!is_plane_duplicate || 710 ctx->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_index[state->res_ctx.pipe_ctx[i].pipe_idx] == plane_index) && 711 !is_pipe_used(pool, state->res_ctx.pipe_ctx[i].pipe_idx)) { 712 free_pipe(&state->res_ctx.pipe_ctx[i]); 713 } 714 } 715} 716 717static void remove_pipes_from_blend_trees(struct dml2_context *ctx, struct dc_state *state, struct dc_plane_pipe_pool *pipe_pool, unsigned int odm_slice) 718{ 719 struct pipe_ctx *pipe; 720 int i; 721 722 for (i = 0; i < pipe_pool->num_pipes_assigned_to_plane_for_mpcc_combine; i++) { 723 pipe = &state->res_ctx.pipe_ctx[pipe_pool->pipes_assigned_to_plane[odm_slice][0]]; 724 if (pipe->top_pipe) 725 pipe->top_pipe->bottom_pipe = pipe->bottom_pipe; 726 727 if (pipe->bottom_pipe) 728 pipe->bottom_pipe = pipe->top_pipe; 729 730 pipe_pool->pipe_used[odm_slice][i] = true; 731 } 732} 733 734static void map_pipes_for_stream(struct dml2_context *ctx, struct dc_state *state, const struct dc_stream_state *stream, 735 struct dc_pipe_mapping_scratch *scratch, const struct dc_state *existing_state) 736{ 737 int odm_slice_index; 738 struct pipe_ctx *master_pipe = NULL; 739 740 741 master_pipe = assign_pipes_to_stream(ctx, state, stream, scratch->odm_info.odm_factor, &scratch->pipe_pool, existing_state); 742 sort_pipes_for_splitting(&scratch->pipe_pool); 743 744 for (odm_slice_index = 0; odm_slice_index < scratch->odm_info.odm_factor; odm_slice_index++) { 745 remove_pipes_from_blend_trees(ctx, state, &scratch->pipe_pool, odm_slice_index); 746 747 add_odm_slice_to_odm_tree(ctx, state, scratch, odm_slice_index); 748 749 ctx->config.callbacks.acquire_secondary_pipe_for_mpc_odm(ctx->config.callbacks.dc, state, 750 master_pipe, &state->res_ctx.pipe_ctx[scratch->pipe_pool.pipes_assigned_to_plane[odm_slice_index][0]], true); 751 } 752} 753 754static void map_pipes_for_plane(struct dml2_context *ctx, struct dc_state *state, const struct dc_stream_state *stream, const struct dc_plane_state *plane, 755 int plane_index, struct dc_pipe_mapping_scratch *scratch, const struct dc_state *existing_state) 756{ 757 int odm_slice_index; 758 unsigned int plane_id; 759 struct pipe_ctx *master_pipe = NULL; 760 int i; 761 762 if (!get_plane_id(ctx, state, plane, stream->stream_id, plane_index, &plane_id)) { 763 ASSERT(false); 764 return; 765 } 766 767 master_pipe = assign_pipes_to_plane(ctx, state, stream, plane, scratch->odm_info.odm_factor, 768 scratch->mpc_info.mpc_factor, plane_index, &scratch->pipe_pool, existing_state); 769 sort_pipes_for_splitting(&scratch->pipe_pool); 770 771 for (odm_slice_index = 0; odm_slice_index < scratch->odm_info.odm_factor; odm_slice_index++) { 772 // Now we have a list of all pipes to be used for this plane/stream, now setup the tree. 773 scratch->odm_info.next_higher_pipe_for_odm_slice[odm_slice_index] = add_plane_to_blend_tree(ctx, state, 774 plane, 775 &scratch->pipe_pool, 776 odm_slice_index, 777 scratch->odm_info.next_higher_pipe_for_odm_slice[odm_slice_index]); 778 779 add_odm_slice_to_odm_tree(ctx, state, scratch, odm_slice_index); 780 781 for (i = 0; i < scratch->pipe_pool.num_pipes_assigned_to_plane_for_mpcc_combine; i++) { 782 783 ctx->config.callbacks.acquire_secondary_pipe_for_mpc_odm(ctx->config.callbacks.dc, state, 784 master_pipe, &state->res_ctx.pipe_ctx[scratch->pipe_pool.pipes_assigned_to_plane[odm_slice_index][i]], true); 785 } 786 } 787 788 free_unused_pipes_for_plane(ctx, state, plane, &scratch->pipe_pool, stream->stream_id, plane_index); 789} 790 791static unsigned int get_target_mpc_factor(struct dml2_context *ctx, 792 struct dc_state *state, 793 const struct dml_display_cfg_st *disp_cfg, 794 struct dml2_dml_to_dc_pipe_mapping *mapping, 795 const struct dc_stream_status *status, 796 const struct dc_stream_state *stream, 797 int plane_idx) 798{ 799 unsigned int plane_id; 800 unsigned int cfg_idx; 801 unsigned int mpc_factor; 802 803 if (ctx->architecture == dml2_architecture_20) { 804 get_plane_id(ctx, state, status->plane_states[plane_idx], 805 stream->stream_id, plane_idx, &plane_id); 806 cfg_idx = find_disp_cfg_idx_by_plane_id(mapping, plane_id); 807 mpc_factor = (unsigned int)disp_cfg->hw.DPPPerSurface[cfg_idx]; 808 } else if (ctx->architecture == dml2_architecture_21) { 809 if (ctx->config.svp_pstate.callbacks.get_stream_subvp_type(state, stream) == SUBVP_PHANTOM) { 810 struct dc_stream_state *main_stream; 811 struct dc_stream_status *main_stream_status; 812 813 /* get stream id of main stream */ 814 main_stream = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(state, stream); 815 if (!main_stream) { 816 ASSERT(false); 817 return 1; 818 } 819 820 main_stream_status = ctx->config.callbacks.get_stream_status(state, main_stream); 821 if (!main_stream_status) { 822 ASSERT(false); 823 return 1; 824 } 825 826 /* get plane id for associated main plane */ 827 get_plane_id(ctx, state, main_stream_status->plane_states[plane_idx], 828 main_stream->stream_id, plane_idx, &plane_id); 829 } else { 830 get_plane_id(ctx, state, status->plane_states[plane_idx], 831 stream->stream_id, plane_idx, &plane_id); 832 } 833 834 cfg_idx = find_disp_cfg_idx_by_plane_id(mapping, plane_id); 835 mpc_factor = ctx->v21.mode_programming.programming->plane_programming[cfg_idx].num_dpps_required; 836 } else { 837 mpc_factor = 1; 838 ASSERT(false); 839 } 840 841 /* For stereo timings, we need to pipe split */ 842 if (dml2_is_stereo_timing(stream)) 843 mpc_factor = 2; 844 845 return mpc_factor; 846} 847 848static unsigned int get_target_odm_factor( 849 const struct dml2_context *ctx, 850 struct dc_state *state, 851 const struct dml_display_cfg_st *disp_cfg, 852 struct dml2_dml_to_dc_pipe_mapping *mapping, 853 const struct dc_stream_state *stream) 854{ 855 unsigned int cfg_idx; 856 857 if (ctx->architecture == dml2_architecture_20) { 858 cfg_idx = find_disp_cfg_idx_by_stream_id( 859 mapping, stream->stream_id); 860 switch (disp_cfg->hw.ODMMode[cfg_idx]) { 861 case dml_odm_mode_bypass: 862 return 1; 863 case dml_odm_mode_combine_2to1: 864 return 2; 865 case dml_odm_mode_combine_4to1: 866 return 4; 867 default: 868 break; 869 } 870 } else if (ctx->architecture == dml2_architecture_21) { 871 if (ctx->config.svp_pstate.callbacks.get_stream_subvp_type(state, stream) == SUBVP_PHANTOM) { 872 struct dc_stream_state *main_stream; 873 874 /* get stream id of main stream */ 875 main_stream = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(state, stream); 876 if (!main_stream) 877 goto failed; 878 879 /* get cfg idx for associated main stream */ 880 cfg_idx = find_disp_cfg_idx_by_stream_id( 881 mapping, main_stream->stream_id); 882 } else { 883 cfg_idx = find_disp_cfg_idx_by_stream_id( 884 mapping, stream->stream_id); 885 } 886 887 return ctx->v21.mode_programming.programming->stream_programming[cfg_idx].num_odms_required; 888 } 889 890failed: 891 ASSERT(false); 892 return 1; 893} 894 895static unsigned int get_source_odm_factor(const struct dml2_context *ctx, 896 struct dc_state *state, 897 const struct dc_stream_state *stream) 898{ 899 struct pipe_ctx *otg_master = ctx->config.callbacks.get_otg_master_for_stream(&state->res_ctx, stream); 900 901 if (!otg_master) 902 return 0; 903 904 return ctx->config.callbacks.get_odm_slice_count(otg_master); 905} 906 907static unsigned int get_source_mpc_factor(const struct dml2_context *ctx, 908 struct dc_state *state, 909 const struct dc_plane_state *plane) 910{ 911 struct pipe_ctx *dpp_pipes[MAX_PIPES] = {0}; 912 int dpp_pipe_count = ctx->config.callbacks.get_dpp_pipes_for_plane(plane, 913 &state->res_ctx, dpp_pipes); 914 915 ASSERT(dpp_pipe_count > 0); 916 return ctx->config.callbacks.get_mpc_slice_count(dpp_pipes[0]); 917} 918 919 920static void populate_mpc_factors_for_stream( 921 struct dml2_context *ctx, 922 const struct dml_display_cfg_st *disp_cfg, 923 struct dml2_dml_to_dc_pipe_mapping *mapping, 924 struct dc_state *state, 925 unsigned int stream_idx, 926 struct dml2_pipe_combine_factor odm_factor, 927 struct dml2_pipe_combine_factor mpc_factors[MAX_PIPES]) 928{ 929 const struct dc_stream_status *status = &state->stream_status[stream_idx]; 930 int i; 931 932 for (i = 0; i < status->plane_count; i++) { 933 mpc_factors[i].source = get_source_mpc_factor(ctx, state, status->plane_states[i]); 934 mpc_factors[i].target = (odm_factor.target == 1) ? 935 get_target_mpc_factor(ctx, state, disp_cfg, mapping, status, state->streams[stream_idx], i) : 1; 936 } 937} 938 939static void populate_odm_factors(const struct dml2_context *ctx, 940 const struct dml_display_cfg_st *disp_cfg, 941 struct dml2_dml_to_dc_pipe_mapping *mapping, 942 struct dc_state *state, 943 struct dml2_pipe_combine_factor odm_factors[MAX_PIPES]) 944{ 945 int i; 946 947 for (i = 0; i < state->stream_count; i++) { 948 odm_factors[i].source = get_source_odm_factor(ctx, state, state->streams[i]); 949 odm_factors[i].target = get_target_odm_factor( 950 ctx, state, disp_cfg, mapping, state->streams[i]); 951 } 952} 953 954static bool unmap_dc_pipes_for_stream(struct dml2_context *ctx, 955 struct dc_state *state, 956 const struct dc_state *existing_state, 957 const struct dc_stream_state *stream, 958 const struct dc_stream_status *status, 959 struct dml2_pipe_combine_factor odm_factor, 960 struct dml2_pipe_combine_factor mpc_factors[MAX_PIPES]) 961{ 962 int plane_idx; 963 bool result = true; 964 965 for (plane_idx = 0; plane_idx < status->plane_count; plane_idx++) 966 if (mpc_factors[plane_idx].target < mpc_factors[plane_idx].source) 967 result &= ctx->config.callbacks.update_pipes_for_plane_with_slice_count( 968 state, 969 existing_state, 970 ctx->config.callbacks.dc->res_pool, 971 status->plane_states[plane_idx], 972 mpc_factors[plane_idx].target); 973 if (odm_factor.target < odm_factor.source) 974 result &= ctx->config.callbacks.update_pipes_for_stream_with_slice_count( 975 state, 976 existing_state, 977 ctx->config.callbacks.dc->res_pool, 978 stream, 979 odm_factor.target); 980 return result; 981} 982 983static bool map_dc_pipes_for_stream(struct dml2_context *ctx, 984 struct dc_state *state, 985 const struct dc_state *existing_state, 986 const struct dc_stream_state *stream, 987 const struct dc_stream_status *status, 988 struct dml2_pipe_combine_factor odm_factor, 989 struct dml2_pipe_combine_factor mpc_factors[MAX_PIPES]) 990{ 991 int plane_idx; 992 bool result = true; 993 994 for (plane_idx = 0; plane_idx < status->plane_count; plane_idx++) 995 if (mpc_factors[plane_idx].target > mpc_factors[plane_idx].source) 996 result &= ctx->config.callbacks.update_pipes_for_plane_with_slice_count( 997 state, 998 existing_state, 999 ctx->config.callbacks.dc->res_pool, 1000 status->plane_states[plane_idx], 1001 mpc_factors[plane_idx].target); 1002 if (odm_factor.target > odm_factor.source) 1003 result &= ctx->config.callbacks.update_pipes_for_stream_with_slice_count( 1004 state, 1005 existing_state, 1006 ctx->config.callbacks.dc->res_pool, 1007 stream, 1008 odm_factor.target); 1009 return result; 1010} 1011 1012static bool map_dc_pipes_with_callbacks(struct dml2_context *ctx, 1013 struct dc_state *state, 1014 const struct dml_display_cfg_st *disp_cfg, 1015 struct dml2_dml_to_dc_pipe_mapping *mapping, 1016 const struct dc_state *existing_state) 1017{ 1018 int i; 1019 bool result = true; 1020 1021 populate_odm_factors(ctx, disp_cfg, mapping, state, ctx->pipe_combine_scratch.odm_factors); 1022 for (i = 0; i < state->stream_count; i++) 1023 populate_mpc_factors_for_stream(ctx, disp_cfg, mapping, state, 1024 i, ctx->pipe_combine_scratch.odm_factors[i], ctx->pipe_combine_scratch.mpc_factors[i]); 1025 for (i = 0; i < state->stream_count; i++) 1026 result &= unmap_dc_pipes_for_stream(ctx, state, existing_state, state->streams[i], 1027 &state->stream_status[i], ctx->pipe_combine_scratch.odm_factors[i], ctx->pipe_combine_scratch.mpc_factors[i]); 1028 for (i = 0; i < state->stream_count; i++) 1029 result &= map_dc_pipes_for_stream(ctx, state, existing_state, state->streams[i], 1030 &state->stream_status[i], ctx->pipe_combine_scratch.odm_factors[i], ctx->pipe_combine_scratch.mpc_factors[i]); 1031 1032 return result; 1033} 1034 1035bool dml2_map_dc_pipes(struct dml2_context *ctx, struct dc_state *state, const struct dml_display_cfg_st *disp_cfg, struct dml2_dml_to_dc_pipe_mapping *mapping, const struct dc_state *existing_state) 1036{ 1037 int stream_index, plane_index, i; 1038 1039 unsigned int stream_disp_cfg_index; 1040 unsigned int plane_disp_cfg_index; 1041 unsigned int disp_cfg_index_max; 1042 1043 unsigned int plane_id; 1044 unsigned int stream_id; 1045 1046 const unsigned int *ODMMode, *DPPPerSurface; 1047 unsigned int odm_mode_array[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0}, dpp_per_surface_array[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0}; 1048 struct dc_pipe_mapping_scratch scratch; 1049 1050 if (ctx->config.map_dc_pipes_with_callbacks) 1051 return map_dc_pipes_with_callbacks( 1052 ctx, state, disp_cfg, mapping, existing_state); 1053 1054 if (ctx->architecture == dml2_architecture_21) { 1055 /* 1056 * Extract ODM and DPP outputs from DML2.1 and map them in an array as required for pipe mapping in dml2_map_dc_pipes. 1057 * As data cannot be directly extracted in const pointers, assign these arrays to const pointers before proceeding to 1058 * maximize the reuse of existing code. Const pointers are required because dml2.0 dml_display_cfg_st is const. 1059 * 1060 */ 1061 for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) { 1062 odm_mode_array[i] = ctx->v21.mode_programming.programming->stream_programming[i].num_odms_required; 1063 dpp_per_surface_array[i] = ctx->v21.mode_programming.programming->plane_programming[i].num_dpps_required; 1064 } 1065 1066 ODMMode = (const unsigned int *)odm_mode_array; 1067 DPPPerSurface = (const unsigned int *)dpp_per_surface_array; 1068 disp_cfg_index_max = __DML2_WRAPPER_MAX_STREAMS_PLANES__; 1069 } else { 1070 ODMMode = (unsigned int *)disp_cfg->hw.ODMMode; 1071 DPPPerSurface = disp_cfg->hw.DPPPerSurface; 1072 disp_cfg_index_max = __DML_NUM_PLANES__; 1073 } 1074 1075 for (stream_index = 0; stream_index < state->stream_count; stream_index++) { 1076 memset(&scratch, 0, sizeof(struct dc_pipe_mapping_scratch)); 1077 1078 stream_id = state->streams[stream_index]->stream_id; 1079 stream_disp_cfg_index = find_disp_cfg_idx_by_stream_id(mapping, stream_id); 1080 if (stream_disp_cfg_index >= disp_cfg_index_max) 1081 continue; 1082 1083 if (ctx->architecture == dml2_architecture_20) { 1084 if (ODMMode[stream_disp_cfg_index] == dml_odm_mode_bypass) { 1085 scratch.odm_info.odm_factor = 1; 1086 } else if (ODMMode[stream_disp_cfg_index] == dml_odm_mode_combine_2to1) { 1087 scratch.odm_info.odm_factor = 2; 1088 } else if (ODMMode[stream_disp_cfg_index] == dml_odm_mode_combine_4to1) { 1089 scratch.odm_info.odm_factor = 4; 1090 } else { 1091 ASSERT(false); 1092 scratch.odm_info.odm_factor = 1; 1093 } 1094 } else if (ctx->architecture == dml2_architecture_21) { 1095 /* After DML2.1 update, ODM interpretation needs to change and is no longer same as for DML2.0. 1096 * This is not an issue with new resource management logic. This block ensure backcompat 1097 * with legacy pipe management with updated DML. 1098 * */ 1099 if (ODMMode[stream_disp_cfg_index] == 1) { 1100 scratch.odm_info.odm_factor = 1; 1101 } else if (ODMMode[stream_disp_cfg_index] == 2) { 1102 scratch.odm_info.odm_factor = 2; 1103 } else if (ODMMode[stream_disp_cfg_index] == 4) { 1104 scratch.odm_info.odm_factor = 4; 1105 } else { 1106 ASSERT(false); 1107 scratch.odm_info.odm_factor = 1; 1108 } 1109 } 1110 calculate_odm_slices(state->streams[stream_index], scratch.odm_info.odm_factor, scratch.odm_info.odm_slice_end_x); 1111 1112 // If there are no planes, you still want to setup ODM... 1113 if (state->stream_status[stream_index].plane_count == 0) { 1114 map_pipes_for_stream(ctx, state, state->streams[stream_index], &scratch, existing_state); 1115 } 1116 1117 for (plane_index = 0; plane_index < state->stream_status[stream_index].plane_count; plane_index++) { 1118 // Planes are ordered top to bottom. 1119 if (get_plane_id(ctx, state, state->stream_status[stream_index].plane_states[plane_index], 1120 stream_id, plane_index, &plane_id)) { 1121 plane_disp_cfg_index = find_disp_cfg_idx_by_plane_id(mapping, plane_id); 1122 1123 // Setup mpc_info for this plane 1124 scratch.mpc_info.prev_odm_pipe = NULL; 1125 if (scratch.odm_info.odm_factor == 1 && plane_disp_cfg_index < disp_cfg_index_max) { 1126 // If ODM combine is not inuse, then the number of pipes 1127 // per plane is determined by MPC combine factor 1128 scratch.mpc_info.mpc_factor = DPPPerSurface[plane_disp_cfg_index]; 1129 1130 //For stereo timings, we need to pipe split 1131 if (dml2_is_stereo_timing(state->streams[stream_index])) 1132 scratch.mpc_info.mpc_factor = 2; 1133 } else { 1134 // If ODM combine is enabled, then we use at most 1 pipe per 1135 // odm slice per plane, i.e. MPC combine is never used 1136 scratch.mpc_info.mpc_factor = 1; 1137 } 1138 1139 ASSERT(scratch.odm_info.odm_factor * scratch.mpc_info.mpc_factor > 0); 1140 1141 // Clear the pool assignment scratch (which is per plane) 1142 memset(&scratch.pipe_pool, 0, sizeof(struct dc_plane_pipe_pool)); 1143 1144 map_pipes_for_plane(ctx, state, state->streams[stream_index], 1145 state->stream_status[stream_index].plane_states[plane_index], plane_index, &scratch, existing_state); 1146 } else { 1147 // Plane ID cannot be generated, therefore no DML mapping can be performed. 1148 ASSERT(false); 1149 } 1150 } 1151 1152 } 1153 1154 if (!validate_pipe_assignment(ctx, state, disp_cfg, mapping)) 1155 ASSERT(false); 1156 1157 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 1158 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; 1159 1160 if (pipe->plane_state) { 1161 if (!ctx->config.callbacks.build_scaling_params(pipe)) { 1162 ASSERT(false); 1163 } 1164 } 1165 1166 if (ctx->config.callbacks.build_test_pattern_params && 1167 pipe->stream && 1168 pipe->prev_odm_pipe == NULL && 1169 pipe->top_pipe == NULL) 1170 ctx->config.callbacks.build_test_pattern_params(&state->res_ctx, pipe); 1171 } 1172 1173 return true; 1174}
~/
Read-only file preview.