1 /* 2 * Copyright 2012-15 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 #include "dm_services.h" 27 28 #include "resource.h" 29 #include "include/irq_service_interface.h" 30 #include "link_encoder.h" 31 #include "stream_encoder.h" 32 #include "opp.h" 33 #include "timing_generator.h" 34 #include "transform.h" 35 #include "dccg.h" 36 #include "dchubbub.h" 37 #include "dpp.h" 38 #include "core_types.h" 39 #include "set_mode_types.h" 40 #include "dio/virtual/virtual_stream_encoder.h" 41 #include "dpcd_defs.h" 42 #include "link_enc_cfg.h" 43 #include "link_service.h" 44 #include "clk_mgr.h" 45 #include "dc_state_priv.h" 46 #include "dc_stream_priv.h" 47 48 #include "link/hwss/link_hwss_virtual.h" 49 #include "link/hwss/link_hwss_dio.h" 50 #include "link/hwss/link_hwss_dpia.h" 51 #include "link/hwss/link_hwss_hpo_dp.h" 52 #include "link/hwss/link_hwss_dio_fixed_vs_pe_retimer.h" 53 #include "link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.h" 54 55 #if defined(CONFIG_DRM_AMD_DC_SI) 56 #include "dce60/dce60_resource.h" 57 #endif 58 #include "dce80/dce80_resource.h" 59 #include "dce100/dce100_resource.h" 60 #include "dce110/dce110_resource.h" 61 #include "dce112/dce112_resource.h" 62 #include "dce120/dce120_resource.h" 63 #include "dcn10/dcn10_resource.h" 64 #include "dcn20/dcn20_resource.h" 65 #include "dcn21/dcn21_resource.h" 66 #include "dcn201/dcn201_resource.h" 67 #include "dcn30/dcn30_resource.h" 68 #include "dcn301/dcn301_resource.h" 69 #include "dcn302/dcn302_resource.h" 70 #include "dcn303/dcn303_resource.h" 71 #include "dcn31/dcn31_resource.h" 72 #include "dcn314/dcn314_resource.h" 73 #include "dcn315/dcn315_resource.h" 74 #include "dcn316/dcn316_resource.h" 75 #include "dcn32/dcn32_resource.h" 76 #include "dcn321/dcn321_resource.h" 77 #include "dcn35/dcn35_resource.h" 78 #include "dcn351/dcn351_resource.h" 79 #include "dcn36/dcn36_resource.h" 80 #include "dcn401/dcn401_resource.h" 81 #include "dcn42/dcn42_resource.h" 82 #if defined(CONFIG_DRM_AMD_DC_FP) 83 #include "dc_spl_translate.h" 84 #endif 85 86 #define VISUAL_CONFIRM_BASE_DEFAULT 3 87 #define VISUAL_CONFIRM_BASE_MIN 1 88 #define VISUAL_CONFIRM_BASE_MAX 10 89 /* we choose 240 because it is a common denominator of common v addressable 90 * such as 2160, 1440, 1200, 960. So we take 1/240 portion of v addressable as 91 * the visual confirm dpp offset height. So visual confirm height can stay 92 * relatively the same independent from timing used. 93 */ 94 #define VISUAL_CONFIRM_DPP_OFFSET_DENO 240 95 96 #define DC_LOGGER \ 97 dc->ctx->logger 98 #define DC_LOGGER_INIT(logger) 99 #include "dml2_0/dml2_wrapper.h" 100 101 #define UNABLE_TO_SPLIT -1 102 103 static void capture_pipe_topology_data(struct dc *dc, int plane_idx, int slice_idx, int stream_idx, 104 int dpp_inst, int opp_inst, int tg_inst, bool is_phantom_pipe) 105 { 106 struct pipe_topology_snapshot *current_snapshot = &dc->debug_data.topology_history.snapshots[dc->debug_data.topology_history.current_snapshot_index]; 107 108 if (current_snapshot->line_count >= MAX_PIPES) 109 return; 110 111 current_snapshot->pipe_log_lines[current_snapshot->line_count].is_phantom_pipe = is_phantom_pipe; 112 current_snapshot->pipe_log_lines[current_snapshot->line_count].plane_idx = plane_idx; 113 current_snapshot->pipe_log_lines[current_snapshot->line_count].slice_idx = slice_idx; 114 current_snapshot->pipe_log_lines[current_snapshot->line_count].stream_idx = stream_idx; 115 current_snapshot->pipe_log_lines[current_snapshot->line_count].dpp_inst = dpp_inst; 116 current_snapshot->pipe_log_lines[current_snapshot->line_count].opp_inst = opp_inst; 117 current_snapshot->pipe_log_lines[current_snapshot->line_count].tg_inst = tg_inst; 118 119 current_snapshot->line_count++; 120 } 121 122 static void start_new_topology_snapshot(struct dc *dc, struct dc_state *state) 123 { 124 // Move to next snapshot slot (circular buffer) 125 dc->debug_data.topology_history.current_snapshot_index = (dc->debug_data.topology_history.current_snapshot_index + 1) % MAX_TOPOLOGY_SNAPSHOTS; 126 127 // Clear the new snapshot 128 struct pipe_topology_snapshot *current_snapshot = &dc->debug_data.topology_history.snapshots[dc->debug_data.topology_history.current_snapshot_index]; 129 memset(current_snapshot, 0, sizeof(*current_snapshot)); 130 131 // Set metadata 132 current_snapshot->timestamp_us = dm_get_timestamp(dc->ctx); 133 current_snapshot->stream_count = state->stream_count; 134 current_snapshot->phantom_stream_count = state->phantom_stream_count; 135 } 136 137 enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) 138 { 139 enum dce_version dc_version = DCE_VERSION_UNKNOWN; 140 141 switch (asic_id.chip_family) { 142 143 #if defined(CONFIG_DRM_AMD_DC_SI) 144 case FAMILY_SI: 145 if (ASIC_REV_IS_TAHITI_P(asic_id.hw_internal_rev) || 146 ASIC_REV_IS_PITCAIRN_PM(asic_id.hw_internal_rev) || 147 ASIC_REV_IS_CAPEVERDE_M(asic_id.hw_internal_rev)) 148 dc_version = DCE_VERSION_6_0; 149 else if (ASIC_REV_IS_OLAND_M(asic_id.hw_internal_rev)) 150 dc_version = DCE_VERSION_6_4; 151 else 152 dc_version = DCE_VERSION_6_1; 153 break; 154 #endif 155 case FAMILY_CI: 156 dc_version = DCE_VERSION_8_0; 157 break; 158 case FAMILY_KV: 159 if (ASIC_REV_IS_KALINDI(asic_id.hw_internal_rev) || 160 ASIC_REV_IS_BHAVANI(asic_id.hw_internal_rev) || 161 ASIC_REV_IS_GODAVARI(asic_id.hw_internal_rev)) 162 dc_version = DCE_VERSION_8_3; 163 else 164 dc_version = DCE_VERSION_8_1; 165 break; 166 case FAMILY_CZ: 167 dc_version = DCE_VERSION_11_0; 168 break; 169 170 case FAMILY_VI: 171 if (ASIC_REV_IS_TONGA_P(asic_id.hw_internal_rev) || 172 ASIC_REV_IS_FIJI_P(asic_id.hw_internal_rev)) { 173 dc_version = DCE_VERSION_10_0; 174 break; 175 } 176 if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev) || 177 ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev) || 178 ASIC_REV_IS_POLARIS12_V(asic_id.hw_internal_rev)) { 179 dc_version = DCE_VERSION_11_2; 180 } 181 if (ASIC_REV_IS_VEGAM(asic_id.hw_internal_rev)) 182 dc_version = DCE_VERSION_11_22; 183 break; 184 case FAMILY_AI: 185 if (ASICREV_IS_VEGA20_P(asic_id.hw_internal_rev)) 186 dc_version = DCE_VERSION_12_1; 187 else 188 dc_version = DCE_VERSION_12_0; 189 break; 190 case FAMILY_RV: 191 dc_version = DCN_VERSION_1_0; 192 if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev)) 193 dc_version = DCN_VERSION_1_01; 194 if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev)) 195 dc_version = DCN_VERSION_2_1; 196 if (ASICREV_IS_GREEN_SARDINE(asic_id.hw_internal_rev)) 197 dc_version = DCN_VERSION_2_1; 198 break; 199 200 case FAMILY_NV: 201 dc_version = DCN_VERSION_2_0; 202 if (asic_id.chip_id == DEVICE_ID_NV_13FE || 203 asic_id.chip_id == DEVICE_ID_NV_143F || 204 asic_id.chip_id == DEVICE_ID_NV_13F9 || 205 asic_id.chip_id == DEVICE_ID_NV_13FA || 206 asic_id.chip_id == DEVICE_ID_NV_13FB || 207 asic_id.chip_id == DEVICE_ID_NV_13FC || 208 asic_id.chip_id == DEVICE_ID_NV_13DB) { 209 dc_version = DCN_VERSION_2_01; 210 break; 211 } 212 if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev)) 213 dc_version = DCN_VERSION_3_0; 214 if (ASICREV_IS_DIMGREY_CAVEFISH_P(asic_id.hw_internal_rev)) 215 dc_version = DCN_VERSION_3_02; 216 if (ASICREV_IS_BEIGE_GOBY_P(asic_id.hw_internal_rev)) 217 dc_version = DCN_VERSION_3_03; 218 break; 219 220 case FAMILY_VGH: 221 dc_version = DCN_VERSION_3_01; 222 break; 223 224 case FAMILY_YELLOW_CARP: 225 if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev)) 226 dc_version = DCN_VERSION_3_1; 227 break; 228 case AMDGPU_FAMILY_GC_10_3_6: 229 if (ASICREV_IS_GC_10_3_6(asic_id.hw_internal_rev)) 230 dc_version = DCN_VERSION_3_15; 231 break; 232 case AMDGPU_FAMILY_GC_10_3_7: 233 if (ASICREV_IS_GC_10_3_7(asic_id.hw_internal_rev)) 234 dc_version = DCN_VERSION_3_16; 235 break; 236 case AMDGPU_FAMILY_GC_11_0_0: 237 dc_version = DCN_VERSION_3_2; 238 if (ASICREV_IS_GC_11_0_2(asic_id.hw_internal_rev)) 239 dc_version = DCN_VERSION_3_21; 240 break; 241 case AMDGPU_FAMILY_GC_11_0_1: 242 dc_version = DCN_VERSION_3_14; 243 break; 244 case AMDGPU_FAMILY_GC_11_5_0: 245 dc_version = DCN_VERSION_3_5; 246 if (ASICREV_IS_GC_11_0_4(asic_id.hw_internal_rev)) 247 dc_version = DCN_VERSION_3_51; 248 if (ASICREV_IS_DCN36(asic_id.hw_internal_rev)) 249 dc_version = DCN_VERSION_3_6; 250 break; 251 case AMDGPU_FAMILY_GC_12_0_0: 252 if (ASICREV_IS_GC_12_0_1_A0(asic_id.hw_internal_rev) || 253 ASICREV_IS_GC_12_0_0_A0(asic_id.hw_internal_rev)) 254 dc_version = DCN_VERSION_4_01; 255 break; 256 case AMDGPU_FAMILY_GC_11_5_4: 257 dc_version = DCN_VERSION_4_2; 258 break; 259 default: 260 dc_version = DCE_VERSION_UNKNOWN; 261 break; 262 } 263 return dc_version; 264 } 265 266 struct resource_pool *dc_create_resource_pool(struct dc *dc, 267 const struct dc_init_data *init_data, 268 enum dce_version dc_version) 269 { 270 struct resource_pool *res_pool = NULL; 271 272 switch (dc_version) { 273 #if defined(CONFIG_DRM_AMD_DC_SI) 274 case DCE_VERSION_6_0: 275 res_pool = dce60_create_resource_pool( 276 init_data->num_virtual_links, dc); 277 break; 278 case DCE_VERSION_6_1: 279 res_pool = dce61_create_resource_pool( 280 init_data->num_virtual_links, dc); 281 break; 282 case DCE_VERSION_6_4: 283 res_pool = dce64_create_resource_pool( 284 init_data->num_virtual_links, dc); 285 break; 286 #endif 287 case DCE_VERSION_8_0: 288 res_pool = dce80_create_resource_pool( 289 init_data->num_virtual_links, dc); 290 break; 291 case DCE_VERSION_8_1: 292 res_pool = dce81_create_resource_pool( 293 init_data->num_virtual_links, dc); 294 break; 295 case DCE_VERSION_8_3: 296 res_pool = dce83_create_resource_pool( 297 init_data->num_virtual_links, dc); 298 break; 299 case DCE_VERSION_10_0: 300 res_pool = dce100_create_resource_pool( 301 init_data->num_virtual_links, dc); 302 break; 303 case DCE_VERSION_11_0: 304 res_pool = dce110_create_resource_pool( 305 init_data->num_virtual_links, dc, 306 init_data->asic_id); 307 break; 308 case DCE_VERSION_11_2: 309 case DCE_VERSION_11_22: 310 res_pool = dce112_create_resource_pool( 311 init_data->num_virtual_links, dc); 312 break; 313 case DCE_VERSION_12_0: 314 case DCE_VERSION_12_1: 315 res_pool = dce120_create_resource_pool( 316 init_data->num_virtual_links, dc); 317 break; 318 319 #if defined(CONFIG_DRM_AMD_DC_FP) 320 case DCN_VERSION_1_0: 321 case DCN_VERSION_1_01: 322 res_pool = dcn10_create_resource_pool(init_data, dc); 323 break; 324 case DCN_VERSION_2_0: 325 res_pool = dcn20_create_resource_pool(init_data, dc); 326 break; 327 case DCN_VERSION_2_1: 328 res_pool = dcn21_create_resource_pool(init_data, dc); 329 break; 330 case DCN_VERSION_2_01: 331 res_pool = dcn201_create_resource_pool(init_data, dc); 332 break; 333 case DCN_VERSION_3_0: 334 res_pool = dcn30_create_resource_pool(init_data, dc); 335 break; 336 case DCN_VERSION_3_01: 337 res_pool = dcn301_create_resource_pool(init_data, dc); 338 break; 339 case DCN_VERSION_3_02: 340 res_pool = dcn302_create_resource_pool(init_data, dc); 341 break; 342 case DCN_VERSION_3_03: 343 res_pool = dcn303_create_resource_pool(init_data, dc); 344 break; 345 case DCN_VERSION_3_1: 346 res_pool = dcn31_create_resource_pool(init_data, dc); 347 break; 348 case DCN_VERSION_3_14: 349 res_pool = dcn314_create_resource_pool(init_data, dc); 350 break; 351 case DCN_VERSION_3_15: 352 res_pool = dcn315_create_resource_pool(init_data, dc); 353 break; 354 case DCN_VERSION_3_16: 355 res_pool = dcn316_create_resource_pool(init_data, dc); 356 break; 357 case DCN_VERSION_3_2: 358 res_pool = dcn32_create_resource_pool(init_data, dc); 359 break; 360 case DCN_VERSION_3_21: 361 res_pool = dcn321_create_resource_pool(init_data, dc); 362 break; 363 case DCN_VERSION_3_5: 364 res_pool = dcn35_create_resource_pool(init_data, dc); 365 break; 366 case DCN_VERSION_3_51: 367 res_pool = dcn351_create_resource_pool(init_data, dc); 368 break; 369 case DCN_VERSION_3_6: 370 res_pool = dcn36_create_resource_pool(init_data, dc); 371 break; 372 case DCN_VERSION_4_01: 373 res_pool = dcn401_create_resource_pool(init_data, dc); 374 break; 375 case DCN_VERSION_4_2: 376 res_pool = dcn42_create_resource_pool(init_data, dc); 377 break; 378 #endif /* CONFIG_DRM_AMD_DC_FP */ 379 default: 380 break; 381 } 382 383 if (res_pool != NULL) { 384 if (dc->ctx->dc_bios->fw_info_valid) { 385 res_pool->ref_clocks.xtalin_clock_inKhz = 386 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; 387 /* initialize with firmware data first, no all 388 * ASIC have DCCG SW component. FPGA or 389 * simulation need initialization of 390 * dccg_ref_clock_inKhz, dchub_ref_clock_inKhz 391 * with xtalin_clock_inKhz 392 */ 393 res_pool->ref_clocks.dccg_ref_clock_inKhz = 394 res_pool->ref_clocks.xtalin_clock_inKhz; 395 res_pool->ref_clocks.dchub_ref_clock_inKhz = 396 res_pool->ref_clocks.xtalin_clock_inKhz; 397 } else 398 ASSERT_CRITICAL(false); 399 } 400 401 return res_pool; 402 } 403 404 void dc_destroy_resource_pool(struct dc *dc) 405 { 406 if (dc) { 407 if (dc->res_pool) 408 dc->res_pool->funcs->destroy(&dc->res_pool); 409 410 kfree(dc->hwseq); 411 } 412 } 413 414 static void update_num_audio( 415 const struct resource_straps *straps, 416 unsigned int *num_audio, 417 struct audio_support *aud_support) 418 { 419 aud_support->dp_audio = true; 420 aud_support->hdmi_audio_native = false; 421 aud_support->hdmi_audio_on_dongle = false; 422 423 if (straps->hdmi_disable == 0) { 424 if (straps->dc_pinstraps_audio & 0x2) { 425 aud_support->hdmi_audio_on_dongle = true; 426 aud_support->hdmi_audio_native = true; 427 } 428 } 429 430 switch (straps->audio_stream_number) { 431 case 0: /* multi streams supported */ 432 break; 433 case 1: /* multi streams not supported */ 434 *num_audio = 1; 435 break; 436 default: 437 DC_ERR("DC: unexpected audio fuse!\n"); 438 } 439 } 440 441 bool resource_construct( 442 unsigned int num_virtual_links, 443 struct dc *dc, 444 struct resource_pool *pool, 445 const struct resource_create_funcs *create_funcs) 446 { 447 struct dc_context *ctx = dc->ctx; 448 const struct resource_caps *caps = pool->res_cap; 449 int i; 450 unsigned int num_audio = caps->num_audio; 451 struct resource_straps straps = {0}; 452 453 if (create_funcs->read_dce_straps) 454 create_funcs->read_dce_straps(dc->ctx, &straps); 455 456 pool->audio_count = 0; 457 if (create_funcs->create_audio) { 458 /* find the total number of streams available via the 459 * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT 460 * registers (one for each pin) starting from pin 1 461 * up to the max number of audio pins. 462 * We stop on the first pin where 463 * PORT_CONNECTIVITY == 1 (as instructed by HW team). 464 */ 465 update_num_audio(&straps, &num_audio, &pool->audio_support); 466 for (i = 0; i < caps->num_audio; i++) { 467 struct audio *aud = create_funcs->create_audio(ctx, i); 468 469 if (aud == NULL) { 470 DC_ERR("DC: failed to create audio!\n"); 471 return false; 472 } 473 if (!aud->funcs->endpoint_valid(aud)) { 474 aud->funcs->destroy(&aud); 475 break; 476 } 477 pool->audios[i] = aud; 478 pool->audio_count++; 479 } 480 } 481 482 pool->stream_enc_count = 0; 483 if (create_funcs->create_stream_encoder) { 484 for (i = 0; i < caps->num_stream_encoder; i++) { 485 pool->stream_enc[i] = create_funcs->create_stream_encoder(i, ctx); 486 if (pool->stream_enc[i] == NULL) 487 DC_ERR("DC: failed to create stream_encoder!\n"); 488 pool->stream_enc_count++; 489 } 490 491 for (i = 0; i < caps->num_analog_stream_encoder; i++) { 492 pool->stream_enc[caps->num_stream_encoder + i] = 493 create_funcs->create_stream_encoder(ENGINE_ID_DACA + i, ctx); 494 if (pool->stream_enc[caps->num_stream_encoder + i] == NULL) 495 DC_ERR("DC: failed to create analog stream_encoder %d!\n", i); 496 pool->stream_enc_count++; 497 } 498 } 499 500 pool->hpo_dp_stream_enc_count = 0; 501 if (create_funcs->create_hpo_dp_stream_encoder) { 502 for (i = 0; i < caps->num_hpo_dp_stream_encoder; i++) { 503 pool->hpo_dp_stream_enc[i] = create_funcs->create_hpo_dp_stream_encoder(i+ENGINE_ID_HPO_DP_0, ctx); 504 if (pool->hpo_dp_stream_enc[i] == NULL) 505 DC_ERR("DC: failed to create HPO DP stream encoder!\n"); 506 pool->hpo_dp_stream_enc_count++; 507 508 } 509 } 510 511 pool->hpo_dp_link_enc_count = 0; 512 if (create_funcs->create_hpo_dp_link_encoder) { 513 for (i = 0; i < caps->num_hpo_dp_link_encoder; i++) { 514 pool->hpo_dp_link_enc[i] = create_funcs->create_hpo_dp_link_encoder(i, ctx); 515 if (pool->hpo_dp_link_enc[i] == NULL) 516 DC_ERR("DC: failed to create HPO DP link encoder!\n"); 517 pool->hpo_dp_link_enc_count++; 518 } 519 } 520 521 for (i = 0; i < caps->num_mpc_3dlut; i++) { 522 pool->mpc_lut[i] = dc_create_3dlut_func(); 523 if (pool->mpc_lut[i] == NULL) 524 DC_ERR("DC: failed to create MPC 3dlut!\n"); 525 pool->mpc_shaper[i] = dc_create_transfer_func(); 526 if (pool->mpc_shaper[i] == NULL) 527 DC_ERR("DC: failed to create MPC shaper!\n"); 528 } 529 530 dc->caps.dynamic_audio = false; 531 if (pool->audio_count < pool->stream_enc_count) { 532 dc->caps.dynamic_audio = true; 533 } 534 for (i = 0; i < num_virtual_links; i++) { 535 pool->stream_enc[pool->stream_enc_count] = 536 virtual_stream_encoder_create( 537 ctx, ctx->dc_bios); 538 if (pool->stream_enc[pool->stream_enc_count] == NULL) { 539 DC_ERR("DC: failed to create stream_encoder!\n"); 540 return false; 541 } 542 pool->stream_enc_count++; 543 } 544 545 dc->hwseq = create_funcs->create_hwseq(ctx); 546 547 return true; 548 } 549 static int find_matching_clock_source( 550 const struct resource_pool *pool, 551 struct clock_source *clock_source) 552 { 553 554 int i; 555 556 for (i = 0; i < pool->clk_src_count; i++) { 557 if (pool->clock_sources[i] == clock_source) 558 return i; 559 } 560 return -1; 561 } 562 563 void resource_unreference_clock_source( 564 struct resource_context *res_ctx, 565 const struct resource_pool *pool, 566 struct clock_source *clock_source) 567 { 568 int i = find_matching_clock_source(pool, clock_source); 569 570 if (i > -1) 571 res_ctx->clock_source_ref_count[i]--; 572 573 if (pool->dp_clock_source == clock_source) 574 res_ctx->dp_clock_source_ref_count--; 575 } 576 577 void resource_reference_clock_source( 578 struct resource_context *res_ctx, 579 const struct resource_pool *pool, 580 struct clock_source *clock_source) 581 { 582 int i = find_matching_clock_source(pool, clock_source); 583 584 if (i > -1) 585 res_ctx->clock_source_ref_count[i]++; 586 587 if (pool->dp_clock_source == clock_source) 588 res_ctx->dp_clock_source_ref_count++; 589 } 590 591 int resource_get_clock_source_reference( 592 struct resource_context *res_ctx, 593 const struct resource_pool *pool, 594 struct clock_source *clock_source) 595 { 596 int i = find_matching_clock_source(pool, clock_source); 597 598 if (i > -1) 599 return res_ctx->clock_source_ref_count[i]; 600 601 if (pool->dp_clock_source == clock_source) 602 return res_ctx->dp_clock_source_ref_count; 603 604 return -1; 605 } 606 607 bool resource_are_vblanks_synchronizable( 608 struct dc_stream_state *stream1, 609 struct dc_stream_state *stream2) 610 { 611 uint32_t base60_refresh_rates[] = {10, 20, 5}; 612 uint8_t i; 613 uint8_t rr_count = ARRAY_SIZE(base60_refresh_rates); 614 uint64_t frame_time_diff; 615 616 if (stream1->ctx->dc->config.vblank_alignment_dto_params && 617 stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0 && 618 dc_is_dp_signal(stream1->signal) && 619 dc_is_dp_signal(stream2->signal) && 620 false == stream1->has_non_synchronizable_pclk && 621 false == stream2->has_non_synchronizable_pclk && 622 stream1->timing.flags.VBLANK_SYNCHRONIZABLE && 623 stream2->timing.flags.VBLANK_SYNCHRONIZABLE) { 624 /* disable refresh rates higher than 60Hz for now */ 625 if (stream1->timing.pix_clk_100hz*100/stream1->timing.h_total/ 626 stream1->timing.v_total > 60) 627 return false; 628 if (stream2->timing.pix_clk_100hz*100/stream2->timing.h_total/ 629 stream2->timing.v_total > 60) 630 return false; 631 frame_time_diff = (uint64_t)10000 * 632 stream1->timing.h_total * 633 stream1->timing.v_total * 634 stream2->timing.pix_clk_100hz; 635 frame_time_diff = div_u64(frame_time_diff, stream1->timing.pix_clk_100hz); 636 frame_time_diff = div_u64(frame_time_diff, stream2->timing.h_total); 637 frame_time_diff = div_u64(frame_time_diff, stream2->timing.v_total); 638 for (i = 0; i < rr_count; i++) { 639 int64_t diff = (int64_t)div_u64(frame_time_diff * base60_refresh_rates[i], 10) - 10000; 640 641 if (diff < 0) 642 diff = -diff; 643 if (diff < stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff) 644 return true; 645 } 646 } 647 return false; 648 } 649 650 bool resource_are_streams_timing_synchronizable( 651 struct dc_stream_state *stream1, 652 struct dc_stream_state *stream2) 653 { 654 if (stream1->timing.h_total != stream2->timing.h_total) 655 return false; 656 657 if (stream1->timing.v_total != stream2->timing.v_total) 658 return false; 659 660 if (stream1->timing.h_addressable 661 != stream2->timing.h_addressable) 662 return false; 663 664 if (stream1->timing.v_addressable 665 != stream2->timing.v_addressable) 666 return false; 667 668 if (stream1->timing.v_front_porch 669 != stream2->timing.v_front_porch) 670 return false; 671 672 if (stream1->timing.pix_clk_100hz 673 != stream2->timing.pix_clk_100hz) 674 return false; 675 676 if (stream1->clamping.c_depth != stream2->clamping.c_depth) 677 return false; 678 679 if (stream1->phy_pix_clk != stream2->phy_pix_clk 680 && (!dc_is_dp_signal(stream1->signal) 681 || !dc_is_dp_signal(stream2->signal))) 682 return false; 683 684 if (stream1->view_format != stream2->view_format) 685 return false; 686 687 if (stream1->ignore_msa_timing_param || stream2->ignore_msa_timing_param) 688 return false; 689 690 return true; 691 } 692 static bool is_dp_and_hdmi_sharable( 693 struct dc_stream_state *stream1, 694 struct dc_stream_state *stream2) 695 { 696 if (stream1->ctx->dc->caps.disable_dp_clk_share) 697 return false; 698 699 if (stream1->clamping.c_depth != COLOR_DEPTH_888 || 700 stream2->clamping.c_depth != COLOR_DEPTH_888) 701 return false; 702 703 return true; 704 705 } 706 707 static bool is_sharable_clk_src( 708 const struct pipe_ctx *pipe_with_clk_src, 709 const struct pipe_ctx *pipe) 710 { 711 if (pipe_with_clk_src->clock_source == NULL) 712 return false; 713 714 if (pipe_with_clk_src->stream->signal == SIGNAL_TYPE_VIRTUAL) 715 return false; 716 717 if (dc_is_dp_signal(pipe_with_clk_src->stream->signal) || 718 (dc_is_dp_signal(pipe->stream->signal) && 719 !is_dp_and_hdmi_sharable(pipe_with_clk_src->stream, 720 pipe->stream))) 721 return false; 722 723 if (dc_is_hdmi_signal(pipe_with_clk_src->stream->signal) 724 && dc_is_dual_link_signal(pipe->stream->signal)) 725 return false; 726 727 if (dc_is_hdmi_signal(pipe->stream->signal) 728 && dc_is_dual_link_signal(pipe_with_clk_src->stream->signal)) 729 return false; 730 731 if (!resource_are_streams_timing_synchronizable( 732 pipe_with_clk_src->stream, pipe->stream)) 733 return false; 734 735 return true; 736 } 737 738 struct clock_source *resource_find_used_clk_src_for_sharing( 739 struct resource_context *res_ctx, 740 struct pipe_ctx *pipe_ctx) 741 { 742 int i; 743 744 for (i = 0; i < MAX_PIPES; i++) { 745 if (is_sharable_clk_src(&res_ctx->pipe_ctx[i], pipe_ctx)) 746 return res_ctx->pipe_ctx[i].clock_source; 747 } 748 749 return NULL; 750 } 751 752 static enum dc_pixel_format convert_pixel_format_to_dalsurface( 753 enum surface_pixel_format surface_pixel_format) 754 { 755 enum dc_pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN; 756 757 switch (surface_pixel_format) { 758 case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS: 759 dal_pixel_format = PIXEL_FORMAT_INDEX8; 760 break; 761 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: 762 dal_pixel_format = PIXEL_FORMAT_RGB565; 763 break; 764 case SURFACE_PIXEL_FORMAT_GRPH_RGB565: 765 dal_pixel_format = PIXEL_FORMAT_RGB565; 766 break; 767 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: 768 dal_pixel_format = PIXEL_FORMAT_ARGB8888; 769 break; 770 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: 771 dal_pixel_format = PIXEL_FORMAT_ARGB8888; 772 break; 773 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: 774 dal_pixel_format = PIXEL_FORMAT_ARGB2101010; 775 break; 776 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: 777 dal_pixel_format = PIXEL_FORMAT_ARGB2101010; 778 break; 779 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS: 780 dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS; 781 break; 782 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: 783 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: 784 dal_pixel_format = PIXEL_FORMAT_FP16; 785 break; 786 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: 787 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: 788 dal_pixel_format = PIXEL_FORMAT_420BPP8; 789 break; 790 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: 791 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: 792 dal_pixel_format = PIXEL_FORMAT_420BPP10; 793 break; 794 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: 795 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: 796 default: 797 dal_pixel_format = PIXEL_FORMAT_UNKNOWN; 798 break; 799 } 800 return dal_pixel_format; 801 } 802 803 static inline void get_vp_scan_direction( 804 enum dc_rotation_angle rotation, 805 bool horizontal_mirror, 806 bool *orthogonal_rotation, 807 bool *flip_vert_scan_dir, 808 bool *flip_horz_scan_dir) 809 { 810 *orthogonal_rotation = false; 811 *flip_vert_scan_dir = false; 812 *flip_horz_scan_dir = false; 813 if (rotation == ROTATION_ANGLE_180) { 814 *flip_vert_scan_dir = true; 815 *flip_horz_scan_dir = true; 816 } else if (rotation == ROTATION_ANGLE_90) { 817 *orthogonal_rotation = true; 818 *flip_horz_scan_dir = true; 819 } else if (rotation == ROTATION_ANGLE_270) { 820 *orthogonal_rotation = true; 821 *flip_vert_scan_dir = true; 822 } 823 824 if (horizontal_mirror) 825 *flip_horz_scan_dir = !*flip_horz_scan_dir; 826 } 827 828 static struct rect intersect_rec(const struct rect *r0, const struct rect *r1) 829 { 830 struct rect rec; 831 int r0_x_end = r0->x + r0->width; 832 int r1_x_end = r1->x + r1->width; 833 int r0_y_end = r0->y + r0->height; 834 int r1_y_end = r1->y + r1->height; 835 836 rec.x = r0->x > r1->x ? r0->x : r1->x; 837 rec.width = r0_x_end > r1_x_end ? r1_x_end - rec.x : r0_x_end - rec.x; 838 rec.y = r0->y > r1->y ? r0->y : r1->y; 839 rec.height = r0_y_end > r1_y_end ? r1_y_end - rec.y : r0_y_end - rec.y; 840 841 /* in case that there is no intersection */ 842 if (rec.width < 0 || rec.height < 0) 843 memset(&rec, 0, sizeof(rec)); 844 845 return rec; 846 } 847 848 static struct rect shift_rec(const struct rect *rec_in, int x, int y) 849 { 850 struct rect rec_out = *rec_in; 851 852 rec_out.x += x; 853 rec_out.y += y; 854 855 return rec_out; 856 } 857 858 static struct rect calculate_plane_rec_in_timing_active( 859 struct pipe_ctx *pipe_ctx, 860 const struct rect *rec_in) 861 { 862 /* 863 * The following diagram shows an example where we map a 1920x1200 864 * desktop to a 2560x1440 timing with a plane rect in the middle 865 * of the screen. To map a plane rect from Stream Source to Timing 866 * Active space, we first multiply stream scaling ratios (i.e 2304/1920 867 * horizontal and 1440/1200 vertical) to the plane's x and y, then 868 * we add stream destination offsets (i.e 128 horizontal, 0 vertical). 869 * This will give us a plane rect's position in Timing Active. However 870 * we have to remove the fractional. The rule is that we find left/right 871 * and top/bottom positions and round the value to the adjacent integer. 872 * 873 * Stream Source Space 874 * ------------ 875 * __________________________________________________ 876 * |Stream Source (1920 x 1200) ^ | 877 * | y | 878 * | <------- w --------|> | 879 * | __________________V | 880 * |<-- x -->|Plane//////////////| ^ | 881 * | |(pre scale)////////| | | 882 * | |///////////////////| | | 883 * | |///////////////////| h | 884 * | |///////////////////| | | 885 * | |///////////////////| | | 886 * | |///////////////////| V | 887 * | | 888 * | | 889 * |__________________________________________________| 890 * 891 * 892 * Timing Active Space 893 * --------------------------------- 894 * 895 * Timing Active (2560 x 1440) 896 * __________________________________________________ 897 * |*****| Stteam Destination (2304 x 1440) |*****| 898 * |*****| |*****| 899 * |<128>| |*****| 900 * |*****| __________________ |*****| 901 * |*****| |Plane/////////////| |*****| 902 * |*****| |(post scale)//////| |*****| 903 * |*****| |//////////////////| |*****| 904 * |*****| |//////////////////| |*****| 905 * |*****| |//////////////////| |*****| 906 * |*****| |//////////////////| |*****| 907 * |*****| |*****| 908 * |*****| |*****| 909 * |*****| |*****| 910 * |*****|______________________________________|*****| 911 * 912 * So the resulting formulas are shown below: 913 * 914 * recout_x = 128 + round(plane_x * 2304 / 1920) 915 * recout_w = 128 + round((plane_x + plane_w) * 2304 / 1920) - recout_x 916 * recout_y = 0 + round(plane_y * 1440 / 1280) 917 * recout_h = 0 + round((plane_y + plane_h) * 1440 / 1200) - recout_y 918 * 919 * NOTE: fixed point division is not error free. To reduce errors 920 * introduced by fixed point division, we divide only after 921 * multiplication is complete. 922 */ 923 const struct dc_stream_state *stream = pipe_ctx->stream; 924 struct rect rec_out = {0}; 925 struct fixed31_32 temp; 926 927 temp = dc_fixpt_from_fraction(rec_in->x * (long long)stream->dst.width, 928 stream->src.width); 929 rec_out.x = stream->dst.x + dc_fixpt_round(temp); 930 931 temp = dc_fixpt_from_fraction( 932 (rec_in->x + rec_in->width) * (long long)stream->dst.width, 933 stream->src.width); 934 rec_out.width = stream->dst.x + dc_fixpt_round(temp) - rec_out.x; 935 936 temp = dc_fixpt_from_fraction(rec_in->y * (long long)stream->dst.height, 937 stream->src.height); 938 rec_out.y = stream->dst.y + dc_fixpt_round(temp); 939 940 temp = dc_fixpt_from_fraction( 941 (rec_in->y + rec_in->height) * (long long)stream->dst.height, 942 stream->src.height); 943 rec_out.height = stream->dst.y + dc_fixpt_round(temp) - rec_out.y; 944 945 return rec_out; 946 } 947 948 static struct rect calculate_mpc_slice_in_timing_active( 949 struct pipe_ctx *pipe_ctx, 950 struct rect *plane_clip_rec) 951 { 952 const struct dc_stream_state *stream = pipe_ctx->stream; 953 int mpc_slice_count = resource_get_mpc_slice_count(pipe_ctx); 954 int mpc_slice_idx = resource_get_mpc_slice_index(pipe_ctx); 955 int epimo = mpc_slice_count - plane_clip_rec->width % mpc_slice_count - 1; 956 struct rect mpc_rec; 957 958 mpc_rec.width = plane_clip_rec->width / mpc_slice_count; 959 mpc_rec.x = plane_clip_rec->x + mpc_rec.width * mpc_slice_idx; 960 mpc_rec.height = plane_clip_rec->height; 961 mpc_rec.y = plane_clip_rec->y; 962 ASSERT(mpc_slice_count == 1 || 963 stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE || 964 mpc_rec.width % 2 == 0); 965 966 if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) 967 mpc_rec.x -= (mpc_rec.width * mpc_slice_idx); 968 969 /* extra pixels in the division remainder need to go to pipes after 970 * the extra pixel index minus one(epimo) defined here as: 971 */ 972 if (mpc_slice_idx > epimo) { 973 mpc_rec.x += mpc_slice_idx - epimo - 1; 974 mpc_rec.width += 1; 975 } 976 977 if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) { 978 ASSERT(mpc_rec.height % 2 == 0); 979 mpc_rec.height /= 2; 980 } 981 return mpc_rec; 982 } 983 984 static void calculate_adjust_recout_for_visual_confirm(struct pipe_ctx *pipe_ctx, 985 int *base_offset, int *dpp_offset) 986 { 987 struct dc *dc = pipe_ctx->stream->ctx->dc; 988 *base_offset = 0; 989 *dpp_offset = 0; 990 991 if (dc->debug.visual_confirm == VISUAL_CONFIRM_DISABLE || !pipe_ctx->plane_res.dpp) 992 return; 993 994 *dpp_offset = pipe_ctx->stream->timing.v_addressable / VISUAL_CONFIRM_DPP_OFFSET_DENO; 995 *dpp_offset *= pipe_ctx->plane_res.dpp->inst; 996 997 if ((dc->debug.visual_confirm_rect_height >= VISUAL_CONFIRM_BASE_MIN) && 998 dc->debug.visual_confirm_rect_height <= VISUAL_CONFIRM_BASE_MAX) 999 *base_offset = dc->debug.visual_confirm_rect_height; 1000 else 1001 *base_offset = VISUAL_CONFIRM_BASE_DEFAULT; 1002 } 1003 1004 static void reverse_adjust_recout_for_visual_confirm(struct rect *recout, 1005 struct pipe_ctx *pipe_ctx) 1006 { 1007 int dpp_offset, base_offset; 1008 1009 calculate_adjust_recout_for_visual_confirm(pipe_ctx, &base_offset, 1010 &dpp_offset); 1011 recout->height += base_offset; 1012 recout->height += dpp_offset; 1013 } 1014 1015 static void adjust_recout_for_visual_confirm(struct rect *recout, 1016 struct pipe_ctx *pipe_ctx) 1017 { 1018 int dpp_offset, base_offset; 1019 1020 calculate_adjust_recout_for_visual_confirm(pipe_ctx, &base_offset, 1021 &dpp_offset); 1022 recout->height -= base_offset; 1023 recout->height -= dpp_offset; 1024 } 1025 1026 /* 1027 * The function maps a plane clip from Stream Source Space to ODM Slice Space 1028 * and calculates the rec of the overlapping area of MPC slice of the plane 1029 * clip, ODM slice associated with the pipe context and stream destination rec. 1030 */ 1031 static void calculate_recout(struct pipe_ctx *pipe_ctx) 1032 { 1033 /* 1034 * A plane clip represents the desired plane size and position in Stream 1035 * Source Space. Stream Source is the destination where all planes are 1036 * blended (i.e. positioned, scaled and overlaid). It is a canvas where 1037 * all planes associated with the current stream are drawn together. 1038 * After Stream Source is completed, we will further scale and 1039 * reposition the entire canvas of the stream source to Stream 1040 * Destination in Timing Active Space. This could be due to display 1041 * overscan adjustment where we will need to rescale and reposition all 1042 * the planes so they can fit into a TV with overscan or downscale 1043 * upscale features such as GPU scaling or VSR. 1044 * 1045 * This two step blending is a virtual procedure in software. In 1046 * hardware there is no such thing as Stream Source. all planes are 1047 * blended once in Timing Active Space. Software virtualizes a Stream 1048 * Source space to decouple the math complicity so scaling param 1049 * calculation focuses on one step at a time. 1050 * 1051 * In the following two diagrams, user applied 10% overscan adjustment 1052 * so the Stream Source needs to be scaled down a little before mapping 1053 * to Timing Active Space. As a result the Plane Clip is also scaled 1054 * down by the same ratio, Plane Clip position (i.e. x and y) with 1055 * respect to Stream Source is also scaled down. To map it in Timing 1056 * Active Space additional x and y offsets from Stream Destination are 1057 * added to Plane Clip as well. 1058 * 1059 * Stream Source Space 1060 * ------------ 1061 * __________________________________________________ 1062 * |Stream Source (3840 x 2160) ^ | 1063 * | y | 1064 * | | | 1065 * | __________________V | 1066 * |<-- x -->|Plane Clip/////////| | 1067 * | |(pre scale)////////| | 1068 * | |///////////////////| | 1069 * | |///////////////////| | 1070 * | |///////////////////| | 1071 * | |///////////////////| | 1072 * | |///////////////////| | 1073 * | | 1074 * | | 1075 * |__________________________________________________| 1076 * 1077 * 1078 * Timing Active Space (3840 x 2160) 1079 * --------------------------------- 1080 * 1081 * Timing Active 1082 * __________________________________________________ 1083 * | y_____________________________________________ | 1084 * |x |Stream Destination (3456 x 1944) | | 1085 * | | | | 1086 * | | __________________ | | 1087 * | | |Plane Clip////////| | | 1088 * | | |(post scale)//////| | | 1089 * | | |//////////////////| | | 1090 * | | |//////////////////| | | 1091 * | | |//////////////////| | | 1092 * | | |//////////////////| | | 1093 * | | | | 1094 * | | | | 1095 * | |____________________________________________| | 1096 * |__________________________________________________| 1097 * 1098 * 1099 * In Timing Active Space a plane clip could be further sliced into 1100 * pieces called MPC slices. Each Pipe Context is responsible for 1101 * processing only one MPC slice so the plane processing workload can be 1102 * distributed to multiple DPP Pipes. MPC slices could be blended 1103 * together to a single ODM slice. Each ODM slice is responsible for 1104 * processing a portion of Timing Active divided horizontally so the 1105 * output pixel processing workload can be distributed to multiple OPP 1106 * pipes. All ODM slices are mapped together in ODM block so all MPC 1107 * slices belong to different ODM slices could be pieced together to 1108 * form a single image in Timing Active. MPC slices must belong to 1109 * single ODM slice. If an MPC slice goes across ODM slice boundary, it 1110 * needs to be divided into two MPC slices one for each ODM slice. 1111 * 1112 * In the following diagram the output pixel processing workload is 1113 * divided horizontally into two ODM slices one for each OPP blend tree. 1114 * OPP0 blend tree is responsible for processing left half of Timing 1115 * Active, while OPP2 blend tree is responsible for processing right 1116 * half. 1117 * 1118 * The plane has two MPC slices. However since the right MPC slice goes 1119 * across ODM boundary, two DPP pipes are needed one for each OPP blend 1120 * tree. (i.e. DPP1 for OPP0 blend tree and DPP2 for OPP2 blend tree). 1121 * 1122 * Assuming that we have a Pipe Context associated with OPP0 and DPP1 1123 * working on processing the plane in the diagram. We want to know the 1124 * width and height of the shaded rectangle and its relative position 1125 * with respect to the ODM slice0. This is called the recout of the pipe 1126 * context. 1127 * 1128 * Planes can be at arbitrary size and position and there could be an 1129 * arbitrary number of MPC and ODM slices. The algorithm needs to take 1130 * all scenarios into account. 1131 * 1132 * Timing Active Space (3840 x 2160) 1133 * --------------------------------- 1134 * 1135 * Timing Active 1136 * __________________________________________________ 1137 * |OPP0(ODM slice0)^ |OPP2(ODM slice1) | 1138 * | y | | 1139 * | | <- w -> | 1140 * | _____V________|____ | 1141 * | |DPP0 ^ |DPP1 |DPP2| | 1142 * |<------ x |-----|->|/////| | | 1143 * | | | |/////| | | 1144 * | | h |/////| | | 1145 * | | | |/////| | | 1146 * | |_____V__|/////|____| | 1147 * | | | 1148 * | | | 1149 * | | | 1150 * |_________________________|________________________| 1151 * 1152 * 1153 */ 1154 struct rect plane_clip; 1155 struct rect mpc_slice_of_plane_clip; 1156 struct rect odm_slice_src; 1157 struct rect overlapping_area; 1158 1159 plane_clip = calculate_plane_rec_in_timing_active(pipe_ctx, 1160 &pipe_ctx->plane_state->clip_rect); 1161 /* guard plane clip from drawing beyond stream dst here */ 1162 plane_clip = intersect_rec(&plane_clip, 1163 &pipe_ctx->stream->dst); 1164 mpc_slice_of_plane_clip = calculate_mpc_slice_in_timing_active( 1165 pipe_ctx, &plane_clip); 1166 odm_slice_src = resource_get_odm_slice_src_rect(pipe_ctx); 1167 overlapping_area = intersect_rec(&mpc_slice_of_plane_clip, &odm_slice_src); 1168 if (overlapping_area.height > 0 && 1169 overlapping_area.width > 0) { 1170 /* shift the overlapping area so it is with respect to current 1171 * ODM slice source's position 1172 */ 1173 pipe_ctx->plane_res.scl_data.recout = shift_rec( 1174 &overlapping_area, 1175 -odm_slice_src.x, -odm_slice_src.y); 1176 adjust_recout_for_visual_confirm( 1177 &pipe_ctx->plane_res.scl_data.recout, 1178 pipe_ctx); 1179 } else { 1180 /* if there is no overlap, zero recout */ 1181 memset(&pipe_ctx->plane_res.scl_data.recout, 0, 1182 sizeof(struct rect)); 1183 } 1184 1185 } 1186 1187 static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) 1188 { 1189 const struct dc_plane_state *plane_state = pipe_ctx->plane_state; 1190 const struct dc_stream_state *stream = pipe_ctx->stream; 1191 struct rect surf_src = plane_state->src_rect; 1192 const int in_w = stream->src.width; 1193 const int in_h = stream->src.height; 1194 const int out_w = stream->dst.width; 1195 const int out_h = stream->dst.height; 1196 1197 /*Swap surf_src height and width since scaling ratios are in recout rotation*/ 1198 if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || 1199 pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) 1200 swap(surf_src.height, surf_src.width); 1201 1202 pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction( 1203 surf_src.width, 1204 plane_state->dst_rect.width); 1205 pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_from_fraction( 1206 surf_src.height, 1207 plane_state->dst_rect.height); 1208 1209 if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) 1210 pipe_ctx->plane_res.scl_data.ratios.horz.value *= 2; 1211 else if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) 1212 pipe_ctx->plane_res.scl_data.ratios.vert.value *= 2; 1213 1214 pipe_ctx->plane_res.scl_data.ratios.vert.value = div64_s64( 1215 pipe_ctx->plane_res.scl_data.ratios.vert.value * in_h, out_h); 1216 pipe_ctx->plane_res.scl_data.ratios.horz.value = div64_s64( 1217 pipe_ctx->plane_res.scl_data.ratios.horz.value * in_w, out_w); 1218 1219 pipe_ctx->plane_res.scl_data.ratios.horz_c = pipe_ctx->plane_res.scl_data.ratios.horz; 1220 pipe_ctx->plane_res.scl_data.ratios.vert_c = pipe_ctx->plane_res.scl_data.ratios.vert; 1221 1222 if (pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP8 1223 || pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP10) { 1224 pipe_ctx->plane_res.scl_data.ratios.horz_c.value /= 2; 1225 pipe_ctx->plane_res.scl_data.ratios.vert_c.value /= 2; 1226 } 1227 pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_truncate( 1228 pipe_ctx->plane_res.scl_data.ratios.horz, 19); 1229 pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_truncate( 1230 pipe_ctx->plane_res.scl_data.ratios.vert, 19); 1231 pipe_ctx->plane_res.scl_data.ratios.horz_c = dc_fixpt_truncate( 1232 pipe_ctx->plane_res.scl_data.ratios.horz_c, 19); 1233 pipe_ctx->plane_res.scl_data.ratios.vert_c = dc_fixpt_truncate( 1234 pipe_ctx->plane_res.scl_data.ratios.vert_c, 19); 1235 } 1236 1237 1238 /* 1239 * We completely calculate vp offset, size and inits here based entirely on scaling 1240 * ratios and recout for pixel perfect pipe combine. 1241 */ 1242 static void calculate_init_and_vp( 1243 bool flip_scan_dir, 1244 int recout_offset_within_recout_full, 1245 int recout_size, 1246 int src_size, 1247 int taps, 1248 struct fixed31_32 ratio, 1249 struct fixed31_32 *init, 1250 int *vp_offset, 1251 int *vp_size) 1252 { 1253 struct fixed31_32 temp; 1254 int int_part; 1255 1256 /* 1257 * First of the taps starts sampling pixel number <init_int_part> corresponding to recout 1258 * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on. 1259 * All following calculations are based on this logic. 1260 * 1261 * Init calculated according to formula: 1262 * init = (scaling_ratio + number_of_taps + 1) / 2 1263 * init_bot = init + scaling_ratio 1264 * to get pixel perfect combine add the fraction from calculating vp offset 1265 */ 1266 temp = dc_fixpt_mul_int(ratio, recout_offset_within_recout_full); 1267 *vp_offset = dc_fixpt_floor(temp); 1268 temp.value &= 0xffffffff; 1269 *init = dc_fixpt_truncate(dc_fixpt_add(dc_fixpt_div_int( 1270 dc_fixpt_add_int(ratio, taps + 1), 2), temp), 19); 1271 /* 1272 * If viewport has non 0 offset and there are more taps than covered by init then 1273 * we should decrease the offset and increase init so we are never sampling 1274 * outside of viewport. 1275 */ 1276 int_part = dc_fixpt_floor(*init); 1277 if (int_part < taps) { 1278 int_part = taps - int_part; 1279 if (int_part > *vp_offset) 1280 int_part = *vp_offset; 1281 *vp_offset -= int_part; 1282 *init = dc_fixpt_add_int(*init, int_part); 1283 } 1284 /* 1285 * If taps are sampling outside of viewport at end of recout and there are more pixels 1286 * available in the surface we should increase the viewport size, regardless set vp to 1287 * only what is used. 1288 */ 1289 temp = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_size - 1)); 1290 *vp_size = dc_fixpt_floor(temp); 1291 if (*vp_size + *vp_offset > src_size) 1292 *vp_size = src_size - *vp_offset; 1293 1294 /* We did all the math assuming we are scanning same direction as display does, 1295 * however mirror/rotation changes how vp scans vs how it is offset. If scan direction 1296 * is flipped we simply need to calculate offset from the other side of plane. 1297 * Note that outside of viewport all scaling hardware works in recout space. 1298 */ 1299 if (flip_scan_dir) 1300 *vp_offset = src_size - *vp_offset - *vp_size; 1301 } 1302 1303 static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx) 1304 { 1305 const struct dc_plane_state *plane_state = pipe_ctx->plane_state; 1306 struct scaler_data *data = &pipe_ctx->plane_res.scl_data; 1307 struct rect src = plane_state->src_rect; 1308 struct rect recout_dst_in_active_timing; 1309 struct rect recout_clip_in_active_timing; 1310 struct rect recout_clip_in_recout_dst; 1311 struct rect overlap_in_active_timing; 1312 struct rect odm_slice_src = resource_get_odm_slice_src_rect(pipe_ctx); 1313 int vpc_div = (data->format == PIXEL_FORMAT_420BPP8 1314 || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; 1315 bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir; 1316 1317 recout_clip_in_active_timing = shift_rec( 1318 &data->recout, odm_slice_src.x, odm_slice_src.y); 1319 recout_dst_in_active_timing = calculate_plane_rec_in_timing_active( 1320 pipe_ctx, &plane_state->dst_rect); 1321 overlap_in_active_timing = intersect_rec(&recout_clip_in_active_timing, 1322 &recout_dst_in_active_timing); 1323 if (overlap_in_active_timing.width > 0 && 1324 overlap_in_active_timing.height > 0) 1325 recout_clip_in_recout_dst = shift_rec(&overlap_in_active_timing, 1326 -recout_dst_in_active_timing.x, 1327 -recout_dst_in_active_timing.y); 1328 else 1329 memset(&recout_clip_in_recout_dst, 0, sizeof(struct rect)); 1330 1331 /* 1332 * Work in recout rotation since that requires less transformations 1333 */ 1334 get_vp_scan_direction( 1335 plane_state->rotation, 1336 plane_state->horizontal_mirror, 1337 &orthogonal_rotation, 1338 &flip_vert_scan_dir, 1339 &flip_horz_scan_dir); 1340 1341 if (orthogonal_rotation) { 1342 swap(src.width, src.height); 1343 swap(flip_vert_scan_dir, flip_horz_scan_dir); 1344 } 1345 1346 calculate_init_and_vp( 1347 flip_horz_scan_dir, 1348 recout_clip_in_recout_dst.x, 1349 data->recout.width, 1350 src.width, 1351 data->taps.h_taps, 1352 data->ratios.horz, 1353 &data->inits.h, 1354 &data->viewport.x, 1355 &data->viewport.width); 1356 calculate_init_and_vp( 1357 flip_horz_scan_dir, 1358 recout_clip_in_recout_dst.x, 1359 data->recout.width, 1360 src.width / vpc_div, 1361 data->taps.h_taps_c, 1362 data->ratios.horz_c, 1363 &data->inits.h_c, 1364 &data->viewport_c.x, 1365 &data->viewport_c.width); 1366 calculate_init_and_vp( 1367 flip_vert_scan_dir, 1368 recout_clip_in_recout_dst.y, 1369 data->recout.height, 1370 src.height, 1371 data->taps.v_taps, 1372 data->ratios.vert, 1373 &data->inits.v, 1374 &data->viewport.y, 1375 &data->viewport.height); 1376 calculate_init_and_vp( 1377 flip_vert_scan_dir, 1378 recout_clip_in_recout_dst.y, 1379 data->recout.height, 1380 src.height / vpc_div, 1381 data->taps.v_taps_c, 1382 data->ratios.vert_c, 1383 &data->inits.v_c, 1384 &data->viewport_c.y, 1385 &data->viewport_c.height); 1386 if (orthogonal_rotation) { 1387 swap(data->viewport.x, data->viewport.y); 1388 swap(data->viewport.width, data->viewport.height); 1389 swap(data->viewport_c.x, data->viewport_c.y); 1390 swap(data->viewport_c.width, data->viewport_c.height); 1391 } 1392 data->viewport.x += src.x; 1393 data->viewport.y += src.y; 1394 ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0); 1395 data->viewport_c.x += src.x / vpc_div; 1396 data->viewport_c.y += src.y / vpc_div; 1397 } 1398 1399 static enum controller_dp_test_pattern convert_dp_to_controller_test_pattern( 1400 enum dp_test_pattern test_pattern) 1401 { 1402 enum controller_dp_test_pattern controller_test_pattern; 1403 1404 switch (test_pattern) { 1405 case DP_TEST_PATTERN_COLOR_SQUARES: 1406 controller_test_pattern = 1407 CONTROLLER_DP_TEST_PATTERN_COLORSQUARES; 1408 break; 1409 case DP_TEST_PATTERN_COLOR_SQUARES_CEA: 1410 controller_test_pattern = 1411 CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA; 1412 break; 1413 case DP_TEST_PATTERN_VERTICAL_BARS: 1414 controller_test_pattern = 1415 CONTROLLER_DP_TEST_PATTERN_VERTICALBARS; 1416 break; 1417 case DP_TEST_PATTERN_HORIZONTAL_BARS: 1418 controller_test_pattern = 1419 CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS; 1420 break; 1421 case DP_TEST_PATTERN_COLOR_RAMP: 1422 controller_test_pattern = 1423 CONTROLLER_DP_TEST_PATTERN_COLORRAMP; 1424 break; 1425 default: 1426 controller_test_pattern = 1427 CONTROLLER_DP_TEST_PATTERN_VIDEOMODE; 1428 break; 1429 } 1430 1431 return controller_test_pattern; 1432 } 1433 1434 static enum controller_dp_color_space convert_dp_to_controller_color_space( 1435 enum dp_test_pattern_color_space color_space) 1436 { 1437 enum controller_dp_color_space controller_color_space; 1438 1439 switch (color_space) { 1440 case DP_TEST_PATTERN_COLOR_SPACE_RGB: 1441 controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB; 1442 break; 1443 case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601: 1444 controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601; 1445 break; 1446 case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709: 1447 controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709; 1448 break; 1449 case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED: 1450 default: 1451 controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED; 1452 break; 1453 } 1454 1455 return controller_color_space; 1456 } 1457 1458 void resource_build_test_pattern_params(struct resource_context *res_ctx, 1459 struct pipe_ctx *otg_master) 1460 { 1461 struct pipe_ctx *opp_heads[MAX_PIPES]; 1462 struct test_pattern_params *params; 1463 int odm_cnt; 1464 enum controller_dp_test_pattern controller_test_pattern; 1465 enum controller_dp_color_space controller_color_space; 1466 enum dc_color_depth color_depth = otg_master->stream->timing.display_color_depth; 1467 struct rect odm_slice_src; 1468 int i; 1469 1470 controller_test_pattern = convert_dp_to_controller_test_pattern( 1471 otg_master->stream->test_pattern.type); 1472 controller_color_space = convert_dp_to_controller_color_space( 1473 otg_master->stream->test_pattern.color_space); 1474 1475 if (controller_test_pattern == CONTROLLER_DP_TEST_PATTERN_VIDEOMODE) 1476 return; 1477 1478 odm_cnt = resource_get_opp_heads_for_otg_master(otg_master, res_ctx, opp_heads); 1479 1480 for (i = 0; i < odm_cnt; i++) { 1481 odm_slice_src = resource_get_odm_slice_src_rect(opp_heads[i]); 1482 params = &opp_heads[i]->stream_res.test_pattern_params; 1483 params->test_pattern = controller_test_pattern; 1484 params->color_space = controller_color_space; 1485 params->color_depth = color_depth; 1486 params->height = odm_slice_src.height; 1487 params->offset = odm_slice_src.x; 1488 params->width = odm_slice_src.width; 1489 } 1490 } 1491 1492 bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) 1493 { 1494 const struct dc_plane_state *plane_state = pipe_ctx->plane_state; 1495 struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; 1496 const struct rect odm_slice_src = resource_get_odm_slice_src_rect(pipe_ctx); 1497 struct scaling_taps temp = {0}; 1498 bool res = false; 1499 1500 DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); 1501 1502 /* Invalid input */ 1503 if (!plane_state || 1504 !plane_state->dst_rect.width || 1505 !plane_state->dst_rect.height || 1506 !plane_state->src_rect.width || 1507 !plane_state->src_rect.height) { 1508 ASSERT(0); 1509 return false; 1510 } 1511 1512 /* Timing borders are part of vactive that we are also supposed to skip in addition 1513 * to any stream dst offset. Since dm logic assumes dst is in addressable 1514 * space we need to add the left and top borders to dst offsets temporarily. 1515 * TODO: fix in DM, stream dst is supposed to be in vactive 1516 */ 1517 pipe_ctx->stream->dst.x += timing->h_border_left; 1518 pipe_ctx->stream->dst.y += timing->v_border_top; 1519 1520 /* Calculate H and V active size */ 1521 pipe_ctx->plane_res.scl_data.h_active = odm_slice_src.width; 1522 pipe_ctx->plane_res.scl_data.v_active = odm_slice_src.height; 1523 pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface( 1524 pipe_ctx->plane_state->format); 1525 1526 #if defined(CONFIG_DRM_AMD_DC_FP) 1527 if ((pipe_ctx->stream->ctx->dc->config.use_spl) && (!pipe_ctx->stream->ctx->dc->debug.disable_spl)) { 1528 struct spl_in *spl_in = &pipe_ctx->plane_res.spl_in; 1529 struct spl_out *spl_out = &pipe_ctx->plane_res.spl_out; 1530 1531 if (plane_state->ctx->dce_version > DCE_VERSION_MAX) 1532 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP; 1533 else 1534 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP; 1535 1536 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha; 1537 1538 // Convert pipe_ctx to respective input params for SPL 1539 translate_SPL_in_params_from_pipe_ctx(pipe_ctx, spl_in); 1540 /* Pass visual confirm debug information */ 1541 calculate_adjust_recout_for_visual_confirm(pipe_ctx, 1542 &spl_in->debug.visual_confirm_base_offset, 1543 &spl_in->debug.visual_confirm_dpp_offset); 1544 // Set SPL output parameters to dscl_prog_data to be used for hw registers 1545 spl_out->dscl_prog_data = resource_get_dscl_prog_data(pipe_ctx); 1546 // Calculate scaler parameters from SPL 1547 res = spl_calculate_scaler_params(spl_in, spl_out); 1548 // Convert respective out params from SPL to scaler data 1549 translate_SPL_out_params_to_pipe_ctx(pipe_ctx, spl_out); 1550 1551 /* Ignore scaler failure if pipe context plane is phantom plane */ 1552 if (!res && plane_state->is_phantom) 1553 res = true; 1554 } else { 1555 #endif 1556 /* depends on h_active */ 1557 calculate_recout(pipe_ctx); 1558 /* depends on pixel format */ 1559 calculate_scaling_ratios(pipe_ctx); 1560 1561 /* 1562 * LB calculations depend on vp size, h/v_active and scaling ratios 1563 * Setting line buffer pixel depth to 24bpp yields banding 1564 * on certain displays, such as the Sharp 4k. 36bpp is needed 1565 * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and 1566 * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc 1567 * precision on DCN display engines, but apparently not for DCE, as 1568 * far as testing on DCE-11.2 and DCE-8 showed. Various DCE parts have 1569 * problems: Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth, 1570 * neither do DCE-8 at 4k resolution, or DCE-11.2 (broken identify pixel 1571 * passthrough). Therefore only use 36 bpp on DCN where it is actually needed. 1572 */ 1573 if (plane_state->ctx->dce_version > DCE_VERSION_MAX) 1574 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP; 1575 else 1576 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP; 1577 1578 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha; 1579 1580 // get TAP value with 100x100 dummy data for max scaling qualify, override 1581 // if a new scaling quality required 1582 pipe_ctx->plane_res.scl_data.viewport.width = 100; 1583 pipe_ctx->plane_res.scl_data.viewport.height = 100; 1584 pipe_ctx->plane_res.scl_data.viewport_c.width = 100; 1585 pipe_ctx->plane_res.scl_data.viewport_c.height = 100; 1586 if (pipe_ctx->plane_res.xfm != NULL) 1587 res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( 1588 pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); 1589 1590 if (pipe_ctx->plane_res.dpp != NULL) 1591 res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps( 1592 pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); 1593 1594 temp = pipe_ctx->plane_res.scl_data.taps; 1595 1596 calculate_inits_and_viewports(pipe_ctx); 1597 1598 if (pipe_ctx->plane_res.xfm != NULL) 1599 res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( 1600 pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); 1601 1602 if (pipe_ctx->plane_res.dpp != NULL) 1603 res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps( 1604 pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); 1605 1606 1607 if (!res) { 1608 /* Try 24 bpp linebuffer */ 1609 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP; 1610 1611 if (pipe_ctx->plane_res.xfm != NULL) 1612 res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( 1613 pipe_ctx->plane_res.xfm, 1614 &pipe_ctx->plane_res.scl_data, 1615 &plane_state->scaling_quality); 1616 1617 if (pipe_ctx->plane_res.dpp != NULL) 1618 res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps( 1619 pipe_ctx->plane_res.dpp, 1620 &pipe_ctx->plane_res.scl_data, 1621 &plane_state->scaling_quality); 1622 } 1623 1624 /* Ignore scaler failure if pipe context plane is phantom plane */ 1625 if (!res && plane_state->is_phantom) 1626 res = true; 1627 1628 if (res && (pipe_ctx->plane_res.scl_data.taps.v_taps != temp.v_taps || 1629 pipe_ctx->plane_res.scl_data.taps.h_taps != temp.h_taps || 1630 pipe_ctx->plane_res.scl_data.taps.v_taps_c != temp.v_taps_c || 1631 pipe_ctx->plane_res.scl_data.taps.h_taps_c != temp.h_taps_c)) 1632 calculate_inits_and_viewports(pipe_ctx); 1633 1634 /* 1635 * Handle side by side and top bottom 3d recout offsets after vp calculation 1636 * since 3d is special and needs to calculate vp as if there is no recout offset 1637 * This may break with rotation, good thing we aren't mixing hw rotation and 3d 1638 */ 1639 if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == plane_state) { 1640 ASSERT(plane_state->rotation == ROTATION_ANGLE_0 || 1641 (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM && 1642 pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE)); 1643 if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) 1644 pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height; 1645 else if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) 1646 pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width; 1647 } 1648 1649 /* Clamp minimum viewport size */ 1650 if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE) 1651 pipe_ctx->plane_res.scl_data.viewport.height = MIN_VIEWPORT_SIZE; 1652 if (pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE) 1653 pipe_ctx->plane_res.scl_data.viewport.width = MIN_VIEWPORT_SIZE; 1654 #ifdef CONFIG_DRM_AMD_DC_FP 1655 } 1656 #endif 1657 DC_LOG_SCALER("%s pipe %d:\nViewport: height:%d width:%d x:%d y:%d Recout: height:%d width:%d x:%d y:%d HACTIVE:%d VACTIVE:%d\n" 1658 "src_rect: height:%d width:%d x:%d y:%d dst_rect: height:%d width:%d x:%d y:%d clip_rect: height:%d width:%d x:%d y:%d\n", 1659 __func__, 1660 pipe_ctx->pipe_idx, 1661 pipe_ctx->plane_res.scl_data.viewport.height, 1662 pipe_ctx->plane_res.scl_data.viewport.width, 1663 pipe_ctx->plane_res.scl_data.viewport.x, 1664 pipe_ctx->plane_res.scl_data.viewport.y, 1665 pipe_ctx->plane_res.scl_data.recout.height, 1666 pipe_ctx->plane_res.scl_data.recout.width, 1667 pipe_ctx->plane_res.scl_data.recout.x, 1668 pipe_ctx->plane_res.scl_data.recout.y, 1669 pipe_ctx->plane_res.scl_data.h_active, 1670 pipe_ctx->plane_res.scl_data.v_active, 1671 plane_state->src_rect.height, 1672 plane_state->src_rect.width, 1673 plane_state->src_rect.x, 1674 plane_state->src_rect.y, 1675 plane_state->dst_rect.height, 1676 plane_state->dst_rect.width, 1677 plane_state->dst_rect.x, 1678 plane_state->dst_rect.y, 1679 plane_state->clip_rect.height, 1680 plane_state->clip_rect.width, 1681 plane_state->clip_rect.x, 1682 plane_state->clip_rect.y); 1683 1684 pipe_ctx->stream->dst.x -= timing->h_border_left; 1685 pipe_ctx->stream->dst.y -= timing->v_border_top; 1686 1687 return res; 1688 } 1689 1690 bool resource_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx) 1691 { 1692 struct pipe_ctx *test_pipe, *split_pipe; 1693 struct rect r1 = pipe_ctx->plane_res.scl_data.recout; 1694 int r1_right, r1_bottom; 1695 int cur_layer = pipe_ctx->plane_state->layer_index; 1696 1697 reverse_adjust_recout_for_visual_confirm(&r1, pipe_ctx); 1698 r1_right = r1.x + r1.width; 1699 r1_bottom = r1.y + r1.height; 1700 1701 /** 1702 * Disable the cursor if there's another pipe above this with a 1703 * plane that contains this pipe's viewport to prevent double cursor 1704 * and incorrect scaling artifacts. 1705 */ 1706 for (test_pipe = pipe_ctx->top_pipe; test_pipe; 1707 test_pipe = test_pipe->top_pipe) { 1708 struct rect r2; 1709 int r2_right, r2_bottom; 1710 // Skip invisible layer and pipe-split plane on same layer 1711 if (!test_pipe->plane_state || 1712 !test_pipe->plane_state->visible || 1713 test_pipe->plane_state->layer_index == cur_layer) 1714 continue; 1715 1716 r2 = test_pipe->plane_res.scl_data.recout; 1717 reverse_adjust_recout_for_visual_confirm(&r2, test_pipe); 1718 r2_right = r2.x + r2.width; 1719 r2_bottom = r2.y + r2.height; 1720 1721 /** 1722 * There is another half plane on same layer because of 1723 * pipe-split, merge together per same height. 1724 */ 1725 for (split_pipe = pipe_ctx->top_pipe; split_pipe; 1726 split_pipe = split_pipe->top_pipe) 1727 if (split_pipe->plane_state->layer_index == test_pipe->plane_state->layer_index) { 1728 struct rect r2_half; 1729 1730 r2_half = split_pipe->plane_res.scl_data.recout; 1731 reverse_adjust_recout_for_visual_confirm(&r2_half, split_pipe); 1732 r2.x = min(r2_half.x, r2.x); 1733 r2.width = r2.width + r2_half.width; 1734 r2_right = r2.x + r2.width; 1735 r2_bottom = min(r2_bottom, r2_half.y + r2_half.height); 1736 break; 1737 } 1738 1739 if (r1.x >= r2.x && r1.y >= r2.y && r1_right <= r2_right && r1_bottom <= r2_bottom) 1740 return true; 1741 } 1742 1743 return false; 1744 } 1745 1746 1747 enum dc_status resource_build_scaling_params_for_context( 1748 const struct dc *dc, 1749 struct dc_state *context) 1750 { 1751 (void)dc; 1752 int i; 1753 1754 for (i = 0; i < MAX_PIPES; i++) { 1755 if (context->res_ctx.pipe_ctx[i].plane_state != NULL && 1756 context->res_ctx.pipe_ctx[i].stream != NULL) 1757 if (!resource_build_scaling_params(&context->res_ctx.pipe_ctx[i])) 1758 return DC_FAIL_SCALING; 1759 } 1760 1761 return DC_OK; 1762 } 1763 1764 struct pipe_ctx *resource_find_free_secondary_pipe_legacy( 1765 struct resource_context *res_ctx, 1766 const struct resource_pool *pool, 1767 const struct pipe_ctx *primary_pipe) 1768 { 1769 int i; 1770 struct pipe_ctx *secondary_pipe = NULL; 1771 1772 /* 1773 * We add a preferred pipe mapping to avoid the chance that 1774 * MPCCs already in use will need to be reassigned to other trees. 1775 * For example, if we went with the strict, assign backwards logic: 1776 * 1777 * (State 1) 1778 * Display A on, no surface, top pipe = 0 1779 * Display B on, no surface, top pipe = 1 1780 * 1781 * (State 2) 1782 * Display A on, no surface, top pipe = 0 1783 * Display B on, surface enable, top pipe = 1, bottom pipe = 5 1784 * 1785 * (State 3) 1786 * Display A on, surface enable, top pipe = 0, bottom pipe = 5 1787 * Display B on, surface enable, top pipe = 1, bottom pipe = 4 1788 * 1789 * The state 2->3 transition requires remapping MPCC 5 from display B 1790 * to display A. 1791 * 1792 * However, with the preferred pipe logic, state 2 would look like: 1793 * 1794 * (State 2) 1795 * Display A on, no surface, top pipe = 0 1796 * Display B on, surface enable, top pipe = 1, bottom pipe = 4 1797 * 1798 * This would then cause 2->3 to not require remapping any MPCCs. 1799 */ 1800 if (primary_pipe) { 1801 int preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx; 1802 if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { 1803 secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; 1804 secondary_pipe->pipe_idx = preferred_pipe_idx; 1805 } 1806 } 1807 1808 /* 1809 * search backwards for the second pipe to keep pipe 1810 * assignment more consistent 1811 */ 1812 if (!secondary_pipe) 1813 for (i = pool->pipe_count - 1; i >= 0; i--) { 1814 if (res_ctx->pipe_ctx[i].stream == NULL) { 1815 secondary_pipe = &res_ctx->pipe_ctx[i]; 1816 secondary_pipe->pipe_idx = i; 1817 break; 1818 } 1819 } 1820 1821 return secondary_pipe; 1822 } 1823 1824 int resource_find_free_pipe_used_as_sec_opp_head_by_cur_otg_master( 1825 const struct resource_context *cur_res_ctx, 1826 struct resource_context *new_res_ctx, 1827 const struct pipe_ctx *cur_otg_master) 1828 { 1829 (void)cur_res_ctx; 1830 const struct pipe_ctx *cur_sec_opp_head = cur_otg_master->next_odm_pipe; 1831 struct pipe_ctx *new_pipe; 1832 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND; 1833 1834 while (cur_sec_opp_head) { 1835 new_pipe = &new_res_ctx->pipe_ctx[cur_sec_opp_head->pipe_idx]; 1836 if (resource_is_pipe_type(new_pipe, FREE_PIPE)) { 1837 free_pipe_idx = cur_sec_opp_head->pipe_idx; 1838 break; 1839 } 1840 cur_sec_opp_head = cur_sec_opp_head->next_odm_pipe; 1841 } 1842 1843 return free_pipe_idx; 1844 } 1845 1846 int resource_find_free_pipe_used_in_cur_mpc_blending_tree( 1847 const struct resource_context *cur_res_ctx, 1848 struct resource_context *new_res_ctx, 1849 const struct pipe_ctx *cur_opp_head) 1850 { 1851 (void)cur_res_ctx; 1852 const struct pipe_ctx *cur_sec_dpp = cur_opp_head->bottom_pipe; 1853 struct pipe_ctx *new_pipe; 1854 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND; 1855 1856 while (cur_sec_dpp) { 1857 /* find a free pipe used in current opp blend tree, 1858 * this is to avoid MPO pipe switching to different opp blending 1859 * tree 1860 */ 1861 new_pipe = &new_res_ctx->pipe_ctx[cur_sec_dpp->pipe_idx]; 1862 if (resource_is_pipe_type(new_pipe, FREE_PIPE)) { 1863 free_pipe_idx = cur_sec_dpp->pipe_idx; 1864 break; 1865 } 1866 cur_sec_dpp = cur_sec_dpp->bottom_pipe; 1867 } 1868 1869 return free_pipe_idx; 1870 } 1871 1872 int recource_find_free_pipe_not_used_in_cur_res_ctx( 1873 const struct resource_context *cur_res_ctx, 1874 struct resource_context *new_res_ctx, 1875 const struct resource_pool *pool) 1876 { 1877 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND; 1878 const struct pipe_ctx *new_pipe, *cur_pipe; 1879 int i; 1880 1881 for (i = 0; i < pool->pipe_count; i++) { 1882 cur_pipe = &cur_res_ctx->pipe_ctx[i]; 1883 new_pipe = &new_res_ctx->pipe_ctx[i]; 1884 1885 if (resource_is_pipe_type(cur_pipe, FREE_PIPE) && 1886 resource_is_pipe_type(new_pipe, FREE_PIPE)) { 1887 free_pipe_idx = i; 1888 break; 1889 } 1890 } 1891 1892 return free_pipe_idx; 1893 } 1894 1895 int recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx( 1896 const struct resource_context *cur_res_ctx, 1897 struct resource_context *new_res_ctx, 1898 const struct resource_pool *pool) 1899 { 1900 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND; 1901 const struct pipe_ctx *new_pipe, *cur_pipe; 1902 int i; 1903 1904 for (i = 0; i < pool->pipe_count; i++) { 1905 cur_pipe = &cur_res_ctx->pipe_ctx[i]; 1906 new_pipe = &new_res_ctx->pipe_ctx[i]; 1907 1908 if (resource_is_pipe_type(cur_pipe, OTG_MASTER) && 1909 resource_is_pipe_type(new_pipe, FREE_PIPE)) { 1910 free_pipe_idx = i; 1911 break; 1912 } 1913 } 1914 1915 return free_pipe_idx; 1916 } 1917 1918 int resource_find_free_pipe_used_as_cur_sec_dpp( 1919 const struct resource_context *cur_res_ctx, 1920 struct resource_context *new_res_ctx, 1921 const struct resource_pool *pool) 1922 { 1923 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND; 1924 const struct pipe_ctx *new_pipe, *cur_pipe; 1925 int i; 1926 1927 for (i = 0; i < pool->pipe_count; i++) { 1928 cur_pipe = &cur_res_ctx->pipe_ctx[i]; 1929 new_pipe = &new_res_ctx->pipe_ctx[i]; 1930 1931 if (resource_is_pipe_type(cur_pipe, DPP_PIPE) && 1932 !resource_is_pipe_type(cur_pipe, OPP_HEAD) && 1933 resource_is_pipe_type(new_pipe, FREE_PIPE)) { 1934 free_pipe_idx = i; 1935 break; 1936 } 1937 } 1938 1939 return free_pipe_idx; 1940 } 1941 1942 int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine( 1943 const struct resource_context *cur_res_ctx, 1944 struct resource_context *new_res_ctx, 1945 const struct resource_pool *pool) 1946 { 1947 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND; 1948 const struct pipe_ctx *new_pipe, *cur_pipe; 1949 int i; 1950 1951 for (i = 0; i < pool->pipe_count; i++) { 1952 cur_pipe = &cur_res_ctx->pipe_ctx[i]; 1953 new_pipe = &new_res_ctx->pipe_ctx[i]; 1954 1955 if (resource_is_pipe_type(cur_pipe, DPP_PIPE) && 1956 !resource_is_pipe_type(cur_pipe, OPP_HEAD) && 1957 resource_get_mpc_slice_index(cur_pipe) > 0 && 1958 resource_is_pipe_type(new_pipe, FREE_PIPE)) { 1959 free_pipe_idx = i; 1960 break; 1961 } 1962 } 1963 1964 return free_pipe_idx; 1965 } 1966 1967 int resource_find_any_free_pipe(struct resource_context *new_res_ctx, 1968 const struct resource_pool *pool) 1969 { 1970 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND; 1971 const struct pipe_ctx *new_pipe; 1972 int i; 1973 1974 for (i = 0; i < pool->pipe_count; i++) { 1975 new_pipe = &new_res_ctx->pipe_ctx[i]; 1976 1977 if (resource_is_pipe_type(new_pipe, FREE_PIPE)) { 1978 free_pipe_idx = i; 1979 break; 1980 } 1981 } 1982 1983 return free_pipe_idx; 1984 } 1985 1986 bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type) 1987 { 1988 switch (type) { 1989 case OTG_MASTER: 1990 return !pipe_ctx->prev_odm_pipe && 1991 !pipe_ctx->top_pipe && 1992 pipe_ctx->stream; 1993 case OPP_HEAD: 1994 return !pipe_ctx->top_pipe && pipe_ctx->stream; 1995 case DPP_PIPE: 1996 return pipe_ctx->plane_state && pipe_ctx->stream; 1997 case FREE_PIPE: 1998 return !pipe_ctx->plane_state && !pipe_ctx->stream; 1999 default: 2000 return false; 2001 } 2002 } 2003 2004 struct pipe_ctx *resource_get_otg_master_for_stream( 2005 struct resource_context *res_ctx, 2006 const struct dc_stream_state *stream) 2007 { 2008 int i; 2009 2010 for (i = 0; i < MAX_PIPES; i++) { 2011 if (res_ctx->pipe_ctx[i].stream == stream && 2012 resource_is_pipe_type(&res_ctx->pipe_ctx[i], OTG_MASTER)) 2013 return &res_ctx->pipe_ctx[i]; 2014 } 2015 return NULL; 2016 } 2017 2018 int resource_get_opp_heads_for_otg_master(const struct pipe_ctx *otg_master, 2019 struct resource_context *res_ctx, 2020 struct pipe_ctx *opp_heads[MAX_PIPES]) 2021 { 2022 struct pipe_ctx *opp_head = &res_ctx->pipe_ctx[otg_master->pipe_idx]; 2023 struct dc *dc = otg_master->stream->ctx->dc; 2024 int i = 0; 2025 2026 DC_LOGGER_INIT(dc->ctx->logger); 2027 2028 if (!resource_is_pipe_type(otg_master, OTG_MASTER)) { 2029 DC_LOG_WARNING("%s called from a non OTG master, something " 2030 "is wrong in the pipe configuration", 2031 __func__); 2032 ASSERT(0); 2033 return 0; 2034 } 2035 while (opp_head) { 2036 ASSERT(i < MAX_PIPES); 2037 opp_heads[i++] = opp_head; 2038 opp_head = opp_head->next_odm_pipe; 2039 } 2040 return i; 2041 } 2042 2043 int resource_get_dpp_pipes_for_opp_head(const struct pipe_ctx *opp_head, 2044 struct resource_context *res_ctx, 2045 struct pipe_ctx *dpp_pipes[MAX_PIPES]) 2046 { 2047 struct pipe_ctx *pipe = &res_ctx->pipe_ctx[opp_head->pipe_idx]; 2048 int i = 0; 2049 2050 if (!resource_is_pipe_type(opp_head, OPP_HEAD)) { 2051 ASSERT(0); 2052 return 0; 2053 } 2054 while (pipe && resource_is_pipe_type(pipe, DPP_PIPE)) { 2055 ASSERT(i < MAX_PIPES); 2056 dpp_pipes[i++] = pipe; 2057 pipe = pipe->bottom_pipe; 2058 } 2059 return i; 2060 } 2061 2062 int resource_get_dpp_pipes_for_plane(const struct dc_plane_state *plane, 2063 struct resource_context *res_ctx, 2064 struct pipe_ctx *dpp_pipes[MAX_PIPES]) 2065 { 2066 int i = 0, j; 2067 struct pipe_ctx *pipe; 2068 2069 for (j = 0; j < MAX_PIPES; j++) { 2070 pipe = &res_ctx->pipe_ctx[j]; 2071 if (pipe->plane_state == plane && pipe->prev_odm_pipe == NULL) { 2072 if (resource_is_pipe_type(pipe, OPP_HEAD) || 2073 pipe->top_pipe->plane_state != plane) 2074 break; 2075 } 2076 } 2077 2078 if (j < MAX_PIPES) { 2079 if (pipe->next_odm_pipe) 2080 while (pipe) { 2081 dpp_pipes[i++] = pipe; 2082 pipe = pipe->next_odm_pipe; 2083 } 2084 else 2085 while (pipe && pipe->plane_state == plane) { 2086 dpp_pipes[i++] = pipe; 2087 pipe = pipe->bottom_pipe; 2088 } 2089 } 2090 return i; 2091 } 2092 2093 struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx) 2094 { 2095 struct pipe_ctx *otg_master = resource_get_opp_head(pipe_ctx); 2096 2097 while (otg_master->prev_odm_pipe) 2098 otg_master = otg_master->prev_odm_pipe; 2099 return otg_master; 2100 } 2101 2102 struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx) 2103 { 2104 struct pipe_ctx *opp_head = (struct pipe_ctx *) pipe_ctx; 2105 2106 ASSERT(!resource_is_pipe_type(opp_head, FREE_PIPE)); 2107 while (opp_head->top_pipe) 2108 opp_head = opp_head->top_pipe; 2109 return opp_head; 2110 } 2111 2112 struct pipe_ctx *resource_get_primary_dpp_pipe(const struct pipe_ctx *dpp_pipe) 2113 { 2114 struct pipe_ctx *pri_dpp_pipe = (struct pipe_ctx *) dpp_pipe; 2115 2116 ASSERT(resource_is_pipe_type(dpp_pipe, DPP_PIPE)); 2117 while (pri_dpp_pipe->prev_odm_pipe) 2118 pri_dpp_pipe = pri_dpp_pipe->prev_odm_pipe; 2119 while (pri_dpp_pipe->top_pipe && 2120 pri_dpp_pipe->top_pipe->plane_state == pri_dpp_pipe->plane_state) 2121 pri_dpp_pipe = pri_dpp_pipe->top_pipe; 2122 return pri_dpp_pipe; 2123 } 2124 2125 2126 int resource_get_mpc_slice_index(const struct pipe_ctx *pipe_ctx) 2127 { 2128 struct pipe_ctx *split_pipe = pipe_ctx->top_pipe; 2129 int index = 0; 2130 2131 while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) { 2132 index++; 2133 split_pipe = split_pipe->top_pipe; 2134 } 2135 2136 return index; 2137 } 2138 2139 int resource_get_mpc_slice_count(const struct pipe_ctx *pipe) 2140 { 2141 int mpc_split_count = 1; 2142 const struct pipe_ctx *other_pipe = pipe->bottom_pipe; 2143 2144 while (other_pipe && other_pipe->plane_state == pipe->plane_state) { 2145 mpc_split_count++; 2146 other_pipe = other_pipe->bottom_pipe; 2147 } 2148 other_pipe = pipe->top_pipe; 2149 while (other_pipe && other_pipe->plane_state == pipe->plane_state) { 2150 mpc_split_count++; 2151 other_pipe = other_pipe->top_pipe; 2152 } 2153 2154 return mpc_split_count; 2155 } 2156 2157 int resource_get_odm_slice_count(const struct pipe_ctx *pipe) 2158 { 2159 int odm_split_count = 1; 2160 2161 pipe = resource_get_otg_master(pipe); 2162 2163 while (pipe->next_odm_pipe) { 2164 odm_split_count++; 2165 pipe = pipe->next_odm_pipe; 2166 } 2167 return odm_split_count; 2168 } 2169 2170 int resource_get_odm_slice_index(const struct pipe_ctx *pipe_ctx) 2171 { 2172 int index = 0; 2173 2174 pipe_ctx = resource_get_opp_head(pipe_ctx); 2175 if (!pipe_ctx) 2176 return 0; 2177 2178 while (pipe_ctx->prev_odm_pipe) { 2179 index++; 2180 pipe_ctx = pipe_ctx->prev_odm_pipe; 2181 } 2182 2183 return index; 2184 } 2185 2186 int resource_get_odm_slice_dst_width(struct pipe_ctx *otg_master, 2187 bool is_last_segment) 2188 { 2189 const struct dc_crtc_timing *timing; 2190 int count; 2191 int h_active; 2192 int width; 2193 bool two_pixel_alignment_required = false; 2194 2195 if (!otg_master || !otg_master->stream) 2196 return 0; 2197 2198 timing = &otg_master->stream->timing; 2199 count = resource_get_odm_slice_count(otg_master); 2200 h_active = timing->h_addressable + 2201 timing->h_border_left + 2202 timing->h_border_right + 2203 otg_master->dsc_padding_params.dsc_hactive_padding; 2204 width = h_active / count; 2205 2206 if (otg_master->stream_res.tg) 2207 two_pixel_alignment_required = 2208 otg_master->stream_res.tg->funcs->is_two_pixels_per_container(timing) || 2209 /* 2210 * 422 is sub-sampled horizontally. 1 set of chromas 2211 * (Cb/Cr) is shared for 2 lumas (i.e 2 Y values). 2212 * Therefore even if 422 is still 1 pixel per container, 2213 * ODM segment width still needs to be 2 pixel aligned. 2214 */ 2215 timing->pixel_encoding == PIXEL_ENCODING_YCBCR422; 2216 if ((width % 2) && two_pixel_alignment_required) 2217 width++; 2218 2219 return is_last_segment ? 2220 h_active - width * (count - 1) : 2221 width; 2222 } 2223 2224 struct rect resource_get_odm_slice_dst_rect(struct pipe_ctx *pipe_ctx) 2225 { 2226 const struct dc_stream_state *stream = pipe_ctx->stream; 2227 bool is_last_odm_slice = pipe_ctx->next_odm_pipe == NULL; 2228 struct pipe_ctx *otg_master = resource_get_otg_master(pipe_ctx); 2229 int odm_slice_idx = resource_get_odm_slice_index(pipe_ctx); 2230 int odm_segment_offset = resource_get_odm_slice_dst_width(otg_master, false); 2231 struct rect odm_slice_dst; 2232 2233 odm_slice_dst.x = odm_segment_offset * odm_slice_idx; 2234 odm_slice_dst.width = resource_get_odm_slice_dst_width(otg_master, is_last_odm_slice); 2235 odm_slice_dst.y = 0; 2236 odm_slice_dst.height = stream->timing.v_addressable + 2237 stream->timing.v_border_bottom + 2238 stream->timing.v_border_top; 2239 2240 return odm_slice_dst; 2241 } 2242 2243 struct rect resource_get_odm_slice_src_rect(struct pipe_ctx *pipe_ctx) 2244 { 2245 struct rect odm_slice_dst; 2246 struct rect odm_slice_src; 2247 struct pipe_ctx *opp_head = resource_get_opp_head(pipe_ctx); 2248 struct output_pixel_processor *opp = opp_head->stream_res.opp; 2249 uint32_t left_edge_extra_pixel_count; 2250 2251 odm_slice_dst = resource_get_odm_slice_dst_rect(opp_head); 2252 odm_slice_src = odm_slice_dst; 2253 2254 if (opp && opp->funcs->opp_get_left_edge_extra_pixel_count) 2255 left_edge_extra_pixel_count = 2256 opp->funcs->opp_get_left_edge_extra_pixel_count( 2257 opp, pipe_ctx->stream->timing.pixel_encoding, 2258 resource_is_pipe_type(opp_head, OTG_MASTER)); 2259 else 2260 left_edge_extra_pixel_count = 0; 2261 2262 odm_slice_src.x -= left_edge_extra_pixel_count; 2263 odm_slice_src.width += left_edge_extra_pixel_count; 2264 2265 return odm_slice_src; 2266 } 2267 2268 bool resource_is_pipe_topology_changed(const struct dc_state *state_a, 2269 const struct dc_state *state_b) 2270 { 2271 int i; 2272 const struct pipe_ctx *pipe_a, *pipe_b; 2273 2274 if (state_a->stream_count != state_b->stream_count) 2275 return true; 2276 2277 for (i = 0; i < MAX_PIPES; i++) { 2278 pipe_a = &state_a->res_ctx.pipe_ctx[i]; 2279 pipe_b = &state_b->res_ctx.pipe_ctx[i]; 2280 2281 if (pipe_a->stream && !pipe_b->stream) 2282 return true; 2283 else if (!pipe_a->stream && pipe_b->stream) 2284 return true; 2285 2286 if (pipe_a->plane_state && !pipe_b->plane_state) 2287 return true; 2288 else if (!pipe_a->plane_state && pipe_b->plane_state) 2289 return true; 2290 2291 if (pipe_a->bottom_pipe && pipe_b->bottom_pipe) { 2292 if (pipe_a->bottom_pipe->pipe_idx != pipe_b->bottom_pipe->pipe_idx) 2293 return true; 2294 if ((pipe_a->bottom_pipe->plane_state == pipe_a->plane_state) && 2295 (pipe_b->bottom_pipe->plane_state != pipe_b->plane_state)) 2296 return true; 2297 else if ((pipe_a->bottom_pipe->plane_state != pipe_a->plane_state) && 2298 (pipe_b->bottom_pipe->plane_state == pipe_b->plane_state)) 2299 return true; 2300 } else if (pipe_a->bottom_pipe || pipe_b->bottom_pipe) { 2301 return true; 2302 } 2303 2304 if (pipe_a->next_odm_pipe && pipe_b->next_odm_pipe) { 2305 if (pipe_a->next_odm_pipe->pipe_idx != pipe_b->next_odm_pipe->pipe_idx) 2306 return true; 2307 } else if (pipe_a->next_odm_pipe || pipe_b->next_odm_pipe) { 2308 return true; 2309 } 2310 } 2311 return false; 2312 } 2313 2314 bool resource_is_odm_topology_changed(const struct pipe_ctx *otg_master_a, 2315 const struct pipe_ctx *otg_master_b) 2316 { 2317 const struct pipe_ctx *opp_head_a = otg_master_a; 2318 const struct pipe_ctx *opp_head_b = otg_master_b; 2319 2320 if (!resource_is_pipe_type(otg_master_a, OTG_MASTER) || 2321 !resource_is_pipe_type(otg_master_b, OTG_MASTER)) 2322 return true; 2323 2324 while (opp_head_a && opp_head_b) { 2325 if (opp_head_a->stream_res.opp != opp_head_b->stream_res.opp) 2326 return true; 2327 if ((opp_head_a->next_odm_pipe && !opp_head_b->next_odm_pipe) || 2328 (!opp_head_a->next_odm_pipe && opp_head_b->next_odm_pipe)) 2329 return true; 2330 opp_head_a = opp_head_a->next_odm_pipe; 2331 opp_head_b = opp_head_b->next_odm_pipe; 2332 } 2333 2334 return false; 2335 } 2336 2337 /* 2338 * Sample log: 2339 * pipe topology update 2340 * ________________________ 2341 * | plane0 slice0 stream0| 2342 * |DPP0----OPP0----OTG0----| <--- case 0 (OTG master pipe with plane) 2343 * | plane1 | | | 2344 * |DPP1----| | | <--- case 5 (DPP pipe not in last slice) 2345 * | plane0 slice1 | | 2346 * |DPP2----OPP2----| | <--- case 2 (OPP head pipe with plane) 2347 * | plane1 | | 2348 * |DPP3----| | <--- case 4 (DPP pipe in last slice) 2349 * | slice0 stream1| 2350 * |DPG4----OPP4----OTG4----| <--- case 1 (OTG master pipe without plane) 2351 * | slice1 | | 2352 * |DPG5----OPP5----| | <--- case 3 (OPP head pipe without plane) 2353 * |________________________| 2354 */ 2355 2356 static void resource_log_pipe(struct dc *dc, struct pipe_ctx *pipe, 2357 int stream_idx, int slice_idx, int plane_idx, int slice_count, 2358 bool is_primary, bool is_phantom_pipe) 2359 { 2360 DC_LOGGER_INIT(dc->ctx->logger); 2361 2362 // new format for logging: bit storing code 2363 if (slice_idx == 0 && plane_idx == 0 && is_primary) { 2364 /* case 0 (OTG master pipe with plane) */ 2365 DC_LOG_DC(" | plane%d slice%d stream%d|", 2366 plane_idx, slice_idx, stream_idx); 2367 DC_LOG_DC(" |DPP%d----OPP%d----OTG%d----|", 2368 pipe->plane_res.dpp->inst, 2369 pipe->stream_res.opp->inst, 2370 pipe->stream_res.tg->inst); 2371 capture_pipe_topology_data(dc, plane_idx, slice_idx, stream_idx, 2372 pipe->plane_res.dpp->inst, 2373 pipe->stream_res.opp->inst, 2374 pipe->stream_res.tg->inst, is_phantom_pipe); 2375 } else if (slice_idx == 0 && plane_idx == -1) { 2376 /* case 1 (OTG master pipe without plane) */ 2377 DC_LOG_DC(" | slice%d stream%d|", 2378 slice_idx, stream_idx); 2379 DC_LOG_DC(" |DPG%d----OPP%d----OTG%d----|", 2380 pipe->stream_res.opp->inst, 2381 pipe->stream_res.opp->inst, 2382 pipe->stream_res.tg->inst); 2383 capture_pipe_topology_data(dc, 0xF, slice_idx, stream_idx, 2384 pipe->plane_res.dpp->inst, 2385 pipe->stream_res.opp->inst, 2386 pipe->stream_res.tg->inst, is_phantom_pipe); 2387 } else if (slice_idx != 0 && plane_idx == 0 && is_primary) { 2388 /* case 2 (OPP head pipe with plane) */ 2389 DC_LOG_DC(" | plane%d slice%d | |", 2390 plane_idx, slice_idx); 2391 DC_LOG_DC(" |DPP%d----OPP%d----| |", 2392 pipe->plane_res.dpp->inst, 2393 pipe->stream_res.opp->inst); 2394 capture_pipe_topology_data(dc, plane_idx, slice_idx, stream_idx, 2395 pipe->plane_res.dpp->inst, 2396 pipe->stream_res.opp->inst, 2397 pipe->stream_res.tg->inst, is_phantom_pipe); 2398 } else if (slice_idx != 0 && plane_idx == -1) { 2399 /* case 3 (OPP head pipe without plane) */ 2400 DC_LOG_DC(" | slice%d | |", slice_idx); 2401 DC_LOG_DC(" |DPG%d----OPP%d----| |", 2402 pipe->plane_res.dpp->inst, 2403 pipe->stream_res.opp->inst); 2404 capture_pipe_topology_data(dc, 0xF, slice_idx, stream_idx, 2405 pipe->plane_res.dpp->inst, 2406 pipe->stream_res.opp->inst, 2407 pipe->stream_res.tg->inst, is_phantom_pipe); 2408 } else if (slice_idx == slice_count - 1) { 2409 /* case 4 (DPP pipe in last slice) */ 2410 DC_LOG_DC(" | plane%d | |", plane_idx); 2411 DC_LOG_DC(" |DPP%d----| |", 2412 pipe->plane_res.dpp->inst); 2413 capture_pipe_topology_data(dc, plane_idx, slice_idx, stream_idx, 2414 pipe->plane_res.dpp->inst, 2415 pipe->stream_res.opp->inst, 2416 pipe->stream_res.tg->inst, is_phantom_pipe); 2417 } else { 2418 /* case 5 (DPP pipe not in last slice) */ 2419 DC_LOG_DC(" | plane%d | | |", plane_idx); 2420 DC_LOG_DC(" |DPP%d----| | |", 2421 pipe->plane_res.dpp->inst); 2422 capture_pipe_topology_data(dc, plane_idx, slice_idx, stream_idx, 2423 pipe->plane_res.dpp->inst, 2424 pipe->stream_res.opp->inst, 2425 pipe->stream_res.tg->inst, is_phantom_pipe); 2426 } 2427 } 2428 2429 static void resource_log_pipe_for_stream(struct dc *dc, struct dc_state *state, 2430 struct pipe_ctx *otg_master, int stream_idx, bool is_phantom_pipe) 2431 { 2432 struct pipe_ctx *opp_heads[MAX_PIPES]; 2433 struct pipe_ctx *dpp_pipes[MAX_PIPES]; 2434 2435 int slice_idx, dpp_idx, plane_idx, slice_count, dpp_count; 2436 bool is_primary; 2437 2438 slice_count = resource_get_opp_heads_for_otg_master(otg_master, 2439 &state->res_ctx, opp_heads); 2440 for (slice_idx = 0; slice_idx < slice_count; slice_idx++) { 2441 plane_idx = -1; 2442 if (opp_heads[slice_idx]->plane_state) { 2443 dpp_count = resource_get_dpp_pipes_for_opp_head( 2444 opp_heads[slice_idx], 2445 &state->res_ctx, 2446 dpp_pipes); 2447 for (dpp_idx = 0; dpp_idx < dpp_count; dpp_idx++) { 2448 is_primary = !dpp_pipes[dpp_idx]->top_pipe || 2449 dpp_pipes[dpp_idx]->top_pipe->plane_state != dpp_pipes[dpp_idx]->plane_state; 2450 if (is_primary) 2451 plane_idx++; 2452 resource_log_pipe(dc, dpp_pipes[dpp_idx], 2453 stream_idx, slice_idx, 2454 plane_idx, slice_count, 2455 is_primary, is_phantom_pipe); 2456 } 2457 } else { 2458 resource_log_pipe(dc, opp_heads[slice_idx], 2459 stream_idx, slice_idx, plane_idx, 2460 slice_count, true, is_phantom_pipe); 2461 } 2462 2463 } 2464 } 2465 2466 static int resource_stream_to_stream_idx(struct dc_state *state, 2467 struct dc_stream_state *stream) 2468 { 2469 int i, stream_idx = -1; 2470 2471 for (i = 0; i < state->stream_count; i++) 2472 if (state->streams[i] == stream) { 2473 stream_idx = i; 2474 break; 2475 } 2476 2477 /* never return negative array index */ 2478 if (stream_idx == -1) { 2479 ASSERT(0); 2480 return 0; 2481 } 2482 2483 return stream_idx; 2484 } 2485 2486 void resource_log_pipe_topology_update(struct dc *dc, struct dc_state *state) 2487 { 2488 struct pipe_ctx *otg_master; 2489 int stream_idx, phantom_stream_idx; 2490 DC_LOGGER_INIT(dc->ctx->logger); 2491 bool is_phantom_pipe = false; 2492 2493 // Start a new snapshot for this topology update 2494 start_new_topology_snapshot(dc, state); 2495 2496 DC_LOG_DC(" pipe topology update"); 2497 DC_LOG_DC(" ________________________"); 2498 for (stream_idx = 0; stream_idx < state->stream_count; stream_idx++) { 2499 if (state->streams[stream_idx]->is_phantom) 2500 continue; 2501 2502 otg_master = resource_get_otg_master_for_stream( 2503 &state->res_ctx, state->streams[stream_idx]); 2504 2505 if (!otg_master) 2506 continue; 2507 2508 resource_log_pipe_for_stream(dc, state, otg_master, stream_idx, is_phantom_pipe); 2509 } 2510 if (state->phantom_stream_count > 0) { 2511 is_phantom_pipe = true; 2512 DC_LOG_DC(" | (phantom pipes) |"); 2513 for (stream_idx = 0; stream_idx < state->stream_count; stream_idx++) { 2514 if (state->stream_status[stream_idx].mall_stream_config.type != SUBVP_MAIN) 2515 continue; 2516 2517 phantom_stream_idx = resource_stream_to_stream_idx(state, 2518 state->stream_status[stream_idx].mall_stream_config.paired_stream); 2519 otg_master = resource_get_otg_master_for_stream( 2520 &state->res_ctx, state->streams[phantom_stream_idx]); 2521 if (!otg_master) 2522 continue; 2523 2524 resource_log_pipe_for_stream(dc, state, otg_master, stream_idx, is_phantom_pipe); 2525 } 2526 } 2527 DC_LOG_DC(" |________________________|\n"); 2528 } 2529 2530 static struct pipe_ctx *get_tail_pipe( 2531 struct pipe_ctx *head_pipe) 2532 { 2533 struct pipe_ctx *tail_pipe = head_pipe->bottom_pipe; 2534 2535 while (tail_pipe) { 2536 head_pipe = tail_pipe; 2537 tail_pipe = tail_pipe->bottom_pipe; 2538 } 2539 2540 return head_pipe; 2541 } 2542 2543 static struct pipe_ctx *get_last_opp_head( 2544 struct pipe_ctx *opp_head) 2545 { 2546 ASSERT(resource_is_pipe_type(opp_head, OPP_HEAD)); 2547 while (opp_head->next_odm_pipe) 2548 opp_head = opp_head->next_odm_pipe; 2549 return opp_head; 2550 } 2551 2552 static struct pipe_ctx *get_last_dpp_pipe_in_mpcc_combine( 2553 struct pipe_ctx *dpp_pipe) 2554 { 2555 ASSERT(resource_is_pipe_type(dpp_pipe, DPP_PIPE)); 2556 while (dpp_pipe->bottom_pipe && 2557 dpp_pipe->plane_state == dpp_pipe->bottom_pipe->plane_state) 2558 dpp_pipe = dpp_pipe->bottom_pipe; 2559 return dpp_pipe; 2560 } 2561 2562 static bool update_pipe_params_after_odm_slice_count_change( 2563 struct pipe_ctx *otg_master, 2564 struct dc_state *context, 2565 const struct resource_pool *pool) 2566 { 2567 int i; 2568 struct pipe_ctx *pipe; 2569 bool result = true; 2570 2571 for (i = 0; i < pool->pipe_count && result; i++) { 2572 pipe = &context->res_ctx.pipe_ctx[i]; 2573 if (pipe->stream == otg_master->stream && pipe->plane_state) 2574 result = resource_build_scaling_params(pipe); 2575 } 2576 2577 if (pool->funcs->build_pipe_pix_clk_params) 2578 pool->funcs->build_pipe_pix_clk_params(otg_master); 2579 2580 resource_build_test_pattern_params(&context->res_ctx, otg_master); 2581 2582 return result; 2583 } 2584 2585 static bool update_pipe_params_after_mpc_slice_count_change( 2586 const struct dc_plane_state *plane, 2587 struct dc_state *context, 2588 const struct resource_pool *pool) 2589 { 2590 int i; 2591 struct pipe_ctx *pipe; 2592 bool result = true; 2593 2594 for (i = 0; i < pool->pipe_count && result; i++) { 2595 pipe = &context->res_ctx.pipe_ctx[i]; 2596 if (pipe->plane_state == plane) 2597 result = resource_build_scaling_params(pipe); 2598 } 2599 return result; 2600 } 2601 2602 static int acquire_first_split_pipe( 2603 struct resource_context *res_ctx, 2604 const struct resource_pool *pool, 2605 struct dc_stream_state *stream) 2606 { 2607 int i; 2608 2609 for (i = 0; i < pool->pipe_count; i++) { 2610 struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i]; 2611 2612 if (split_pipe->top_pipe && 2613 split_pipe->top_pipe->plane_state == split_pipe->plane_state) { 2614 split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe; 2615 if (split_pipe->bottom_pipe) 2616 split_pipe->bottom_pipe->top_pipe = split_pipe->top_pipe; 2617 2618 if (split_pipe->top_pipe->plane_state) 2619 resource_build_scaling_params(split_pipe->top_pipe); 2620 2621 memset(split_pipe, 0, sizeof(*split_pipe)); 2622 split_pipe->stream_res.tg = pool->timing_generators[i]; 2623 split_pipe->plane_res.hubp = pool->hubps[i]; 2624 split_pipe->plane_res.ipp = pool->ipps[i]; 2625 split_pipe->plane_res.dpp = pool->dpps[i]; 2626 split_pipe->stream_res.opp = pool->opps[i]; 2627 split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst; 2628 split_pipe->pipe_idx = i; 2629 2630 split_pipe->stream = stream; 2631 return i; 2632 } 2633 } 2634 return FREE_PIPE_INDEX_NOT_FOUND; 2635 } 2636 2637 static void update_stream_engine_usage( 2638 struct resource_context *res_ctx, 2639 const struct resource_pool *pool, 2640 struct stream_encoder *stream_enc, 2641 bool acquired) 2642 { 2643 int i; 2644 2645 for (i = 0; i < pool->stream_enc_count; i++) { 2646 if (pool->stream_enc[i] == stream_enc) 2647 res_ctx->is_stream_enc_acquired[i] = acquired; 2648 } 2649 } 2650 2651 static void update_hpo_dp_stream_engine_usage( 2652 struct resource_context *res_ctx, 2653 const struct resource_pool *pool, 2654 struct hpo_dp_stream_encoder *hpo_dp_stream_enc, 2655 bool acquired) 2656 { 2657 int i; 2658 2659 for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { 2660 if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc) 2661 res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired; 2662 } 2663 } 2664 2665 static inline int find_acquired_hpo_dp_link_enc_for_link( 2666 const struct resource_context *res_ctx, 2667 const struct dc_link *link) 2668 { 2669 int i; 2670 2671 for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++) 2672 if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 && 2673 res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index) 2674 return i; 2675 2676 return -1; 2677 } 2678 2679 static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx, 2680 const struct resource_pool *pool) 2681 { 2682 int i; 2683 2684 for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++) 2685 if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0) 2686 break; 2687 2688 return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) && 2689 i < pool->hpo_dp_link_enc_count) ? i : -1; 2690 } 2691 2692 static inline void acquire_hpo_dp_link_enc( 2693 struct resource_context *res_ctx, 2694 unsigned int link_index, 2695 int enc_index) 2696 { 2697 res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index; 2698 res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1; 2699 } 2700 2701 static inline void retain_hpo_dp_link_enc( 2702 struct resource_context *res_ctx, 2703 int enc_index) 2704 { 2705 res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++; 2706 } 2707 2708 static inline void release_hpo_dp_link_enc( 2709 struct resource_context *res_ctx, 2710 int enc_index) 2711 { 2712 ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0); 2713 res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--; 2714 } 2715 2716 static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx, 2717 const struct resource_pool *pool, 2718 struct pipe_ctx *pipe_ctx, 2719 struct dc_stream_state *stream) 2720 { 2721 int enc_index; 2722 2723 enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); 2724 2725 if (enc_index >= 0) { 2726 retain_hpo_dp_link_enc(res_ctx, enc_index); 2727 } else { 2728 enc_index = find_free_hpo_dp_link_enc(res_ctx, pool); 2729 if (enc_index >= 0) 2730 acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index); 2731 } 2732 2733 if (enc_index >= 0) 2734 pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index]; 2735 2736 return pipe_ctx->link_res.hpo_dp_link_enc != NULL; 2737 } 2738 2739 static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx, 2740 struct pipe_ctx *pipe_ctx, 2741 struct dc_stream_state *stream) 2742 { 2743 int enc_index; 2744 2745 enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); 2746 2747 if (enc_index >= 0) { 2748 release_hpo_dp_link_enc(res_ctx, enc_index); 2749 pipe_ctx->link_res.hpo_dp_link_enc = NULL; 2750 } 2751 } 2752 2753 static inline int find_acquired_dio_link_enc_for_link( 2754 const struct resource_context *res_ctx, 2755 const struct dc_link *link) 2756 { 2757 int i; 2758 2759 for (i = 0; i < ARRAY_SIZE(res_ctx->dio_link_enc_ref_cnts); i++) 2760 if (res_ctx->dio_link_enc_ref_cnts[i] > 0 && 2761 res_ctx->dio_link_enc_to_link_idx[i] == link->link_index) 2762 return i; 2763 2764 return -1; 2765 } 2766 2767 static inline int find_fixed_dio_link_enc(const struct dc_link *link) 2768 { 2769 /* the 8b10b dp phy can only use fixed link encoder */ 2770 return link->eng_id; 2771 } 2772 2773 static inline int find_free_dio_link_enc(const struct resource_context *res_ctx, 2774 const struct dc_link *link, const struct resource_pool *pool, struct dc_stream_state *stream) 2775 { 2776 int i, j = -1; 2777 int stream_enc_inst = -1; 2778 int enc_count = pool->dig_link_enc_count; 2779 2780 /* Find stream encoder instance for the stream */ 2781 if (stream) { 2782 for (i = 0; i < pool->pipe_count; i++) { 2783 if ((res_ctx->pipe_ctx[i].stream == stream) && 2784 (res_ctx->pipe_ctx[i].stream_res.stream_enc != NULL)) { 2785 stream_enc_inst = res_ctx->pipe_ctx[i].stream_res.stream_enc->id; 2786 break; 2787 } 2788 } 2789 } 2790 2791 /* Assign dpia preferred > stream enc instance > available */ 2792 for (i = 0; i < enc_count; i++) { 2793 if (res_ctx->dio_link_enc_ref_cnts[i] == 0) { 2794 if (j == -1) 2795 j = i; 2796 2797 if (link->dpia_preferred_eng_id == i) { 2798 j = i; 2799 break; 2800 } 2801 2802 if (stream_enc_inst == i) { 2803 j = stream_enc_inst; 2804 } 2805 } 2806 } 2807 return j; 2808 } 2809 2810 static inline void acquire_dio_link_enc( 2811 struct resource_context *res_ctx, 2812 unsigned int link_index, 2813 int enc_index) 2814 { 2815 res_ctx->dio_link_enc_to_link_idx[enc_index] = link_index; 2816 res_ctx->dio_link_enc_ref_cnts[enc_index] = 1; 2817 } 2818 2819 static inline void retain_dio_link_enc( 2820 struct resource_context *res_ctx, 2821 int enc_index) 2822 { 2823 res_ctx->dio_link_enc_ref_cnts[enc_index]++; 2824 } 2825 2826 static inline void release_dio_link_enc( 2827 struct resource_context *res_ctx, 2828 int enc_index) 2829 { 2830 ASSERT(res_ctx->dio_link_enc_ref_cnts[enc_index] > 0); 2831 res_ctx->dio_link_enc_ref_cnts[enc_index]--; 2832 } 2833 2834 static bool is_dio_enc_acquired_by_other_link(const struct dc_link *link, 2835 int enc_index, 2836 int *link_index) 2837 { 2838 const struct dc *dc = link->dc; 2839 const struct resource_context *res_ctx = &dc->current_state->res_ctx; 2840 2841 /* pass the link_index that acquired the enc_index */ 2842 if (res_ctx->dio_link_enc_ref_cnts[enc_index] > 0 && 2843 res_ctx->dio_link_enc_to_link_idx[enc_index] != link->link_index) { 2844 *link_index = res_ctx->dio_link_enc_to_link_idx[enc_index]; 2845 return true; 2846 } 2847 2848 return false; 2849 } 2850 2851 static void swap_dio_link_enc_to_muxable_ctx(struct dc_state *context, 2852 const struct resource_pool *pool, 2853 int new_encoder, 2854 int old_encoder) 2855 { 2856 struct resource_context *res_ctx = &context->res_ctx; 2857 int stream_count = context->stream_count; 2858 int i = 0; 2859 2860 res_ctx->dio_link_enc_ref_cnts[new_encoder] = res_ctx->dio_link_enc_ref_cnts[old_encoder]; 2861 res_ctx->dio_link_enc_to_link_idx[new_encoder] = res_ctx->dio_link_enc_to_link_idx[old_encoder]; 2862 res_ctx->dio_link_enc_ref_cnts[old_encoder] = 0; 2863 2864 for (i = 0; i < stream_count; i++) { 2865 struct dc_stream_state *stream = context->streams[i]; 2866 struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); 2867 2868 if (pipe_ctx && pipe_ctx->link_res.dio_link_enc == pool->link_encoders[old_encoder]) 2869 pipe_ctx->link_res.dio_link_enc = pool->link_encoders[new_encoder]; 2870 } 2871 } 2872 2873 static bool add_dio_link_enc_to_ctx(const struct dc *dc, 2874 struct dc_state *context, 2875 const struct resource_pool *pool, 2876 struct pipe_ctx *pipe_ctx, 2877 struct dc_stream_state *stream) 2878 { 2879 struct resource_context *res_ctx = &context->res_ctx; 2880 int enc_index; 2881 2882 enc_index = find_acquired_dio_link_enc_for_link(res_ctx, stream->link); 2883 2884 if (enc_index >= 0) { 2885 retain_dio_link_enc(res_ctx, enc_index); 2886 } else { 2887 if (stream->link->is_dig_mapping_flexible) 2888 enc_index = find_free_dio_link_enc(res_ctx, stream->link, pool, stream); 2889 else { 2890 int link_index = 0; 2891 2892 enc_index = find_fixed_dio_link_enc(stream->link); 2893 /* Fixed mapping link can only use its fixed link encoder. 2894 * If the encoder is acquired by other link then get a new free encoder and swap the new 2895 * one into the acquiring link. 2896 */ 2897 if (enc_index >= 0 && is_dio_enc_acquired_by_other_link(stream->link, enc_index, &link_index)) { 2898 int new_enc_index = find_free_dio_link_enc(res_ctx, dc->links[link_index], pool, stream); 2899 2900 if (new_enc_index >= 0) 2901 swap_dio_link_enc_to_muxable_ctx(context, pool, new_enc_index, enc_index); 2902 else 2903 return false; 2904 } 2905 } 2906 2907 if (enc_index >= 0) 2908 acquire_dio_link_enc(res_ctx, stream->link->link_index, enc_index); 2909 } 2910 2911 if (enc_index >= 0) 2912 pipe_ctx->link_res.dio_link_enc = pool->link_encoders[enc_index]; 2913 2914 return pipe_ctx->link_res.dio_link_enc != NULL; 2915 } 2916 2917 static void remove_dio_link_enc_from_ctx(struct resource_context *res_ctx, 2918 struct pipe_ctx *pipe_ctx, 2919 struct dc_stream_state *stream) 2920 { 2921 int enc_index = -1; 2922 2923 if (stream->link) 2924 enc_index = find_acquired_dio_link_enc_for_link(res_ctx, stream->link); 2925 2926 if (enc_index >= 0) { 2927 release_dio_link_enc(res_ctx, enc_index); 2928 pipe_ctx->link_res.dio_link_enc = NULL; 2929 } 2930 } 2931 2932 static int get_num_of_free_pipes(const struct resource_pool *pool, const struct dc_state *context) 2933 { 2934 int i; 2935 int count = 0; 2936 2937 for (i = 0; i < pool->pipe_count; i++) 2938 if (resource_is_pipe_type(&context->res_ctx.pipe_ctx[i], FREE_PIPE)) 2939 count++; 2940 return count; 2941 } 2942 2943 enum dc_status resource_add_otg_master_for_stream_output(struct dc_state *new_ctx, 2944 const struct resource_pool *pool, 2945 struct dc_stream_state *stream) 2946 { 2947 (void)pool; 2948 struct dc *dc = stream->ctx->dc; 2949 2950 return dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream); 2951 } 2952 2953 void resource_remove_otg_master_for_stream_output(struct dc_state *context, 2954 const struct resource_pool *pool, 2955 struct dc_stream_state *stream) 2956 { 2957 struct pipe_ctx *otg_master = resource_get_otg_master_for_stream( 2958 &context->res_ctx, stream); 2959 2960 if (!otg_master) 2961 return; 2962 2963 ASSERT(resource_get_odm_slice_count(otg_master) == 1); 2964 ASSERT(otg_master->plane_state == NULL); 2965 ASSERT(otg_master->stream_res.stream_enc); 2966 update_stream_engine_usage( 2967 &context->res_ctx, 2968 pool, 2969 otg_master->stream_res.stream_enc, 2970 false); 2971 2972 if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(otg_master)) { 2973 update_hpo_dp_stream_engine_usage( 2974 &context->res_ctx, pool, 2975 otg_master->stream_res.hpo_dp_stream_enc, 2976 false); 2977 remove_hpo_dp_link_enc_from_ctx( 2978 &context->res_ctx, otg_master, stream); 2979 } 2980 2981 if (stream->ctx->dc->config.unify_link_enc_assignment) 2982 remove_dio_link_enc_from_ctx(&context->res_ctx, otg_master, stream); 2983 2984 if (otg_master->stream_res.audio) 2985 update_audio_usage( 2986 &context->res_ctx, 2987 pool, 2988 otg_master->stream_res.audio, 2989 false); 2990 2991 resource_unreference_clock_source(&context->res_ctx, 2992 pool, 2993 otg_master->clock_source); 2994 2995 if (pool->funcs->remove_stream_from_ctx) 2996 pool->funcs->remove_stream_from_ctx( 2997 stream->ctx->dc, context, stream); 2998 2999 memset(otg_master, 0, sizeof(*otg_master)); 3000 } 3001 3002 /* For each OPP head of an OTG master, add top plane at plane index 0. 3003 * 3004 * In the following example, the stream has 2 ODM slices without a top plane. 3005 * By adding a plane 0 to OPP heads, we are configuring our hardware to render 3006 * plane 0 by using each OPP head's DPP. 3007 * 3008 * Inter-pipe Relation (Before Adding Plane) 3009 * __________________________________________________ 3010 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | 3011 * | | | slice 0 | | 3012 * | 0 | |blank ----ODM----------- | 3013 * | | | slice 1 | | | 3014 * | 1 | |blank ---- | | 3015 * |________|_______________|___________|_____________| 3016 * 3017 * Inter-pipe Relation (After Adding Plane) 3018 * __________________________________________________ 3019 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | 3020 * | | plane 0 | slice 0 | | 3021 * | 0 | -------------------------ODM----------- | 3022 * | | plane 0 | slice 1 | | | 3023 * | 1 | ------------------------- | | 3024 * |________|_______________|___________|_____________| 3025 */ 3026 static bool add_plane_to_opp_head_pipes(struct pipe_ctx *otg_master_pipe, 3027 struct dc_plane_state *plane_state, 3028 struct dc_state *context) 3029 { 3030 (void)context; 3031 struct pipe_ctx *opp_head_pipe = otg_master_pipe; 3032 3033 while (opp_head_pipe) { 3034 if (opp_head_pipe->plane_state) { 3035 ASSERT(0); 3036 return false; 3037 } 3038 opp_head_pipe->plane_state = plane_state; 3039 opp_head_pipe = opp_head_pipe->next_odm_pipe; 3040 } 3041 3042 return true; 3043 } 3044 3045 /* For each OPP head of an OTG master, acquire a secondary DPP pipe and add 3046 * the plane. So the plane is added to all ODM slices associated with the OTG 3047 * master pipe in the bottom layer. 3048 * 3049 * In the following example, the stream has 2 ODM slices and a top plane 0. 3050 * By acquiring secondary DPP pipes and adding a plane 1, we are configuring our 3051 * hardware to render the plane 1 by acquiring a new pipe for each ODM slice and 3052 * render plane 1 using new pipes' DPP in the Z axis below plane 0. 3053 * 3054 * Inter-pipe Relation (Before Adding Plane) 3055 * __________________________________________________ 3056 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | 3057 * | | plane 0 | slice 0 | | 3058 * | 0 | -------------------------ODM----------- | 3059 * | | plane 0 | slice 1 | | | 3060 * | 1 | ------------------------- | | 3061 * |________|_______________|___________|_____________| 3062 * 3063 * Inter-pipe Relation (After Acquiring and Adding Plane) 3064 * __________________________________________________ 3065 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | 3066 * | | plane 0 | slice 0 | | 3067 * | 0 | -------------MPC---------ODM----------- | 3068 * | | plane 1 | | | | | 3069 * | 2 | ------------- | | | | 3070 * | | plane 0 | slice 1 | | | 3071 * | 1 | -------------MPC--------- | | 3072 * | | plane 1 | | | | 3073 * | 3 | ------------- | | | 3074 * |________|_______________|___________|_____________| 3075 */ 3076 static bool acquire_secondary_dpp_pipes_and_add_plane( 3077 struct pipe_ctx *otg_master_pipe, 3078 struct dc_plane_state *plane_state, 3079 struct dc_state *new_ctx, 3080 struct dc_state *cur_ctx, 3081 struct resource_pool *pool) 3082 { 3083 struct pipe_ctx *sec_pipe, *tail_pipe; 3084 struct pipe_ctx *opp_heads[MAX_PIPES]; 3085 int opp_head_count; 3086 int i; 3087 3088 if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe) { 3089 ASSERT(0); 3090 return false; 3091 } 3092 3093 opp_head_count = resource_get_opp_heads_for_otg_master(otg_master_pipe, 3094 &new_ctx->res_ctx, opp_heads); 3095 if (get_num_of_free_pipes(pool, new_ctx) < opp_head_count) 3096 /* not enough free pipes */ 3097 return false; 3098 3099 for (i = 0; i < opp_head_count; i++) { 3100 sec_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe( 3101 cur_ctx, 3102 new_ctx, 3103 pool, 3104 opp_heads[i]); 3105 ASSERT(sec_pipe); 3106 sec_pipe->plane_state = plane_state; 3107 3108 /* establish pipe relationship */ 3109 tail_pipe = get_tail_pipe(opp_heads[i]); 3110 tail_pipe->bottom_pipe = sec_pipe; 3111 sec_pipe->top_pipe = tail_pipe; 3112 sec_pipe->bottom_pipe = NULL; 3113 if (tail_pipe->prev_odm_pipe) { 3114 ASSERT(tail_pipe->prev_odm_pipe->bottom_pipe); 3115 sec_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe; 3116 tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = sec_pipe; 3117 } else { 3118 sec_pipe->prev_odm_pipe = NULL; 3119 } 3120 } 3121 return true; 3122 } 3123 3124 bool resource_append_dpp_pipes_for_plane_composition( 3125 struct dc_state *new_ctx, 3126 struct dc_state *cur_ctx, 3127 struct resource_pool *pool, 3128 struct pipe_ctx *otg_master_pipe, 3129 struct dc_plane_state *plane_state) 3130 { 3131 bool success; 3132 3133 if (otg_master_pipe->plane_state == NULL) 3134 success = add_plane_to_opp_head_pipes(otg_master_pipe, 3135 plane_state, new_ctx); 3136 else 3137 success = acquire_secondary_dpp_pipes_and_add_plane( 3138 otg_master_pipe, plane_state, new_ctx, 3139 cur_ctx, pool); 3140 if (success) { 3141 /* when appending a plane mpc slice count changes from 0 to 1 */ 3142 success = update_pipe_params_after_mpc_slice_count_change( 3143 plane_state, new_ctx, pool); 3144 if (!success) 3145 resource_remove_dpp_pipes_for_plane_composition(new_ctx, 3146 pool, plane_state); 3147 } 3148 3149 return success; 3150 } 3151 3152 void resource_remove_dpp_pipes_for_plane_composition( 3153 struct dc_state *context, 3154 const struct resource_pool *pool, 3155 const struct dc_plane_state *plane_state) 3156 { 3157 int i; 3158 3159 for (i = pool->pipe_count - 1; i >= 0; i--) { 3160 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 3161 3162 if (pipe_ctx->plane_state == plane_state) { 3163 if (pipe_ctx->top_pipe) 3164 pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe; 3165 3166 /* Second condition is to avoid setting NULL to top pipe 3167 * of tail pipe making it look like head pipe in subsequent 3168 * deletes 3169 */ 3170 if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe) 3171 pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe; 3172 3173 /* 3174 * For head pipe detach surfaces from pipe for tail 3175 * pipe just zero it out 3176 */ 3177 if (!pipe_ctx->top_pipe) 3178 pipe_ctx->plane_state = NULL; 3179 else 3180 memset(pipe_ctx, 0, sizeof(*pipe_ctx)); 3181 } 3182 } 3183 } 3184 3185 /* 3186 * Increase ODM slice count by 1 by acquiring pipes and adding a new ODM slice 3187 * at the last index. 3188 * return - true if a new ODM slice is added and required pipes are acquired. 3189 * false if new_ctx is no longer a valid state after new ODM slice is added. 3190 * 3191 * This is achieved by duplicating MPC blending tree from previous ODM slice. 3192 * In the following example, we have a single MPC tree and 1 ODM slice 0. We 3193 * want to add a new odm slice by duplicating the MPC blending tree and add 3194 * ODM slice 1. 3195 * 3196 * Inter-pipe Relation (Before Acquiring and Adding ODM Slice) 3197 * __________________________________________________ 3198 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | 3199 * | | plane 0 | slice 0 | | 3200 * | 0 | -------------MPC---------ODM----------- | 3201 * | | plane 1 | | | | 3202 * | 1 | ------------- | | | 3203 * |________|_______________|___________|_____________| 3204 * 3205 * Inter-pipe Relation (After Acquiring and Adding ODM Slice) 3206 * __________________________________________________ 3207 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | 3208 * | | plane 0 | slice 0 | | 3209 * | 0 | -------------MPC---------ODM----------- | 3210 * | | plane 1 | | | | | 3211 * | 1 | ------------- | | | | 3212 * | | plane 0 | slice 1 | | | 3213 * | 2 | -------------MPC--------- | | 3214 * | | plane 1 | | | | 3215 * | 3 | ------------- | | | 3216 * |________|_______________|___________|_____________| 3217 */ 3218 static bool acquire_pipes_and_add_odm_slice( 3219 struct pipe_ctx *otg_master_pipe, 3220 struct dc_state *new_ctx, 3221 const struct dc_state *cur_ctx, 3222 const struct resource_pool *pool) 3223 { 3224 struct pipe_ctx *last_opp_head = get_last_opp_head(otg_master_pipe); 3225 struct pipe_ctx *new_opp_head; 3226 struct pipe_ctx *last_top_dpp_pipe, *last_bottom_dpp_pipe, 3227 *new_top_dpp_pipe, *new_bottom_dpp_pipe; 3228 3229 if (!pool->funcs->acquire_free_pipe_as_secondary_opp_head) { 3230 ASSERT(0); 3231 return false; 3232 } 3233 new_opp_head = pool->funcs->acquire_free_pipe_as_secondary_opp_head( 3234 cur_ctx, new_ctx, pool, 3235 otg_master_pipe); 3236 if (!new_opp_head) 3237 return false; 3238 3239 last_opp_head->next_odm_pipe = new_opp_head; 3240 new_opp_head->prev_odm_pipe = last_opp_head; 3241 new_opp_head->next_odm_pipe = NULL; 3242 new_opp_head->plane_state = last_opp_head->plane_state; 3243 last_top_dpp_pipe = last_opp_head; 3244 new_top_dpp_pipe = new_opp_head; 3245 3246 while (last_top_dpp_pipe->bottom_pipe) { 3247 last_bottom_dpp_pipe = last_top_dpp_pipe->bottom_pipe; 3248 new_bottom_dpp_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe( 3249 cur_ctx, new_ctx, pool, 3250 new_opp_head); 3251 if (!new_bottom_dpp_pipe) 3252 return false; 3253 3254 new_bottom_dpp_pipe->plane_state = last_bottom_dpp_pipe->plane_state; 3255 new_top_dpp_pipe->bottom_pipe = new_bottom_dpp_pipe; 3256 new_bottom_dpp_pipe->top_pipe = new_top_dpp_pipe; 3257 last_bottom_dpp_pipe->next_odm_pipe = new_bottom_dpp_pipe; 3258 new_bottom_dpp_pipe->prev_odm_pipe = last_bottom_dpp_pipe; 3259 new_bottom_dpp_pipe->next_odm_pipe = NULL; 3260 last_top_dpp_pipe = last_bottom_dpp_pipe; 3261 } 3262 3263 return true; 3264 } 3265 3266 /* 3267 * Decrease ODM slice count by 1 by releasing pipes and removing the ODM slice 3268 * at the last index. 3269 * return - true if the last ODM slice is removed and related pipes are 3270 * released. false if there is no removable ODM slice. 3271 * 3272 * In the following example, we have 2 MPC trees and ODM slice 0 and slice 1. 3273 * We want to remove the last ODM i.e slice 1. We are releasing secondary DPP 3274 * pipe 3 and OPP head pipe 2. 3275 * 3276 * Inter-pipe Relation (Before Releasing and Removing ODM Slice) 3277 * __________________________________________________ 3278 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | 3279 * | | plane 0 | slice 0 | | 3280 * | 0 | -------------MPC---------ODM----------- | 3281 * | | plane 1 | | | | | 3282 * | 1 | ------------- | | | | 3283 * | | plane 0 | slice 1 | | | 3284 * | 2 | -------------MPC--------- | | 3285 * | | plane 1 | | | | 3286 * | 3 | ------------- | | | 3287 * |________|_______________|___________|_____________| 3288 * 3289 * Inter-pipe Relation (After Releasing and Removing ODM Slice) 3290 * __________________________________________________ 3291 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | 3292 * | | plane 0 | slice 0 | | 3293 * | 0 | -------------MPC---------ODM----------- | 3294 * | | plane 1 | | | | 3295 * | 1 | ------------- | | | 3296 * |________|_______________|___________|_____________| 3297 */ 3298 static bool release_pipes_and_remove_odm_slice( 3299 struct pipe_ctx *otg_master_pipe, 3300 struct dc_state *context, 3301 const struct resource_pool *pool) 3302 { 3303 struct pipe_ctx *last_opp_head = get_last_opp_head(otg_master_pipe); 3304 struct pipe_ctx *tail_pipe = get_tail_pipe(last_opp_head); 3305 3306 if (!pool->funcs->release_pipe) { 3307 ASSERT(0); 3308 return false; 3309 } 3310 3311 if (resource_is_pipe_type(last_opp_head, OTG_MASTER)) 3312 return false; 3313 3314 while (tail_pipe->top_pipe) { 3315 tail_pipe->prev_odm_pipe->next_odm_pipe = NULL; 3316 tail_pipe = tail_pipe->top_pipe; 3317 pool->funcs->release_pipe(context, tail_pipe->bottom_pipe, pool); 3318 tail_pipe->bottom_pipe = NULL; 3319 } 3320 last_opp_head->prev_odm_pipe->next_odm_pipe = NULL; 3321 pool->funcs->release_pipe(context, last_opp_head, pool); 3322 3323 return true; 3324 } 3325 3326 /* 3327 * Increase MPC slice count by 1 by acquiring a new DPP pipe and add it as the 3328 * last MPC slice of the plane associated with dpp_pipe. 3329 * 3330 * return - true if a new MPC slice is added and required pipes are acquired. 3331 * false if new_ctx is no longer a valid state after new MPC slice is added. 3332 * 3333 * In the following example, we add a new MPC slice for plane 0 into the 3334 * new_ctx. To do so we pass pipe 0 as dpp_pipe. The function acquires a new DPP 3335 * pipe 2 for plane 0 as the bottom most pipe for plane 0. 3336 * 3337 * Inter-pipe Relation (Before Acquiring and Adding MPC Slice) 3338 * __________________________________________________ 3339 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | 3340 * | | plane 0 | | | 3341 * | 0 | -------------MPC----------------------- | 3342 * | | plane 1 | | | | 3343 * | 1 | ------------- | | | 3344 * |________|_______________|___________|_____________| 3345 * 3346 * Inter-pipe Relation (After Acquiring and Adding MPC Slice) 3347 * __________________________________________________ 3348 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | 3349 * | | plane 0 | | | 3350 * | 0 | -------------MPC----------------------- | 3351 * | | plane 0 | | | | 3352 * | 2 | ------------- | | | 3353 * | | plane 1 | | | | 3354 * | 1 | ------------- | | | 3355 * |________|_______________|___________|_____________| 3356 */ 3357 static bool acquire_dpp_pipe_and_add_mpc_slice( 3358 struct pipe_ctx *dpp_pipe, 3359 struct dc_state *new_ctx, 3360 const struct dc_state *cur_ctx, 3361 const struct resource_pool *pool) 3362 { 3363 struct pipe_ctx *last_dpp_pipe = 3364 get_last_dpp_pipe_in_mpcc_combine(dpp_pipe); 3365 struct pipe_ctx *opp_head = resource_get_opp_head(dpp_pipe); 3366 struct pipe_ctx *new_dpp_pipe; 3367 3368 if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe) { 3369 ASSERT(0); 3370 return false; 3371 } 3372 new_dpp_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe( 3373 cur_ctx, new_ctx, pool, opp_head); 3374 if (!new_dpp_pipe || resource_get_odm_slice_count(dpp_pipe) > 1) 3375 return false; 3376 3377 new_dpp_pipe->bottom_pipe = last_dpp_pipe->bottom_pipe; 3378 if (new_dpp_pipe->bottom_pipe) 3379 new_dpp_pipe->bottom_pipe->top_pipe = new_dpp_pipe; 3380 new_dpp_pipe->top_pipe = last_dpp_pipe; 3381 last_dpp_pipe->bottom_pipe = new_dpp_pipe; 3382 new_dpp_pipe->plane_state = last_dpp_pipe->plane_state; 3383 3384 return true; 3385 } 3386 3387 /* 3388 * Reduce MPC slice count by 1 by releasing the bottom DPP pipe in MPCC combine 3389 * with dpp_pipe and removing last MPC slice of the plane associated with 3390 * dpp_pipe. 3391 * 3392 * return - true if the last MPC slice of the plane associated with dpp_pipe is 3393 * removed and last DPP pipe in MPCC combine with dpp_pipe is released. 3394 * false if there is no removable MPC slice. 3395 * 3396 * In the following example, we remove an MPC slice for plane 0 from the 3397 * context. To do so we pass pipe 0 as dpp_pipe. The function releases pipe 1 as 3398 * it is the last pipe for plane 0. 3399 * 3400 * Inter-pipe Relation (Before Releasing and Removing MPC Slice) 3401 * __________________________________________________ 3402 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | 3403 * | | plane 0 | | | 3404 * | 0 | -------------MPC----------------------- | 3405 * | | plane 0 | | | | 3406 * | 1 | ------------- | | | 3407 * | | plane 1 | | | | 3408 * | 2 | ------------- | | | 3409 * |________|_______________|___________|_____________| 3410 * 3411 * Inter-pipe Relation (After Releasing and Removing MPC Slice) 3412 * __________________________________________________ 3413 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | 3414 * | | plane 0 | | | 3415 * | 0 | -------------MPC----------------------- | 3416 * | | plane 1 | | | | 3417 * | 2 | ------------- | | | 3418 * |________|_______________|___________|_____________| 3419 */ 3420 static bool release_dpp_pipe_and_remove_mpc_slice( 3421 struct pipe_ctx *dpp_pipe, 3422 struct dc_state *context, 3423 const struct resource_pool *pool) 3424 { 3425 struct pipe_ctx *last_dpp_pipe = 3426 get_last_dpp_pipe_in_mpcc_combine(dpp_pipe); 3427 3428 if (!pool->funcs->release_pipe) { 3429 ASSERT(0); 3430 return false; 3431 } 3432 3433 if (resource_is_pipe_type(last_dpp_pipe, OPP_HEAD) || 3434 resource_get_odm_slice_count(dpp_pipe) > 1) 3435 return false; 3436 3437 last_dpp_pipe->top_pipe->bottom_pipe = last_dpp_pipe->bottom_pipe; 3438 if (last_dpp_pipe->bottom_pipe) 3439 last_dpp_pipe->bottom_pipe->top_pipe = last_dpp_pipe->top_pipe; 3440 pool->funcs->release_pipe(context, last_dpp_pipe, pool); 3441 3442 return true; 3443 } 3444 3445 bool resource_update_pipes_for_stream_with_slice_count( 3446 struct dc_state *new_ctx, 3447 const struct dc_state *cur_ctx, 3448 const struct resource_pool *pool, 3449 const struct dc_stream_state *stream, 3450 int new_slice_count) 3451 { 3452 int i; 3453 struct pipe_ctx *otg_master = resource_get_otg_master_for_stream( 3454 &new_ctx->res_ctx, stream); 3455 int cur_slice_count; 3456 bool result = true; 3457 3458 if (!otg_master) 3459 return false; 3460 3461 cur_slice_count = resource_get_odm_slice_count(otg_master); 3462 3463 if (new_slice_count == cur_slice_count) 3464 return result; 3465 3466 if (new_slice_count > cur_slice_count) 3467 for (i = 0; i < new_slice_count - cur_slice_count && result; i++) 3468 result = acquire_pipes_and_add_odm_slice( 3469 otg_master, new_ctx, cur_ctx, pool); 3470 else 3471 for (i = 0; i < cur_slice_count - new_slice_count && result; i++) 3472 result = release_pipes_and_remove_odm_slice( 3473 otg_master, new_ctx, pool); 3474 if (result) 3475 result = update_pipe_params_after_odm_slice_count_change( 3476 otg_master, new_ctx, pool); 3477 return result; 3478 } 3479 3480 bool resource_update_pipes_for_plane_with_slice_count( 3481 struct dc_state *new_ctx, 3482 const struct dc_state *cur_ctx, 3483 const struct resource_pool *pool, 3484 const struct dc_plane_state *plane, 3485 int new_slice_count) 3486 { 3487 int i; 3488 int dpp_pipe_count; 3489 int cur_slice_count; 3490 struct pipe_ctx *dpp_pipes[MAX_PIPES] = {0}; 3491 bool result = true; 3492 3493 dpp_pipe_count = resource_get_dpp_pipes_for_plane(plane, 3494 &new_ctx->res_ctx, dpp_pipes); 3495 ASSERT(dpp_pipe_count > 0); 3496 cur_slice_count = resource_get_mpc_slice_count(dpp_pipes[0]); 3497 3498 if (new_slice_count == cur_slice_count) 3499 return result; 3500 3501 if (new_slice_count > cur_slice_count) 3502 for (i = 0; i < new_slice_count - cur_slice_count && result; i++) 3503 result = acquire_dpp_pipe_and_add_mpc_slice( 3504 dpp_pipes[0], new_ctx, cur_ctx, pool); 3505 else 3506 for (i = 0; i < cur_slice_count - new_slice_count && result; i++) 3507 result = release_dpp_pipe_and_remove_mpc_slice( 3508 dpp_pipes[0], new_ctx, pool); 3509 if (result) 3510 result = update_pipe_params_after_mpc_slice_count_change( 3511 dpp_pipes[0]->plane_state, new_ctx, pool); 3512 return result; 3513 } 3514 3515 bool dc_is_timing_changed(struct dc_stream_state *cur_stream, 3516 struct dc_stream_state *new_stream) 3517 { 3518 if (cur_stream == NULL) 3519 return true; 3520 3521 /* If output color space is changed, need to reprogram info frames */ 3522 if (cur_stream->output_color_space != new_stream->output_color_space) 3523 return true; 3524 3525 return memcmp( 3526 &cur_stream->timing, 3527 &new_stream->timing, 3528 sizeof(struct dc_crtc_timing)) != 0; 3529 } 3530 3531 static bool are_stream_backends_same( 3532 struct dc_stream_state *stream_a, struct dc_stream_state *stream_b) 3533 { 3534 if (stream_a == stream_b) 3535 return true; 3536 3537 if (stream_a == NULL || stream_b == NULL) 3538 return false; 3539 3540 if (dc_is_timing_changed(stream_a, stream_b)) 3541 return false; 3542 3543 if (stream_a->signal != stream_b->signal) 3544 return false; 3545 3546 if (stream_a->dpms_off != stream_b->dpms_off) 3547 return false; 3548 3549 return true; 3550 } 3551 3552 /* 3553 * dc_is_stream_unchanged() - Compare two stream states for equivalence. 3554 * 3555 * Checks if there a difference between the two states 3556 * that would require a mode change. 3557 * 3558 * Does not compare cursor position or attributes. 3559 */ 3560 bool dc_is_stream_unchanged( 3561 struct dc_stream_state *old_stream, struct dc_stream_state *stream) 3562 { 3563 if (!old_stream || !stream) 3564 return false; 3565 3566 if (!are_stream_backends_same(old_stream, stream)) 3567 return false; 3568 3569 if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param) 3570 return false; 3571 3572 /*compare audio info*/ 3573 if (memcmp(&old_stream->audio_info, &stream->audio_info, sizeof(stream->audio_info)) != 0) 3574 return false; 3575 3576 return true; 3577 } 3578 3579 /* 3580 * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams. 3581 */ 3582 bool dc_is_stream_scaling_unchanged(struct dc_stream_state *old_stream, 3583 struct dc_stream_state *stream) 3584 { 3585 if (old_stream == stream) 3586 return true; 3587 3588 if (old_stream == NULL || stream == NULL) 3589 return false; 3590 3591 if (memcmp(&old_stream->src, 3592 &stream->src, 3593 sizeof(struct rect)) != 0) 3594 return false; 3595 3596 if (memcmp(&old_stream->dst, 3597 &stream->dst, 3598 sizeof(struct rect)) != 0) 3599 return false; 3600 3601 return true; 3602 } 3603 3604 /* TODO: release audio object */ 3605 void update_audio_usage( 3606 struct resource_context *res_ctx, 3607 const struct resource_pool *pool, 3608 struct audio *audio, 3609 bool acquired) 3610 { 3611 int i; 3612 for (i = 0; i < pool->audio_count; i++) { 3613 if (pool->audios[i] == audio) 3614 res_ctx->is_audio_acquired[i] = acquired; 3615 } 3616 } 3617 3618 static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for_link( 3619 struct resource_context *res_ctx, 3620 const struct resource_pool *pool, 3621 struct dc_stream_state *stream) 3622 { 3623 (void)stream; 3624 int i; 3625 3626 for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { 3627 if (!res_ctx->is_hpo_dp_stream_enc_acquired[i] && 3628 pool->hpo_dp_stream_enc[i]) { 3629 3630 return pool->hpo_dp_stream_enc[i]; 3631 } 3632 } 3633 3634 return NULL; 3635 } 3636 3637 static struct audio *find_first_free_audio( 3638 struct resource_context *res_ctx, 3639 const struct resource_pool *pool, 3640 enum engine_id id, 3641 enum dce_version dc_version) 3642 { 3643 (void)dc_version; 3644 int i, available_audio_count; 3645 3646 if (id == ENGINE_ID_UNKNOWN) 3647 return NULL; 3648 3649 available_audio_count = pool->audio_count; 3650 3651 for (i = 0; i < available_audio_count; i++) { 3652 if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) { 3653 /*we have enough audio endpoint, find the matching inst*/ 3654 if (id != i) 3655 continue; 3656 return pool->audios[i]; 3657 } 3658 } 3659 3660 /* use engine id to find free audio */ 3661 if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false)) { 3662 return pool->audios[id]; 3663 } 3664 /*not found the matching one, first come first serve*/ 3665 for (i = 0; i < available_audio_count; i++) { 3666 if (res_ctx->is_audio_acquired[i] == false) { 3667 return pool->audios[i]; 3668 } 3669 } 3670 return NULL; 3671 } 3672 3673 static struct dc_stream_state *find_pll_sharable_stream( 3674 struct dc_stream_state *stream_needs_pll, 3675 struct dc_state *context) 3676 { 3677 int i; 3678 3679 for (i = 0; i < context->stream_count; i++) { 3680 struct dc_stream_state *stream_has_pll = context->streams[i]; 3681 3682 /* We are looking for non dp, non virtual stream */ 3683 if (resource_are_streams_timing_synchronizable( 3684 stream_needs_pll, stream_has_pll) 3685 && !dc_is_dp_signal(stream_has_pll->signal) 3686 && stream_has_pll->link->connector_signal 3687 != SIGNAL_TYPE_VIRTUAL) 3688 return stream_has_pll; 3689 3690 } 3691 3692 return NULL; 3693 } 3694 3695 static int get_norm_pix_clk(const struct dc_crtc_timing *timing) 3696 { 3697 uint32_t pix_clk = timing->pix_clk_100hz; 3698 uint32_t normalized_pix_clk = pix_clk; 3699 3700 if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) 3701 pix_clk /= 2; 3702 if (timing->pixel_encoding != PIXEL_ENCODING_YCBCR422) { 3703 switch (timing->display_color_depth) { 3704 case COLOR_DEPTH_666: 3705 case COLOR_DEPTH_888: 3706 normalized_pix_clk = pix_clk; 3707 break; 3708 case COLOR_DEPTH_101010: 3709 normalized_pix_clk = (pix_clk * 30) / 24; 3710 break; 3711 case COLOR_DEPTH_121212: 3712 normalized_pix_clk = (pix_clk * 36) / 24; 3713 break; 3714 case COLOR_DEPTH_141414: 3715 normalized_pix_clk = (pix_clk * 42) / 24; 3716 break; 3717 case COLOR_DEPTH_161616: 3718 normalized_pix_clk = (pix_clk * 48) / 24; 3719 break; 3720 default: 3721 ASSERT(0); 3722 break; 3723 } 3724 } 3725 return normalized_pix_clk; 3726 } 3727 3728 static void calculate_phy_pix_clks(struct dc_stream_state *stream) 3729 { 3730 /* update actual pixel clock on all streams */ 3731 if (dc_is_hdmi_signal(stream->signal)) 3732 stream->phy_pix_clk = get_norm_pix_clk( 3733 &stream->timing) / 10; 3734 else 3735 stream->phy_pix_clk = 3736 stream->timing.pix_clk_100hz / 10; 3737 3738 if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) 3739 stream->phy_pix_clk *= 2; 3740 } 3741 3742 static int acquire_resource_from_hw_enabled_state( 3743 struct resource_context *res_ctx, 3744 const struct resource_pool *pool, 3745 struct dc_stream_state *stream) 3746 { 3747 struct dc_link *link = stream->link; 3748 unsigned int i, inst, tg_inst = 0; 3749 uint32_t numPipes = 1; 3750 uint32_t id_src[4] = {0}; 3751 3752 /* Check for enabled DIG to identify enabled display */ 3753 if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) 3754 return -1; 3755 3756 inst = link->link_enc->funcs->get_dig_frontend(link->link_enc); 3757 3758 if (inst == ENGINE_ID_UNKNOWN) 3759 return -1; 3760 3761 for (i = 0; i < pool->stream_enc_count; i++) { 3762 if (pool->stream_enc[i]->id == inst) { 3763 tg_inst = pool->stream_enc[i]->funcs->dig_source_otg( 3764 pool->stream_enc[i]); 3765 break; 3766 } 3767 } 3768 3769 // tg_inst not found 3770 if (i == pool->stream_enc_count) 3771 return -1; 3772 3773 if (tg_inst >= pool->timing_generator_count) 3774 return -1; 3775 3776 if (!res_ctx->pipe_ctx[tg_inst].stream) { 3777 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst]; 3778 3779 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; 3780 id_src[0] = tg_inst; 3781 3782 if (pipe_ctx->stream_res.tg->funcs->get_optc_source) 3783 pipe_ctx->stream_res.tg->funcs->get_optc_source(pipe_ctx->stream_res.tg, 3784 &numPipes, &id_src[0], &id_src[1]); 3785 3786 if (id_src[0] == 0xf && id_src[1] == 0xf) { 3787 id_src[0] = tg_inst; 3788 numPipes = 1; 3789 } 3790 3791 for (i = 0; i < numPipes; i++) { 3792 //Check if src id invalid 3793 if (id_src[i] == 0xf) 3794 return -1; 3795 3796 pipe_ctx = &res_ctx->pipe_ctx[id_src[i]]; 3797 3798 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; 3799 pipe_ctx->plane_res.mi = pool->mis[id_src[i]]; 3800 pipe_ctx->plane_res.hubp = pool->hubps[id_src[i]]; 3801 pipe_ctx->plane_res.ipp = pool->ipps[id_src[i]]; 3802 pipe_ctx->plane_res.xfm = pool->transforms[id_src[i]]; 3803 pipe_ctx->plane_res.dpp = pool->dpps[id_src[i]]; 3804 pipe_ctx->stream_res.opp = pool->opps[id_src[i]]; 3805 3806 if (pool->dpps[id_src[i]]) { 3807 pipe_ctx->plane_res.mpcc_inst = pool->dpps[id_src[i]]->inst; 3808 3809 if (pool->mpc->funcs->read_mpcc_state) { 3810 struct mpcc_state s = {0}; 3811 3812 pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s); 3813 3814 if (s.dpp_id < MAX_MPCC) 3815 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id = 3816 s.dpp_id; 3817 3818 if (s.bot_mpcc_id < MAX_MPCC) 3819 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot = 3820 &pool->mpc->mpcc_array[s.bot_mpcc_id]; 3821 3822 if (s.opp_id < MAX_OPP) 3823 pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id; 3824 } 3825 } 3826 pipe_ctx->pipe_idx = id_src[i]; 3827 3828 if (id_src[i] >= pool->timing_generator_count) { 3829 id_src[i] = pool->timing_generator_count - 1; 3830 3831 pipe_ctx->stream_res.tg = pool->timing_generators[id_src[i]]; 3832 pipe_ctx->stream_res.opp = pool->opps[id_src[i]]; 3833 } 3834 3835 pipe_ctx->stream = stream; 3836 } 3837 3838 if (numPipes == 2) { 3839 stream->apply_boot_odm_mode = dm_odm_combine_policy_2to1; 3840 res_ctx->pipe_ctx[id_src[0]].next_odm_pipe = &res_ctx->pipe_ctx[id_src[1]]; 3841 res_ctx->pipe_ctx[id_src[0]].prev_odm_pipe = NULL; 3842 res_ctx->pipe_ctx[id_src[1]].next_odm_pipe = NULL; 3843 res_ctx->pipe_ctx[id_src[1]].prev_odm_pipe = &res_ctx->pipe_ctx[id_src[0]]; 3844 } else 3845 stream->apply_boot_odm_mode = dm_odm_combine_mode_disabled; 3846 3847 return id_src[0]; 3848 } 3849 3850 return -1; 3851 } 3852 3853 static void mark_seamless_boot_stream(const struct dc *dc, 3854 struct dc_stream_state *stream) 3855 { 3856 struct dc_bios *dcb = dc->ctx->dc_bios; 3857 3858 DC_LOGGER_INIT(dc->ctx->logger); 3859 3860 if (stream->apply_seamless_boot_optimization) 3861 return; 3862 if (!dc->config.allow_seamless_boot_optimization) 3863 return; 3864 if (dcb->funcs->is_accelerated_mode(dcb)) 3865 return; 3866 if (dc_validate_boot_timing(dc, stream->sink, &stream->timing)) { 3867 stream->apply_seamless_boot_optimization = true; 3868 DC_LOG_DC("Marked stream for seamless boot optimization\n"); 3869 } 3870 } 3871 3872 /* 3873 * Acquire a pipe as OTG master and assign to the stream in new dc context. 3874 * return - true if OTG master pipe is acquired and new dc context is updated. 3875 * false if it fails to acquire an OTG master pipe for this stream. 3876 * 3877 * In the example below, we acquired pipe 0 as OTG master pipe for the stream. 3878 * After the function its Inter-pipe Relation is represented by the diagram 3879 * below. 3880 * 3881 * Inter-pipe Relation 3882 * __________________________________________________ 3883 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | 3884 * | | | | | 3885 * | 0 | |blank ------------------ | 3886 * |________|_______________|___________|_____________| 3887 */ 3888 static bool acquire_otg_master_pipe_for_stream( 3889 const struct dc_state *cur_ctx, 3890 struct dc_state *new_ctx, 3891 const struct resource_pool *pool, 3892 struct dc_stream_state *stream) 3893 { 3894 /* TODO: Move this function to DCN specific resource file and acquire 3895 * DSC resource here. The reason is that the function should have the 3896 * same level of responsibility as when we acquire secondary OPP head. 3897 * We acquire DSC when we acquire secondary OPP head, so we should 3898 * acquire DSC when we acquire OTG master. 3899 */ 3900 int pipe_idx; 3901 struct pipe_ctx *pipe_ctx = NULL; 3902 3903 /* 3904 * Upper level code is responsible to optimize unnecessary addition and 3905 * removal for unchanged streams. So unchanged stream will keep the same 3906 * OTG master instance allocated. When current stream is removed and a 3907 * new stream is added, we want to reuse the OTG instance made available 3908 * by the removed stream first. If not found, we try to avoid of using 3909 * any free pipes already used in current context as this could tear 3910 * down exiting ODM/MPC/MPO configuration unnecessarily. 3911 */ 3912 3913 /* 3914 * Try to acquire the same OTG master already in use. This is not 3915 * optimal because resetting an enabled OTG master pipe for a new stream 3916 * requires an extra frame of wait. However there are test automation 3917 * and eDP assumptions that rely on reusing the same OTG master pipe 3918 * during mode change. We have to keep this logic as is for now. 3919 */ 3920 pipe_idx = recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx( 3921 &cur_ctx->res_ctx, &new_ctx->res_ctx, pool); 3922 /* 3923 * Try to acquire a pipe not used in current resource context to avoid 3924 * pipe swapping. 3925 */ 3926 if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) 3927 pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx( 3928 &cur_ctx->res_ctx, &new_ctx->res_ctx, pool); 3929 /* 3930 * If pipe swapping is unavoidable, try to acquire pipe used as 3931 * secondary DPP pipe in current state as we prioritize to support more 3932 * streams over supporting MPO planes. 3933 */ 3934 if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) 3935 pipe_idx = resource_find_free_pipe_used_as_cur_sec_dpp( 3936 &cur_ctx->res_ctx, &new_ctx->res_ctx, pool); 3937 if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) 3938 pipe_idx = resource_find_any_free_pipe(&new_ctx->res_ctx, pool); 3939 if (pipe_idx != FREE_PIPE_INDEX_NOT_FOUND) { 3940 pipe_ctx = &new_ctx->res_ctx.pipe_ctx[pipe_idx]; 3941 memset(pipe_ctx, 0, sizeof(*pipe_ctx)); 3942 pipe_ctx->pipe_idx = pipe_idx; 3943 pipe_ctx->stream_res.tg = pool->timing_generators[pipe_idx]; 3944 pipe_ctx->plane_res.mi = pool->mis[pipe_idx]; 3945 pipe_ctx->plane_res.hubp = pool->hubps[pipe_idx]; 3946 pipe_ctx->plane_res.ipp = pool->ipps[pipe_idx]; 3947 pipe_ctx->plane_res.xfm = pool->transforms[pipe_idx]; 3948 pipe_ctx->plane_res.dpp = pool->dpps[pipe_idx]; 3949 pipe_ctx->stream_res.opp = pool->opps[pipe_idx]; 3950 if (pool->dpps[pipe_idx]) 3951 pipe_ctx->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst; 3952 3953 if (pipe_idx >= pool->timing_generator_count && pool->timing_generator_count != 0) { 3954 int tg_inst = pool->timing_generator_count - 1; 3955 3956 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; 3957 pipe_ctx->stream_res.opp = pool->opps[tg_inst]; 3958 } 3959 3960 pipe_ctx->stream = stream; 3961 } else { 3962 pipe_idx = acquire_first_split_pipe(&new_ctx->res_ctx, pool, stream); 3963 } 3964 3965 return pipe_idx != FREE_PIPE_INDEX_NOT_FOUND; 3966 } 3967 3968 enum dc_status resource_map_pool_resources( 3969 const struct dc *dc, 3970 struct dc_state *context, 3971 struct dc_stream_state *stream) 3972 { 3973 const struct resource_pool *pool = dc->res_pool; 3974 int i; 3975 struct dc_context *dc_ctx = dc->ctx; 3976 struct pipe_ctx *pipe_ctx = NULL; 3977 int pipe_idx = -1; 3978 bool acquired = false; 3979 bool is_dio_encoder = true; 3980 3981 calculate_phy_pix_clks(stream); 3982 3983 mark_seamless_boot_stream(dc, stream); 3984 3985 if (stream->apply_seamless_boot_optimization) { 3986 pipe_idx = acquire_resource_from_hw_enabled_state( 3987 &context->res_ctx, 3988 pool, 3989 stream); 3990 if (pipe_idx < 0) 3991 /* hw resource was assigned to other stream */ 3992 stream->apply_seamless_boot_optimization = false; 3993 else 3994 acquired = true; 3995 } 3996 3997 if (!acquired) 3998 /* acquire new resources */ 3999 acquired = acquire_otg_master_pipe_for_stream(dc->current_state, 4000 context, pool, stream); 4001 4002 pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); 4003 4004 if (!pipe_ctx || pipe_ctx->stream_res.tg == NULL) 4005 return DC_NO_CONTROLLER_RESOURCE; 4006 4007 pipe_ctx->stream_res.stream_enc = 4008 dc->res_pool->funcs->find_first_free_match_stream_enc_for_link( 4009 &context->res_ctx, pool, stream); 4010 4011 if (!pipe_ctx->stream_res.stream_enc) 4012 return DC_NO_STREAM_ENC_RESOURCE; 4013 4014 update_stream_engine_usage( 4015 &context->res_ctx, pool, 4016 pipe_ctx->stream_res.stream_enc, 4017 true); 4018 4019 /* Allocate DP HPO Stream Encoder based on signal, hw capabilities 4020 * and link settings 4021 */ 4022 if (dc_is_dp_signal(stream->signal) || 4023 dc_is_virtual_signal(stream->signal)) { 4024 if (!dc->link_srv->dp_decide_link_settings(stream, 4025 &pipe_ctx->link_config.dp_link_settings)) 4026 return DC_FAIL_DP_LINK_BANDWIDTH; 4027 4028 dc->link_srv->dp_decide_tunnel_settings(stream, 4029 &pipe_ctx->link_config.dp_tunnel_settings); 4030 4031 if (dc->link_srv->dp_get_encoding_format( 4032 &pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) { 4033 pipe_ctx->stream_res.hpo_dp_stream_enc = 4034 find_first_free_match_hpo_dp_stream_enc_for_link( 4035 &context->res_ctx, pool, stream); 4036 4037 if (!pipe_ctx->stream_res.hpo_dp_stream_enc) 4038 return DC_NO_STREAM_ENC_RESOURCE; 4039 4040 update_hpo_dp_stream_engine_usage( 4041 &context->res_ctx, pool, 4042 pipe_ctx->stream_res.hpo_dp_stream_enc, 4043 true); 4044 if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, pool, pipe_ctx, stream)) 4045 return DC_NO_LINK_ENC_RESOURCE; 4046 } 4047 } 4048 4049 if (dc->config.unify_link_enc_assignment && is_dio_encoder) 4050 if (!add_dio_link_enc_to_ctx(dc, context, pool, pipe_ctx, stream)) 4051 return DC_NO_LINK_ENC_RESOURCE; 4052 4053 /* TODO: Add check if ASIC support and EDID audio */ 4054 if (!stream->converter_disable_audio && 4055 dc_is_audio_capable_signal(pipe_ctx->stream->signal) && 4056 stream->audio_info.mode_count && 4057 (stream->audio_info.flags.all || 4058 (stream->sink && stream->sink->edid_caps.panel_patch.skip_audio_sab_check))) { 4059 pipe_ctx->stream_res.audio = find_first_free_audio( 4060 &context->res_ctx, pool, pipe_ctx->stream_res.stream_enc->id, dc_ctx->dce_version); 4061 4062 /* 4063 * Audio assigned in order first come first get. 4064 * There are asics which has number of audio 4065 * resources less then number of pipes 4066 */ 4067 if (pipe_ctx->stream_res.audio) 4068 update_audio_usage(&context->res_ctx, pool, 4069 pipe_ctx->stream_res.audio, true); 4070 } 4071 4072 /* Add ABM to the resource if on EDP */ 4073 if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) { 4074 if (pool->abm) 4075 pipe_ctx->stream_res.abm = pool->abm; 4076 else 4077 pipe_ctx->stream_res.abm = pool->multiple_abms[pipe_ctx->stream_res.tg->inst]; 4078 } 4079 4080 for (i = 0; i < context->stream_count; i++) 4081 if (context->streams[i] == stream) { 4082 context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst; 4083 context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->stream_enc_inst; 4084 context->stream_status[i].audio_inst = 4085 pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1; 4086 4087 return DC_OK; 4088 } 4089 4090 DC_ERROR("Stream %p not found in new ctx!\n", stream); 4091 return DC_ERROR_UNEXPECTED; 4092 } 4093 4094 bool dc_resource_is_dsc_encoding_supported(const struct dc *dc) 4095 { 4096 if (dc->res_pool == NULL) 4097 return false; 4098 4099 return dc->res_pool->res_cap->num_dsc > 0; 4100 } 4101 4102 static bool planes_changed_for_existing_stream(struct dc_state *context, 4103 struct dc_stream_state *stream, 4104 const struct dc_validation_set set[], 4105 int set_count) 4106 { 4107 int i, j; 4108 struct dc_stream_status *stream_status = NULL; 4109 4110 for (i = 0; i < context->stream_count; i++) { 4111 if (context->streams[i] == stream) { 4112 stream_status = &context->stream_status[i]; 4113 break; 4114 } 4115 } 4116 4117 if (!stream_status) { 4118 ASSERT(0); 4119 return false; 4120 } 4121 4122 for (i = 0; i < set_count; i++) 4123 if (set[i].stream == stream) 4124 break; 4125 4126 if (i == set_count) 4127 ASSERT(0); 4128 4129 if (set[i].plane_count != stream_status->plane_count) 4130 return true; 4131 4132 for (j = 0; j < set[i].plane_count; j++) 4133 if (set[i].plane_states[j] != stream_status->plane_states[j]) 4134 return true; 4135 4136 return false; 4137 } 4138 4139 static bool add_all_planes_for_stream( 4140 const struct dc *dc, 4141 struct dc_stream_state *stream, 4142 const struct dc_validation_set set[], 4143 int set_count, 4144 struct dc_state *state) 4145 { 4146 int i, j; 4147 4148 for (i = 0; i < set_count; i++) 4149 if (set[i].stream == stream) 4150 break; 4151 4152 if (i == set_count) { 4153 dm_error("Stream %p not found in set!\n", stream); 4154 return false; 4155 } 4156 4157 for (j = 0; j < set[i].plane_count; j++) 4158 if (!dc_state_add_plane(dc, stream, set[i].plane_states[j], state)) 4159 return false; 4160 4161 return true; 4162 } 4163 4164 /** 4165 * dc_validate_with_context - Validate and update the potential new stream in the context object 4166 * 4167 * @dc: Used to get the current state status 4168 * @set: An array of dc_validation_set with all the current streams reference 4169 * @set_count: Total of streams 4170 * @context: New context 4171 * @validate_mode: identify the validation mode 4172 * 4173 * This function updates the potential new stream in the context object. It 4174 * creates multiple lists for the add, remove, and unchanged streams. In 4175 * particular, if the unchanged streams have a plane that changed, it is 4176 * necessary to remove all planes from the unchanged streams. In summary, this 4177 * function is responsible for validating the new context. 4178 * 4179 * Return: 4180 * In case of success, return DC_OK (1), otherwise, return a DC error. 4181 */ 4182 enum dc_status dc_validate_with_context(struct dc *dc, 4183 const struct dc_validation_set set[], 4184 int set_count, 4185 struct dc_state *context, 4186 enum dc_validate_mode validate_mode) 4187 { 4188 struct dc_stream_state *unchanged_streams[MAX_PIPES] = { 0 }; 4189 struct dc_stream_state *del_streams[MAX_PIPES] = { 0 }; 4190 struct dc_stream_state *add_streams[MAX_PIPES] = { 0 }; 4191 int old_stream_count = context->stream_count; 4192 enum dc_status res = DC_ERROR_UNEXPECTED; 4193 int unchanged_streams_count = 0; 4194 int del_streams_count = 0; 4195 int add_streams_count = 0; 4196 bool found = false; 4197 int i, j, k; 4198 4199 DC_LOGGER_INIT(dc->ctx->logger); 4200 4201 /* First build a list of streams to be remove from current context */ 4202 for (i = 0; i < old_stream_count; i++) { 4203 struct dc_stream_state *stream = context->streams[i]; 4204 4205 for (j = 0; j < set_count; j++) { 4206 if (stream == set[j].stream) { 4207 found = true; 4208 break; 4209 } 4210 } 4211 4212 if (!found) 4213 del_streams[del_streams_count++] = stream; 4214 4215 found = false; 4216 } 4217 4218 /* Second, build a list of new streams */ 4219 for (i = 0; i < set_count; i++) { 4220 struct dc_stream_state *stream = set[i].stream; 4221 4222 for (j = 0; j < old_stream_count; j++) { 4223 if (stream == context->streams[j]) { 4224 found = true; 4225 break; 4226 } 4227 } 4228 4229 if (!found) 4230 add_streams[add_streams_count++] = stream; 4231 4232 found = false; 4233 } 4234 4235 /* Build a list of unchanged streams which is necessary for handling 4236 * planes change such as added, removed, and updated. 4237 */ 4238 for (i = 0; i < set_count; i++) { 4239 /* Check if stream is part of the delete list */ 4240 for (j = 0; j < del_streams_count; j++) { 4241 if (set[i].stream == del_streams[j]) { 4242 found = true; 4243 break; 4244 } 4245 } 4246 4247 if (!found) { 4248 /* Check if stream is part of the add list */ 4249 for (j = 0; j < add_streams_count; j++) { 4250 if (set[i].stream == add_streams[j]) { 4251 found = true; 4252 break; 4253 } 4254 } 4255 } 4256 4257 if (!found) 4258 unchanged_streams[unchanged_streams_count++] = set[i].stream; 4259 4260 found = false; 4261 } 4262 4263 /* Remove all planes for unchanged streams if planes changed */ 4264 for (i = 0; i < unchanged_streams_count; i++) { 4265 if (planes_changed_for_existing_stream(context, 4266 unchanged_streams[i], 4267 set, 4268 set_count)) { 4269 4270 if (!dc_state_rem_all_planes_for_stream(dc, 4271 unchanged_streams[i], 4272 context)) { 4273 res = DC_FAIL_DETACH_SURFACES; 4274 goto fail; 4275 } 4276 } 4277 } 4278 4279 /* Remove all planes for removed streams and then remove the streams */ 4280 for (i = 0; i < del_streams_count; i++) { 4281 /* Need to cpy the dwb data from the old stream in order to efc to work */ 4282 if (del_streams[i]->num_wb_info > 0) { 4283 for (j = 0; j < add_streams_count; j++) { 4284 if (del_streams[i]->sink == add_streams[j]->sink) { 4285 add_streams[j]->num_wb_info = del_streams[i]->num_wb_info; 4286 for (k = 0; k < del_streams[i]->num_wb_info; k++) 4287 add_streams[j]->writeback_info[k] = del_streams[i]->writeback_info[k]; 4288 } 4289 } 4290 } 4291 4292 if (dc_state_get_stream_subvp_type(context, del_streams[i]) == SUBVP_PHANTOM) { 4293 /* remove phantoms specifically */ 4294 if (!dc_state_rem_all_phantom_planes_for_stream(dc, del_streams[i], context, true)) { 4295 res = DC_FAIL_DETACH_SURFACES; 4296 goto fail; 4297 } 4298 4299 res = dc_state_remove_phantom_stream(dc, context, del_streams[i]); 4300 dc_state_release_phantom_stream(dc, context, del_streams[i]); 4301 } else { 4302 if (!dc_state_rem_all_planes_for_stream(dc, del_streams[i], context)) { 4303 res = DC_FAIL_DETACH_SURFACES; 4304 goto fail; 4305 } 4306 4307 res = dc_state_remove_stream(dc, context, del_streams[i]); 4308 } 4309 4310 if (res != DC_OK) 4311 goto fail; 4312 } 4313 4314 /* Swap seamless boot stream to pipe 0 (if needed) to ensure pipe_ctx 4315 * matches. This may change in the future if seamless_boot_stream can be 4316 * multiple. 4317 */ 4318 for (i = 0; i < add_streams_count; i++) { 4319 mark_seamless_boot_stream(dc, add_streams[i]); 4320 if (add_streams[i]->apply_seamless_boot_optimization && i != 0) { 4321 struct dc_stream_state *temp = add_streams[0]; 4322 4323 add_streams[0] = add_streams[i]; 4324 add_streams[i] = temp; 4325 break; 4326 } 4327 } 4328 4329 /* Add new streams and then add all planes for the new stream */ 4330 for (i = 0; i < add_streams_count; i++) { 4331 calculate_phy_pix_clks(add_streams[i]); 4332 res = dc_state_add_stream(dc, context, add_streams[i]); 4333 if (res != DC_OK) 4334 goto fail; 4335 4336 if (!add_all_planes_for_stream(dc, add_streams[i], set, set_count, context)) { 4337 res = DC_FAIL_ATTACH_SURFACES; 4338 goto fail; 4339 } 4340 } 4341 4342 /* Add all planes for unchanged streams if planes changed */ 4343 for (i = 0; i < unchanged_streams_count; i++) { 4344 if (planes_changed_for_existing_stream(context, 4345 unchanged_streams[i], 4346 set, 4347 set_count)) { 4348 if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, set_count, context)) { 4349 res = DC_FAIL_ATTACH_SURFACES; 4350 goto fail; 4351 } 4352 } 4353 } 4354 4355 /* clear subvp cursor limitations */ 4356 for (i = 0; i < context->stream_count; i++) { 4357 dc_state_set_stream_subvp_cursor_limit(context->streams[i], context, false); 4358 } 4359 4360 res = dc_validate_global_state(dc, context, validate_mode); 4361 4362 /* calculate pixel rate divider after deciding pxiel clock & odm combine */ 4363 if ((dc->hwss.calculate_pix_rate_divider) && (res == DC_OK)) { 4364 for (i = 0; i < add_streams_count; i++) 4365 dc->hwss.calculate_pix_rate_divider(dc, context, add_streams[i]); 4366 } 4367 4368 fail: 4369 if (res != DC_OK) 4370 DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n", 4371 __func__, 4372 res); 4373 4374 return res; 4375 } 4376 4377 #if defined(CONFIG_DRM_AMD_DC_FP) 4378 #endif /* CONFIG_DRM_AMD_DC_FP */ 4379 4380 /** 4381 * calculate_timing_params_for_dsc_with_padding - Calculates timing parameters for DSC with padding. 4382 * @pipe_ctx: Pointer to the pipe context structure. 4383 * 4384 * This function calculates the timing parameters for a given pipe context based on the 4385 * display stream compression (DSC) configuration. If the horizontal active pixels (hactive) are less 4386 * than the total width of the DSC slices, it sets the dsc_hactive_padding value to the difference. If the 4387 * total horizontal timing minus the dsc_hactive_padding value is less than 32, it resets the dsc_hactive_padding 4388 * value to 0. 4389 */ 4390 static void calculate_timing_params_for_dsc_with_padding(struct pipe_ctx *pipe_ctx) 4391 { 4392 struct dc_stream_state *stream = NULL; 4393 4394 if (!pipe_ctx) 4395 return; 4396 4397 stream = pipe_ctx->stream; 4398 pipe_ctx->dsc_padding_params.dsc_hactive_padding = 0; 4399 pipe_ctx->dsc_padding_params.dsc_htotal_padding = 0; 4400 4401 if (stream) 4402 pipe_ctx->dsc_padding_params.dsc_pix_clk_100hz = stream->timing.pix_clk_100hz; 4403 4404 } 4405 4406 /** 4407 * dc_validate_global_state() - Determine if hardware can support a given state 4408 * 4409 * @dc: dc struct for this driver 4410 * @new_ctx: state to be validated 4411 * @validate_mode: identify the validation mode 4412 * 4413 * Checks hardware resource availability and bandwidth requirement. 4414 * 4415 * Return: 4416 * DC_OK if the result can be programmed. Otherwise, an error code. 4417 */ 4418 enum dc_status dc_validate_global_state( 4419 struct dc *dc, 4420 struct dc_state *new_ctx, 4421 enum dc_validate_mode validate_mode) 4422 { 4423 enum dc_status result = DC_ERROR_UNEXPECTED; 4424 int i, j; 4425 4426 if (!new_ctx) 4427 return DC_ERROR_UNEXPECTED; 4428 4429 if (dc->res_pool->funcs->validate_global) { 4430 result = dc->res_pool->funcs->validate_global(dc, new_ctx); 4431 if (result != DC_OK) 4432 return result; 4433 } 4434 4435 for (i = 0; i < new_ctx->stream_count; i++) { 4436 struct dc_stream_state *stream = new_ctx->streams[i]; 4437 4438 for (j = 0; j < dc->res_pool->pipe_count; j++) { 4439 struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[j]; 4440 4441 if (pipe_ctx->stream != stream) 4442 continue; 4443 4444 /* Decide whether hblank borrow is needed and save it in pipe_ctx */ 4445 if (dc->debug.enable_hblank_borrow) 4446 calculate_timing_params_for_dsc_with_padding(pipe_ctx); 4447 4448 if (dc->res_pool->funcs->patch_unknown_plane_state && 4449 pipe_ctx->plane_state && 4450 pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) { 4451 result = dc->res_pool->funcs->patch_unknown_plane_state(pipe_ctx->plane_state); 4452 if (result != DC_OK) 4453 return result; 4454 } 4455 4456 /* Switch to dp clock source only if there is 4457 * no non dp stream that shares the same timing 4458 * with the dp stream. 4459 */ 4460 if (dc_is_dp_signal(pipe_ctx->stream->signal) && 4461 !find_pll_sharable_stream(stream, new_ctx)) { 4462 4463 resource_unreference_clock_source( 4464 &new_ctx->res_ctx, 4465 dc->res_pool, 4466 pipe_ctx->clock_source); 4467 4468 pipe_ctx->clock_source = dc->res_pool->dp_clock_source; 4469 resource_reference_clock_source( 4470 &new_ctx->res_ctx, 4471 dc->res_pool, 4472 pipe_ctx->clock_source); 4473 } 4474 } 4475 } 4476 4477 result = resource_build_scaling_params_for_context(dc, new_ctx); 4478 4479 if (result == DC_OK) 4480 result = dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, validate_mode); 4481 4482 return result; 4483 } 4484 4485 static void patch_gamut_packet_checksum( 4486 struct dc_info_packet *gamut_packet) 4487 { 4488 /* For gamut we recalc checksum */ 4489 if (gamut_packet->valid) { 4490 uint8_t chk_sum = 0; 4491 uint8_t *ptr; 4492 uint8_t i; 4493 4494 /*start of the Gamut data. */ 4495 ptr = &gamut_packet->sb[3]; 4496 4497 for (i = 0; i <= gamut_packet->sb[1]; i++) 4498 chk_sum += ptr[i]; 4499 4500 gamut_packet->sb[2] = (uint8_t) (0x100 - chk_sum); 4501 } 4502 } 4503 4504 static void set_avi_info_frame( 4505 struct dc_info_packet *info_packet, 4506 struct pipe_ctx *pipe_ctx) 4507 { 4508 struct dc_stream_state *stream = pipe_ctx->stream; 4509 enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; 4510 uint32_t pixel_encoding = 0; 4511 enum scanning_type scan_type = SCANNING_TYPE_NODATA; 4512 enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA; 4513 uint8_t *check_sum = NULL; 4514 uint8_t byte_index = 0; 4515 union hdmi_info_packet hdmi_info; 4516 unsigned int vic = pipe_ctx->stream->timing.vic; 4517 unsigned int rid = pipe_ctx->stream->timing.rid; 4518 unsigned int fr_ind = pipe_ctx->stream->timing.fr_index; 4519 enum dc_timing_3d_format format; 4520 4521 if (stream->avi_infopacket.valid) { 4522 *info_packet = stream->avi_infopacket; 4523 return; 4524 } 4525 4526 memset(&hdmi_info, 0, sizeof(union hdmi_info_packet)); 4527 4528 4529 color_space = pipe_ctx->stream->output_color_space; 4530 if (color_space == COLOR_SPACE_UNKNOWN) 4531 color_space = (stream->timing.pixel_encoding == PIXEL_ENCODING_RGB) ? 4532 COLOR_SPACE_SRGB:COLOR_SPACE_YCBCR709; 4533 4534 /* Initialize header */ 4535 hdmi_info.bits.header.info_frame_type = HDMI_INFOFRAME_TYPE_AVI; 4536 /* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall 4537 * not be used in HDMI 2.0 (Section 10.1) */ 4538 hdmi_info.bits.header.version = 2; 4539 hdmi_info.bits.header.length = HDMI_AVI_INFOFRAME_SIZE; 4540 4541 /* 4542 * IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built 4543 * according to HDMI 2.0 spec (Section 10.1) 4544 */ 4545 4546 switch (stream->timing.pixel_encoding) { 4547 case PIXEL_ENCODING_YCBCR422: 4548 pixel_encoding = 1; 4549 break; 4550 4551 case PIXEL_ENCODING_YCBCR444: 4552 pixel_encoding = 2; 4553 break; 4554 case PIXEL_ENCODING_YCBCR420: 4555 pixel_encoding = 3; 4556 break; 4557 4558 case PIXEL_ENCODING_RGB: 4559 default: 4560 pixel_encoding = 0; 4561 } 4562 4563 /* Y0_Y1_Y2 : The pixel encoding */ 4564 /* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */ 4565 hdmi_info.bits.Y0_Y1_Y2 = pixel_encoding; 4566 4567 /* A0 = 1 Active Format Information valid */ 4568 hdmi_info.bits.A0 = ACTIVE_FORMAT_VALID; 4569 4570 /* B0, B1 = 3; Bar info data is valid */ 4571 hdmi_info.bits.B0_B1 = BAR_INFO_BOTH_VALID; 4572 4573 hdmi_info.bits.SC0_SC1 = PICTURE_SCALING_UNIFORM; 4574 4575 /* S0, S1 : Underscan / Overscan */ 4576 /* TODO: un-hardcode scan type */ 4577 scan_type = SCANNING_TYPE_UNDERSCAN; 4578 hdmi_info.bits.S0_S1 = scan_type; 4579 4580 /* C0, C1 : Colorimetry */ 4581 switch (color_space) { 4582 case COLOR_SPACE_YCBCR709: 4583 case COLOR_SPACE_YCBCR709_LIMITED: 4584 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709; 4585 break; 4586 case COLOR_SPACE_YCBCR601: 4587 case COLOR_SPACE_YCBCR601_LIMITED: 4588 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU601; 4589 break; 4590 case COLOR_SPACE_2020_RGB_FULLRANGE: 4591 case COLOR_SPACE_2020_RGB_LIMITEDRANGE: 4592 case COLOR_SPACE_2020_YCBCR_LIMITED: 4593 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR; 4594 hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; 4595 break; 4596 case COLOR_SPACE_ADOBERGB: 4597 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB; 4598 hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; 4599 break; 4600 case COLOR_SPACE_SRGB: 4601 default: 4602 hdmi_info.bits.C0_C1 = COLORIMETRY_NO_DATA; 4603 break; 4604 } 4605 4606 if (pixel_encoding && color_space == COLOR_SPACE_2020_YCBCR_LIMITED && 4607 stream->out_transfer_func.tf == TRANSFER_FUNCTION_GAMMA22) { 4608 hdmi_info.bits.EC0_EC2 = 0; 4609 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709; 4610 } 4611 4612 /* TODO: un-hardcode aspect ratio */ 4613 aspect = stream->timing.aspect_ratio; 4614 4615 switch (aspect) { 4616 case ASPECT_RATIO_4_3: 4617 case ASPECT_RATIO_16_9: 4618 hdmi_info.bits.M0_M1 = aspect; 4619 break; 4620 4621 case ASPECT_RATIO_NO_DATA: 4622 case ASPECT_RATIO_64_27: 4623 case ASPECT_RATIO_256_135: 4624 default: 4625 hdmi_info.bits.M0_M1 = 0; 4626 } 4627 4628 /* Active Format Aspect ratio - same as Picture Aspect Ratio. */ 4629 hdmi_info.bits.R0_R3 = ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE; 4630 4631 switch (stream->content_type) { 4632 case DISPLAY_CONTENT_TYPE_NO_DATA: 4633 hdmi_info.bits.CN0_CN1 = 0; 4634 hdmi_info.bits.ITC = 1; 4635 break; 4636 case DISPLAY_CONTENT_TYPE_GRAPHICS: 4637 hdmi_info.bits.CN0_CN1 = 0; 4638 hdmi_info.bits.ITC = 1; 4639 break; 4640 case DISPLAY_CONTENT_TYPE_PHOTO: 4641 hdmi_info.bits.CN0_CN1 = 1; 4642 hdmi_info.bits.ITC = 1; 4643 break; 4644 case DISPLAY_CONTENT_TYPE_CINEMA: 4645 hdmi_info.bits.CN0_CN1 = 2; 4646 hdmi_info.bits.ITC = 1; 4647 break; 4648 case DISPLAY_CONTENT_TYPE_GAME: 4649 hdmi_info.bits.CN0_CN1 = 3; 4650 hdmi_info.bits.ITC = 1; 4651 break; 4652 } 4653 4654 if (stream->qs_bit == 1) { 4655 if (color_space == COLOR_SPACE_SRGB || 4656 color_space == COLOR_SPACE_2020_RGB_FULLRANGE) 4657 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_FULL_RANGE; 4658 else if (color_space == COLOR_SPACE_SRGB_LIMITED || 4659 color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE) 4660 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_LIMITED_RANGE; 4661 else 4662 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE; 4663 } else 4664 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE; 4665 4666 /* TODO : We should handle YCC quantization */ 4667 /* but we do not have matrix calculation */ 4668 hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE; 4669 4670 ///VIC 4671 if (pipe_ctx->stream->timing.hdmi_vic != 0) 4672 vic = 0; 4673 format = stream->timing.timing_3d_format; 4674 /*todo, add 3DStereo support*/ 4675 if (format != TIMING_3D_FORMAT_NONE) { 4676 // Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled 4677 switch (pipe_ctx->stream->timing.hdmi_vic) { 4678 case 1: 4679 vic = 95; 4680 break; 4681 case 2: 4682 vic = 94; 4683 break; 4684 case 3: 4685 vic = 93; 4686 break; 4687 case 4: 4688 vic = 98; 4689 break; 4690 default: 4691 break; 4692 } 4693 } 4694 /* If VIC >= 128, the Source shall use AVI InfoFrame Version 3*/ 4695 hdmi_info.bits.VIC0_VIC7 = vic; 4696 if (vic >= 128) 4697 hdmi_info.bits.header.version = 3; 4698 /* If (C1, C0)=(1, 1) and (EC2, EC1, EC0)=(1, 1, 1), 4699 * the Source shall use 20 AVI InfoFrame Version 4 4700 */ 4701 if (hdmi_info.bits.C0_C1 == COLORIMETRY_EXTENDED && 4702 hdmi_info.bits.EC0_EC2 == COLORIMETRYEX_RESERVED) { 4703 hdmi_info.bits.header.version = 4; 4704 hdmi_info.bits.header.length = 14; 4705 } 4706 4707 if (rid != 0 && fr_ind != 0) { 4708 hdmi_info.bits.header.version = 4; 4709 hdmi_info.bits.header.length = 15; 4710 4711 hdmi_info.bits.FR0_FR3 = fr_ind & 0xF; 4712 hdmi_info.bits.FR4 = (fr_ind >> 4) & 0x1; 4713 hdmi_info.bits.RID0_RID5 = rid; 4714 } 4715 4716 /* pixel repetition 4717 * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel 4718 * repetition start from 1 */ 4719 hdmi_info.bits.PR0_PR3 = 0; 4720 4721 /* Bar Info 4722 * barTop: Line Number of End of Top Bar. 4723 * barBottom: Line Number of Start of Bottom Bar. 4724 * barLeft: Pixel Number of End of Left Bar. 4725 * barRight: Pixel Number of Start of Right Bar. */ 4726 hdmi_info.bits.bar_top = stream->timing.v_border_top; 4727 hdmi_info.bits.bar_bottom = (stream->timing.v_total 4728 - stream->timing.v_border_bottom + 1); 4729 hdmi_info.bits.bar_left = stream->timing.h_border_left; 4730 hdmi_info.bits.bar_right = (stream->timing.h_total 4731 - stream->timing.h_border_right + 1); 4732 4733 /* Additional Colorimetry Extension 4734 * Used in conduction with C0-C1 and EC0-EC2 4735 * 0 = DCI-P3 RGB (D65) 4736 * 1 = DCI-P3 RGB (theater) 4737 */ 4738 hdmi_info.bits.ACE0_ACE3 = 0; 4739 4740 /* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */ 4741 check_sum = &hdmi_info.packet_raw_data.sb[0]; 4742 4743 *check_sum = HDMI_INFOFRAME_TYPE_AVI + hdmi_info.bits.header.length + hdmi_info.bits.header.version; 4744 4745 for (byte_index = 1; byte_index <= hdmi_info.bits.header.length; byte_index++) 4746 *check_sum += hdmi_info.packet_raw_data.sb[byte_index]; 4747 4748 /* one byte complement */ 4749 *check_sum = (uint8_t) (0x100 - *check_sum); 4750 4751 /* Store in hw_path_mode */ 4752 info_packet->hb0 = hdmi_info.packet_raw_data.hb0; 4753 info_packet->hb1 = hdmi_info.packet_raw_data.hb1; 4754 info_packet->hb2 = hdmi_info.packet_raw_data.hb2; 4755 4756 for (byte_index = 0; byte_index < sizeof(hdmi_info.packet_raw_data.sb); byte_index++) 4757 info_packet->sb[byte_index] = hdmi_info.packet_raw_data.sb[byte_index]; 4758 4759 info_packet->valid = true; 4760 } 4761 4762 static void set_vendor_info_packet( 4763 struct dc_info_packet *info_packet, 4764 struct dc_stream_state *stream) 4765 { 4766 /* SPD info packet for FreeSync */ 4767 4768 /* Check if Freesync is supported. Return if false. If true, 4769 * set the corresponding bit in the info packet 4770 */ 4771 if (!stream->vsp_infopacket.valid) 4772 return; 4773 4774 *info_packet = stream->vsp_infopacket; 4775 } 4776 4777 static void set_spd_info_packet( 4778 struct dc_info_packet *info_packet, 4779 struct dc_stream_state *stream) 4780 { 4781 /* SPD info packet for FreeSync */ 4782 4783 /* Check if Freesync is supported. Return if false. If true, 4784 * set the corresponding bit in the info packet 4785 */ 4786 if (!stream->vrr_infopacket.valid) 4787 return; 4788 4789 *info_packet = stream->vrr_infopacket; 4790 } 4791 4792 static void set_hdr_static_info_packet( 4793 struct dc_info_packet *info_packet, 4794 struct dc_stream_state *stream) 4795 { 4796 /* HDR Static Metadata info packet for HDR10 */ 4797 4798 if (!stream->hdr_static_metadata.valid || 4799 stream->use_dynamic_meta) 4800 return; 4801 4802 *info_packet = stream->hdr_static_metadata; 4803 } 4804 4805 static void set_vsc_info_packet( 4806 struct dc_info_packet *info_packet, 4807 struct dc_stream_state *stream) 4808 { 4809 if (!stream->vsc_infopacket.valid) 4810 return; 4811 4812 *info_packet = stream->vsc_infopacket; 4813 } 4814 static void set_hfvs_info_packet( 4815 struct dc_info_packet *info_packet, 4816 struct dc_stream_state *stream) 4817 { 4818 if (!stream->hfvsif_infopacket.valid) 4819 return; 4820 4821 *info_packet = stream->hfvsif_infopacket; 4822 } 4823 4824 static void adaptive_sync_override_dp_info_packets_sdp_line_num( 4825 const struct dc_crtc_timing *timing, 4826 struct enc_sdp_line_num *sdp_line_num, 4827 unsigned int vstartup_start) 4828 { 4829 uint32_t asic_blank_start = 0; 4830 uint32_t asic_blank_end = 0; 4831 uint32_t v_update = 0; 4832 4833 const struct dc_crtc_timing *tg = timing; 4834 4835 /* blank_start = frame end - front porch */ 4836 asic_blank_start = tg->v_total - tg->v_front_porch; 4837 4838 /* blank_end = blank_start - active */ 4839 asic_blank_end = (asic_blank_start - tg->v_border_bottom - 4840 tg->v_addressable - tg->v_border_top); 4841 4842 if (vstartup_start > asic_blank_end) { 4843 v_update = (tg->v_total - (vstartup_start - asic_blank_end)); 4844 sdp_line_num->adaptive_sync_line_num_valid = true; 4845 sdp_line_num->adaptive_sync_line_num = (tg->v_total - v_update - 1); 4846 } else { 4847 sdp_line_num->adaptive_sync_line_num_valid = false; 4848 sdp_line_num->adaptive_sync_line_num = 0; 4849 } 4850 } 4851 4852 static void set_adaptive_sync_info_packet( 4853 struct dc_info_packet *info_packet, 4854 const struct dc_stream_state *stream, 4855 struct encoder_info_frame *info_frame, 4856 unsigned int vstartup_start) 4857 { 4858 if (!stream->adaptive_sync_infopacket.valid) 4859 return; 4860 4861 adaptive_sync_override_dp_info_packets_sdp_line_num( 4862 &stream->timing, 4863 &info_frame->sdp_line_num, 4864 vstartup_start); 4865 4866 *info_packet = stream->adaptive_sync_infopacket; 4867 } 4868 4869 static void set_vtem_info_packet( 4870 struct dc_info_packet *info_packet, 4871 struct dc_stream_state *stream) 4872 { 4873 if (!stream->vtem_infopacket.valid) 4874 return; 4875 4876 *info_packet = stream->vtem_infopacket; 4877 } 4878 4879 struct clock_source *dc_resource_find_first_free_pll( 4880 struct resource_context *res_ctx, 4881 const struct resource_pool *pool) 4882 { 4883 int i; 4884 4885 for (i = 0; i < pool->clk_src_count; ++i) { 4886 if (res_ctx->clock_source_ref_count[i] == 0) 4887 return pool->clock_sources[i]; 4888 } 4889 4890 return NULL; 4891 } 4892 4893 void resource_build_info_frame(struct pipe_ctx *pipe_ctx) 4894 { 4895 enum signal_type signal = SIGNAL_TYPE_NONE; 4896 struct encoder_info_frame *info = &pipe_ctx->stream_res.encoder_info_frame; 4897 unsigned int vstartup_start = 0; 4898 4899 /* default all packets to invalid */ 4900 info->avi.valid = false; 4901 info->gamut.valid = false; 4902 info->vendor.valid = false; 4903 info->spd.valid = false; 4904 info->hdrsmd.valid = false; 4905 info->vsc.valid = false; 4906 info->hfvsif.valid = false; 4907 info->vtem.valid = false; 4908 info->adaptive_sync.valid = false; 4909 signal = pipe_ctx->stream->signal; 4910 4911 if (pipe_ctx->stream->ctx->dc->res_pool->funcs->get_vstartup_for_pipe) 4912 vstartup_start = pipe_ctx->stream->ctx->dc->res_pool->funcs->get_vstartup_for_pipe(pipe_ctx); 4913 4914 /* HDMi and DP have different info packets*/ 4915 if (dc_is_hdmi_signal(signal)) { 4916 set_avi_info_frame(&info->avi, pipe_ctx); 4917 4918 set_vendor_info_packet(&info->vendor, pipe_ctx->stream); 4919 set_hfvs_info_packet(&info->hfvsif, pipe_ctx->stream); 4920 set_vtem_info_packet(&info->vtem, pipe_ctx->stream); 4921 4922 set_spd_info_packet(&info->spd, pipe_ctx->stream); 4923 4924 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream); 4925 4926 } else if (dc_is_dp_signal(signal)) { 4927 set_vsc_info_packet(&info->vsc, pipe_ctx->stream); 4928 4929 set_spd_info_packet(&info->spd, pipe_ctx->stream); 4930 4931 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream); 4932 set_adaptive_sync_info_packet(&info->adaptive_sync, 4933 pipe_ctx->stream, 4934 info, 4935 vstartup_start); 4936 } 4937 4938 patch_gamut_packet_checksum(&info->gamut); 4939 } 4940 4941 enum dc_status resource_map_clock_resources( 4942 const struct dc *dc, 4943 struct dc_state *context, 4944 struct dc_stream_state *stream) 4945 { 4946 /* acquire new resources */ 4947 const struct resource_pool *pool = dc->res_pool; 4948 struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream( 4949 &context->res_ctx, stream); 4950 4951 if (!pipe_ctx) 4952 return DC_ERROR_UNEXPECTED; 4953 4954 if (dc_is_dp_signal(pipe_ctx->stream->signal) 4955 || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL) 4956 pipe_ctx->clock_source = pool->dp_clock_source; 4957 else { 4958 pipe_ctx->clock_source = NULL; 4959 4960 if (!dc->config.disable_disp_pll_sharing) 4961 pipe_ctx->clock_source = resource_find_used_clk_src_for_sharing( 4962 &context->res_ctx, 4963 pipe_ctx); 4964 4965 if (pipe_ctx->clock_source == NULL) 4966 pipe_ctx->clock_source = 4967 dc_resource_find_first_free_pll( 4968 &context->res_ctx, 4969 pool); 4970 } 4971 4972 if (pipe_ctx->clock_source == NULL) 4973 return DC_NO_CLOCK_SOURCE_RESOURCE; 4974 4975 resource_reference_clock_source( 4976 &context->res_ctx, pool, 4977 pipe_ctx->clock_source); 4978 4979 return DC_OK; 4980 } 4981 4982 /* 4983 * Note: We need to disable output if clock sources change, 4984 * since bios does optimization and doesn't apply if changing 4985 * PHY when not already disabled. 4986 */ 4987 bool pipe_need_reprogram( 4988 struct pipe_ctx *pipe_ctx_old, 4989 struct pipe_ctx *pipe_ctx) 4990 { 4991 if (!pipe_ctx_old->stream) 4992 return false; 4993 4994 if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink) 4995 return true; 4996 4997 if (pipe_ctx_old->stream->signal != pipe_ctx->stream->signal) 4998 return true; 4999 5000 if (pipe_ctx_old->stream_res.audio != pipe_ctx->stream_res.audio) 5001 return true; 5002 5003 if (pipe_ctx_old->clock_source != pipe_ctx->clock_source 5004 && pipe_ctx_old->stream != pipe_ctx->stream) 5005 return true; 5006 5007 if (pipe_ctx_old->stream_res.stream_enc != pipe_ctx->stream_res.stream_enc) 5008 return true; 5009 5010 if (dc_is_timing_changed(pipe_ctx_old->stream, pipe_ctx->stream)) 5011 return true; 5012 5013 if (pipe_ctx_old->stream->dpms_off != pipe_ctx->stream->dpms_off) 5014 return true; 5015 5016 if (false == pipe_ctx_old->stream->link->link_state_valid && 5017 false == pipe_ctx_old->stream->dpms_off) 5018 return true; 5019 5020 if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc) 5021 return true; 5022 5023 if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc) 5024 return true; 5025 if (pipe_ctx_old->link_res.hpo_dp_link_enc != pipe_ctx->link_res.hpo_dp_link_enc) 5026 return true; 5027 5028 /* DIG link encoder resource assignment for stream changed. */ 5029 if (pipe_ctx_old->stream->ctx->dc->config.unify_link_enc_assignment) { 5030 if (pipe_ctx_old->link_res.dio_link_enc != pipe_ctx->link_res.dio_link_enc) 5031 return true; 5032 } else if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) { 5033 bool need_reprogram = false; 5034 struct dc *dc = pipe_ctx_old->stream->ctx->dc; 5035 struct link_encoder *link_enc_prev = 5036 link_enc_cfg_get_link_enc_used_by_stream_current(dc, pipe_ctx_old->stream); 5037 5038 if (link_enc_prev != pipe_ctx->stream->link_enc) 5039 need_reprogram = true; 5040 5041 return need_reprogram; 5042 } 5043 5044 return false; 5045 } 5046 5047 void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream, 5048 struct bit_depth_reduction_params *fmt_bit_depth) 5049 { 5050 enum dc_dither_option option = stream->dither_option; 5051 enum dc_pixel_encoding pixel_encoding = 5052 stream->timing.pixel_encoding; 5053 5054 memset(fmt_bit_depth, 0, sizeof(*fmt_bit_depth)); 5055 5056 if (option == DITHER_OPTION_DEFAULT) { 5057 switch (stream->timing.display_color_depth) { 5058 case COLOR_DEPTH_666: 5059 option = DITHER_OPTION_SPATIAL6; 5060 break; 5061 case COLOR_DEPTH_888: 5062 option = DITHER_OPTION_SPATIAL8; 5063 break; 5064 case COLOR_DEPTH_101010: 5065 option = DITHER_OPTION_TRUN10; 5066 break; 5067 default: 5068 option = DITHER_OPTION_DISABLE; 5069 } 5070 } 5071 5072 if (option == DITHER_OPTION_DISABLE) 5073 return; 5074 5075 if (option == DITHER_OPTION_TRUN6) { 5076 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; 5077 fmt_bit_depth->flags.TRUNCATE_DEPTH = 0; 5078 } else if (option == DITHER_OPTION_TRUN8 || 5079 option == DITHER_OPTION_TRUN8_SPATIAL6 || 5080 option == DITHER_OPTION_TRUN8_FM6) { 5081 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; 5082 fmt_bit_depth->flags.TRUNCATE_DEPTH = 1; 5083 } else if (option == DITHER_OPTION_TRUN10 || 5084 option == DITHER_OPTION_TRUN10_SPATIAL6 || 5085 option == DITHER_OPTION_TRUN10_SPATIAL8 || 5086 option == DITHER_OPTION_TRUN10_FM8 || 5087 option == DITHER_OPTION_TRUN10_FM6 || 5088 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { 5089 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; 5090 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2; 5091 if (option == DITHER_OPTION_TRUN10) 5092 fmt_bit_depth->flags.TRUNCATE_MODE = 1; 5093 } 5094 5095 /* special case - Formatter can only reduce by 4 bits at most. 5096 * When reducing from 12 to 6 bits, 5097 * HW recommends we use trunc with round mode 5098 * (if we did nothing, trunc to 10 bits would be used) 5099 * note that any 12->10 bit reduction is ignored prior to DCE8, 5100 * as the input was 10 bits. 5101 */ 5102 if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM || 5103 option == DITHER_OPTION_SPATIAL6 || 5104 option == DITHER_OPTION_FM6) { 5105 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; 5106 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2; 5107 fmt_bit_depth->flags.TRUNCATE_MODE = 1; 5108 } 5109 5110 /* spatial dither 5111 * note that spatial modes 1-3 are never used 5112 */ 5113 if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM || 5114 option == DITHER_OPTION_SPATIAL6 || 5115 option == DITHER_OPTION_TRUN10_SPATIAL6 || 5116 option == DITHER_OPTION_TRUN8_SPATIAL6) { 5117 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1; 5118 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 0; 5119 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1; 5120 fmt_bit_depth->flags.RGB_RANDOM = 5121 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0; 5122 } else if (option == DITHER_OPTION_SPATIAL8_FRAME_RANDOM || 5123 option == DITHER_OPTION_SPATIAL8 || 5124 option == DITHER_OPTION_SPATIAL8_FM6 || 5125 option == DITHER_OPTION_TRUN10_SPATIAL8 || 5126 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { 5127 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1; 5128 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 1; 5129 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1; 5130 fmt_bit_depth->flags.RGB_RANDOM = 5131 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0; 5132 } else if (option == DITHER_OPTION_SPATIAL10_FRAME_RANDOM || 5133 option == DITHER_OPTION_SPATIAL10 || 5134 option == DITHER_OPTION_SPATIAL10_FM8 || 5135 option == DITHER_OPTION_SPATIAL10_FM6) { 5136 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1; 5137 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 2; 5138 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1; 5139 fmt_bit_depth->flags.RGB_RANDOM = 5140 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0; 5141 } 5142 5143 if (option == DITHER_OPTION_SPATIAL6 || 5144 option == DITHER_OPTION_SPATIAL8 || 5145 option == DITHER_OPTION_SPATIAL10) { 5146 fmt_bit_depth->flags.FRAME_RANDOM = 0; 5147 } else { 5148 fmt_bit_depth->flags.FRAME_RANDOM = 1; 5149 } 5150 5151 ////////////////////// 5152 //// temporal dither 5153 ////////////////////// 5154 if (option == DITHER_OPTION_FM6 || 5155 option == DITHER_OPTION_SPATIAL8_FM6 || 5156 option == DITHER_OPTION_SPATIAL10_FM6 || 5157 option == DITHER_OPTION_TRUN10_FM6 || 5158 option == DITHER_OPTION_TRUN8_FM6 || 5159 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { 5160 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1; 5161 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 0; 5162 } else if (option == DITHER_OPTION_FM8 || 5163 option == DITHER_OPTION_SPATIAL10_FM8 || 5164 option == DITHER_OPTION_TRUN10_FM8) { 5165 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1; 5166 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 1; 5167 } else if (option == DITHER_OPTION_FM10) { 5168 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1; 5169 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 2; 5170 } 5171 5172 fmt_bit_depth->pixel_encoding = pixel_encoding; 5173 } 5174 5175 enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream) 5176 { 5177 if (dc == NULL || stream == NULL) 5178 return DC_ERROR_UNEXPECTED; 5179 5180 struct dc_link *link = stream->link; 5181 struct timing_generator *tg = dc->res_pool->timing_generators[0]; 5182 enum dc_status res = DC_OK; 5183 5184 calculate_phy_pix_clks(stream); 5185 5186 if (!tg->funcs->validate_timing(tg, &stream->timing)) 5187 res = DC_FAIL_CONTROLLER_VALIDATE; 5188 5189 if (res == DC_OK) { 5190 if (link->ep_type == DISPLAY_ENDPOINT_PHY && 5191 !link->link_enc->funcs->validate_output_with_stream( 5192 link->link_enc, stream)) 5193 res = DC_FAIL_ENC_VALIDATE; 5194 } 5195 5196 /* TODO: validate audio ASIC caps, encoder */ 5197 5198 if (res == DC_OK) 5199 res = dc->link_srv->validate_mode_timing(stream, 5200 link, 5201 &stream->timing); 5202 5203 return res; 5204 } 5205 5206 enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state) 5207 { 5208 enum dc_status res = DC_OK; 5209 5210 /* check if surface has invalid dimensions */ 5211 if (plane_state->src_rect.width == 0 || plane_state->src_rect.height == 0 || 5212 plane_state->dst_rect.width == 0 || plane_state->dst_rect.height == 0) 5213 return DC_FAIL_SURFACE_VALIDATE; 5214 5215 /* TODO For now validates pixel format only */ 5216 if (dc->res_pool->funcs->validate_plane) 5217 return dc->res_pool->funcs->validate_plane(plane_state, &dc->caps); 5218 5219 return res; 5220 } 5221 5222 unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format) 5223 { 5224 switch (format) { 5225 case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS: 5226 return 8; 5227 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: 5228 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: 5229 return 12; 5230 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: 5231 case SURFACE_PIXEL_FORMAT_GRPH_RGB565: 5232 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: 5233 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: 5234 return 16; 5235 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: 5236 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: 5237 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: 5238 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: 5239 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS: 5240 case SURFACE_PIXEL_FORMAT_GRPH_RGBE: 5241 case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA: 5242 return 32; 5243 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: 5244 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: 5245 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: 5246 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: 5247 return 64; 5248 default: 5249 ASSERT_CRITICAL(false); 5250 return UINT_MAX; 5251 } 5252 } 5253 static unsigned int get_max_audio_sample_rate(struct audio_mode *modes) 5254 { 5255 if (modes) { 5256 if (modes->sample_rates.rate.RATE_192) 5257 return 192000; 5258 if (modes->sample_rates.rate.RATE_176_4) 5259 return 176400; 5260 if (modes->sample_rates.rate.RATE_96) 5261 return 96000; 5262 if (modes->sample_rates.rate.RATE_88_2) 5263 return 88200; 5264 if (modes->sample_rates.rate.RATE_48) 5265 return 48000; 5266 if (modes->sample_rates.rate.RATE_44_1) 5267 return 44100; 5268 if (modes->sample_rates.rate.RATE_32) 5269 return 32000; 5270 } 5271 /*original logic when no audio info*/ 5272 return 441000; 5273 } 5274 5275 void get_audio_check(struct audio_info *aud_modes, 5276 struct audio_check *audio_chk) 5277 { 5278 unsigned int i; 5279 unsigned int max_sample_rate = 0; 5280 5281 if (aud_modes) { 5282 audio_chk->audio_packet_type = 0x2;/*audio sample packet AP = .25 for layout0, 1 for layout1*/ 5283 5284 audio_chk->max_audiosample_rate = 0; 5285 for (i = 0; i < aud_modes->mode_count; i++) { 5286 max_sample_rate = get_max_audio_sample_rate(&aud_modes->modes[i]); 5287 if (audio_chk->max_audiosample_rate < max_sample_rate) 5288 audio_chk->max_audiosample_rate = max_sample_rate; 5289 /*dts takes the same as type 2: AP = 0.25*/ 5290 } 5291 /*check which one take more bandwidth*/ 5292 if (audio_chk->max_audiosample_rate > 192000) 5293 audio_chk->audio_packet_type = 0x9;/*AP =1*/ 5294 audio_chk->acat = 0;/*not support*/ 5295 } 5296 } 5297 5298 struct link_encoder *get_temp_dio_link_enc( 5299 const struct resource_context *res_ctx, 5300 const struct resource_pool *const pool, 5301 const struct dc_link *link) 5302 { 5303 struct link_encoder *link_enc = NULL; 5304 int enc_index; 5305 5306 if (link->is_dig_mapping_flexible) 5307 enc_index = find_acquired_dio_link_enc_for_link(res_ctx, link); 5308 else 5309 enc_index = link->eng_id; 5310 5311 if (enc_index < 0) 5312 enc_index = find_free_dio_link_enc(res_ctx, link, pool, NULL); 5313 5314 if (enc_index >= 0) 5315 link_enc = pool->link_encoders[enc_index]; 5316 5317 return link_enc; 5318 } 5319 5320 static struct hpo_dp_link_encoder *get_temp_hpo_dp_link_enc( 5321 const struct resource_context *res_ctx, 5322 const struct resource_pool *const pool, 5323 const struct dc_link *link) 5324 { 5325 struct hpo_dp_link_encoder *hpo_dp_link_enc = NULL; 5326 int enc_index; 5327 5328 enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, link); 5329 5330 if (enc_index < 0) 5331 enc_index = find_free_hpo_dp_link_enc(res_ctx, pool); 5332 5333 if (enc_index >= 0) 5334 hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index]; 5335 5336 return hpo_dp_link_enc; 5337 } 5338 5339 bool get_temp_dp_link_res(struct dc_link *link, 5340 struct link_resource *link_res, 5341 struct dc_link_settings *link_settings) 5342 { 5343 const struct dc *dc = link->dc; 5344 const struct resource_context *res_ctx = &dc->current_state->res_ctx; 5345 5346 memset(link_res, 0, sizeof(*link_res)); 5347 5348 if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) { 5349 link_res->hpo_dp_link_enc = get_temp_hpo_dp_link_enc(res_ctx, dc->res_pool, link); 5350 if (!link_res->hpo_dp_link_enc) 5351 return false; 5352 } else if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING && 5353 dc->config.unify_link_enc_assignment) { 5354 link_res->dio_link_enc = get_temp_dio_link_enc(res_ctx, 5355 dc->res_pool, link); 5356 if (!link_res->dio_link_enc) 5357 return false; 5358 } 5359 5360 return true; 5361 } 5362 5363 void reset_syncd_pipes_from_disabled_pipes(struct dc *dc, 5364 struct dc_state *context) 5365 { 5366 int i, j; 5367 struct pipe_ctx *pipe_ctx_old, *pipe_ctx, *pipe_ctx_syncd; 5368 5369 /* If pipe backend is reset, need to reset pipe syncd status */ 5370 for (i = 0; i < dc->res_pool->pipe_count; i++) { 5371 pipe_ctx_old = &dc->current_state->res_ctx.pipe_ctx[i]; 5372 pipe_ctx = &context->res_ctx.pipe_ctx[i]; 5373 5374 if (!resource_is_pipe_type(pipe_ctx_old, OTG_MASTER)) 5375 continue; 5376 5377 if (!pipe_ctx->stream || 5378 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { 5379 5380 /* Reset all the syncd pipes from the disabled pipe */ 5381 for (j = 0; j < dc->res_pool->pipe_count; j++) { 5382 pipe_ctx_syncd = &context->res_ctx.pipe_ctx[j]; 5383 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_syncd) == pipe_ctx_old->pipe_idx) || 5384 !IS_PIPE_SYNCD_VALID(pipe_ctx_syncd)) 5385 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_syncd, j); 5386 } 5387 } 5388 } 5389 } 5390 5391 void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc, 5392 struct dc_state *context, 5393 uint8_t disabled_master_pipe_idx) 5394 { 5395 int i; 5396 struct pipe_ctx *pipe_ctx, *pipe_ctx_check; 5397 5398 pipe_ctx = &context->res_ctx.pipe_ctx[disabled_master_pipe_idx]; 5399 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx) != disabled_master_pipe_idx) || 5400 !IS_PIPE_SYNCD_VALID(pipe_ctx)) 5401 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx, disabled_master_pipe_idx); 5402 5403 /* for the pipe disabled, check if any slave pipe exists and assert */ 5404 for (i = 0; i < dc->res_pool->pipe_count; i++) { 5405 pipe_ctx_check = &context->res_ctx.pipe_ctx[i]; 5406 5407 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_check) == disabled_master_pipe_idx) && 5408 IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx)) { 5409 struct pipe_ctx *first_pipe = pipe_ctx_check; 5410 5411 while (first_pipe->prev_odm_pipe) 5412 first_pipe = first_pipe->prev_odm_pipe; 5413 /* When ODM combine is enabled, this case is expected. If the disabled pipe 5414 * is part of the ODM tree, then we should not print an error. 5415 * */ 5416 if (first_pipe->pipe_idx == disabled_master_pipe_idx) 5417 continue; 5418 5419 DC_ERR("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n", 5420 i, disabled_master_pipe_idx); 5421 } 5422 } 5423 } 5424 5425 void reset_sync_context_for_pipe(const struct dc *dc, 5426 struct dc_state *context, 5427 uint8_t pipe_idx) 5428 { 5429 int i; 5430 struct pipe_ctx *pipe_ctx_reset; 5431 5432 /* reset the otg sync context for the pipe and its slave pipes if any */ 5433 for (i = 0; i < dc->res_pool->pipe_count; i++) { 5434 pipe_ctx_reset = &context->res_ctx.pipe_ctx[i]; 5435 5436 if (((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_reset) == pipe_idx) && 5437 IS_PIPE_SYNCD_VALID(pipe_ctx_reset)) || (i == pipe_idx)) 5438 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_reset, i); 5439 } 5440 } 5441 5442 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter) 5443 { 5444 /* TODO - get transmitter to phy idx mapping from DMUB */ 5445 uint8_t phy_idx = transmitter - TRANSMITTER_UNIPHY_A; 5446 5447 if (dc->ctx->dce_version == DCN_VERSION_3_1 && 5448 dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { 5449 switch (transmitter) { 5450 case TRANSMITTER_UNIPHY_A: 5451 phy_idx = 0; 5452 break; 5453 case TRANSMITTER_UNIPHY_B: 5454 phy_idx = 1; 5455 break; 5456 case TRANSMITTER_UNIPHY_C: 5457 phy_idx = 5; 5458 break; 5459 case TRANSMITTER_UNIPHY_D: 5460 phy_idx = 6; 5461 break; 5462 case TRANSMITTER_UNIPHY_E: 5463 phy_idx = 4; 5464 break; 5465 default: 5466 phy_idx = 0; 5467 break; 5468 } 5469 } 5470 5471 return phy_idx; 5472 } 5473 5474 const struct link_hwss *get_link_hwss(const struct dc_link *link, 5475 const struct link_resource *link_res) 5476 { 5477 /* Link_hwss is only accessible by getter function instead of accessing 5478 * by pointers in dc with the intent to protect against breaking polymorphism. 5479 */ 5480 if (can_use_hpo_dp_link_hwss(link, link_res)) 5481 /* TODO: some assumes that if decided link settings is 128b/132b 5482 * channel coding format hpo_dp_link_enc should be used. 5483 * Others believe that if hpo_dp_link_enc is available in link 5484 * resource then hpo_dp_link_enc must be used. This bound between 5485 * hpo_dp_link_enc != NULL and decided link settings is loosely coupled 5486 * with a premise that both hpo_dp_link_enc pointer and decided link 5487 * settings are determined based on single policy function like 5488 * "decide_link_settings" from upper layer. This "convention" 5489 * cannot be maintained and enforced at current level. 5490 * Therefore a refactor is due so we can enforce a strong bound 5491 * between those two parameters at this level. 5492 * 5493 * To put it simple, we want to make enforcement at low level so that 5494 * we will not return link hwss if caller plans to do 8b/10b 5495 * with an hpo encoder. Or we can return a very dummy one that doesn't 5496 * do work for all functions 5497 */ 5498 return (requires_fixed_vs_pe_retimer_hpo_link_hwss(link) ? 5499 get_hpo_fixed_vs_pe_retimer_dp_link_hwss() : get_hpo_dp_link_hwss()); 5500 else if (can_use_dpia_link_hwss(link, link_res)) 5501 return get_dpia_link_hwss(); 5502 else if (can_use_dio_link_hwss(link, link_res)) 5503 return (requires_fixed_vs_pe_retimer_dio_link_hwss(link)) ? 5504 get_dio_fixed_vs_pe_retimer_link_hwss() : get_dio_link_hwss(); 5505 else 5506 return get_virtual_link_hwss(); 5507 } 5508 5509 bool is_h_timing_divisible_by_2(struct dc_stream_state *stream) 5510 { 5511 bool divisible = false; 5512 uint16_t h_blank_start = 0; 5513 uint16_t h_blank_end = 0; 5514 5515 if (stream) { 5516 h_blank_start = stream->timing.h_total - stream->timing.h_front_porch; 5517 h_blank_end = h_blank_start - stream->timing.h_addressable; 5518 5519 /* HTOTAL, Hblank start/end, and Hsync start/end all must be 5520 * divisible by 2 in order for the horizontal timing params 5521 * to be considered divisible by 2. Hsync start is always 0. 5522 */ 5523 divisible = (stream->timing.h_total % 2 == 0) && 5524 (h_blank_start % 2 == 0) && 5525 (h_blank_end % 2 == 0) && 5526 (stream->timing.h_sync_width % 2 == 0); 5527 } 5528 return divisible; 5529 } 5530 5531 /* This interface is deprecated for new DCNs. It is replaced by the following 5532 * new interfaces. These two interfaces encapsulate pipe selection priority 5533 * with DCN specific minimum hardware transition optimization algorithm. With 5534 * the new interfaces caller no longer needs to know the implementation detail 5535 * of a pipe topology. 5536 * 5537 * resource_update_pipes_with_odm_slice_count 5538 * resource_update_pipes_with_mpc_slice_count 5539 * 5540 */ 5541 bool dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy( 5542 const struct dc *dc, 5543 struct dc_state *state, 5544 struct pipe_ctx *pri_pipe, 5545 struct pipe_ctx *sec_pipe, 5546 bool odm) 5547 { 5548 int pipe_idx = sec_pipe->pipe_idx; 5549 struct pipe_ctx *sec_top, *sec_bottom, *sec_next, *sec_prev; 5550 const struct resource_pool *pool = dc->res_pool; 5551 5552 sec_top = sec_pipe->top_pipe; 5553 sec_bottom = sec_pipe->bottom_pipe; 5554 sec_next = sec_pipe->next_odm_pipe; 5555 sec_prev = sec_pipe->prev_odm_pipe; 5556 5557 if (pri_pipe == NULL) 5558 return false; 5559 5560 *sec_pipe = *pri_pipe; 5561 5562 sec_pipe->top_pipe = sec_top; 5563 sec_pipe->bottom_pipe = sec_bottom; 5564 sec_pipe->next_odm_pipe = sec_next; 5565 sec_pipe->prev_odm_pipe = sec_prev; 5566 5567 sec_pipe->pipe_idx = pipe_idx; 5568 sec_pipe->plane_res.mi = pool->mis[pipe_idx]; 5569 sec_pipe->plane_res.hubp = pool->hubps[pipe_idx]; 5570 sec_pipe->plane_res.ipp = pool->ipps[pipe_idx]; 5571 sec_pipe->plane_res.xfm = pool->transforms[pipe_idx]; 5572 sec_pipe->plane_res.dpp = pool->dpps[pipe_idx]; 5573 sec_pipe->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst; 5574 sec_pipe->stream_res.dsc = NULL; 5575 if (odm) { 5576 if (!sec_pipe->top_pipe) 5577 sec_pipe->stream_res.opp = pool->opps[pipe_idx]; 5578 else 5579 sec_pipe->stream_res.opp = sec_pipe->top_pipe->stream_res.opp; 5580 if (sec_pipe->stream->timing.flags.DSC == 1) { 5581 #if defined(CONFIG_DRM_AMD_DC_FP) 5582 dcn20_acquire_dsc(dc, &state->res_ctx, &sec_pipe->stream_res.dsc, sec_pipe->stream_res.opp->inst); 5583 #endif 5584 ASSERT(sec_pipe->stream_res.dsc); 5585 if (sec_pipe->stream_res.dsc == NULL) 5586 return false; 5587 } 5588 #if defined(CONFIG_DRM_AMD_DC_FP) 5589 dcn20_build_mapped_resource(dc, state, sec_pipe->stream); 5590 #endif 5591 } 5592 5593 return true; 5594 } 5595 5596 enum dc_status update_dp_encoder_resources_for_test_harness(const struct dc *dc, 5597 struct dc_state *context, 5598 struct pipe_ctx *pipe_ctx) 5599 { 5600 if (dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) { 5601 if (pipe_ctx->stream_res.hpo_dp_stream_enc == NULL) { 5602 pipe_ctx->stream_res.hpo_dp_stream_enc = 5603 find_first_free_match_hpo_dp_stream_enc_for_link( 5604 &context->res_ctx, dc->res_pool, pipe_ctx->stream); 5605 5606 if (!pipe_ctx->stream_res.hpo_dp_stream_enc) 5607 return DC_NO_STREAM_ENC_RESOURCE; 5608 5609 update_hpo_dp_stream_engine_usage( 5610 &context->res_ctx, dc->res_pool, 5611 pipe_ctx->stream_res.hpo_dp_stream_enc, 5612 true); 5613 } 5614 5615 if (pipe_ctx->link_res.hpo_dp_link_enc == NULL) { 5616 if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, dc->res_pool, pipe_ctx, pipe_ctx->stream)) 5617 return DC_NO_LINK_ENC_RESOURCE; 5618 } 5619 } else { 5620 if (pipe_ctx->stream_res.hpo_dp_stream_enc) { 5621 update_hpo_dp_stream_engine_usage( 5622 &context->res_ctx, dc->res_pool, 5623 pipe_ctx->stream_res.hpo_dp_stream_enc, 5624 false); 5625 pipe_ctx->stream_res.hpo_dp_stream_enc = NULL; 5626 } 5627 if (pipe_ctx->link_res.hpo_dp_link_enc) 5628 remove_hpo_dp_link_enc_from_ctx(&context->res_ctx, pipe_ctx, pipe_ctx->stream); 5629 } 5630 5631 if (pipe_ctx->link_res.dio_link_enc == NULL && dc->config.unify_link_enc_assignment) 5632 if (!add_dio_link_enc_to_ctx(dc, context, dc->res_pool, pipe_ctx, pipe_ctx->stream)) 5633 return DC_NO_LINK_ENC_RESOURCE; 5634 5635 return DC_OK; 5636 } 5637 5638 struct dscl_prog_data *resource_get_dscl_prog_data(struct pipe_ctx *pipe_ctx) 5639 { 5640 return &pipe_ctx->plane_res.scl_data.dscl_prog_data; 5641 } 5642 5643 static bool resource_allocate_mcache(struct dc_state *context, const struct dc_mcache_params *mcache_params) 5644 { 5645 if (context->clk_mgr->ctx->dc->res_pool->funcs->program_mcache_pipe_config) 5646 context->clk_mgr->ctx->dc->res_pool->funcs->program_mcache_pipe_config(context, mcache_params); 5647 5648 return true; 5649 } 5650 5651 void resource_init_common_dml2_callbacks(struct dc *dc, struct dml2_configuration_options *dml2_options) 5652 { 5653 dml2_options->callbacks.dc = dc; 5654 dml2_options->callbacks.build_scaling_params = &resource_build_scaling_params; 5655 dml2_options->callbacks.build_test_pattern_params = &resource_build_test_pattern_params; 5656 dml2_options->callbacks.acquire_secondary_pipe_for_mpc_odm = &dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy; 5657 dml2_options->callbacks.update_pipes_for_stream_with_slice_count = &resource_update_pipes_for_stream_with_slice_count; 5658 dml2_options->callbacks.update_pipes_for_plane_with_slice_count = &resource_update_pipes_for_plane_with_slice_count; 5659 dml2_options->callbacks.get_mpc_slice_index = &resource_get_mpc_slice_index; 5660 dml2_options->callbacks.get_mpc_slice_count = &resource_get_mpc_slice_count; 5661 dml2_options->callbacks.get_odm_slice_index = &resource_get_odm_slice_index; 5662 dml2_options->callbacks.get_odm_slice_count = &resource_get_odm_slice_count; 5663 dml2_options->callbacks.get_opp_head = &resource_get_opp_head; 5664 dml2_options->callbacks.get_otg_master_for_stream = &resource_get_otg_master_for_stream; 5665 dml2_options->callbacks.get_opp_heads_for_otg_master = &resource_get_opp_heads_for_otg_master; 5666 dml2_options->callbacks.get_dpp_pipes_for_plane = &resource_get_dpp_pipes_for_plane; 5667 dml2_options->callbacks.get_stream_status = &dc_state_get_stream_status; 5668 dml2_options->callbacks.get_stream_from_id = &dc_state_get_stream_from_id; 5669 dml2_options->callbacks.get_max_flickerless_instant_vtotal_increase = &dc_stream_get_max_flickerless_instant_vtotal_increase; 5670 dml2_options->callbacks.allocate_mcache = &resource_allocate_mcache; 5671 5672 dml2_options->svp_pstate.callbacks.dc = dc; 5673 dml2_options->svp_pstate.callbacks.add_phantom_plane = &dc_state_add_phantom_plane; 5674 dml2_options->svp_pstate.callbacks.add_phantom_stream = &dc_state_add_phantom_stream; 5675 dml2_options->svp_pstate.callbacks.build_scaling_params = &resource_build_scaling_params; 5676 dml2_options->svp_pstate.callbacks.create_phantom_plane = &dc_state_create_phantom_plane; 5677 dml2_options->svp_pstate.callbacks.remove_phantom_plane = &dc_state_remove_phantom_plane; 5678 dml2_options->svp_pstate.callbacks.remove_phantom_stream = &dc_state_remove_phantom_stream; 5679 dml2_options->svp_pstate.callbacks.create_phantom_stream = &dc_state_create_phantom_stream; 5680 dml2_options->svp_pstate.callbacks.release_phantom_plane = &dc_state_release_phantom_plane; 5681 dml2_options->svp_pstate.callbacks.release_phantom_stream = &dc_state_release_phantom_stream; 5682 dml2_options->svp_pstate.callbacks.get_pipe_subvp_type = &dc_state_get_pipe_subvp_type; 5683 dml2_options->svp_pstate.callbacks.get_stream_subvp_type = &dc_state_get_stream_subvp_type; 5684 dml2_options->svp_pstate.callbacks.get_paired_subvp_stream = &dc_state_get_paired_subvp_stream; 5685 dml2_options->svp_pstate.callbacks.remove_phantom_streams_and_planes = &dc_state_remove_phantom_streams_and_planes; 5686 dml2_options->svp_pstate.callbacks.release_phantom_streams_and_planes = &dc_state_release_phantom_streams_and_planes; 5687 } 5688 5689 /* Returns number of DET segments allocated for a given OTG_MASTER pipe */ 5690 int resource_calculate_det_for_stream(struct dc_state *state, struct pipe_ctx *otg_master) 5691 { 5692 struct pipe_ctx *opp_heads[MAX_PIPES]; 5693 struct pipe_ctx *dpp_pipes[MAX_PIPES]; 5694 5695 int dpp_count = 0; 5696 int det_segments = 0; 5697 5698 if (!otg_master->stream) 5699 return 0; 5700 5701 int slice_count = resource_get_opp_heads_for_otg_master(otg_master, 5702 &state->res_ctx, opp_heads); 5703 5704 for (int slice_idx = 0; slice_idx < slice_count; slice_idx++) { 5705 if (opp_heads[slice_idx]->plane_state) { 5706 dpp_count = resource_get_dpp_pipes_for_opp_head( 5707 opp_heads[slice_idx], 5708 &state->res_ctx, 5709 dpp_pipes); 5710 for (int dpp_idx = 0; dpp_idx < dpp_count; dpp_idx++) 5711 det_segments += dpp_pipes[dpp_idx]->hubp_regs.det_size; 5712 } 5713 } 5714 return det_segments; 5715 } 5716 5717 bool resource_is_hpo_acquired(struct dc_state *context) 5718 { 5719 int i; 5720 5721 for (i = 0; i < MAX_HPO_DP2_ENCODERS; i++) { 5722 if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i]) { 5723 return true; 5724 } 5725 } 5726 5727 return false; 5728 } 5729