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 "virtual/virtual_stream_encoder.h" 41 #include "dpcd_defs.h" 42 #include "link_enc_cfg.h" 43 #include "link.h" 44 #include "virtual/virtual_link_hwss.h" 45 #include "link/hwss/link_hwss_dio.h" 46 #include "link/hwss/link_hwss_dpia.h" 47 #include "link/hwss/link_hwss_hpo_dp.h" 48 49 #if defined(CONFIG_DRM_AMD_DC_SI) 50 #include "dce60/dce60_resource.h" 51 #endif 52 #include "dce80/dce80_resource.h" 53 #include "dce100/dce100_resource.h" 54 #include "dce110/dce110_resource.h" 55 #include "dce112/dce112_resource.h" 56 #include "dce120/dce120_resource.h" 57 #include "dcn10/dcn10_resource.h" 58 #include "dcn20/dcn20_resource.h" 59 #include "dcn21/dcn21_resource.h" 60 #include "dcn201/dcn201_resource.h" 61 #include "dcn30/dcn30_resource.h" 62 #include "dcn301/dcn301_resource.h" 63 #include "dcn302/dcn302_resource.h" 64 #include "dcn303/dcn303_resource.h" 65 #include "dcn31/dcn31_resource.h" 66 #include "dcn314/dcn314_resource.h" 67 #include "dcn315/dcn315_resource.h" 68 #include "dcn316/dcn316_resource.h" 69 #include "../dcn32/dcn32_resource.h" 70 #include "../dcn321/dcn321_resource.h" 71 72 73 #define DC_LOGGER_INIT(logger) 74 75 enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) 76 { 77 enum dce_version dc_version = DCE_VERSION_UNKNOWN; 78 79 switch (asic_id.chip_family) { 80 81 #if defined(CONFIG_DRM_AMD_DC_SI) 82 case FAMILY_SI: 83 if (ASIC_REV_IS_TAHITI_P(asic_id.hw_internal_rev) || 84 ASIC_REV_IS_PITCAIRN_PM(asic_id.hw_internal_rev) || 85 ASIC_REV_IS_CAPEVERDE_M(asic_id.hw_internal_rev)) 86 dc_version = DCE_VERSION_6_0; 87 else if (ASIC_REV_IS_OLAND_M(asic_id.hw_internal_rev)) 88 dc_version = DCE_VERSION_6_4; 89 else 90 dc_version = DCE_VERSION_6_1; 91 break; 92 #endif 93 case FAMILY_CI: 94 dc_version = DCE_VERSION_8_0; 95 break; 96 case FAMILY_KV: 97 if (ASIC_REV_IS_KALINDI(asic_id.hw_internal_rev) || 98 ASIC_REV_IS_BHAVANI(asic_id.hw_internal_rev) || 99 ASIC_REV_IS_GODAVARI(asic_id.hw_internal_rev)) 100 dc_version = DCE_VERSION_8_3; 101 else 102 dc_version = DCE_VERSION_8_1; 103 break; 104 case FAMILY_CZ: 105 dc_version = DCE_VERSION_11_0; 106 break; 107 108 case FAMILY_VI: 109 if (ASIC_REV_IS_TONGA_P(asic_id.hw_internal_rev) || 110 ASIC_REV_IS_FIJI_P(asic_id.hw_internal_rev)) { 111 dc_version = DCE_VERSION_10_0; 112 break; 113 } 114 if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev) || 115 ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev) || 116 ASIC_REV_IS_POLARIS12_V(asic_id.hw_internal_rev)) { 117 dc_version = DCE_VERSION_11_2; 118 } 119 if (ASIC_REV_IS_VEGAM(asic_id.hw_internal_rev)) 120 dc_version = DCE_VERSION_11_22; 121 break; 122 case FAMILY_AI: 123 if (ASICREV_IS_VEGA20_P(asic_id.hw_internal_rev)) 124 dc_version = DCE_VERSION_12_1; 125 else 126 dc_version = DCE_VERSION_12_0; 127 break; 128 case FAMILY_RV: 129 dc_version = DCN_VERSION_1_0; 130 if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev)) 131 dc_version = DCN_VERSION_1_01; 132 if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev)) 133 dc_version = DCN_VERSION_2_1; 134 if (ASICREV_IS_GREEN_SARDINE(asic_id.hw_internal_rev)) 135 dc_version = DCN_VERSION_2_1; 136 break; 137 138 case FAMILY_NV: 139 dc_version = DCN_VERSION_2_0; 140 if (asic_id.chip_id == DEVICE_ID_NV_13FE || asic_id.chip_id == DEVICE_ID_NV_143F) { 141 dc_version = DCN_VERSION_2_01; 142 break; 143 } 144 if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev)) 145 dc_version = DCN_VERSION_3_0; 146 if (ASICREV_IS_DIMGREY_CAVEFISH_P(asic_id.hw_internal_rev)) 147 dc_version = DCN_VERSION_3_02; 148 if (ASICREV_IS_BEIGE_GOBY_P(asic_id.hw_internal_rev)) 149 dc_version = DCN_VERSION_3_03; 150 break; 151 152 case FAMILY_VGH: 153 dc_version = DCN_VERSION_3_01; 154 break; 155 156 case FAMILY_YELLOW_CARP: 157 if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev)) 158 dc_version = DCN_VERSION_3_1; 159 break; 160 case AMDGPU_FAMILY_GC_10_3_6: 161 if (ASICREV_IS_GC_10_3_6(asic_id.hw_internal_rev)) 162 dc_version = DCN_VERSION_3_15; 163 break; 164 case AMDGPU_FAMILY_GC_10_3_7: 165 if (ASICREV_IS_GC_10_3_7(asic_id.hw_internal_rev)) 166 dc_version = DCN_VERSION_3_16; 167 break; 168 case AMDGPU_FAMILY_GC_11_0_0: 169 dc_version = DCN_VERSION_3_2; 170 if (ASICREV_IS_GC_11_0_2(asic_id.hw_internal_rev)) 171 dc_version = DCN_VERSION_3_21; 172 break; 173 case AMDGPU_FAMILY_GC_11_0_1: 174 dc_version = DCN_VERSION_3_14; 175 break; 176 default: 177 dc_version = DCE_VERSION_UNKNOWN; 178 break; 179 } 180 return dc_version; 181 } 182 183 struct resource_pool *dc_create_resource_pool(struct dc *dc, 184 const struct dc_init_data *init_data, 185 enum dce_version dc_version) 186 { 187 struct resource_pool *res_pool = NULL; 188 189 switch (dc_version) { 190 #if defined(CONFIG_DRM_AMD_DC_SI) 191 case DCE_VERSION_6_0: 192 res_pool = dce60_create_resource_pool( 193 init_data->num_virtual_links, dc); 194 break; 195 case DCE_VERSION_6_1: 196 res_pool = dce61_create_resource_pool( 197 init_data->num_virtual_links, dc); 198 break; 199 case DCE_VERSION_6_4: 200 res_pool = dce64_create_resource_pool( 201 init_data->num_virtual_links, dc); 202 break; 203 #endif 204 case DCE_VERSION_8_0: 205 res_pool = dce80_create_resource_pool( 206 init_data->num_virtual_links, dc); 207 break; 208 case DCE_VERSION_8_1: 209 res_pool = dce81_create_resource_pool( 210 init_data->num_virtual_links, dc); 211 break; 212 case DCE_VERSION_8_3: 213 res_pool = dce83_create_resource_pool( 214 init_data->num_virtual_links, dc); 215 break; 216 case DCE_VERSION_10_0: 217 res_pool = dce100_create_resource_pool( 218 init_data->num_virtual_links, dc); 219 break; 220 case DCE_VERSION_11_0: 221 res_pool = dce110_create_resource_pool( 222 init_data->num_virtual_links, dc, 223 init_data->asic_id); 224 break; 225 case DCE_VERSION_11_2: 226 case DCE_VERSION_11_22: 227 res_pool = dce112_create_resource_pool( 228 init_data->num_virtual_links, dc); 229 break; 230 case DCE_VERSION_12_0: 231 case DCE_VERSION_12_1: 232 res_pool = dce120_create_resource_pool( 233 init_data->num_virtual_links, dc); 234 break; 235 236 #if defined(CONFIG_DRM_AMD_DC_FP) 237 case DCN_VERSION_1_0: 238 case DCN_VERSION_1_01: 239 res_pool = dcn10_create_resource_pool(init_data, dc); 240 break; 241 case DCN_VERSION_2_0: 242 res_pool = dcn20_create_resource_pool(init_data, dc); 243 break; 244 case DCN_VERSION_2_1: 245 res_pool = dcn21_create_resource_pool(init_data, dc); 246 break; 247 case DCN_VERSION_2_01: 248 res_pool = dcn201_create_resource_pool(init_data, dc); 249 break; 250 case DCN_VERSION_3_0: 251 res_pool = dcn30_create_resource_pool(init_data, dc); 252 break; 253 case DCN_VERSION_3_01: 254 res_pool = dcn301_create_resource_pool(init_data, dc); 255 break; 256 case DCN_VERSION_3_02: 257 res_pool = dcn302_create_resource_pool(init_data, dc); 258 break; 259 case DCN_VERSION_3_03: 260 res_pool = dcn303_create_resource_pool(init_data, dc); 261 break; 262 case DCN_VERSION_3_1: 263 res_pool = dcn31_create_resource_pool(init_data, dc); 264 break; 265 case DCN_VERSION_3_14: 266 res_pool = dcn314_create_resource_pool(init_data, dc); 267 break; 268 case DCN_VERSION_3_15: 269 res_pool = dcn315_create_resource_pool(init_data, dc); 270 break; 271 case DCN_VERSION_3_16: 272 res_pool = dcn316_create_resource_pool(init_data, dc); 273 break; 274 case DCN_VERSION_3_2: 275 res_pool = dcn32_create_resource_pool(init_data, dc); 276 break; 277 case DCN_VERSION_3_21: 278 res_pool = dcn321_create_resource_pool(init_data, dc); 279 break; 280 #endif /* CONFIG_DRM_AMD_DC_FP */ 281 default: 282 break; 283 } 284 285 if (res_pool != NULL) { 286 if (dc->ctx->dc_bios->fw_info_valid) { 287 res_pool->ref_clocks.xtalin_clock_inKhz = 288 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; 289 /* initialize with firmware data first, no all 290 * ASIC have DCCG SW component. FPGA or 291 * simulation need initialization of 292 * dccg_ref_clock_inKhz, dchub_ref_clock_inKhz 293 * with xtalin_clock_inKhz 294 */ 295 res_pool->ref_clocks.dccg_ref_clock_inKhz = 296 res_pool->ref_clocks.xtalin_clock_inKhz; 297 res_pool->ref_clocks.dchub_ref_clock_inKhz = 298 res_pool->ref_clocks.xtalin_clock_inKhz; 299 } else 300 ASSERT_CRITICAL(false); 301 } 302 303 return res_pool; 304 } 305 306 void dc_destroy_resource_pool(struct dc *dc) 307 { 308 if (dc) { 309 if (dc->res_pool) 310 dc->res_pool->funcs->destroy(&dc->res_pool); 311 312 kfree(dc->hwseq); 313 } 314 } 315 316 static void update_num_audio( 317 const struct resource_straps *straps, 318 unsigned int *num_audio, 319 struct audio_support *aud_support) 320 { 321 aud_support->dp_audio = true; 322 aud_support->hdmi_audio_native = false; 323 aud_support->hdmi_audio_on_dongle = false; 324 325 if (straps->hdmi_disable == 0) { 326 if (straps->dc_pinstraps_audio & 0x2) { 327 aud_support->hdmi_audio_on_dongle = true; 328 aud_support->hdmi_audio_native = true; 329 } 330 } 331 332 switch (straps->audio_stream_number) { 333 case 0: /* multi streams supported */ 334 break; 335 case 1: /* multi streams not supported */ 336 *num_audio = 1; 337 break; 338 default: 339 DC_ERR("DC: unexpected audio fuse!\n"); 340 } 341 } 342 343 bool resource_construct( 344 unsigned int num_virtual_links, 345 struct dc *dc, 346 struct resource_pool *pool, 347 const struct resource_create_funcs *create_funcs) 348 { 349 struct dc_context *ctx = dc->ctx; 350 const struct resource_caps *caps = pool->res_cap; 351 int i; 352 unsigned int num_audio = caps->num_audio; 353 struct resource_straps straps = {0}; 354 355 if (create_funcs->read_dce_straps) 356 create_funcs->read_dce_straps(dc->ctx, &straps); 357 358 pool->audio_count = 0; 359 if (create_funcs->create_audio) { 360 /* find the total number of streams available via the 361 * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT 362 * registers (one for each pin) starting from pin 1 363 * up to the max number of audio pins. 364 * We stop on the first pin where 365 * PORT_CONNECTIVITY == 1 (as instructed by HW team). 366 */ 367 update_num_audio(&straps, &num_audio, &pool->audio_support); 368 for (i = 0; i < caps->num_audio; i++) { 369 struct audio *aud = create_funcs->create_audio(ctx, i); 370 371 if (aud == NULL) { 372 DC_ERR("DC: failed to create audio!\n"); 373 return false; 374 } 375 if (!aud->funcs->endpoint_valid(aud)) { 376 aud->funcs->destroy(&aud); 377 break; 378 } 379 pool->audios[i] = aud; 380 pool->audio_count++; 381 } 382 } 383 384 pool->stream_enc_count = 0; 385 if (create_funcs->create_stream_encoder) { 386 for (i = 0; i < caps->num_stream_encoder; i++) { 387 pool->stream_enc[i] = create_funcs->create_stream_encoder(i, ctx); 388 if (pool->stream_enc[i] == NULL) 389 DC_ERR("DC: failed to create stream_encoder!\n"); 390 pool->stream_enc_count++; 391 } 392 } 393 394 pool->hpo_dp_stream_enc_count = 0; 395 if (create_funcs->create_hpo_dp_stream_encoder) { 396 for (i = 0; i < caps->num_hpo_dp_stream_encoder; i++) { 397 pool->hpo_dp_stream_enc[i] = create_funcs->create_hpo_dp_stream_encoder(i+ENGINE_ID_HPO_DP_0, ctx); 398 if (pool->hpo_dp_stream_enc[i] == NULL) 399 DC_ERR("DC: failed to create HPO DP stream encoder!\n"); 400 pool->hpo_dp_stream_enc_count++; 401 402 } 403 } 404 405 pool->hpo_dp_link_enc_count = 0; 406 if (create_funcs->create_hpo_dp_link_encoder) { 407 for (i = 0; i < caps->num_hpo_dp_link_encoder; i++) { 408 pool->hpo_dp_link_enc[i] = create_funcs->create_hpo_dp_link_encoder(i, ctx); 409 if (pool->hpo_dp_link_enc[i] == NULL) 410 DC_ERR("DC: failed to create HPO DP link encoder!\n"); 411 pool->hpo_dp_link_enc_count++; 412 } 413 } 414 415 for (i = 0; i < caps->num_mpc_3dlut; i++) { 416 pool->mpc_lut[i] = dc_create_3dlut_func(); 417 if (pool->mpc_lut[i] == NULL) 418 DC_ERR("DC: failed to create MPC 3dlut!\n"); 419 pool->mpc_shaper[i] = dc_create_transfer_func(); 420 if (pool->mpc_shaper[i] == NULL) 421 DC_ERR("DC: failed to create MPC shaper!\n"); 422 } 423 424 dc->caps.dynamic_audio = false; 425 if (pool->audio_count < pool->stream_enc_count) { 426 dc->caps.dynamic_audio = true; 427 } 428 for (i = 0; i < num_virtual_links; i++) { 429 pool->stream_enc[pool->stream_enc_count] = 430 virtual_stream_encoder_create( 431 ctx, ctx->dc_bios); 432 if (pool->stream_enc[pool->stream_enc_count] == NULL) { 433 DC_ERR("DC: failed to create stream_encoder!\n"); 434 return false; 435 } 436 pool->stream_enc_count++; 437 } 438 439 dc->hwseq = create_funcs->create_hwseq(ctx); 440 441 return true; 442 } 443 static int find_matching_clock_source( 444 const struct resource_pool *pool, 445 struct clock_source *clock_source) 446 { 447 448 int i; 449 450 for (i = 0; i < pool->clk_src_count; i++) { 451 if (pool->clock_sources[i] == clock_source) 452 return i; 453 } 454 return -1; 455 } 456 457 void resource_unreference_clock_source( 458 struct resource_context *res_ctx, 459 const struct resource_pool *pool, 460 struct clock_source *clock_source) 461 { 462 int i = find_matching_clock_source(pool, clock_source); 463 464 if (i > -1) 465 res_ctx->clock_source_ref_count[i]--; 466 467 if (pool->dp_clock_source == clock_source) 468 res_ctx->dp_clock_source_ref_count--; 469 } 470 471 void resource_reference_clock_source( 472 struct resource_context *res_ctx, 473 const struct resource_pool *pool, 474 struct clock_source *clock_source) 475 { 476 int i = find_matching_clock_source(pool, clock_source); 477 478 if (i > -1) 479 res_ctx->clock_source_ref_count[i]++; 480 481 if (pool->dp_clock_source == clock_source) 482 res_ctx->dp_clock_source_ref_count++; 483 } 484 485 int resource_get_clock_source_reference( 486 struct resource_context *res_ctx, 487 const struct resource_pool *pool, 488 struct clock_source *clock_source) 489 { 490 int i = find_matching_clock_source(pool, clock_source); 491 492 if (i > -1) 493 return res_ctx->clock_source_ref_count[i]; 494 495 if (pool->dp_clock_source == clock_source) 496 return res_ctx->dp_clock_source_ref_count; 497 498 return -1; 499 } 500 501 bool resource_are_vblanks_synchronizable( 502 struct dc_stream_state *stream1, 503 struct dc_stream_state *stream2) 504 { 505 uint32_t base60_refresh_rates[] = {10, 20, 5}; 506 uint8_t i; 507 uint8_t rr_count = ARRAY_SIZE(base60_refresh_rates); 508 uint64_t frame_time_diff; 509 510 if (stream1->ctx->dc->config.vblank_alignment_dto_params && 511 stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0 && 512 dc_is_dp_signal(stream1->signal) && 513 dc_is_dp_signal(stream2->signal) && 514 false == stream1->has_non_synchronizable_pclk && 515 false == stream2->has_non_synchronizable_pclk && 516 stream1->timing.flags.VBLANK_SYNCHRONIZABLE && 517 stream2->timing.flags.VBLANK_SYNCHRONIZABLE) { 518 /* disable refresh rates higher than 60Hz for now */ 519 if (stream1->timing.pix_clk_100hz*100/stream1->timing.h_total/ 520 stream1->timing.v_total > 60) 521 return false; 522 if (stream2->timing.pix_clk_100hz*100/stream2->timing.h_total/ 523 stream2->timing.v_total > 60) 524 return false; 525 frame_time_diff = (uint64_t)10000 * 526 stream1->timing.h_total * 527 stream1->timing.v_total * 528 stream2->timing.pix_clk_100hz; 529 frame_time_diff = div_u64(frame_time_diff, stream1->timing.pix_clk_100hz); 530 frame_time_diff = div_u64(frame_time_diff, stream2->timing.h_total); 531 frame_time_diff = div_u64(frame_time_diff, stream2->timing.v_total); 532 for (i = 0; i < rr_count; i++) { 533 int64_t diff = (int64_t)div_u64(frame_time_diff * base60_refresh_rates[i], 10) - 10000; 534 535 if (diff < 0) 536 diff = -diff; 537 if (diff < stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff) 538 return true; 539 } 540 } 541 return false; 542 } 543 544 bool resource_are_streams_timing_synchronizable( 545 struct dc_stream_state *stream1, 546 struct dc_stream_state *stream2) 547 { 548 if (stream1->timing.h_total != stream2->timing.h_total) 549 return false; 550 551 if (stream1->timing.v_total != stream2->timing.v_total) 552 return false; 553 554 if (stream1->timing.h_addressable 555 != stream2->timing.h_addressable) 556 return false; 557 558 if (stream1->timing.v_addressable 559 != stream2->timing.v_addressable) 560 return false; 561 562 if (stream1->timing.v_front_porch 563 != stream2->timing.v_front_porch) 564 return false; 565 566 if (stream1->timing.pix_clk_100hz 567 != stream2->timing.pix_clk_100hz) 568 return false; 569 570 if (stream1->clamping.c_depth != stream2->clamping.c_depth) 571 return false; 572 573 if (stream1->phy_pix_clk != stream2->phy_pix_clk 574 && (!dc_is_dp_signal(stream1->signal) 575 || !dc_is_dp_signal(stream2->signal))) 576 return false; 577 578 if (stream1->view_format != stream2->view_format) 579 return false; 580 581 if (stream1->ignore_msa_timing_param || stream2->ignore_msa_timing_param) 582 return false; 583 584 return true; 585 } 586 static bool is_dp_and_hdmi_sharable( 587 struct dc_stream_state *stream1, 588 struct dc_stream_state *stream2) 589 { 590 if (stream1->ctx->dc->caps.disable_dp_clk_share) 591 return false; 592 593 if (stream1->clamping.c_depth != COLOR_DEPTH_888 || 594 stream2->clamping.c_depth != COLOR_DEPTH_888) 595 return false; 596 597 return true; 598 599 } 600 601 static bool is_sharable_clk_src( 602 const struct pipe_ctx *pipe_with_clk_src, 603 const struct pipe_ctx *pipe) 604 { 605 if (pipe_with_clk_src->clock_source == NULL) 606 return false; 607 608 if (pipe_with_clk_src->stream->signal == SIGNAL_TYPE_VIRTUAL) 609 return false; 610 611 if (dc_is_dp_signal(pipe_with_clk_src->stream->signal) || 612 (dc_is_dp_signal(pipe->stream->signal) && 613 !is_dp_and_hdmi_sharable(pipe_with_clk_src->stream, 614 pipe->stream))) 615 return false; 616 617 if (dc_is_hdmi_signal(pipe_with_clk_src->stream->signal) 618 && dc_is_dual_link_signal(pipe->stream->signal)) 619 return false; 620 621 if (dc_is_hdmi_signal(pipe->stream->signal) 622 && dc_is_dual_link_signal(pipe_with_clk_src->stream->signal)) 623 return false; 624 625 if (!resource_are_streams_timing_synchronizable( 626 pipe_with_clk_src->stream, pipe->stream)) 627 return false; 628 629 return true; 630 } 631 632 struct clock_source *resource_find_used_clk_src_for_sharing( 633 struct resource_context *res_ctx, 634 struct pipe_ctx *pipe_ctx) 635 { 636 int i; 637 638 for (i = 0; i < MAX_PIPES; i++) { 639 if (is_sharable_clk_src(&res_ctx->pipe_ctx[i], pipe_ctx)) 640 return res_ctx->pipe_ctx[i].clock_source; 641 } 642 643 return NULL; 644 } 645 646 static enum pixel_format convert_pixel_format_to_dalsurface( 647 enum surface_pixel_format surface_pixel_format) 648 { 649 enum pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN; 650 651 switch (surface_pixel_format) { 652 case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS: 653 dal_pixel_format = PIXEL_FORMAT_INDEX8; 654 break; 655 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: 656 dal_pixel_format = PIXEL_FORMAT_RGB565; 657 break; 658 case SURFACE_PIXEL_FORMAT_GRPH_RGB565: 659 dal_pixel_format = PIXEL_FORMAT_RGB565; 660 break; 661 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: 662 dal_pixel_format = PIXEL_FORMAT_ARGB8888; 663 break; 664 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: 665 dal_pixel_format = PIXEL_FORMAT_ARGB8888; 666 break; 667 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: 668 dal_pixel_format = PIXEL_FORMAT_ARGB2101010; 669 break; 670 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: 671 dal_pixel_format = PIXEL_FORMAT_ARGB2101010; 672 break; 673 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS: 674 dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS; 675 break; 676 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: 677 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: 678 dal_pixel_format = PIXEL_FORMAT_FP16; 679 break; 680 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: 681 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: 682 dal_pixel_format = PIXEL_FORMAT_420BPP8; 683 break; 684 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: 685 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: 686 dal_pixel_format = PIXEL_FORMAT_420BPP10; 687 break; 688 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: 689 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: 690 default: 691 dal_pixel_format = PIXEL_FORMAT_UNKNOWN; 692 break; 693 } 694 return dal_pixel_format; 695 } 696 697 static inline void get_vp_scan_direction( 698 enum dc_rotation_angle rotation, 699 bool horizontal_mirror, 700 bool *orthogonal_rotation, 701 bool *flip_vert_scan_dir, 702 bool *flip_horz_scan_dir) 703 { 704 *orthogonal_rotation = false; 705 *flip_vert_scan_dir = false; 706 *flip_horz_scan_dir = false; 707 if (rotation == ROTATION_ANGLE_180) { 708 *flip_vert_scan_dir = true; 709 *flip_horz_scan_dir = true; 710 } else if (rotation == ROTATION_ANGLE_90) { 711 *orthogonal_rotation = true; 712 *flip_horz_scan_dir = true; 713 } else if (rotation == ROTATION_ANGLE_270) { 714 *orthogonal_rotation = true; 715 *flip_vert_scan_dir = true; 716 } 717 718 if (horizontal_mirror) 719 *flip_horz_scan_dir = !*flip_horz_scan_dir; 720 } 721 722 int get_num_mpc_splits(struct pipe_ctx *pipe) 723 { 724 int mpc_split_count = 0; 725 struct pipe_ctx *other_pipe = pipe->bottom_pipe; 726 727 while (other_pipe && other_pipe->plane_state == pipe->plane_state) { 728 mpc_split_count++; 729 other_pipe = other_pipe->bottom_pipe; 730 } 731 other_pipe = pipe->top_pipe; 732 while (other_pipe && other_pipe->plane_state == pipe->plane_state) { 733 mpc_split_count++; 734 other_pipe = other_pipe->top_pipe; 735 } 736 737 return mpc_split_count; 738 } 739 740 int get_num_odm_splits(struct pipe_ctx *pipe) 741 { 742 int odm_split_count = 0; 743 struct pipe_ctx *next_pipe = pipe->next_odm_pipe; 744 while (next_pipe) { 745 odm_split_count++; 746 next_pipe = next_pipe->next_odm_pipe; 747 } 748 pipe = pipe->prev_odm_pipe; 749 while (pipe) { 750 odm_split_count++; 751 pipe = pipe->prev_odm_pipe; 752 } 753 return odm_split_count; 754 } 755 756 static void calculate_split_count_and_index(struct pipe_ctx *pipe_ctx, int *split_count, int *split_idx) 757 { 758 *split_count = get_num_odm_splits(pipe_ctx); 759 *split_idx = 0; 760 if (*split_count == 0) { 761 /*Check for mpc split*/ 762 struct pipe_ctx *split_pipe = pipe_ctx->top_pipe; 763 764 *split_count = get_num_mpc_splits(pipe_ctx); 765 while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) { 766 (*split_idx)++; 767 split_pipe = split_pipe->top_pipe; 768 } 769 770 /* MPO window on right side of ODM split */ 771 if (split_pipe && split_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe) 772 (*split_idx)++; 773 } else { 774 /*Get odm split index*/ 775 struct pipe_ctx *split_pipe = pipe_ctx->prev_odm_pipe; 776 777 while (split_pipe) { 778 (*split_idx)++; 779 split_pipe = split_pipe->prev_odm_pipe; 780 } 781 } 782 } 783 784 /* 785 * This is a preliminary vp size calculation to allow us to check taps support. 786 * The result is completely overridden afterwards. 787 */ 788 static void calculate_viewport_size(struct pipe_ctx *pipe_ctx) 789 { 790 struct scaler_data *data = &pipe_ctx->plane_res.scl_data; 791 792 data->viewport.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz, data->recout.width)); 793 data->viewport.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert, data->recout.height)); 794 data->viewport_c.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz_c, data->recout.width)); 795 data->viewport_c.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert_c, data->recout.height)); 796 if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || 797 pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) { 798 swap(data->viewport.width, data->viewport.height); 799 swap(data->viewport_c.width, data->viewport_c.height); 800 } 801 } 802 803 static void calculate_recout(struct pipe_ctx *pipe_ctx) 804 { 805 const struct dc_plane_state *plane_state = pipe_ctx->plane_state; 806 const struct dc_stream_state *stream = pipe_ctx->stream; 807 struct scaler_data *data = &pipe_ctx->plane_res.scl_data; 808 struct rect surf_clip = plane_state->clip_rect; 809 bool split_tb = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM; 810 int split_count, split_idx; 811 812 calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx); 813 if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) 814 split_idx = 0; 815 816 /* 817 * Only the leftmost ODM pipe should be offset by a nonzero distance 818 */ 819 if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe) { 820 /* MPO window on right side of ODM split */ 821 data->recout.x = stream->dst.x + (surf_clip.x - stream->src.x - stream->src.width/2) * 822 stream->dst.width / stream->src.width; 823 } else if (!pipe_ctx->prev_odm_pipe || split_idx == split_count) { 824 data->recout.x = stream->dst.x; 825 if (stream->src.x < surf_clip.x) 826 data->recout.x += (surf_clip.x - stream->src.x) * stream->dst.width 827 / stream->src.width; 828 } else 829 data->recout.x = 0; 830 831 if (stream->src.x > surf_clip.x) 832 surf_clip.width -= stream->src.x - surf_clip.x; 833 data->recout.width = surf_clip.width * stream->dst.width / stream->src.width; 834 if (data->recout.width + data->recout.x > stream->dst.x + stream->dst.width) 835 data->recout.width = stream->dst.x + stream->dst.width - data->recout.x; 836 837 data->recout.y = stream->dst.y; 838 if (stream->src.y < surf_clip.y) 839 data->recout.y += (surf_clip.y - stream->src.y) * stream->dst.height 840 / stream->src.height; 841 else if (stream->src.y > surf_clip.y) 842 surf_clip.height -= stream->src.y - surf_clip.y; 843 844 data->recout.height = surf_clip.height * stream->dst.height / stream->src.height; 845 if (data->recout.height + data->recout.y > stream->dst.y + stream->dst.height) 846 data->recout.height = stream->dst.y + stream->dst.height - data->recout.y; 847 848 /* Handle h & v split */ 849 if (split_tb) { 850 ASSERT(data->recout.height % 2 == 0); 851 data->recout.height /= 2; 852 } else if (split_count) { 853 if (!pipe_ctx->next_odm_pipe && !pipe_ctx->prev_odm_pipe) { 854 /* extra pixels in the division remainder need to go to pipes after 855 * the extra pixel index minus one(epimo) defined here as: 856 */ 857 int epimo = split_count - data->recout.width % (split_count + 1); 858 859 data->recout.x += (data->recout.width / (split_count + 1)) * split_idx; 860 if (split_idx > epimo) 861 data->recout.x += split_idx - epimo - 1; 862 ASSERT(stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE || data->recout.width % 2 == 0); 863 data->recout.width = data->recout.width / (split_count + 1) + (split_idx > epimo ? 1 : 0); 864 } else { 865 /* odm */ 866 if (split_idx == split_count) { 867 /* rightmost pipe is the remainder recout */ 868 data->recout.width -= data->h_active * split_count - data->recout.x; 869 870 /* ODM combine cases with MPO we can get negative widths */ 871 if (data->recout.width < 0) 872 data->recout.width = 0; 873 874 data->recout.x = 0; 875 } else 876 data->recout.width = data->h_active - data->recout.x; 877 } 878 } 879 } 880 881 static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) 882 { 883 const struct dc_plane_state *plane_state = pipe_ctx->plane_state; 884 const struct dc_stream_state *stream = pipe_ctx->stream; 885 struct rect surf_src = plane_state->src_rect; 886 const int in_w = stream->src.width; 887 const int in_h = stream->src.height; 888 const int out_w = stream->dst.width; 889 const int out_h = stream->dst.height; 890 891 /*Swap surf_src height and width since scaling ratios are in recout rotation*/ 892 if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || 893 pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) 894 swap(surf_src.height, surf_src.width); 895 896 pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction( 897 surf_src.width, 898 plane_state->dst_rect.width); 899 pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_from_fraction( 900 surf_src.height, 901 plane_state->dst_rect.height); 902 903 if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) 904 pipe_ctx->plane_res.scl_data.ratios.horz.value *= 2; 905 else if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) 906 pipe_ctx->plane_res.scl_data.ratios.vert.value *= 2; 907 908 pipe_ctx->plane_res.scl_data.ratios.vert.value = div64_s64( 909 pipe_ctx->plane_res.scl_data.ratios.vert.value * in_h, out_h); 910 pipe_ctx->plane_res.scl_data.ratios.horz.value = div64_s64( 911 pipe_ctx->plane_res.scl_data.ratios.horz.value * in_w, out_w); 912 913 pipe_ctx->plane_res.scl_data.ratios.horz_c = pipe_ctx->plane_res.scl_data.ratios.horz; 914 pipe_ctx->plane_res.scl_data.ratios.vert_c = pipe_ctx->plane_res.scl_data.ratios.vert; 915 916 if (pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP8 917 || pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP10) { 918 pipe_ctx->plane_res.scl_data.ratios.horz_c.value /= 2; 919 pipe_ctx->plane_res.scl_data.ratios.vert_c.value /= 2; 920 } 921 pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_truncate( 922 pipe_ctx->plane_res.scl_data.ratios.horz, 19); 923 pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_truncate( 924 pipe_ctx->plane_res.scl_data.ratios.vert, 19); 925 pipe_ctx->plane_res.scl_data.ratios.horz_c = dc_fixpt_truncate( 926 pipe_ctx->plane_res.scl_data.ratios.horz_c, 19); 927 pipe_ctx->plane_res.scl_data.ratios.vert_c = dc_fixpt_truncate( 928 pipe_ctx->plane_res.scl_data.ratios.vert_c, 19); 929 } 930 931 932 /* 933 * We completely calculate vp offset, size and inits here based entirely on scaling 934 * ratios and recout for pixel perfect pipe combine. 935 */ 936 static void calculate_init_and_vp( 937 bool flip_scan_dir, 938 int recout_offset_within_recout_full, 939 int recout_size, 940 int src_size, 941 int taps, 942 struct fixed31_32 ratio, 943 struct fixed31_32 *init, 944 int *vp_offset, 945 int *vp_size) 946 { 947 struct fixed31_32 temp; 948 int int_part; 949 950 /* 951 * First of the taps starts sampling pixel number <init_int_part> corresponding to recout 952 * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on. 953 * All following calculations are based on this logic. 954 * 955 * Init calculated according to formula: 956 * init = (scaling_ratio + number_of_taps + 1) / 2 957 * init_bot = init + scaling_ratio 958 * to get pixel perfect combine add the fraction from calculating vp offset 959 */ 960 temp = dc_fixpt_mul_int(ratio, recout_offset_within_recout_full); 961 *vp_offset = dc_fixpt_floor(temp); 962 temp.value &= 0xffffffff; 963 *init = dc_fixpt_truncate(dc_fixpt_add(dc_fixpt_div_int( 964 dc_fixpt_add_int(ratio, taps + 1), 2), temp), 19); 965 /* 966 * If viewport has non 0 offset and there are more taps than covered by init then 967 * we should decrease the offset and increase init so we are never sampling 968 * outside of viewport. 969 */ 970 int_part = dc_fixpt_floor(*init); 971 if (int_part < taps) { 972 int_part = taps - int_part; 973 if (int_part > *vp_offset) 974 int_part = *vp_offset; 975 *vp_offset -= int_part; 976 *init = dc_fixpt_add_int(*init, int_part); 977 } 978 /* 979 * If taps are sampling outside of viewport at end of recout and there are more pixels 980 * available in the surface we should increase the viewport size, regardless set vp to 981 * only what is used. 982 */ 983 temp = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_size - 1)); 984 *vp_size = dc_fixpt_floor(temp); 985 if (*vp_size + *vp_offset > src_size) 986 *vp_size = src_size - *vp_offset; 987 988 /* We did all the math assuming we are scanning same direction as display does, 989 * however mirror/rotation changes how vp scans vs how it is offset. If scan direction 990 * is flipped we simply need to calculate offset from the other side of plane. 991 * Note that outside of viewport all scaling hardware works in recout space. 992 */ 993 if (flip_scan_dir) 994 *vp_offset = src_size - *vp_offset - *vp_size; 995 } 996 997 static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx) 998 { 999 const struct dc_plane_state *plane_state = pipe_ctx->plane_state; 1000 const struct dc_stream_state *stream = pipe_ctx->stream; 1001 struct scaler_data *data = &pipe_ctx->plane_res.scl_data; 1002 struct rect src = plane_state->src_rect; 1003 int vpc_div = (data->format == PIXEL_FORMAT_420BPP8 1004 || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; 1005 int split_count, split_idx, ro_lb, ro_tb, recout_full_x, recout_full_y; 1006 bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir; 1007 1008 calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx); 1009 /* 1010 * recout full is what the recout would have been if we didnt clip 1011 * the source plane at all. We only care about left(ro_lb) and top(ro_tb) 1012 * offsets of recout within recout full because those are the directions 1013 * we scan from and therefore the only ones that affect inits. 1014 */ 1015 recout_full_x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x) 1016 * stream->dst.width / stream->src.width; 1017 recout_full_y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y) 1018 * stream->dst.height / stream->src.height; 1019 if (pipe_ctx->prev_odm_pipe && split_idx) 1020 ro_lb = data->h_active * split_idx - recout_full_x; 1021 else if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe) 1022 ro_lb = data->h_active * split_idx - recout_full_x + data->recout.x; 1023 else 1024 ro_lb = data->recout.x - recout_full_x; 1025 ro_tb = data->recout.y - recout_full_y; 1026 ASSERT(ro_lb >= 0 && ro_tb >= 0); 1027 1028 /* 1029 * Work in recout rotation since that requires less transformations 1030 */ 1031 get_vp_scan_direction( 1032 plane_state->rotation, 1033 plane_state->horizontal_mirror, 1034 &orthogonal_rotation, 1035 &flip_vert_scan_dir, 1036 &flip_horz_scan_dir); 1037 1038 if (orthogonal_rotation) { 1039 swap(src.width, src.height); 1040 swap(flip_vert_scan_dir, flip_horz_scan_dir); 1041 } 1042 1043 calculate_init_and_vp( 1044 flip_horz_scan_dir, 1045 ro_lb, 1046 data->recout.width, 1047 src.width, 1048 data->taps.h_taps, 1049 data->ratios.horz, 1050 &data->inits.h, 1051 &data->viewport.x, 1052 &data->viewport.width); 1053 calculate_init_and_vp( 1054 flip_horz_scan_dir, 1055 ro_lb, 1056 data->recout.width, 1057 src.width / vpc_div, 1058 data->taps.h_taps_c, 1059 data->ratios.horz_c, 1060 &data->inits.h_c, 1061 &data->viewport_c.x, 1062 &data->viewport_c.width); 1063 calculate_init_and_vp( 1064 flip_vert_scan_dir, 1065 ro_tb, 1066 data->recout.height, 1067 src.height, 1068 data->taps.v_taps, 1069 data->ratios.vert, 1070 &data->inits.v, 1071 &data->viewport.y, 1072 &data->viewport.height); 1073 calculate_init_and_vp( 1074 flip_vert_scan_dir, 1075 ro_tb, 1076 data->recout.height, 1077 src.height / vpc_div, 1078 data->taps.v_taps_c, 1079 data->ratios.vert_c, 1080 &data->inits.v_c, 1081 &data->viewport_c.y, 1082 &data->viewport_c.height); 1083 if (orthogonal_rotation) { 1084 swap(data->viewport.x, data->viewport.y); 1085 swap(data->viewport.width, data->viewport.height); 1086 swap(data->viewport_c.x, data->viewport_c.y); 1087 swap(data->viewport_c.width, data->viewport_c.height); 1088 } 1089 data->viewport.x += src.x; 1090 data->viewport.y += src.y; 1091 ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0); 1092 data->viewport_c.x += src.x / vpc_div; 1093 data->viewport_c.y += src.y / vpc_div; 1094 } 1095 1096 bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) 1097 { 1098 const struct dc_plane_state *plane_state = pipe_ctx->plane_state; 1099 struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; 1100 bool res = false; 1101 DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); 1102 1103 /* Invalid input */ 1104 if (!plane_state->dst_rect.width || 1105 !plane_state->dst_rect.height || 1106 !plane_state->src_rect.width || 1107 !plane_state->src_rect.height) { 1108 ASSERT(0); 1109 return false; 1110 } 1111 1112 pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface( 1113 pipe_ctx->plane_state->format); 1114 1115 /* Timing borders are part of vactive that we are also supposed to skip in addition 1116 * to any stream dst offset. Since dm logic assumes dst is in addressable 1117 * space we need to add the left and top borders to dst offsets temporarily. 1118 * TODO: fix in DM, stream dst is supposed to be in vactive 1119 */ 1120 pipe_ctx->stream->dst.x += timing->h_border_left; 1121 pipe_ctx->stream->dst.y += timing->v_border_top; 1122 1123 /* Calculate H and V active size */ 1124 pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable + 1125 timing->h_border_left + timing->h_border_right; 1126 pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable + 1127 timing->v_border_top + timing->v_border_bottom; 1128 if (pipe_ctx->next_odm_pipe || pipe_ctx->prev_odm_pipe) { 1129 pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx) + 1; 1130 1131 DC_LOG_SCALER("%s pipe %d: next_odm_pipe:%d prev_odm_pipe:%d\n", 1132 __func__, 1133 pipe_ctx->pipe_idx, 1134 pipe_ctx->next_odm_pipe ? pipe_ctx->next_odm_pipe->pipe_idx : -1, 1135 pipe_ctx->prev_odm_pipe ? pipe_ctx->prev_odm_pipe->pipe_idx : -1); 1136 } /* ODM + windows MPO, where window is on either right or left ODM half */ 1137 else if (pipe_ctx->top_pipe && (pipe_ctx->top_pipe->next_odm_pipe || pipe_ctx->top_pipe->prev_odm_pipe)) { 1138 1139 pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx->top_pipe) + 1; 1140 1141 DC_LOG_SCALER("%s ODM + windows MPO: pipe:%d top_pipe:%d top_pipe->next_odm_pipe:%d top_pipe->prev_odm_pipe:%d\n", 1142 __func__, 1143 pipe_ctx->pipe_idx, 1144 pipe_ctx->top_pipe->pipe_idx, 1145 pipe_ctx->top_pipe->next_odm_pipe ? pipe_ctx->top_pipe->next_odm_pipe->pipe_idx : -1, 1146 pipe_ctx->top_pipe->prev_odm_pipe ? pipe_ctx->top_pipe->prev_odm_pipe->pipe_idx : -1); 1147 } 1148 /* depends on h_active */ 1149 calculate_recout(pipe_ctx); 1150 /* depends on pixel format */ 1151 calculate_scaling_ratios(pipe_ctx); 1152 /* depends on scaling ratios and recout, does not calculate offset yet */ 1153 calculate_viewport_size(pipe_ctx); 1154 1155 if (!pipe_ctx->stream->ctx->dc->config.enable_windowed_mpo_odm) { 1156 /* Stopgap for validation of ODM + MPO on one side of screen case */ 1157 if (pipe_ctx->plane_res.scl_data.viewport.height < 1 || 1158 pipe_ctx->plane_res.scl_data.viewport.width < 1) 1159 return false; 1160 } 1161 1162 /* 1163 * LB calculations depend on vp size, h/v_active and scaling ratios 1164 * Setting line buffer pixel depth to 24bpp yields banding 1165 * on certain displays, such as the Sharp 4k. 36bpp is needed 1166 * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and 1167 * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc 1168 * precision on DCN display engines, but apparently not for DCE, as 1169 * far as testing on DCE-11.2 and DCE-8 showed. Various DCE parts have 1170 * problems: Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth, 1171 * neither do DCE-8 at 4k resolution, or DCE-11.2 (broken identify pixel 1172 * passthrough). Therefore only use 36 bpp on DCN where it is actually needed. 1173 */ 1174 if (plane_state->ctx->dce_version > DCE_VERSION_MAX) 1175 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP; 1176 else 1177 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP; 1178 1179 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha; 1180 1181 if (pipe_ctx->plane_res.xfm != NULL) 1182 res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( 1183 pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); 1184 1185 if (pipe_ctx->plane_res.dpp != NULL) 1186 res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps( 1187 pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); 1188 1189 1190 if (!res) { 1191 /* Try 24 bpp linebuffer */ 1192 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP; 1193 1194 if (pipe_ctx->plane_res.xfm != NULL) 1195 res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( 1196 pipe_ctx->plane_res.xfm, 1197 &pipe_ctx->plane_res.scl_data, 1198 &plane_state->scaling_quality); 1199 1200 if (pipe_ctx->plane_res.dpp != NULL) 1201 res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps( 1202 pipe_ctx->plane_res.dpp, 1203 &pipe_ctx->plane_res.scl_data, 1204 &plane_state->scaling_quality); 1205 } 1206 1207 /* 1208 * Depends on recout, scaling ratios, h_active and taps 1209 * May need to re-check lb size after this in some obscure scenario 1210 */ 1211 if (res) 1212 calculate_inits_and_viewports(pipe_ctx); 1213 1214 /* 1215 * Handle side by side and top bottom 3d recout offsets after vp calculation 1216 * since 3d is special and needs to calculate vp as if there is no recout offset 1217 * This may break with rotation, good thing we aren't mixing hw rotation and 3d 1218 */ 1219 if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == plane_state) { 1220 ASSERT(plane_state->rotation == ROTATION_ANGLE_0 || 1221 (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM && 1222 pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE)); 1223 if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) 1224 pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height; 1225 else if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) 1226 pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width; 1227 } 1228 1229 if (!pipe_ctx->stream->ctx->dc->config.enable_windowed_mpo_odm) { 1230 if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE || 1231 pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE) 1232 res = false; 1233 } else { 1234 /* Clamp minimum viewport size */ 1235 if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE) 1236 pipe_ctx->plane_res.scl_data.viewport.height = MIN_VIEWPORT_SIZE; 1237 if (pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE) 1238 pipe_ctx->plane_res.scl_data.viewport.width = MIN_VIEWPORT_SIZE; 1239 } 1240 1241 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" 1242 "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", 1243 __func__, 1244 pipe_ctx->pipe_idx, 1245 pipe_ctx->plane_res.scl_data.viewport.height, 1246 pipe_ctx->plane_res.scl_data.viewport.width, 1247 pipe_ctx->plane_res.scl_data.viewport.x, 1248 pipe_ctx->plane_res.scl_data.viewport.y, 1249 pipe_ctx->plane_res.scl_data.recout.height, 1250 pipe_ctx->plane_res.scl_data.recout.width, 1251 pipe_ctx->plane_res.scl_data.recout.x, 1252 pipe_ctx->plane_res.scl_data.recout.y, 1253 pipe_ctx->plane_res.scl_data.h_active, 1254 pipe_ctx->plane_res.scl_data.v_active, 1255 plane_state->src_rect.height, 1256 plane_state->src_rect.width, 1257 plane_state->src_rect.x, 1258 plane_state->src_rect.y, 1259 plane_state->dst_rect.height, 1260 plane_state->dst_rect.width, 1261 plane_state->dst_rect.x, 1262 plane_state->dst_rect.y, 1263 plane_state->clip_rect.height, 1264 plane_state->clip_rect.width, 1265 plane_state->clip_rect.x, 1266 plane_state->clip_rect.y); 1267 1268 pipe_ctx->stream->dst.x -= timing->h_border_left; 1269 pipe_ctx->stream->dst.y -= timing->v_border_top; 1270 1271 return res; 1272 } 1273 1274 1275 enum dc_status resource_build_scaling_params_for_context( 1276 const struct dc *dc, 1277 struct dc_state *context) 1278 { 1279 int i; 1280 1281 for (i = 0; i < MAX_PIPES; i++) { 1282 if (context->res_ctx.pipe_ctx[i].plane_state != NULL && 1283 context->res_ctx.pipe_ctx[i].stream != NULL) 1284 if (!resource_build_scaling_params(&context->res_ctx.pipe_ctx[i])) 1285 return DC_FAIL_SCALING; 1286 } 1287 1288 return DC_OK; 1289 } 1290 1291 struct pipe_ctx *find_idle_secondary_pipe( 1292 struct resource_context *res_ctx, 1293 const struct resource_pool *pool, 1294 const struct pipe_ctx *primary_pipe) 1295 { 1296 int i; 1297 struct pipe_ctx *secondary_pipe = NULL; 1298 1299 /* 1300 * We add a preferred pipe mapping to avoid the chance that 1301 * MPCCs already in use will need to be reassigned to other trees. 1302 * For example, if we went with the strict, assign backwards logic: 1303 * 1304 * (State 1) 1305 * Display A on, no surface, top pipe = 0 1306 * Display B on, no surface, top pipe = 1 1307 * 1308 * (State 2) 1309 * Display A on, no surface, top pipe = 0 1310 * Display B on, surface enable, top pipe = 1, bottom pipe = 5 1311 * 1312 * (State 3) 1313 * Display A on, surface enable, top pipe = 0, bottom pipe = 5 1314 * Display B on, surface enable, top pipe = 1, bottom pipe = 4 1315 * 1316 * The state 2->3 transition requires remapping MPCC 5 from display B 1317 * to display A. 1318 * 1319 * However, with the preferred pipe logic, state 2 would look like: 1320 * 1321 * (State 2) 1322 * Display A on, no surface, top pipe = 0 1323 * Display B on, surface enable, top pipe = 1, bottom pipe = 4 1324 * 1325 * This would then cause 2->3 to not require remapping any MPCCs. 1326 */ 1327 if (primary_pipe) { 1328 int preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx; 1329 if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { 1330 secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; 1331 secondary_pipe->pipe_idx = preferred_pipe_idx; 1332 } 1333 } 1334 1335 /* 1336 * search backwards for the second pipe to keep pipe 1337 * assignment more consistent 1338 */ 1339 if (!secondary_pipe) 1340 for (i = pool->pipe_count - 1; i >= 0; i--) { 1341 if (res_ctx->pipe_ctx[i].stream == NULL) { 1342 secondary_pipe = &res_ctx->pipe_ctx[i]; 1343 secondary_pipe->pipe_idx = i; 1344 break; 1345 } 1346 } 1347 1348 return secondary_pipe; 1349 } 1350 1351 struct pipe_ctx *resource_get_head_pipe_for_stream( 1352 struct resource_context *res_ctx, 1353 struct dc_stream_state *stream) 1354 { 1355 int i; 1356 1357 for (i = 0; i < MAX_PIPES; i++) { 1358 if (res_ctx->pipe_ctx[i].stream == stream 1359 && !res_ctx->pipe_ctx[i].top_pipe 1360 && !res_ctx->pipe_ctx[i].prev_odm_pipe) 1361 return &res_ctx->pipe_ctx[i]; 1362 } 1363 return NULL; 1364 } 1365 1366 static struct pipe_ctx *resource_get_tail_pipe( 1367 struct resource_context *res_ctx, 1368 struct pipe_ctx *head_pipe) 1369 { 1370 struct pipe_ctx *tail_pipe; 1371 1372 tail_pipe = head_pipe->bottom_pipe; 1373 1374 while (tail_pipe) { 1375 head_pipe = tail_pipe; 1376 tail_pipe = tail_pipe->bottom_pipe; 1377 } 1378 1379 return head_pipe; 1380 } 1381 1382 /* 1383 * A free_pipe for a stream is defined here as a pipe 1384 * that has no surface attached yet 1385 */ 1386 static struct pipe_ctx *acquire_free_pipe_for_head( 1387 struct dc_state *context, 1388 const struct resource_pool *pool, 1389 struct pipe_ctx *head_pipe) 1390 { 1391 int i; 1392 struct resource_context *res_ctx = &context->res_ctx; 1393 1394 if (!head_pipe->plane_state) 1395 return head_pipe; 1396 1397 /* Re-use pipe already acquired for this stream if available*/ 1398 for (i = pool->pipe_count - 1; i >= 0; i--) { 1399 if (res_ctx->pipe_ctx[i].stream == head_pipe->stream && 1400 !res_ctx->pipe_ctx[i].plane_state) { 1401 return &res_ctx->pipe_ctx[i]; 1402 } 1403 } 1404 1405 /* 1406 * At this point we have no re-useable pipe for this stream and we need 1407 * to acquire an idle one to satisfy the request 1408 */ 1409 1410 if (!pool->funcs->acquire_idle_pipe_for_layer) { 1411 if (!pool->funcs->acquire_idle_pipe_for_head_pipe_in_layer) 1412 return NULL; 1413 else 1414 return pool->funcs->acquire_idle_pipe_for_head_pipe_in_layer(context, pool, head_pipe->stream, head_pipe); 1415 } 1416 1417 return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream); 1418 } 1419 1420 static int acquire_first_split_pipe( 1421 struct resource_context *res_ctx, 1422 const struct resource_pool *pool, 1423 struct dc_stream_state *stream) 1424 { 1425 int i; 1426 1427 for (i = 0; i < pool->pipe_count; i++) { 1428 struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i]; 1429 1430 if (split_pipe->top_pipe && 1431 split_pipe->top_pipe->plane_state == split_pipe->plane_state) { 1432 split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe; 1433 if (split_pipe->bottom_pipe) 1434 split_pipe->bottom_pipe->top_pipe = split_pipe->top_pipe; 1435 1436 if (split_pipe->top_pipe->plane_state) 1437 resource_build_scaling_params(split_pipe->top_pipe); 1438 1439 memset(split_pipe, 0, sizeof(*split_pipe)); 1440 split_pipe->stream_res.tg = pool->timing_generators[i]; 1441 split_pipe->plane_res.hubp = pool->hubps[i]; 1442 split_pipe->plane_res.ipp = pool->ipps[i]; 1443 split_pipe->plane_res.dpp = pool->dpps[i]; 1444 split_pipe->stream_res.opp = pool->opps[i]; 1445 split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst; 1446 split_pipe->pipe_idx = i; 1447 1448 split_pipe->stream = stream; 1449 return i; 1450 } else if (split_pipe->prev_odm_pipe && 1451 split_pipe->prev_odm_pipe->plane_state == split_pipe->plane_state) { 1452 split_pipe->prev_odm_pipe->next_odm_pipe = split_pipe->next_odm_pipe; 1453 if (split_pipe->next_odm_pipe) 1454 split_pipe->next_odm_pipe->prev_odm_pipe = split_pipe->prev_odm_pipe; 1455 1456 if (split_pipe->prev_odm_pipe->plane_state) 1457 resource_build_scaling_params(split_pipe->prev_odm_pipe); 1458 1459 memset(split_pipe, 0, sizeof(*split_pipe)); 1460 split_pipe->stream_res.tg = pool->timing_generators[i]; 1461 split_pipe->plane_res.hubp = pool->hubps[i]; 1462 split_pipe->plane_res.ipp = pool->ipps[i]; 1463 split_pipe->plane_res.dpp = pool->dpps[i]; 1464 split_pipe->stream_res.opp = pool->opps[i]; 1465 split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst; 1466 split_pipe->pipe_idx = i; 1467 1468 split_pipe->stream = stream; 1469 return i; 1470 } 1471 } 1472 return -1; 1473 } 1474 1475 bool dc_add_plane_to_context( 1476 const struct dc *dc, 1477 struct dc_stream_state *stream, 1478 struct dc_plane_state *plane_state, 1479 struct dc_state *context) 1480 { 1481 int i; 1482 struct resource_pool *pool = dc->res_pool; 1483 struct pipe_ctx *head_pipe, *tail_pipe, *free_pipe; 1484 struct dc_stream_status *stream_status = NULL; 1485 struct pipe_ctx *prev_right_head = NULL; 1486 struct pipe_ctx *free_right_pipe = NULL; 1487 struct pipe_ctx *prev_left_head = NULL; 1488 1489 DC_LOGGER_INIT(stream->ctx->logger); 1490 for (i = 0; i < context->stream_count; i++) 1491 if (context->streams[i] == stream) { 1492 stream_status = &context->stream_status[i]; 1493 break; 1494 } 1495 if (stream_status == NULL) { 1496 dm_error("Existing stream not found; failed to attach surface!\n"); 1497 return false; 1498 } 1499 1500 1501 if (stream_status->plane_count == MAX_SURFACE_NUM) { 1502 dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n", 1503 plane_state, MAX_SURFACE_NUM); 1504 return false; 1505 } 1506 1507 head_pipe = resource_get_head_pipe_for_stream(&context->res_ctx, stream); 1508 1509 if (!head_pipe) { 1510 dm_error("Head pipe not found for stream_state %p !\n", stream); 1511 return false; 1512 } 1513 1514 /* retain new surface, but only once per stream */ 1515 dc_plane_state_retain(plane_state); 1516 1517 while (head_pipe) { 1518 free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe); 1519 1520 if (!free_pipe) { 1521 int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); 1522 if (pipe_idx >= 0) 1523 free_pipe = &context->res_ctx.pipe_ctx[pipe_idx]; 1524 } 1525 1526 if (!free_pipe) { 1527 dc_plane_state_release(plane_state); 1528 return false; 1529 } 1530 1531 free_pipe->plane_state = plane_state; 1532 1533 if (head_pipe != free_pipe) { 1534 tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe); 1535 ASSERT(tail_pipe); 1536 1537 /* ODM + window MPO, where MPO window is on right half only */ 1538 if (free_pipe->plane_state && 1539 (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2) && 1540 tail_pipe->next_odm_pipe) { 1541 1542 /* For ODM + window MPO, in 3 plane case, if we already have a MPO window on 1543 * the right side, then we will invalidate a 2nd one on the right side 1544 */ 1545 if (head_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) { 1546 dc_plane_state_release(plane_state); 1547 return false; 1548 } 1549 1550 DC_LOG_SCALER("%s - ODM + window MPO(right). free_pipe:%d tail_pipe->next_odm_pipe:%d\n", 1551 __func__, 1552 free_pipe->pipe_idx, 1553 tail_pipe->next_odm_pipe ? tail_pipe->next_odm_pipe->pipe_idx : -1); 1554 1555 /* 1556 * We want to avoid the case where the right side already has a pipe assigned to 1557 * it and is different from free_pipe ( which would cause trigger a pipe 1558 * reallocation ). 1559 * Check the old context to see if the right side already has a pipe allocated 1560 * - If not, continue to use free_pipe 1561 * - If the right side already has a pipe, use that pipe instead if its available 1562 */ 1563 1564 /* 1565 * We also want to avoid the case where with three plane ( 2 MPO videos ), we have 1566 * both videos on the left side so one of the videos is invalidated. Then we 1567 * move the invalidated video back to the right side. If the order of the plane 1568 * states is such that the right MPO plane is processed first, the free pipe 1569 * selected by the head will be the left MPO pipe. But since there was no right 1570 * MPO pipe, it will assign the free pipe to the right MPO pipe instead and 1571 * a pipe reallocation will occur. 1572 * Check the old context to see if the left side already has a pipe allocated 1573 * - If not, continue to use free_pipe 1574 * - If the left side is already using this pipe, then pick another pipe for right 1575 */ 1576 1577 prev_right_head = &dc->current_state->res_ctx.pipe_ctx[tail_pipe->next_odm_pipe->pipe_idx]; 1578 if ((prev_right_head->bottom_pipe) && 1579 (free_pipe->pipe_idx != prev_right_head->bottom_pipe->pipe_idx)) { 1580 free_right_pipe = acquire_free_pipe_for_head(context, pool, tail_pipe->next_odm_pipe); 1581 } else { 1582 prev_left_head = &dc->current_state->res_ctx.pipe_ctx[head_pipe->pipe_idx]; 1583 if ((prev_left_head->bottom_pipe) && 1584 (free_pipe->pipe_idx == prev_left_head->bottom_pipe->pipe_idx)) { 1585 free_right_pipe = acquire_free_pipe_for_head(context, pool, head_pipe); 1586 } 1587 } 1588 1589 if (free_right_pipe) { 1590 free_pipe->stream = NULL; 1591 memset(&free_pipe->stream_res, 0, sizeof(struct stream_resource)); 1592 memset(&free_pipe->plane_res, 0, sizeof(struct plane_resource)); 1593 free_pipe->plane_state = NULL; 1594 free_pipe->pipe_idx = 0; 1595 free_right_pipe->plane_state = plane_state; 1596 free_pipe = free_right_pipe; 1597 } 1598 1599 free_pipe->stream_res.tg = tail_pipe->next_odm_pipe->stream_res.tg; 1600 free_pipe->stream_res.abm = tail_pipe->next_odm_pipe->stream_res.abm; 1601 free_pipe->stream_res.opp = tail_pipe->next_odm_pipe->stream_res.opp; 1602 free_pipe->stream_res.stream_enc = tail_pipe->next_odm_pipe->stream_res.stream_enc; 1603 free_pipe->stream_res.audio = tail_pipe->next_odm_pipe->stream_res.audio; 1604 free_pipe->clock_source = tail_pipe->next_odm_pipe->clock_source; 1605 1606 free_pipe->top_pipe = tail_pipe->next_odm_pipe; 1607 tail_pipe->next_odm_pipe->bottom_pipe = free_pipe; 1608 } else if (free_pipe->plane_state && 1609 (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2) 1610 && head_pipe->next_odm_pipe) { 1611 1612 /* For ODM + window MPO, support 3 plane ( 2 MPO ) case. 1613 * Here we have a desktop ODM + left window MPO and a new MPO window appears 1614 * on the right side only. It fails the first case, because tail_pipe is the 1615 * left window MPO, so it has no next_odm_pipe. So in this scenario, we check 1616 * for head_pipe->next_odm_pipe instead 1617 */ 1618 DC_LOG_SCALER("%s - ODM + win MPO (left) + win MPO (right). free_pipe:%d head_pipe->next_odm:%d\n", 1619 __func__, 1620 free_pipe->pipe_idx, 1621 head_pipe->next_odm_pipe ? head_pipe->next_odm_pipe->pipe_idx : -1); 1622 1623 /* 1624 * We want to avoid the case where the right side already has a pipe assigned to 1625 * it and is different from free_pipe ( which would cause trigger a pipe 1626 * reallocation ). 1627 * Check the old context to see if the right side already has a pipe allocated 1628 * - If not, continue to use free_pipe 1629 * - If the right side already has a pipe, use that pipe instead if its available 1630 */ 1631 prev_right_head = &dc->current_state->res_ctx.pipe_ctx[head_pipe->next_odm_pipe->pipe_idx]; 1632 if ((prev_right_head->bottom_pipe) && 1633 (free_pipe->pipe_idx != prev_right_head->bottom_pipe->pipe_idx)) { 1634 free_right_pipe = acquire_free_pipe_for_head(context, pool, head_pipe->next_odm_pipe); 1635 if (free_right_pipe) { 1636 free_pipe->stream = NULL; 1637 memset(&free_pipe->stream_res, 0, sizeof(struct stream_resource)); 1638 memset(&free_pipe->plane_res, 0, sizeof(struct plane_resource)); 1639 free_pipe->plane_state = NULL; 1640 free_pipe->pipe_idx = 0; 1641 free_right_pipe->plane_state = plane_state; 1642 free_pipe = free_right_pipe; 1643 } 1644 } 1645 1646 free_pipe->stream_res.tg = head_pipe->next_odm_pipe->stream_res.tg; 1647 free_pipe->stream_res.abm = head_pipe->next_odm_pipe->stream_res.abm; 1648 free_pipe->stream_res.opp = head_pipe->next_odm_pipe->stream_res.opp; 1649 free_pipe->stream_res.stream_enc = head_pipe->next_odm_pipe->stream_res.stream_enc; 1650 free_pipe->stream_res.audio = head_pipe->next_odm_pipe->stream_res.audio; 1651 free_pipe->clock_source = head_pipe->next_odm_pipe->clock_source; 1652 1653 free_pipe->top_pipe = head_pipe->next_odm_pipe; 1654 head_pipe->next_odm_pipe->bottom_pipe = free_pipe; 1655 } else { 1656 1657 /* For ODM + window MPO, in 3 plane case, if we already have a MPO window on 1658 * the left side, then we will invalidate a 2nd one on the left side 1659 */ 1660 if (head_pipe->next_odm_pipe && tail_pipe->top_pipe) { 1661 dc_plane_state_release(plane_state); 1662 return false; 1663 } 1664 1665 free_pipe->stream_res.tg = tail_pipe->stream_res.tg; 1666 free_pipe->stream_res.abm = tail_pipe->stream_res.abm; 1667 free_pipe->stream_res.opp = tail_pipe->stream_res.opp; 1668 free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc; 1669 free_pipe->stream_res.audio = tail_pipe->stream_res.audio; 1670 free_pipe->clock_source = tail_pipe->clock_source; 1671 1672 free_pipe->top_pipe = tail_pipe; 1673 tail_pipe->bottom_pipe = free_pipe; 1674 1675 /* Connect MPO pipes together if MPO window is in the centre */ 1676 if (!(free_pipe->plane_state && 1677 (free_pipe->plane_state->clip_rect.x + free_pipe->plane_state->clip_rect.width <= 1678 free_pipe->stream->src.x + free_pipe->stream->src.width/2))) { 1679 if (!free_pipe->next_odm_pipe && 1680 tail_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) { 1681 free_pipe->next_odm_pipe = tail_pipe->next_odm_pipe->bottom_pipe; 1682 tail_pipe->next_odm_pipe->bottom_pipe->prev_odm_pipe = free_pipe; 1683 } 1684 if (!free_pipe->prev_odm_pipe && 1685 tail_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe->bottom_pipe) { 1686 free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe; 1687 tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_pipe; 1688 } 1689 } 1690 } 1691 } 1692 1693 /* ODM + window MPO, where MPO window is on left half only */ 1694 if (free_pipe->plane_state && 1695 (free_pipe->plane_state->clip_rect.x + free_pipe->plane_state->clip_rect.width <= 1696 free_pipe->stream->src.x + free_pipe->stream->src.width/2)) { 1697 DC_LOG_SCALER("%s - ODM + window MPO(left). free_pipe:%d\n", 1698 __func__, 1699 free_pipe->pipe_idx); 1700 break; 1701 } 1702 /* ODM + window MPO, where MPO window is on right half only */ 1703 if (free_pipe->plane_state && 1704 (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2)) { 1705 DC_LOG_SCALER("%s - ODM + window MPO(right). free_pipe:%d\n", 1706 __func__, 1707 free_pipe->pipe_idx); 1708 break; 1709 } 1710 1711 head_pipe = head_pipe->next_odm_pipe; 1712 } 1713 /* assign new surfaces*/ 1714 stream_status->plane_states[stream_status->plane_count] = plane_state; 1715 1716 stream_status->plane_count++; 1717 1718 return true; 1719 } 1720 1721 bool dc_remove_plane_from_context( 1722 const struct dc *dc, 1723 struct dc_stream_state *stream, 1724 struct dc_plane_state *plane_state, 1725 struct dc_state *context) 1726 { 1727 int i; 1728 struct dc_stream_status *stream_status = NULL; 1729 struct resource_pool *pool = dc->res_pool; 1730 1731 if (!plane_state) 1732 return true; 1733 1734 for (i = 0; i < context->stream_count; i++) 1735 if (context->streams[i] == stream) { 1736 stream_status = &context->stream_status[i]; 1737 break; 1738 } 1739 1740 if (stream_status == NULL) { 1741 dm_error("Existing stream not found; failed to remove plane.\n"); 1742 return false; 1743 } 1744 1745 /* release pipe for plane*/ 1746 for (i = pool->pipe_count - 1; i >= 0; i--) { 1747 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1748 1749 if (pipe_ctx->plane_state == plane_state) { 1750 if (pipe_ctx->top_pipe) 1751 pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe; 1752 1753 /* Second condition is to avoid setting NULL to top pipe 1754 * of tail pipe making it look like head pipe in subsequent 1755 * deletes 1756 */ 1757 if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe) 1758 pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe; 1759 1760 /* 1761 * For head pipe detach surfaces from pipe for tail 1762 * pipe just zero it out 1763 */ 1764 if (!pipe_ctx->top_pipe) 1765 pipe_ctx->plane_state = NULL; 1766 else 1767 memset(pipe_ctx, 0, sizeof(*pipe_ctx)); 1768 } 1769 } 1770 1771 1772 for (i = 0; i < stream_status->plane_count; i++) { 1773 if (stream_status->plane_states[i] == plane_state) { 1774 dc_plane_state_release(stream_status->plane_states[i]); 1775 break; 1776 } 1777 } 1778 1779 if (i == stream_status->plane_count) { 1780 dm_error("Existing plane_state not found; failed to detach it!\n"); 1781 return false; 1782 } 1783 1784 stream_status->plane_count--; 1785 1786 /* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */ 1787 for (; i < stream_status->plane_count; i++) 1788 stream_status->plane_states[i] = stream_status->plane_states[i + 1]; 1789 1790 stream_status->plane_states[stream_status->plane_count] = NULL; 1791 1792 return true; 1793 } 1794 1795 /** 1796 * dc_rem_all_planes_for_stream - Remove planes attached to the target stream. 1797 * 1798 * @dc: Current dc state. 1799 * @stream: Target stream, which we want to remove the attached plans. 1800 * @context: New context. 1801 * 1802 * Return: 1803 * Return true if DC was able to remove all planes from the target 1804 * stream, otherwise, return false. 1805 */ 1806 bool dc_rem_all_planes_for_stream( 1807 const struct dc *dc, 1808 struct dc_stream_state *stream, 1809 struct dc_state *context) 1810 { 1811 int i, old_plane_count; 1812 struct dc_stream_status *stream_status = NULL; 1813 struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 }; 1814 1815 for (i = 0; i < context->stream_count; i++) 1816 if (context->streams[i] == stream) { 1817 stream_status = &context->stream_status[i]; 1818 break; 1819 } 1820 1821 if (stream_status == NULL) { 1822 dm_error("Existing stream %p not found!\n", stream); 1823 return false; 1824 } 1825 1826 old_plane_count = stream_status->plane_count; 1827 1828 for (i = 0; i < old_plane_count; i++) 1829 del_planes[i] = stream_status->plane_states[i]; 1830 1831 for (i = 0; i < old_plane_count; i++) 1832 if (!dc_remove_plane_from_context(dc, stream, del_planes[i], context)) 1833 return false; 1834 1835 return true; 1836 } 1837 1838 static bool add_all_planes_for_stream( 1839 const struct dc *dc, 1840 struct dc_stream_state *stream, 1841 const struct dc_validation_set set[], 1842 int set_count, 1843 struct dc_state *context) 1844 { 1845 int i, j; 1846 1847 for (i = 0; i < set_count; i++) 1848 if (set[i].stream == stream) 1849 break; 1850 1851 if (i == set_count) { 1852 dm_error("Stream %p not found in set!\n", stream); 1853 return false; 1854 } 1855 1856 for (j = 0; j < set[i].plane_count; j++) 1857 if (!dc_add_plane_to_context(dc, stream, set[i].plane_states[j], context)) 1858 return false; 1859 1860 return true; 1861 } 1862 1863 bool dc_add_all_planes_for_stream( 1864 const struct dc *dc, 1865 struct dc_stream_state *stream, 1866 struct dc_plane_state * const *plane_states, 1867 int plane_count, 1868 struct dc_state *context) 1869 { 1870 struct dc_validation_set set; 1871 int i; 1872 1873 set.stream = stream; 1874 set.plane_count = plane_count; 1875 1876 for (i = 0; i < plane_count; i++) 1877 set.plane_states[i] = plane_states[i]; 1878 1879 return add_all_planes_for_stream(dc, stream, &set, 1, context); 1880 } 1881 1882 bool dc_is_timing_changed(struct dc_stream_state *cur_stream, 1883 struct dc_stream_state *new_stream) 1884 { 1885 if (cur_stream == NULL) 1886 return true; 1887 1888 /* If output color space is changed, need to reprogram info frames */ 1889 if (cur_stream->output_color_space != new_stream->output_color_space) 1890 return true; 1891 1892 return memcmp( 1893 &cur_stream->timing, 1894 &new_stream->timing, 1895 sizeof(struct dc_crtc_timing)) != 0; 1896 } 1897 1898 static bool are_stream_backends_same( 1899 struct dc_stream_state *stream_a, struct dc_stream_state *stream_b) 1900 { 1901 if (stream_a == stream_b) 1902 return true; 1903 1904 if (stream_a == NULL || stream_b == NULL) 1905 return false; 1906 1907 if (dc_is_timing_changed(stream_a, stream_b)) 1908 return false; 1909 1910 if (stream_a->signal != stream_b->signal) 1911 return false; 1912 1913 if (stream_a->dpms_off != stream_b->dpms_off) 1914 return false; 1915 1916 return true; 1917 } 1918 1919 /* 1920 * dc_is_stream_unchanged() - Compare two stream states for equivalence. 1921 * 1922 * Checks if there a difference between the two states 1923 * that would require a mode change. 1924 * 1925 * Does not compare cursor position or attributes. 1926 */ 1927 bool dc_is_stream_unchanged( 1928 struct dc_stream_state *old_stream, struct dc_stream_state *stream) 1929 { 1930 1931 if (!are_stream_backends_same(old_stream, stream)) 1932 return false; 1933 1934 if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param) 1935 return false; 1936 1937 /*compare audio info*/ 1938 if (memcmp(&old_stream->audio_info, &stream->audio_info, sizeof(stream->audio_info)) != 0) 1939 return false; 1940 1941 return true; 1942 } 1943 1944 /* 1945 * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams. 1946 */ 1947 bool dc_is_stream_scaling_unchanged(struct dc_stream_state *old_stream, 1948 struct dc_stream_state *stream) 1949 { 1950 if (old_stream == stream) 1951 return true; 1952 1953 if (old_stream == NULL || stream == NULL) 1954 return false; 1955 1956 if (memcmp(&old_stream->src, 1957 &stream->src, 1958 sizeof(struct rect)) != 0) 1959 return false; 1960 1961 if (memcmp(&old_stream->dst, 1962 &stream->dst, 1963 sizeof(struct rect)) != 0) 1964 return false; 1965 1966 return true; 1967 } 1968 1969 static void update_stream_engine_usage( 1970 struct resource_context *res_ctx, 1971 const struct resource_pool *pool, 1972 struct stream_encoder *stream_enc, 1973 bool acquired) 1974 { 1975 int i; 1976 1977 for (i = 0; i < pool->stream_enc_count; i++) { 1978 if (pool->stream_enc[i] == stream_enc) 1979 res_ctx->is_stream_enc_acquired[i] = acquired; 1980 } 1981 } 1982 1983 static void update_hpo_dp_stream_engine_usage( 1984 struct resource_context *res_ctx, 1985 const struct resource_pool *pool, 1986 struct hpo_dp_stream_encoder *hpo_dp_stream_enc, 1987 bool acquired) 1988 { 1989 int i; 1990 1991 for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { 1992 if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc) 1993 res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired; 1994 } 1995 } 1996 1997 static inline int find_acquired_hpo_dp_link_enc_for_link( 1998 const struct resource_context *res_ctx, 1999 const struct dc_link *link) 2000 { 2001 int i; 2002 2003 for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++) 2004 if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 && 2005 res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index) 2006 return i; 2007 2008 return -1; 2009 } 2010 2011 static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx, 2012 const struct resource_pool *pool) 2013 { 2014 int i; 2015 2016 for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++) 2017 if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0) 2018 break; 2019 2020 return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) && 2021 i < pool->hpo_dp_link_enc_count) ? i : -1; 2022 } 2023 2024 static inline void acquire_hpo_dp_link_enc( 2025 struct resource_context *res_ctx, 2026 unsigned int link_index, 2027 int enc_index) 2028 { 2029 res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index; 2030 res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1; 2031 } 2032 2033 static inline void retain_hpo_dp_link_enc( 2034 struct resource_context *res_ctx, 2035 int enc_index) 2036 { 2037 res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++; 2038 } 2039 2040 static inline void release_hpo_dp_link_enc( 2041 struct resource_context *res_ctx, 2042 int enc_index) 2043 { 2044 ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0); 2045 res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--; 2046 } 2047 2048 static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx, 2049 const struct resource_pool *pool, 2050 struct pipe_ctx *pipe_ctx, 2051 struct dc_stream_state *stream) 2052 { 2053 int enc_index; 2054 2055 enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); 2056 2057 if (enc_index >= 0) { 2058 retain_hpo_dp_link_enc(res_ctx, enc_index); 2059 } else { 2060 enc_index = find_free_hpo_dp_link_enc(res_ctx, pool); 2061 if (enc_index >= 0) 2062 acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index); 2063 } 2064 2065 if (enc_index >= 0) 2066 pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index]; 2067 2068 return pipe_ctx->link_res.hpo_dp_link_enc != NULL; 2069 } 2070 2071 static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx, 2072 struct pipe_ctx *pipe_ctx, 2073 struct dc_stream_state *stream) 2074 { 2075 int enc_index; 2076 2077 enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); 2078 2079 if (enc_index >= 0) { 2080 release_hpo_dp_link_enc(res_ctx, enc_index); 2081 pipe_ctx->link_res.hpo_dp_link_enc = NULL; 2082 } 2083 } 2084 2085 /* TODO: release audio object */ 2086 void update_audio_usage( 2087 struct resource_context *res_ctx, 2088 const struct resource_pool *pool, 2089 struct audio *audio, 2090 bool acquired) 2091 { 2092 int i; 2093 for (i = 0; i < pool->audio_count; i++) { 2094 if (pool->audios[i] == audio) 2095 res_ctx->is_audio_acquired[i] = acquired; 2096 } 2097 } 2098 2099 static int acquire_first_free_pipe( 2100 struct resource_context *res_ctx, 2101 const struct resource_pool *pool, 2102 struct dc_stream_state *stream) 2103 { 2104 int i; 2105 2106 for (i = 0; i < pool->pipe_count; i++) { 2107 if (!res_ctx->pipe_ctx[i].stream) { 2108 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; 2109 2110 pipe_ctx->stream_res.tg = pool->timing_generators[i]; 2111 pipe_ctx->plane_res.mi = pool->mis[i]; 2112 pipe_ctx->plane_res.hubp = pool->hubps[i]; 2113 pipe_ctx->plane_res.ipp = pool->ipps[i]; 2114 pipe_ctx->plane_res.xfm = pool->transforms[i]; 2115 pipe_ctx->plane_res.dpp = pool->dpps[i]; 2116 pipe_ctx->stream_res.opp = pool->opps[i]; 2117 if (pool->dpps[i]) 2118 pipe_ctx->plane_res.mpcc_inst = pool->dpps[i]->inst; 2119 pipe_ctx->pipe_idx = i; 2120 2121 if (i >= pool->timing_generator_count) { 2122 int tg_inst = pool->timing_generator_count - 1; 2123 2124 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; 2125 pipe_ctx->stream_res.opp = pool->opps[tg_inst]; 2126 } 2127 2128 pipe_ctx->stream = stream; 2129 return i; 2130 } 2131 } 2132 return -1; 2133 } 2134 2135 static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for_link( 2136 struct resource_context *res_ctx, 2137 const struct resource_pool *pool, 2138 struct dc_stream_state *stream) 2139 { 2140 int i; 2141 2142 for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { 2143 if (!res_ctx->is_hpo_dp_stream_enc_acquired[i] && 2144 pool->hpo_dp_stream_enc[i]) { 2145 2146 return pool->hpo_dp_stream_enc[i]; 2147 } 2148 } 2149 2150 return NULL; 2151 } 2152 2153 static struct audio *find_first_free_audio( 2154 struct resource_context *res_ctx, 2155 const struct resource_pool *pool, 2156 enum engine_id id, 2157 enum dce_version dc_version) 2158 { 2159 int i, available_audio_count; 2160 2161 available_audio_count = pool->audio_count; 2162 2163 for (i = 0; i < available_audio_count; i++) { 2164 if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) { 2165 /*we have enough audio endpoint, find the matching inst*/ 2166 if (id != i) 2167 continue; 2168 return pool->audios[i]; 2169 } 2170 } 2171 2172 /* use engine id to find free audio */ 2173 if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false)) { 2174 return pool->audios[id]; 2175 } 2176 /*not found the matching one, first come first serve*/ 2177 for (i = 0; i < available_audio_count; i++) { 2178 if (res_ctx->is_audio_acquired[i] == false) { 2179 return pool->audios[i]; 2180 } 2181 } 2182 return NULL; 2183 } 2184 2185 /* 2186 * dc_add_stream_to_ctx() - Add a new dc_stream_state to a dc_state. 2187 */ 2188 enum dc_status dc_add_stream_to_ctx( 2189 struct dc *dc, 2190 struct dc_state *new_ctx, 2191 struct dc_stream_state *stream) 2192 { 2193 enum dc_status res; 2194 DC_LOGGER_INIT(dc->ctx->logger); 2195 2196 if (new_ctx->stream_count >= dc->res_pool->timing_generator_count) { 2197 DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream); 2198 return DC_ERROR_UNEXPECTED; 2199 } 2200 2201 new_ctx->streams[new_ctx->stream_count] = stream; 2202 dc_stream_retain(stream); 2203 new_ctx->stream_count++; 2204 2205 res = dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream); 2206 if (res != DC_OK) 2207 DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res); 2208 2209 return res; 2210 } 2211 2212 /* 2213 * dc_remove_stream_from_ctx() - Remove a stream from a dc_state. 2214 */ 2215 enum dc_status dc_remove_stream_from_ctx( 2216 struct dc *dc, 2217 struct dc_state *new_ctx, 2218 struct dc_stream_state *stream) 2219 { 2220 int i; 2221 struct dc_context *dc_ctx = dc->ctx; 2222 struct pipe_ctx *del_pipe = resource_get_head_pipe_for_stream(&new_ctx->res_ctx, stream); 2223 struct pipe_ctx *odm_pipe; 2224 2225 if (!del_pipe) { 2226 DC_ERROR("Pipe not found for stream %p !\n", stream); 2227 return DC_ERROR_UNEXPECTED; 2228 } 2229 2230 odm_pipe = del_pipe->next_odm_pipe; 2231 2232 /* Release primary pipe */ 2233 ASSERT(del_pipe->stream_res.stream_enc); 2234 update_stream_engine_usage( 2235 &new_ctx->res_ctx, 2236 dc->res_pool, 2237 del_pipe->stream_res.stream_enc, 2238 false); 2239 2240 if (dc->link_srv->dp_is_128b_132b_signal(del_pipe)) { 2241 update_hpo_dp_stream_engine_usage( 2242 &new_ctx->res_ctx, dc->res_pool, 2243 del_pipe->stream_res.hpo_dp_stream_enc, 2244 false); 2245 remove_hpo_dp_link_enc_from_ctx(&new_ctx->res_ctx, del_pipe, del_pipe->stream); 2246 } 2247 2248 if (del_pipe->stream_res.audio) 2249 update_audio_usage( 2250 &new_ctx->res_ctx, 2251 dc->res_pool, 2252 del_pipe->stream_res.audio, 2253 false); 2254 2255 resource_unreference_clock_source(&new_ctx->res_ctx, 2256 dc->res_pool, 2257 del_pipe->clock_source); 2258 2259 if (dc->res_pool->funcs->remove_stream_from_ctx) 2260 dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream); 2261 2262 while (odm_pipe) { 2263 struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe; 2264 2265 memset(odm_pipe, 0, sizeof(*odm_pipe)); 2266 odm_pipe = next_odm_pipe; 2267 } 2268 memset(del_pipe, 0, sizeof(*del_pipe)); 2269 2270 for (i = 0; i < new_ctx->stream_count; i++) 2271 if (new_ctx->streams[i] == stream) 2272 break; 2273 2274 if (new_ctx->streams[i] != stream) { 2275 DC_ERROR("Context doesn't have stream %p !\n", stream); 2276 return DC_ERROR_UNEXPECTED; 2277 } 2278 2279 dc_stream_release(new_ctx->streams[i]); 2280 new_ctx->stream_count--; 2281 2282 /* Trim back arrays */ 2283 for (; i < new_ctx->stream_count; i++) { 2284 new_ctx->streams[i] = new_ctx->streams[i + 1]; 2285 new_ctx->stream_status[i] = new_ctx->stream_status[i + 1]; 2286 } 2287 2288 new_ctx->streams[new_ctx->stream_count] = NULL; 2289 memset( 2290 &new_ctx->stream_status[new_ctx->stream_count], 2291 0, 2292 sizeof(new_ctx->stream_status[0])); 2293 2294 return DC_OK; 2295 } 2296 2297 static struct dc_stream_state *find_pll_sharable_stream( 2298 struct dc_stream_state *stream_needs_pll, 2299 struct dc_state *context) 2300 { 2301 int i; 2302 2303 for (i = 0; i < context->stream_count; i++) { 2304 struct dc_stream_state *stream_has_pll = context->streams[i]; 2305 2306 /* We are looking for non dp, non virtual stream */ 2307 if (resource_are_streams_timing_synchronizable( 2308 stream_needs_pll, stream_has_pll) 2309 && !dc_is_dp_signal(stream_has_pll->signal) 2310 && stream_has_pll->link->connector_signal 2311 != SIGNAL_TYPE_VIRTUAL) 2312 return stream_has_pll; 2313 2314 } 2315 2316 return NULL; 2317 } 2318 2319 static int get_norm_pix_clk(const struct dc_crtc_timing *timing) 2320 { 2321 uint32_t pix_clk = timing->pix_clk_100hz; 2322 uint32_t normalized_pix_clk = pix_clk; 2323 2324 if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) 2325 pix_clk /= 2; 2326 if (timing->pixel_encoding != PIXEL_ENCODING_YCBCR422) { 2327 switch (timing->display_color_depth) { 2328 case COLOR_DEPTH_666: 2329 case COLOR_DEPTH_888: 2330 normalized_pix_clk = pix_clk; 2331 break; 2332 case COLOR_DEPTH_101010: 2333 normalized_pix_clk = (pix_clk * 30) / 24; 2334 break; 2335 case COLOR_DEPTH_121212: 2336 normalized_pix_clk = (pix_clk * 36) / 24; 2337 break; 2338 case COLOR_DEPTH_161616: 2339 normalized_pix_clk = (pix_clk * 48) / 24; 2340 break; 2341 default: 2342 ASSERT(0); 2343 break; 2344 } 2345 } 2346 return normalized_pix_clk; 2347 } 2348 2349 static void calculate_phy_pix_clks(struct dc_stream_state *stream) 2350 { 2351 /* update actual pixel clock on all streams */ 2352 if (dc_is_hdmi_signal(stream->signal)) 2353 stream->phy_pix_clk = get_norm_pix_clk( 2354 &stream->timing) / 10; 2355 else 2356 stream->phy_pix_clk = 2357 stream->timing.pix_clk_100hz / 10; 2358 2359 if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) 2360 stream->phy_pix_clk *= 2; 2361 } 2362 2363 static int acquire_resource_from_hw_enabled_state( 2364 struct resource_context *res_ctx, 2365 const struct resource_pool *pool, 2366 struct dc_stream_state *stream) 2367 { 2368 struct dc_link *link = stream->link; 2369 unsigned int i, inst, tg_inst = 0; 2370 uint32_t numPipes = 1; 2371 uint32_t id_src[4] = {0}; 2372 2373 /* Check for enabled DIG to identify enabled display */ 2374 if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) 2375 return -1; 2376 2377 inst = link->link_enc->funcs->get_dig_frontend(link->link_enc); 2378 2379 if (inst == ENGINE_ID_UNKNOWN) 2380 return -1; 2381 2382 for (i = 0; i < pool->stream_enc_count; i++) { 2383 if (pool->stream_enc[i]->id == inst) { 2384 tg_inst = pool->stream_enc[i]->funcs->dig_source_otg( 2385 pool->stream_enc[i]); 2386 break; 2387 } 2388 } 2389 2390 // tg_inst not found 2391 if (i == pool->stream_enc_count) 2392 return -1; 2393 2394 if (tg_inst >= pool->timing_generator_count) 2395 return -1; 2396 2397 if (!res_ctx->pipe_ctx[tg_inst].stream) { 2398 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst]; 2399 2400 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; 2401 id_src[0] = tg_inst; 2402 2403 if (pipe_ctx->stream_res.tg->funcs->get_optc_source) 2404 pipe_ctx->stream_res.tg->funcs->get_optc_source(pipe_ctx->stream_res.tg, 2405 &numPipes, &id_src[0], &id_src[1]); 2406 2407 if (id_src[0] == 0xf && id_src[1] == 0xf) { 2408 id_src[0] = tg_inst; 2409 numPipes = 1; 2410 } 2411 2412 for (i = 0; i < numPipes; i++) { 2413 //Check if src id invalid 2414 if (id_src[i] == 0xf) 2415 return -1; 2416 2417 pipe_ctx = &res_ctx->pipe_ctx[id_src[i]]; 2418 2419 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; 2420 pipe_ctx->plane_res.mi = pool->mis[id_src[i]]; 2421 pipe_ctx->plane_res.hubp = pool->hubps[id_src[i]]; 2422 pipe_ctx->plane_res.ipp = pool->ipps[id_src[i]]; 2423 pipe_ctx->plane_res.xfm = pool->transforms[id_src[i]]; 2424 pipe_ctx->plane_res.dpp = pool->dpps[id_src[i]]; 2425 pipe_ctx->stream_res.opp = pool->opps[id_src[i]]; 2426 2427 if (pool->dpps[id_src[i]]) { 2428 pipe_ctx->plane_res.mpcc_inst = pool->dpps[id_src[i]]->inst; 2429 2430 if (pool->mpc->funcs->read_mpcc_state) { 2431 struct mpcc_state s = {0}; 2432 2433 pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s); 2434 2435 if (s.dpp_id < MAX_MPCC) 2436 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id = 2437 s.dpp_id; 2438 2439 if (s.bot_mpcc_id < MAX_MPCC) 2440 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot = 2441 &pool->mpc->mpcc_array[s.bot_mpcc_id]; 2442 2443 if (s.opp_id < MAX_OPP) 2444 pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id; 2445 } 2446 } 2447 pipe_ctx->pipe_idx = id_src[i]; 2448 2449 if (id_src[i] >= pool->timing_generator_count) { 2450 id_src[i] = pool->timing_generator_count - 1; 2451 2452 pipe_ctx->stream_res.tg = pool->timing_generators[id_src[i]]; 2453 pipe_ctx->stream_res.opp = pool->opps[id_src[i]]; 2454 } 2455 2456 pipe_ctx->stream = stream; 2457 } 2458 2459 if (numPipes == 2) { 2460 stream->apply_boot_odm_mode = dm_odm_combine_policy_2to1; 2461 res_ctx->pipe_ctx[id_src[0]].next_odm_pipe = &res_ctx->pipe_ctx[id_src[1]]; 2462 res_ctx->pipe_ctx[id_src[0]].prev_odm_pipe = NULL; 2463 res_ctx->pipe_ctx[id_src[1]].next_odm_pipe = NULL; 2464 res_ctx->pipe_ctx[id_src[1]].prev_odm_pipe = &res_ctx->pipe_ctx[id_src[0]]; 2465 } else 2466 stream->apply_boot_odm_mode = dm_odm_combine_mode_disabled; 2467 2468 return id_src[0]; 2469 } 2470 2471 return -1; 2472 } 2473 2474 static void mark_seamless_boot_stream( 2475 const struct dc *dc, 2476 struct dc_stream_state *stream) 2477 { 2478 struct dc_bios *dcb = dc->ctx->dc_bios; 2479 2480 if (dc->config.allow_seamless_boot_optimization && 2481 !dcb->funcs->is_accelerated_mode(dcb)) { 2482 if (dc_validate_boot_timing(dc, stream->sink, &stream->timing)) 2483 stream->apply_seamless_boot_optimization = true; 2484 } 2485 } 2486 2487 enum dc_status resource_map_pool_resources( 2488 const struct dc *dc, 2489 struct dc_state *context, 2490 struct dc_stream_state *stream) 2491 { 2492 const struct resource_pool *pool = dc->res_pool; 2493 int i; 2494 struct dc_context *dc_ctx = dc->ctx; 2495 struct pipe_ctx *pipe_ctx = NULL; 2496 int pipe_idx = -1; 2497 2498 calculate_phy_pix_clks(stream); 2499 2500 mark_seamless_boot_stream(dc, stream); 2501 2502 if (stream->apply_seamless_boot_optimization) { 2503 pipe_idx = acquire_resource_from_hw_enabled_state( 2504 &context->res_ctx, 2505 pool, 2506 stream); 2507 if (pipe_idx < 0) 2508 /* hw resource was assigned to other stream */ 2509 stream->apply_seamless_boot_optimization = false; 2510 } 2511 2512 if (pipe_idx < 0) 2513 /* acquire new resources */ 2514 pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream); 2515 2516 if (pipe_idx < 0) 2517 pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); 2518 2519 if (pipe_idx < 0 || context->res_ctx.pipe_ctx[pipe_idx].stream_res.tg == NULL) 2520 return DC_NO_CONTROLLER_RESOURCE; 2521 2522 pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; 2523 2524 pipe_ctx->stream_res.stream_enc = 2525 dc->res_pool->funcs->find_first_free_match_stream_enc_for_link( 2526 &context->res_ctx, pool, stream); 2527 2528 if (!pipe_ctx->stream_res.stream_enc) 2529 return DC_NO_STREAM_ENC_RESOURCE; 2530 2531 update_stream_engine_usage( 2532 &context->res_ctx, pool, 2533 pipe_ctx->stream_res.stream_enc, 2534 true); 2535 2536 /* Allocate DP HPO Stream Encoder based on signal, hw capabilities 2537 * and link settings 2538 */ 2539 if (dc_is_dp_signal(stream->signal)) { 2540 if (!dc->link_srv->dp_decide_link_settings(stream, &pipe_ctx->link_config.dp_link_settings)) 2541 return DC_FAIL_DP_LINK_BANDWIDTH; 2542 if (dc->link_srv->dp_get_encoding_format( 2543 &pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) { 2544 pipe_ctx->stream_res.hpo_dp_stream_enc = 2545 find_first_free_match_hpo_dp_stream_enc_for_link( 2546 &context->res_ctx, pool, stream); 2547 2548 if (!pipe_ctx->stream_res.hpo_dp_stream_enc) 2549 return DC_NO_STREAM_ENC_RESOURCE; 2550 2551 update_hpo_dp_stream_engine_usage( 2552 &context->res_ctx, pool, 2553 pipe_ctx->stream_res.hpo_dp_stream_enc, 2554 true); 2555 if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, pool, pipe_ctx, stream)) 2556 return DC_NO_LINK_ENC_RESOURCE; 2557 } 2558 } 2559 2560 /* TODO: Add check if ASIC support and EDID audio */ 2561 if (!stream->converter_disable_audio && 2562 dc_is_audio_capable_signal(pipe_ctx->stream->signal) && 2563 stream->audio_info.mode_count && stream->audio_info.flags.all) { 2564 pipe_ctx->stream_res.audio = find_first_free_audio( 2565 &context->res_ctx, pool, pipe_ctx->stream_res.stream_enc->id, dc_ctx->dce_version); 2566 2567 /* 2568 * Audio assigned in order first come first get. 2569 * There are asics which has number of audio 2570 * resources less then number of pipes 2571 */ 2572 if (pipe_ctx->stream_res.audio) 2573 update_audio_usage(&context->res_ctx, pool, 2574 pipe_ctx->stream_res.audio, true); 2575 } 2576 2577 /* Add ABM to the resource if on EDP */ 2578 if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) { 2579 if (pool->abm) 2580 pipe_ctx->stream_res.abm = pool->abm; 2581 else 2582 pipe_ctx->stream_res.abm = pool->multiple_abms[pipe_ctx->stream_res.tg->inst]; 2583 } 2584 2585 for (i = 0; i < context->stream_count; i++) 2586 if (context->streams[i] == stream) { 2587 context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst; 2588 context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->stream_enc_inst; 2589 context->stream_status[i].audio_inst = 2590 pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1; 2591 2592 return DC_OK; 2593 } 2594 2595 DC_ERROR("Stream %p not found in new ctx!\n", stream); 2596 return DC_ERROR_UNEXPECTED; 2597 } 2598 2599 /** 2600 * dc_resource_state_copy_construct_current() - Creates a new dc_state from existing state 2601 * 2602 * @dc: copy out of dc->current_state 2603 * @dst_ctx: copy into this 2604 * 2605 * This function makes a shallow copy of the current DC state and increments 2606 * refcounts on existing streams and planes. 2607 */ 2608 void dc_resource_state_copy_construct_current( 2609 const struct dc *dc, 2610 struct dc_state *dst_ctx) 2611 { 2612 dc_resource_state_copy_construct(dc->current_state, dst_ctx); 2613 } 2614 2615 2616 void dc_resource_state_construct( 2617 const struct dc *dc, 2618 struct dc_state *dst_ctx) 2619 { 2620 dst_ctx->clk_mgr = dc->clk_mgr; 2621 2622 /* Initialise DIG link encoder resource tracking variables. */ 2623 link_enc_cfg_init(dc, dst_ctx); 2624 } 2625 2626 2627 bool dc_resource_is_dsc_encoding_supported(const struct dc *dc) 2628 { 2629 if (dc->res_pool == NULL) 2630 return false; 2631 2632 return dc->res_pool->res_cap->num_dsc > 0; 2633 } 2634 2635 static bool planes_changed_for_existing_stream(struct dc_state *context, 2636 struct dc_stream_state *stream, 2637 const struct dc_validation_set set[], 2638 int set_count) 2639 { 2640 int i, j; 2641 struct dc_stream_status *stream_status = NULL; 2642 2643 for (i = 0; i < context->stream_count; i++) { 2644 if (context->streams[i] == stream) { 2645 stream_status = &context->stream_status[i]; 2646 break; 2647 } 2648 } 2649 2650 if (!stream_status) 2651 ASSERT(0); 2652 2653 for (i = 0; i < set_count; i++) 2654 if (set[i].stream == stream) 2655 break; 2656 2657 if (i == set_count) 2658 ASSERT(0); 2659 2660 if (set[i].plane_count != stream_status->plane_count) 2661 return true; 2662 2663 for (j = 0; j < set[i].plane_count; j++) 2664 if (set[i].plane_states[j] != stream_status->plane_states[j]) 2665 return true; 2666 2667 return false; 2668 } 2669 2670 /** 2671 * dc_validate_with_context - Validate and update the potential new stream in the context object 2672 * 2673 * @dc: Used to get the current state status 2674 * @set: An array of dc_validation_set with all the current streams reference 2675 * @set_count: Total of streams 2676 * @context: New context 2677 * @fast_validate: Enable or disable fast validation 2678 * 2679 * This function updates the potential new stream in the context object. It 2680 * creates multiple lists for the add, remove, and unchanged streams. In 2681 * particular, if the unchanged streams have a plane that changed, it is 2682 * necessary to remove all planes from the unchanged streams. In summary, this 2683 * function is responsible for validating the new context. 2684 * 2685 * Return: 2686 * In case of success, return DC_OK (1), otherwise, return a DC error. 2687 */ 2688 enum dc_status dc_validate_with_context(struct dc *dc, 2689 const struct dc_validation_set set[], 2690 int set_count, 2691 struct dc_state *context, 2692 bool fast_validate) 2693 { 2694 struct dc_stream_state *unchanged_streams[MAX_PIPES] = { 0 }; 2695 struct dc_stream_state *del_streams[MAX_PIPES] = { 0 }; 2696 struct dc_stream_state *add_streams[MAX_PIPES] = { 0 }; 2697 int old_stream_count = context->stream_count; 2698 enum dc_status res = DC_ERROR_UNEXPECTED; 2699 int unchanged_streams_count = 0; 2700 int del_streams_count = 0; 2701 int add_streams_count = 0; 2702 bool found = false; 2703 int i, j, k; 2704 2705 DC_LOGGER_INIT(dc->ctx->logger); 2706 2707 /* First build a list of streams to be remove from current context */ 2708 for (i = 0; i < old_stream_count; i++) { 2709 struct dc_stream_state *stream = context->streams[i]; 2710 2711 for (j = 0; j < set_count; j++) { 2712 if (stream == set[j].stream) { 2713 found = true; 2714 break; 2715 } 2716 } 2717 2718 if (!found) 2719 del_streams[del_streams_count++] = stream; 2720 2721 found = false; 2722 } 2723 2724 /* Second, build a list of new streams */ 2725 for (i = 0; i < set_count; i++) { 2726 struct dc_stream_state *stream = set[i].stream; 2727 2728 for (j = 0; j < old_stream_count; j++) { 2729 if (stream == context->streams[j]) { 2730 found = true; 2731 break; 2732 } 2733 } 2734 2735 if (!found) 2736 add_streams[add_streams_count++] = stream; 2737 2738 found = false; 2739 } 2740 2741 /* Build a list of unchanged streams which is necessary for handling 2742 * planes change such as added, removed, and updated. 2743 */ 2744 for (i = 0; i < set_count; i++) { 2745 /* Check if stream is part of the delete list */ 2746 for (j = 0; j < del_streams_count; j++) { 2747 if (set[i].stream == del_streams[j]) { 2748 found = true; 2749 break; 2750 } 2751 } 2752 2753 if (!found) { 2754 /* Check if stream is part of the add list */ 2755 for (j = 0; j < add_streams_count; j++) { 2756 if (set[i].stream == add_streams[j]) { 2757 found = true; 2758 break; 2759 } 2760 } 2761 } 2762 2763 if (!found) 2764 unchanged_streams[unchanged_streams_count++] = set[i].stream; 2765 2766 found = false; 2767 } 2768 2769 /* Remove all planes for unchanged streams if planes changed */ 2770 for (i = 0; i < unchanged_streams_count; i++) { 2771 if (planes_changed_for_existing_stream(context, 2772 unchanged_streams[i], 2773 set, 2774 set_count)) { 2775 if (!dc_rem_all_planes_for_stream(dc, 2776 unchanged_streams[i], 2777 context)) { 2778 res = DC_FAIL_DETACH_SURFACES; 2779 goto fail; 2780 } 2781 } 2782 } 2783 2784 /* Remove all planes for removed streams and then remove the streams */ 2785 for (i = 0; i < del_streams_count; i++) { 2786 /* Need to cpy the dwb data from the old stream in order to efc to work */ 2787 if (del_streams[i]->num_wb_info > 0) { 2788 for (j = 0; j < add_streams_count; j++) { 2789 if (del_streams[i]->sink == add_streams[j]->sink) { 2790 add_streams[j]->num_wb_info = del_streams[i]->num_wb_info; 2791 for (k = 0; k < del_streams[i]->num_wb_info; k++) 2792 add_streams[j]->writeback_info[k] = del_streams[i]->writeback_info[k]; 2793 } 2794 } 2795 } 2796 2797 if (!dc_rem_all_planes_for_stream(dc, del_streams[i], context)) { 2798 res = DC_FAIL_DETACH_SURFACES; 2799 goto fail; 2800 } 2801 2802 res = dc_remove_stream_from_ctx(dc, context, del_streams[i]); 2803 if (res != DC_OK) 2804 goto fail; 2805 } 2806 2807 /* Swap seamless boot stream to pipe 0 (if needed) to ensure pipe_ctx 2808 * matches. This may change in the future if seamless_boot_stream can be 2809 * multiple. 2810 */ 2811 for (i = 0; i < add_streams_count; i++) { 2812 mark_seamless_boot_stream(dc, add_streams[i]); 2813 if (add_streams[i]->apply_seamless_boot_optimization && i != 0) { 2814 struct dc_stream_state *temp = add_streams[0]; 2815 2816 add_streams[0] = add_streams[i]; 2817 add_streams[i] = temp; 2818 break; 2819 } 2820 } 2821 2822 /* Add new streams and then add all planes for the new stream */ 2823 for (i = 0; i < add_streams_count; i++) { 2824 calculate_phy_pix_clks(add_streams[i]); 2825 res = dc_add_stream_to_ctx(dc, context, add_streams[i]); 2826 if (res != DC_OK) 2827 goto fail; 2828 2829 if (!add_all_planes_for_stream(dc, add_streams[i], set, set_count, context)) { 2830 res = DC_FAIL_ATTACH_SURFACES; 2831 goto fail; 2832 } 2833 } 2834 2835 /* Add all planes for unchanged streams if planes changed */ 2836 for (i = 0; i < unchanged_streams_count; i++) { 2837 if (planes_changed_for_existing_stream(context, 2838 unchanged_streams[i], 2839 set, 2840 set_count)) { 2841 if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, set_count, context)) { 2842 res = DC_FAIL_ATTACH_SURFACES; 2843 goto fail; 2844 } 2845 } 2846 } 2847 2848 res = dc_validate_global_state(dc, context, fast_validate); 2849 2850 fail: 2851 if (res != DC_OK) 2852 DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n", 2853 __func__, 2854 res); 2855 2856 return res; 2857 } 2858 2859 /** 2860 * dc_validate_global_state() - Determine if hardware can support a given state 2861 * 2862 * @dc: dc struct for this driver 2863 * @new_ctx: state to be validated 2864 * @fast_validate: set to true if only yes/no to support matters 2865 * 2866 * Checks hardware resource availability and bandwidth requirement. 2867 * 2868 * Return: 2869 * DC_OK if the result can be programmed. Otherwise, an error code. 2870 */ 2871 enum dc_status dc_validate_global_state( 2872 struct dc *dc, 2873 struct dc_state *new_ctx, 2874 bool fast_validate) 2875 { 2876 enum dc_status result = DC_ERROR_UNEXPECTED; 2877 int i, j; 2878 2879 if (!new_ctx) 2880 return DC_ERROR_UNEXPECTED; 2881 2882 if (dc->res_pool->funcs->validate_global) { 2883 result = dc->res_pool->funcs->validate_global(dc, new_ctx); 2884 if (result != DC_OK) 2885 return result; 2886 } 2887 2888 for (i = 0; i < new_ctx->stream_count; i++) { 2889 struct dc_stream_state *stream = new_ctx->streams[i]; 2890 2891 for (j = 0; j < dc->res_pool->pipe_count; j++) { 2892 struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[j]; 2893 2894 if (pipe_ctx->stream != stream) 2895 continue; 2896 2897 if (dc->res_pool->funcs->patch_unknown_plane_state && 2898 pipe_ctx->plane_state && 2899 pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) { 2900 result = dc->res_pool->funcs->patch_unknown_plane_state(pipe_ctx->plane_state); 2901 if (result != DC_OK) 2902 return result; 2903 } 2904 2905 /* Switch to dp clock source only if there is 2906 * no non dp stream that shares the same timing 2907 * with the dp stream. 2908 */ 2909 if (dc_is_dp_signal(pipe_ctx->stream->signal) && 2910 !find_pll_sharable_stream(stream, new_ctx)) { 2911 2912 resource_unreference_clock_source( 2913 &new_ctx->res_ctx, 2914 dc->res_pool, 2915 pipe_ctx->clock_source); 2916 2917 pipe_ctx->clock_source = dc->res_pool->dp_clock_source; 2918 resource_reference_clock_source( 2919 &new_ctx->res_ctx, 2920 dc->res_pool, 2921 pipe_ctx->clock_source); 2922 } 2923 } 2924 } 2925 2926 result = resource_build_scaling_params_for_context(dc, new_ctx); 2927 2928 if (result == DC_OK) 2929 if (!dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, fast_validate)) 2930 result = DC_FAIL_BANDWIDTH_VALIDATE; 2931 2932 /* 2933 * Only update link encoder to stream assignment after bandwidth validation passed. 2934 * TODO: Split out assignment and validation. 2935 */ 2936 if (result == DC_OK && dc->res_pool->funcs->link_encs_assign && fast_validate == false) 2937 dc->res_pool->funcs->link_encs_assign( 2938 dc, new_ctx, new_ctx->streams, new_ctx->stream_count); 2939 2940 return result; 2941 } 2942 2943 static void patch_gamut_packet_checksum( 2944 struct dc_info_packet *gamut_packet) 2945 { 2946 /* For gamut we recalc checksum */ 2947 if (gamut_packet->valid) { 2948 uint8_t chk_sum = 0; 2949 uint8_t *ptr; 2950 uint8_t i; 2951 2952 /*start of the Gamut data. */ 2953 ptr = &gamut_packet->sb[3]; 2954 2955 for (i = 0; i <= gamut_packet->sb[1]; i++) 2956 chk_sum += ptr[i]; 2957 2958 gamut_packet->sb[2] = (uint8_t) (0x100 - chk_sum); 2959 } 2960 } 2961 2962 static void set_avi_info_frame( 2963 struct dc_info_packet *info_packet, 2964 struct pipe_ctx *pipe_ctx) 2965 { 2966 struct dc_stream_state *stream = pipe_ctx->stream; 2967 enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; 2968 uint32_t pixel_encoding = 0; 2969 enum scanning_type scan_type = SCANNING_TYPE_NODATA; 2970 enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA; 2971 bool itc = false; 2972 uint8_t itc_value = 0; 2973 uint8_t cn0_cn1 = 0; 2974 unsigned int cn0_cn1_value = 0; 2975 uint8_t *check_sum = NULL; 2976 uint8_t byte_index = 0; 2977 union hdmi_info_packet hdmi_info; 2978 union display_content_support support = {0}; 2979 unsigned int vic = pipe_ctx->stream->timing.vic; 2980 unsigned int rid = pipe_ctx->stream->timing.rid; 2981 unsigned int fr_ind = pipe_ctx->stream->timing.fr_index; 2982 enum dc_timing_3d_format format; 2983 2984 memset(&hdmi_info, 0, sizeof(union hdmi_info_packet)); 2985 2986 color_space = pipe_ctx->stream->output_color_space; 2987 if (color_space == COLOR_SPACE_UNKNOWN) 2988 color_space = (stream->timing.pixel_encoding == PIXEL_ENCODING_RGB) ? 2989 COLOR_SPACE_SRGB:COLOR_SPACE_YCBCR709; 2990 2991 /* Initialize header */ 2992 hdmi_info.bits.header.info_frame_type = HDMI_INFOFRAME_TYPE_AVI; 2993 /* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall 2994 * not be used in HDMI 2.0 (Section 10.1) */ 2995 hdmi_info.bits.header.version = 2; 2996 hdmi_info.bits.header.length = HDMI_AVI_INFOFRAME_SIZE; 2997 2998 /* 2999 * IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built 3000 * according to HDMI 2.0 spec (Section 10.1) 3001 */ 3002 3003 switch (stream->timing.pixel_encoding) { 3004 case PIXEL_ENCODING_YCBCR422: 3005 pixel_encoding = 1; 3006 break; 3007 3008 case PIXEL_ENCODING_YCBCR444: 3009 pixel_encoding = 2; 3010 break; 3011 case PIXEL_ENCODING_YCBCR420: 3012 pixel_encoding = 3; 3013 break; 3014 3015 case PIXEL_ENCODING_RGB: 3016 default: 3017 pixel_encoding = 0; 3018 } 3019 3020 /* Y0_Y1_Y2 : The pixel encoding */ 3021 /* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */ 3022 hdmi_info.bits.Y0_Y1_Y2 = pixel_encoding; 3023 3024 /* A0 = 1 Active Format Information valid */ 3025 hdmi_info.bits.A0 = ACTIVE_FORMAT_VALID; 3026 3027 /* B0, B1 = 3; Bar info data is valid */ 3028 hdmi_info.bits.B0_B1 = BAR_INFO_BOTH_VALID; 3029 3030 hdmi_info.bits.SC0_SC1 = PICTURE_SCALING_UNIFORM; 3031 3032 /* S0, S1 : Underscan / Overscan */ 3033 /* TODO: un-hardcode scan type */ 3034 scan_type = SCANNING_TYPE_UNDERSCAN; 3035 hdmi_info.bits.S0_S1 = scan_type; 3036 3037 /* C0, C1 : Colorimetry */ 3038 switch (color_space) { 3039 case COLOR_SPACE_YCBCR709: 3040 case COLOR_SPACE_YCBCR709_LIMITED: 3041 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709; 3042 break; 3043 case COLOR_SPACE_YCBCR601: 3044 case COLOR_SPACE_YCBCR601_LIMITED: 3045 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU601; 3046 break; 3047 case COLOR_SPACE_2020_RGB_FULLRANGE: 3048 case COLOR_SPACE_2020_RGB_LIMITEDRANGE: 3049 case COLOR_SPACE_2020_YCBCR: 3050 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR; 3051 hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; 3052 break; 3053 case COLOR_SPACE_ADOBERGB: 3054 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB; 3055 hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; 3056 break; 3057 case COLOR_SPACE_SRGB: 3058 default: 3059 hdmi_info.bits.C0_C1 = COLORIMETRY_NO_DATA; 3060 break; 3061 } 3062 3063 if (pixel_encoding && color_space == COLOR_SPACE_2020_YCBCR && 3064 stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) { 3065 hdmi_info.bits.EC0_EC2 = 0; 3066 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709; 3067 } 3068 3069 /* TODO: un-hardcode aspect ratio */ 3070 aspect = stream->timing.aspect_ratio; 3071 3072 switch (aspect) { 3073 case ASPECT_RATIO_4_3: 3074 case ASPECT_RATIO_16_9: 3075 hdmi_info.bits.M0_M1 = aspect; 3076 break; 3077 3078 case ASPECT_RATIO_NO_DATA: 3079 case ASPECT_RATIO_64_27: 3080 case ASPECT_RATIO_256_135: 3081 default: 3082 hdmi_info.bits.M0_M1 = 0; 3083 } 3084 3085 /* Active Format Aspect ratio - same as Picture Aspect Ratio. */ 3086 hdmi_info.bits.R0_R3 = ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE; 3087 3088 /* TODO: un-hardcode cn0_cn1 and itc */ 3089 3090 cn0_cn1 = 0; 3091 cn0_cn1_value = 0; 3092 3093 itc = true; 3094 itc_value = 1; 3095 3096 support = stream->content_support; 3097 3098 if (itc) { 3099 if (!support.bits.valid_content_type) { 3100 cn0_cn1_value = 0; 3101 } else { 3102 if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GRAPHICS) { 3103 if (support.bits.graphics_content == 1) { 3104 cn0_cn1_value = 0; 3105 } 3106 } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_PHOTO) { 3107 if (support.bits.photo_content == 1) { 3108 cn0_cn1_value = 1; 3109 } else { 3110 cn0_cn1_value = 0; 3111 itc_value = 0; 3112 } 3113 } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_CINEMA) { 3114 if (support.bits.cinema_content == 1) { 3115 cn0_cn1_value = 2; 3116 } else { 3117 cn0_cn1_value = 0; 3118 itc_value = 0; 3119 } 3120 } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GAME) { 3121 if (support.bits.game_content == 1) { 3122 cn0_cn1_value = 3; 3123 } else { 3124 cn0_cn1_value = 0; 3125 itc_value = 0; 3126 } 3127 } 3128 } 3129 hdmi_info.bits.CN0_CN1 = cn0_cn1_value; 3130 hdmi_info.bits.ITC = itc_value; 3131 } 3132 3133 if (stream->qs_bit == 1) { 3134 if (color_space == COLOR_SPACE_SRGB || 3135 color_space == COLOR_SPACE_2020_RGB_FULLRANGE) 3136 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_FULL_RANGE; 3137 else if (color_space == COLOR_SPACE_SRGB_LIMITED || 3138 color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE) 3139 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_LIMITED_RANGE; 3140 else 3141 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE; 3142 } else 3143 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE; 3144 3145 /* TODO : We should handle YCC quantization */ 3146 /* but we do not have matrix calculation */ 3147 hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE; 3148 3149 ///VIC 3150 if (pipe_ctx->stream->timing.hdmi_vic != 0) 3151 vic = 0; 3152 format = stream->timing.timing_3d_format; 3153 /*todo, add 3DStereo support*/ 3154 if (format != TIMING_3D_FORMAT_NONE) { 3155 // Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled 3156 switch (pipe_ctx->stream->timing.hdmi_vic) { 3157 case 1: 3158 vic = 95; 3159 break; 3160 case 2: 3161 vic = 94; 3162 break; 3163 case 3: 3164 vic = 93; 3165 break; 3166 case 4: 3167 vic = 98; 3168 break; 3169 default: 3170 break; 3171 } 3172 } 3173 /* If VIC >= 128, the Source shall use AVI InfoFrame Version 3*/ 3174 hdmi_info.bits.VIC0_VIC7 = vic; 3175 if (vic >= 128) 3176 hdmi_info.bits.header.version = 3; 3177 /* If (C1, C0)=(1, 1) and (EC2, EC1, EC0)=(1, 1, 1), 3178 * the Source shall use 20 AVI InfoFrame Version 4 3179 */ 3180 if (hdmi_info.bits.C0_C1 == COLORIMETRY_EXTENDED && 3181 hdmi_info.bits.EC0_EC2 == COLORIMETRYEX_RESERVED) { 3182 hdmi_info.bits.header.version = 4; 3183 hdmi_info.bits.header.length = 14; 3184 } 3185 3186 if (rid != 0 && fr_ind != 0) { 3187 hdmi_info.bits.header.version = 5; 3188 hdmi_info.bits.header.length = 15; 3189 3190 hdmi_info.bits.FR0_FR3 = fr_ind & 0xF; 3191 hdmi_info.bits.FR4 = (fr_ind >> 4) & 0x1; 3192 hdmi_info.bits.RID0_RID5 = rid; 3193 } 3194 3195 /* pixel repetition 3196 * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel 3197 * repetition start from 1 */ 3198 hdmi_info.bits.PR0_PR3 = 0; 3199 3200 /* Bar Info 3201 * barTop: Line Number of End of Top Bar. 3202 * barBottom: Line Number of Start of Bottom Bar. 3203 * barLeft: Pixel Number of End of Left Bar. 3204 * barRight: Pixel Number of Start of Right Bar. */ 3205 hdmi_info.bits.bar_top = stream->timing.v_border_top; 3206 hdmi_info.bits.bar_bottom = (stream->timing.v_total 3207 - stream->timing.v_border_bottom + 1); 3208 hdmi_info.bits.bar_left = stream->timing.h_border_left; 3209 hdmi_info.bits.bar_right = (stream->timing.h_total 3210 - stream->timing.h_border_right + 1); 3211 3212 /* Additional Colorimetry Extension 3213 * Used in conduction with C0-C1 and EC0-EC2 3214 * 0 = DCI-P3 RGB (D65) 3215 * 1 = DCI-P3 RGB (theater) 3216 */ 3217 hdmi_info.bits.ACE0_ACE3 = 0; 3218 3219 /* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */ 3220 check_sum = &hdmi_info.packet_raw_data.sb[0]; 3221 3222 *check_sum = HDMI_INFOFRAME_TYPE_AVI + hdmi_info.bits.header.length + hdmi_info.bits.header.version; 3223 3224 for (byte_index = 1; byte_index <= hdmi_info.bits.header.length; byte_index++) 3225 *check_sum += hdmi_info.packet_raw_data.sb[byte_index]; 3226 3227 /* one byte complement */ 3228 *check_sum = (uint8_t) (0x100 - *check_sum); 3229 3230 /* Store in hw_path_mode */ 3231 info_packet->hb0 = hdmi_info.packet_raw_data.hb0; 3232 info_packet->hb1 = hdmi_info.packet_raw_data.hb1; 3233 info_packet->hb2 = hdmi_info.packet_raw_data.hb2; 3234 3235 for (byte_index = 0; byte_index < sizeof(hdmi_info.packet_raw_data.sb); byte_index++) 3236 info_packet->sb[byte_index] = hdmi_info.packet_raw_data.sb[byte_index]; 3237 3238 info_packet->valid = true; 3239 } 3240 3241 static void set_vendor_info_packet( 3242 struct dc_info_packet *info_packet, 3243 struct dc_stream_state *stream) 3244 { 3245 /* SPD info packet for FreeSync */ 3246 3247 /* Check if Freesync is supported. Return if false. If true, 3248 * set the corresponding bit in the info packet 3249 */ 3250 if (!stream->vsp_infopacket.valid) 3251 return; 3252 3253 *info_packet = stream->vsp_infopacket; 3254 } 3255 3256 static void set_spd_info_packet( 3257 struct dc_info_packet *info_packet, 3258 struct dc_stream_state *stream) 3259 { 3260 /* SPD info packet for FreeSync */ 3261 3262 /* Check if Freesync is supported. Return if false. If true, 3263 * set the corresponding bit in the info packet 3264 */ 3265 if (!stream->vrr_infopacket.valid) 3266 return; 3267 3268 *info_packet = stream->vrr_infopacket; 3269 } 3270 3271 static void set_hdr_static_info_packet( 3272 struct dc_info_packet *info_packet, 3273 struct dc_stream_state *stream) 3274 { 3275 /* HDR Static Metadata info packet for HDR10 */ 3276 3277 if (!stream->hdr_static_metadata.valid || 3278 stream->use_dynamic_meta) 3279 return; 3280 3281 *info_packet = stream->hdr_static_metadata; 3282 } 3283 3284 static void set_vsc_info_packet( 3285 struct dc_info_packet *info_packet, 3286 struct dc_stream_state *stream) 3287 { 3288 if (!stream->vsc_infopacket.valid) 3289 return; 3290 3291 *info_packet = stream->vsc_infopacket; 3292 } 3293 static void set_hfvs_info_packet( 3294 struct dc_info_packet *info_packet, 3295 struct dc_stream_state *stream) 3296 { 3297 if (!stream->hfvsif_infopacket.valid) 3298 return; 3299 3300 *info_packet = stream->hfvsif_infopacket; 3301 } 3302 3303 static void adaptive_sync_override_dp_info_packets_sdp_line_num( 3304 const struct dc_crtc_timing *timing, 3305 struct enc_sdp_line_num *sdp_line_num, 3306 struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param) 3307 { 3308 uint32_t asic_blank_start = 0; 3309 uint32_t asic_blank_end = 0; 3310 uint32_t v_update = 0; 3311 3312 const struct dc_crtc_timing *tg = timing; 3313 3314 /* blank_start = frame end - front porch */ 3315 asic_blank_start = tg->v_total - tg->v_front_porch; 3316 3317 /* blank_end = blank_start - active */ 3318 asic_blank_end = (asic_blank_start - tg->v_border_bottom - 3319 tg->v_addressable - tg->v_border_top); 3320 3321 if (pipe_dlg_param->vstartup_start > asic_blank_end) { 3322 v_update = (tg->v_total - (pipe_dlg_param->vstartup_start - asic_blank_end)); 3323 sdp_line_num->adaptive_sync_line_num_valid = true; 3324 sdp_line_num->adaptive_sync_line_num = (tg->v_total - v_update - 1); 3325 } else { 3326 sdp_line_num->adaptive_sync_line_num_valid = false; 3327 sdp_line_num->adaptive_sync_line_num = 0; 3328 } 3329 } 3330 3331 static void set_adaptive_sync_info_packet( 3332 struct dc_info_packet *info_packet, 3333 const struct dc_stream_state *stream, 3334 struct encoder_info_frame *info_frame, 3335 struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param) 3336 { 3337 if (!stream->adaptive_sync_infopacket.valid) 3338 return; 3339 3340 adaptive_sync_override_dp_info_packets_sdp_line_num( 3341 &stream->timing, 3342 &info_frame->sdp_line_num, 3343 pipe_dlg_param); 3344 3345 *info_packet = stream->adaptive_sync_infopacket; 3346 } 3347 3348 static void set_vtem_info_packet( 3349 struct dc_info_packet *info_packet, 3350 struct dc_stream_state *stream) 3351 { 3352 if (!stream->vtem_infopacket.valid) 3353 return; 3354 3355 *info_packet = stream->vtem_infopacket; 3356 } 3357 3358 void dc_resource_state_destruct(struct dc_state *context) 3359 { 3360 int i, j; 3361 3362 for (i = 0; i < context->stream_count; i++) { 3363 for (j = 0; j < context->stream_status[i].plane_count; j++) 3364 dc_plane_state_release( 3365 context->stream_status[i].plane_states[j]); 3366 3367 context->stream_status[i].plane_count = 0; 3368 dc_stream_release(context->streams[i]); 3369 context->streams[i] = NULL; 3370 } 3371 context->stream_count = 0; 3372 } 3373 3374 void dc_resource_state_copy_construct( 3375 const struct dc_state *src_ctx, 3376 struct dc_state *dst_ctx) 3377 { 3378 int i, j; 3379 struct kref refcount = dst_ctx->refcount; 3380 3381 *dst_ctx = *src_ctx; 3382 3383 for (i = 0; i < MAX_PIPES; i++) { 3384 struct pipe_ctx *cur_pipe = &dst_ctx->res_ctx.pipe_ctx[i]; 3385 3386 if (cur_pipe->top_pipe) 3387 cur_pipe->top_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx]; 3388 3389 if (cur_pipe->bottom_pipe) 3390 cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx]; 3391 3392 if (cur_pipe->next_odm_pipe) 3393 cur_pipe->next_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx]; 3394 3395 if (cur_pipe->prev_odm_pipe) 3396 cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx]; 3397 } 3398 3399 for (i = 0; i < dst_ctx->stream_count; i++) { 3400 dc_stream_retain(dst_ctx->streams[i]); 3401 for (j = 0; j < dst_ctx->stream_status[i].plane_count; j++) 3402 dc_plane_state_retain( 3403 dst_ctx->stream_status[i].plane_states[j]); 3404 } 3405 3406 /* context refcount should not be overridden */ 3407 dst_ctx->refcount = refcount; 3408 3409 } 3410 3411 struct clock_source *dc_resource_find_first_free_pll( 3412 struct resource_context *res_ctx, 3413 const struct resource_pool *pool) 3414 { 3415 int i; 3416 3417 for (i = 0; i < pool->clk_src_count; ++i) { 3418 if (res_ctx->clock_source_ref_count[i] == 0) 3419 return pool->clock_sources[i]; 3420 } 3421 3422 return NULL; 3423 } 3424 3425 void resource_build_info_frame(struct pipe_ctx *pipe_ctx) 3426 { 3427 enum signal_type signal = SIGNAL_TYPE_NONE; 3428 struct encoder_info_frame *info = &pipe_ctx->stream_res.encoder_info_frame; 3429 3430 /* default all packets to invalid */ 3431 info->avi.valid = false; 3432 info->gamut.valid = false; 3433 info->vendor.valid = false; 3434 info->spd.valid = false; 3435 info->hdrsmd.valid = false; 3436 info->vsc.valid = false; 3437 info->hfvsif.valid = false; 3438 info->vtem.valid = false; 3439 info->adaptive_sync.valid = false; 3440 signal = pipe_ctx->stream->signal; 3441 3442 /* HDMi and DP have different info packets*/ 3443 if (dc_is_hdmi_signal(signal)) { 3444 set_avi_info_frame(&info->avi, pipe_ctx); 3445 3446 set_vendor_info_packet(&info->vendor, pipe_ctx->stream); 3447 set_hfvs_info_packet(&info->hfvsif, pipe_ctx->stream); 3448 set_vtem_info_packet(&info->vtem, pipe_ctx->stream); 3449 3450 set_spd_info_packet(&info->spd, pipe_ctx->stream); 3451 3452 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream); 3453 3454 } else if (dc_is_dp_signal(signal)) { 3455 set_vsc_info_packet(&info->vsc, pipe_ctx->stream); 3456 3457 set_spd_info_packet(&info->spd, pipe_ctx->stream); 3458 3459 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream); 3460 set_adaptive_sync_info_packet(&info->adaptive_sync, 3461 pipe_ctx->stream, 3462 info, 3463 &pipe_ctx->pipe_dlg_param); 3464 } 3465 3466 patch_gamut_packet_checksum(&info->gamut); 3467 } 3468 3469 enum dc_status resource_map_clock_resources( 3470 const struct dc *dc, 3471 struct dc_state *context, 3472 struct dc_stream_state *stream) 3473 { 3474 /* acquire new resources */ 3475 const struct resource_pool *pool = dc->res_pool; 3476 struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream( 3477 &context->res_ctx, stream); 3478 3479 if (!pipe_ctx) 3480 return DC_ERROR_UNEXPECTED; 3481 3482 if (dc_is_dp_signal(pipe_ctx->stream->signal) 3483 || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL) 3484 pipe_ctx->clock_source = pool->dp_clock_source; 3485 else { 3486 pipe_ctx->clock_source = NULL; 3487 3488 if (!dc->config.disable_disp_pll_sharing) 3489 pipe_ctx->clock_source = resource_find_used_clk_src_for_sharing( 3490 &context->res_ctx, 3491 pipe_ctx); 3492 3493 if (pipe_ctx->clock_source == NULL) 3494 pipe_ctx->clock_source = 3495 dc_resource_find_first_free_pll( 3496 &context->res_ctx, 3497 pool); 3498 } 3499 3500 if (pipe_ctx->clock_source == NULL) 3501 return DC_NO_CLOCK_SOURCE_RESOURCE; 3502 3503 resource_reference_clock_source( 3504 &context->res_ctx, pool, 3505 pipe_ctx->clock_source); 3506 3507 return DC_OK; 3508 } 3509 3510 /* 3511 * Note: We need to disable output if clock sources change, 3512 * since bios does optimization and doesn't apply if changing 3513 * PHY when not already disabled. 3514 */ 3515 bool pipe_need_reprogram( 3516 struct pipe_ctx *pipe_ctx_old, 3517 struct pipe_ctx *pipe_ctx) 3518 { 3519 if (!pipe_ctx_old->stream) 3520 return false; 3521 3522 if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink) 3523 return true; 3524 3525 if (pipe_ctx_old->stream->signal != pipe_ctx->stream->signal) 3526 return true; 3527 3528 if (pipe_ctx_old->stream_res.audio != pipe_ctx->stream_res.audio) 3529 return true; 3530 3531 if (pipe_ctx_old->clock_source != pipe_ctx->clock_source 3532 && pipe_ctx_old->stream != pipe_ctx->stream) 3533 return true; 3534 3535 if (pipe_ctx_old->stream_res.stream_enc != pipe_ctx->stream_res.stream_enc) 3536 return true; 3537 3538 if (dc_is_timing_changed(pipe_ctx_old->stream, pipe_ctx->stream)) 3539 return true; 3540 3541 if (pipe_ctx_old->stream->dpms_off != pipe_ctx->stream->dpms_off) 3542 return true; 3543 3544 if (false == pipe_ctx_old->stream->link->link_state_valid && 3545 false == pipe_ctx_old->stream->dpms_off) 3546 return true; 3547 3548 if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc) 3549 return true; 3550 3551 if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc) 3552 return true; 3553 if (pipe_ctx_old->link_res.hpo_dp_link_enc != pipe_ctx->link_res.hpo_dp_link_enc) 3554 return true; 3555 3556 /* DIG link encoder resource assignment for stream changed. */ 3557 if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) { 3558 bool need_reprogram = false; 3559 struct dc *dc = pipe_ctx_old->stream->ctx->dc; 3560 struct link_encoder *link_enc_prev = 3561 link_enc_cfg_get_link_enc_used_by_stream_current(dc, pipe_ctx_old->stream); 3562 3563 if (link_enc_prev != pipe_ctx->stream->link_enc) 3564 need_reprogram = true; 3565 3566 return need_reprogram; 3567 } 3568 3569 return false; 3570 } 3571 3572 void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream, 3573 struct bit_depth_reduction_params *fmt_bit_depth) 3574 { 3575 enum dc_dither_option option = stream->dither_option; 3576 enum dc_pixel_encoding pixel_encoding = 3577 stream->timing.pixel_encoding; 3578 3579 memset(fmt_bit_depth, 0, sizeof(*fmt_bit_depth)); 3580 3581 if (option == DITHER_OPTION_DEFAULT) { 3582 switch (stream->timing.display_color_depth) { 3583 case COLOR_DEPTH_666: 3584 option = DITHER_OPTION_SPATIAL6; 3585 break; 3586 case COLOR_DEPTH_888: 3587 option = DITHER_OPTION_SPATIAL8; 3588 break; 3589 case COLOR_DEPTH_101010: 3590 option = DITHER_OPTION_SPATIAL10; 3591 break; 3592 default: 3593 option = DITHER_OPTION_DISABLE; 3594 } 3595 } 3596 3597 if (option == DITHER_OPTION_DISABLE) 3598 return; 3599 3600 if (option == DITHER_OPTION_TRUN6) { 3601 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; 3602 fmt_bit_depth->flags.TRUNCATE_DEPTH = 0; 3603 } else if (option == DITHER_OPTION_TRUN8 || 3604 option == DITHER_OPTION_TRUN8_SPATIAL6 || 3605 option == DITHER_OPTION_TRUN8_FM6) { 3606 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; 3607 fmt_bit_depth->flags.TRUNCATE_DEPTH = 1; 3608 } else if (option == DITHER_OPTION_TRUN10 || 3609 option == DITHER_OPTION_TRUN10_SPATIAL6 || 3610 option == DITHER_OPTION_TRUN10_SPATIAL8 || 3611 option == DITHER_OPTION_TRUN10_FM8 || 3612 option == DITHER_OPTION_TRUN10_FM6 || 3613 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { 3614 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; 3615 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2; 3616 } 3617 3618 /* special case - Formatter can only reduce by 4 bits at most. 3619 * When reducing from 12 to 6 bits, 3620 * HW recommends we use trunc with round mode 3621 * (if we did nothing, trunc to 10 bits would be used) 3622 * note that any 12->10 bit reduction is ignored prior to DCE8, 3623 * as the input was 10 bits. 3624 */ 3625 if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM || 3626 option == DITHER_OPTION_SPATIAL6 || 3627 option == DITHER_OPTION_FM6) { 3628 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; 3629 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2; 3630 fmt_bit_depth->flags.TRUNCATE_MODE = 1; 3631 } 3632 3633 /* spatial dither 3634 * note that spatial modes 1-3 are never used 3635 */ 3636 if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM || 3637 option == DITHER_OPTION_SPATIAL6 || 3638 option == DITHER_OPTION_TRUN10_SPATIAL6 || 3639 option == DITHER_OPTION_TRUN8_SPATIAL6) { 3640 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1; 3641 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 0; 3642 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1; 3643 fmt_bit_depth->flags.RGB_RANDOM = 3644 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0; 3645 } else if (option == DITHER_OPTION_SPATIAL8_FRAME_RANDOM || 3646 option == DITHER_OPTION_SPATIAL8 || 3647 option == DITHER_OPTION_SPATIAL8_FM6 || 3648 option == DITHER_OPTION_TRUN10_SPATIAL8 || 3649 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { 3650 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1; 3651 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 1; 3652 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1; 3653 fmt_bit_depth->flags.RGB_RANDOM = 3654 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0; 3655 } else if (option == DITHER_OPTION_SPATIAL10_FRAME_RANDOM || 3656 option == DITHER_OPTION_SPATIAL10 || 3657 option == DITHER_OPTION_SPATIAL10_FM8 || 3658 option == DITHER_OPTION_SPATIAL10_FM6) { 3659 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1; 3660 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 2; 3661 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1; 3662 fmt_bit_depth->flags.RGB_RANDOM = 3663 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0; 3664 } 3665 3666 if (option == DITHER_OPTION_SPATIAL6 || 3667 option == DITHER_OPTION_SPATIAL8 || 3668 option == DITHER_OPTION_SPATIAL10) { 3669 fmt_bit_depth->flags.FRAME_RANDOM = 0; 3670 } else { 3671 fmt_bit_depth->flags.FRAME_RANDOM = 1; 3672 } 3673 3674 ////////////////////// 3675 //// temporal dither 3676 ////////////////////// 3677 if (option == DITHER_OPTION_FM6 || 3678 option == DITHER_OPTION_SPATIAL8_FM6 || 3679 option == DITHER_OPTION_SPATIAL10_FM6 || 3680 option == DITHER_OPTION_TRUN10_FM6 || 3681 option == DITHER_OPTION_TRUN8_FM6 || 3682 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { 3683 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1; 3684 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 0; 3685 } else if (option == DITHER_OPTION_FM8 || 3686 option == DITHER_OPTION_SPATIAL10_FM8 || 3687 option == DITHER_OPTION_TRUN10_FM8) { 3688 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1; 3689 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 1; 3690 } else if (option == DITHER_OPTION_FM10) { 3691 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1; 3692 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 2; 3693 } 3694 3695 fmt_bit_depth->pixel_encoding = pixel_encoding; 3696 } 3697 3698 enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream) 3699 { 3700 struct dc_link *link = stream->link; 3701 struct timing_generator *tg = dc->res_pool->timing_generators[0]; 3702 enum dc_status res = DC_OK; 3703 3704 calculate_phy_pix_clks(stream); 3705 3706 if (!tg->funcs->validate_timing(tg, &stream->timing)) 3707 res = DC_FAIL_CONTROLLER_VALIDATE; 3708 3709 if (res == DC_OK) { 3710 if (link->ep_type == DISPLAY_ENDPOINT_PHY && 3711 !link->link_enc->funcs->validate_output_with_stream( 3712 link->link_enc, stream)) 3713 res = DC_FAIL_ENC_VALIDATE; 3714 } 3715 3716 /* TODO: validate audio ASIC caps, encoder */ 3717 3718 if (res == DC_OK) 3719 res = dc->link_srv->validate_mode_timing(stream, 3720 link, 3721 &stream->timing); 3722 3723 return res; 3724 } 3725 3726 enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state) 3727 { 3728 enum dc_status res = DC_OK; 3729 3730 /* check if surface has invalid dimensions */ 3731 if (plane_state->src_rect.width == 0 || plane_state->src_rect.height == 0 || 3732 plane_state->dst_rect.width == 0 || plane_state->dst_rect.height == 0) 3733 return DC_FAIL_SURFACE_VALIDATE; 3734 3735 /* TODO For now validates pixel format only */ 3736 if (dc->res_pool->funcs->validate_plane) 3737 return dc->res_pool->funcs->validate_plane(plane_state, &dc->caps); 3738 3739 return res; 3740 } 3741 3742 unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format) 3743 { 3744 switch (format) { 3745 case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS: 3746 return 8; 3747 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: 3748 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: 3749 return 12; 3750 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: 3751 case SURFACE_PIXEL_FORMAT_GRPH_RGB565: 3752 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: 3753 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: 3754 return 16; 3755 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: 3756 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: 3757 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: 3758 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: 3759 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS: 3760 case SURFACE_PIXEL_FORMAT_GRPH_RGBE: 3761 case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA: 3762 return 32; 3763 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: 3764 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: 3765 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: 3766 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: 3767 return 64; 3768 default: 3769 ASSERT_CRITICAL(false); 3770 return -1; 3771 } 3772 } 3773 static unsigned int get_max_audio_sample_rate(struct audio_mode *modes) 3774 { 3775 if (modes) { 3776 if (modes->sample_rates.rate.RATE_192) 3777 return 192000; 3778 if (modes->sample_rates.rate.RATE_176_4) 3779 return 176400; 3780 if (modes->sample_rates.rate.RATE_96) 3781 return 96000; 3782 if (modes->sample_rates.rate.RATE_88_2) 3783 return 88200; 3784 if (modes->sample_rates.rate.RATE_48) 3785 return 48000; 3786 if (modes->sample_rates.rate.RATE_44_1) 3787 return 44100; 3788 if (modes->sample_rates.rate.RATE_32) 3789 return 32000; 3790 } 3791 /*original logic when no audio info*/ 3792 return 441000; 3793 } 3794 3795 void get_audio_check(struct audio_info *aud_modes, 3796 struct audio_check *audio_chk) 3797 { 3798 unsigned int i; 3799 unsigned int max_sample_rate = 0; 3800 3801 if (aud_modes) { 3802 audio_chk->audio_packet_type = 0x2;/*audio sample packet AP = .25 for layout0, 1 for layout1*/ 3803 3804 audio_chk->max_audiosample_rate = 0; 3805 for (i = 0; i < aud_modes->mode_count; i++) { 3806 max_sample_rate = get_max_audio_sample_rate(&aud_modes->modes[i]); 3807 if (audio_chk->max_audiosample_rate < max_sample_rate) 3808 audio_chk->max_audiosample_rate = max_sample_rate; 3809 /*dts takes the same as type 2: AP = 0.25*/ 3810 } 3811 /*check which one take more bandwidth*/ 3812 if (audio_chk->max_audiosample_rate > 192000) 3813 audio_chk->audio_packet_type = 0x9;/*AP =1*/ 3814 audio_chk->acat = 0;/*not support*/ 3815 } 3816 } 3817 3818 static struct hpo_dp_link_encoder *get_temp_hpo_dp_link_enc( 3819 const struct resource_context *res_ctx, 3820 const struct resource_pool *const pool, 3821 const struct dc_link *link) 3822 { 3823 struct hpo_dp_link_encoder *hpo_dp_link_enc = NULL; 3824 int enc_index; 3825 3826 enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, link); 3827 3828 if (enc_index < 0) 3829 enc_index = find_free_hpo_dp_link_enc(res_ctx, pool); 3830 3831 if (enc_index >= 0) 3832 hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index]; 3833 3834 return hpo_dp_link_enc; 3835 } 3836 3837 bool get_temp_dp_link_res(struct dc_link *link, 3838 struct link_resource *link_res, 3839 struct dc_link_settings *link_settings) 3840 { 3841 const struct dc *dc = link->dc; 3842 const struct resource_context *res_ctx = &dc->current_state->res_ctx; 3843 3844 memset(link_res, 0, sizeof(*link_res)); 3845 3846 if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) { 3847 link_res->hpo_dp_link_enc = get_temp_hpo_dp_link_enc(res_ctx, 3848 dc->res_pool, link); 3849 if (!link_res->hpo_dp_link_enc) 3850 return false; 3851 } 3852 return true; 3853 } 3854 3855 void reset_syncd_pipes_from_disabled_pipes(struct dc *dc, 3856 struct dc_state *context) 3857 { 3858 int i, j; 3859 struct pipe_ctx *pipe_ctx_old, *pipe_ctx, *pipe_ctx_syncd; 3860 3861 /* If pipe backend is reset, need to reset pipe syncd status */ 3862 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3863 pipe_ctx_old = &dc->current_state->res_ctx.pipe_ctx[i]; 3864 pipe_ctx = &context->res_ctx.pipe_ctx[i]; 3865 3866 if (!pipe_ctx_old->stream) 3867 continue; 3868 3869 if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) 3870 continue; 3871 3872 if (!pipe_ctx->stream || 3873 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { 3874 3875 /* Reset all the syncd pipes from the disabled pipe */ 3876 for (j = 0; j < dc->res_pool->pipe_count; j++) { 3877 pipe_ctx_syncd = &context->res_ctx.pipe_ctx[j]; 3878 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_syncd) == pipe_ctx_old->pipe_idx) || 3879 !IS_PIPE_SYNCD_VALID(pipe_ctx_syncd)) 3880 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_syncd, j); 3881 } 3882 } 3883 } 3884 } 3885 3886 void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc, 3887 struct dc_state *context, 3888 uint8_t disabled_master_pipe_idx) 3889 { 3890 int i; 3891 struct pipe_ctx *pipe_ctx, *pipe_ctx_check; 3892 3893 pipe_ctx = &context->res_ctx.pipe_ctx[disabled_master_pipe_idx]; 3894 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx) != disabled_master_pipe_idx) || 3895 !IS_PIPE_SYNCD_VALID(pipe_ctx)) 3896 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx, disabled_master_pipe_idx); 3897 3898 /* for the pipe disabled, check if any slave pipe exists and assert */ 3899 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3900 pipe_ctx_check = &context->res_ctx.pipe_ctx[i]; 3901 3902 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_check) == disabled_master_pipe_idx) && 3903 IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx)) { 3904 struct pipe_ctx *first_pipe = pipe_ctx_check; 3905 3906 while (first_pipe->prev_odm_pipe) 3907 first_pipe = first_pipe->prev_odm_pipe; 3908 /* When ODM combine is enabled, this case is expected. If the disabled pipe 3909 * is part of the ODM tree, then we should not print an error. 3910 * */ 3911 if (first_pipe->pipe_idx == disabled_master_pipe_idx) 3912 continue; 3913 3914 DC_ERR("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n", 3915 i, disabled_master_pipe_idx); 3916 } 3917 } 3918 } 3919 3920 void reset_sync_context_for_pipe(const struct dc *dc, 3921 struct dc_state *context, 3922 uint8_t pipe_idx) 3923 { 3924 int i; 3925 struct pipe_ctx *pipe_ctx_reset; 3926 3927 /* reset the otg sync context for the pipe and its slave pipes if any */ 3928 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3929 pipe_ctx_reset = &context->res_ctx.pipe_ctx[i]; 3930 3931 if (((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_reset) == pipe_idx) && 3932 IS_PIPE_SYNCD_VALID(pipe_ctx_reset)) || (i == pipe_idx)) 3933 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_reset, i); 3934 } 3935 } 3936 3937 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter) 3938 { 3939 /* TODO - get transmitter to phy idx mapping from DMUB */ 3940 uint8_t phy_idx = transmitter - TRANSMITTER_UNIPHY_A; 3941 3942 if (dc->ctx->dce_version == DCN_VERSION_3_1 && 3943 dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { 3944 switch (transmitter) { 3945 case TRANSMITTER_UNIPHY_A: 3946 phy_idx = 0; 3947 break; 3948 case TRANSMITTER_UNIPHY_B: 3949 phy_idx = 1; 3950 break; 3951 case TRANSMITTER_UNIPHY_C: 3952 phy_idx = 5; 3953 break; 3954 case TRANSMITTER_UNIPHY_D: 3955 phy_idx = 6; 3956 break; 3957 case TRANSMITTER_UNIPHY_E: 3958 phy_idx = 4; 3959 break; 3960 default: 3961 phy_idx = 0; 3962 break; 3963 } 3964 } 3965 3966 return phy_idx; 3967 } 3968 3969 const struct link_hwss *get_link_hwss(const struct dc_link *link, 3970 const struct link_resource *link_res) 3971 { 3972 /* Link_hwss is only accessible by getter function instead of accessing 3973 * by pointers in dc with the intent to protect against breaking polymorphism. 3974 */ 3975 if (can_use_hpo_dp_link_hwss(link, link_res)) 3976 /* TODO: some assumes that if decided link settings is 128b/132b 3977 * channel coding format hpo_dp_link_enc should be used. 3978 * Others believe that if hpo_dp_link_enc is available in link 3979 * resource then hpo_dp_link_enc must be used. This bound between 3980 * hpo_dp_link_enc != NULL and decided link settings is loosely coupled 3981 * with a premise that both hpo_dp_link_enc pointer and decided link 3982 * settings are determined based on single policy function like 3983 * "decide_link_settings" from upper layer. This "convention" 3984 * cannot be maintained and enforced at current level. 3985 * Therefore a refactor is due so we can enforce a strong bound 3986 * between those two parameters at this level. 3987 * 3988 * To put it simple, we want to make enforcement at low level so that 3989 * we will not return link hwss if caller plans to do 8b/10b 3990 * with an hpo encoder. Or we can return a very dummy one that doesn't 3991 * do work for all functions 3992 */ 3993 return get_hpo_dp_link_hwss(); 3994 else if (can_use_dpia_link_hwss(link, link_res)) 3995 return get_dpia_link_hwss(); 3996 else if (can_use_dio_link_hwss(link, link_res)) 3997 return get_dio_link_hwss(); 3998 else 3999 return get_virtual_link_hwss(); 4000 } 4001 4002 bool is_h_timing_divisible_by_2(struct dc_stream_state *stream) 4003 { 4004 bool divisible = false; 4005 uint16_t h_blank_start = 0; 4006 uint16_t h_blank_end = 0; 4007 4008 if (stream) { 4009 h_blank_start = stream->timing.h_total - stream->timing.h_front_porch; 4010 h_blank_end = h_blank_start - stream->timing.h_addressable; 4011 4012 /* HTOTAL, Hblank start/end, and Hsync start/end all must be 4013 * divisible by 2 in order for the horizontal timing params 4014 * to be considered divisible by 2. Hsync start is always 0. 4015 */ 4016 divisible = (stream->timing.h_total % 2 == 0) && 4017 (h_blank_start % 2 == 0) && 4018 (h_blank_end % 2 == 0) && 4019 (stream->timing.h_sync_width % 2 == 0); 4020 } 4021 return divisible; 4022 } 4023 4024 bool dc_resource_acquire_secondary_pipe_for_mpc_odm( 4025 const struct dc *dc, 4026 struct dc_state *state, 4027 struct pipe_ctx *pri_pipe, 4028 struct pipe_ctx *sec_pipe, 4029 bool odm) 4030 { 4031 int pipe_idx = sec_pipe->pipe_idx; 4032 struct pipe_ctx *sec_top, *sec_bottom, *sec_next, *sec_prev; 4033 const struct resource_pool *pool = dc->res_pool; 4034 4035 sec_top = sec_pipe->top_pipe; 4036 sec_bottom = sec_pipe->bottom_pipe; 4037 sec_next = sec_pipe->next_odm_pipe; 4038 sec_prev = sec_pipe->prev_odm_pipe; 4039 4040 *sec_pipe = *pri_pipe; 4041 4042 sec_pipe->top_pipe = sec_top; 4043 sec_pipe->bottom_pipe = sec_bottom; 4044 sec_pipe->next_odm_pipe = sec_next; 4045 sec_pipe->prev_odm_pipe = sec_prev; 4046 4047 sec_pipe->pipe_idx = pipe_idx; 4048 sec_pipe->plane_res.mi = pool->mis[pipe_idx]; 4049 sec_pipe->plane_res.hubp = pool->hubps[pipe_idx]; 4050 sec_pipe->plane_res.ipp = pool->ipps[pipe_idx]; 4051 sec_pipe->plane_res.xfm = pool->transforms[pipe_idx]; 4052 sec_pipe->plane_res.dpp = pool->dpps[pipe_idx]; 4053 sec_pipe->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst; 4054 sec_pipe->stream_res.dsc = NULL; 4055 if (odm) { 4056 if (!sec_pipe->top_pipe) 4057 sec_pipe->stream_res.opp = pool->opps[pipe_idx]; 4058 else 4059 sec_pipe->stream_res.opp = sec_pipe->top_pipe->stream_res.opp; 4060 if (sec_pipe->stream->timing.flags.DSC == 1) { 4061 #if defined(CONFIG_DRM_AMD_DC_FP) 4062 dcn20_acquire_dsc(dc, &state->res_ctx, &sec_pipe->stream_res.dsc, pipe_idx); 4063 #endif 4064 ASSERT(sec_pipe->stream_res.dsc); 4065 if (sec_pipe->stream_res.dsc == NULL) 4066 return false; 4067 } 4068 #if defined(CONFIG_DRM_AMD_DC_FP) 4069 dcn20_build_mapped_resource(dc, state, sec_pipe->stream); 4070 #endif 4071 } 4072 4073 return true; 4074 } 4075 4076 enum dc_status update_dp_encoder_resources_for_test_harness(const struct dc *dc, 4077 struct dc_state *context, 4078 struct pipe_ctx *pipe_ctx) 4079 { 4080 if (dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) { 4081 if (pipe_ctx->stream_res.hpo_dp_stream_enc == NULL) { 4082 pipe_ctx->stream_res.hpo_dp_stream_enc = 4083 find_first_free_match_hpo_dp_stream_enc_for_link( 4084 &context->res_ctx, dc->res_pool, pipe_ctx->stream); 4085 4086 if (!pipe_ctx->stream_res.hpo_dp_stream_enc) 4087 return DC_NO_STREAM_ENC_RESOURCE; 4088 4089 update_hpo_dp_stream_engine_usage( 4090 &context->res_ctx, dc->res_pool, 4091 pipe_ctx->stream_res.hpo_dp_stream_enc, 4092 true); 4093 } 4094 4095 if (pipe_ctx->link_res.hpo_dp_link_enc == NULL) { 4096 if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, dc->res_pool, pipe_ctx, pipe_ctx->stream)) 4097 return DC_NO_LINK_ENC_RESOURCE; 4098 } 4099 } else { 4100 if (pipe_ctx->stream_res.hpo_dp_stream_enc) { 4101 update_hpo_dp_stream_engine_usage( 4102 &context->res_ctx, dc->res_pool, 4103 pipe_ctx->stream_res.hpo_dp_stream_enc, 4104 false); 4105 pipe_ctx->stream_res.hpo_dp_stream_enc = NULL; 4106 } 4107 if (pipe_ctx->link_res.hpo_dp_link_enc) 4108 remove_hpo_dp_link_enc_from_ctx(&context->res_ctx, pipe_ctx, pipe_ctx->stream); 4109 } 4110 4111 return DC_OK; 4112 } 4113 4114