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 "dc_link_dp.h" 44 #include "link.h" 45 #include "virtual/virtual_link_hwss.h" 46 #include "link/hwss/link_hwss_dio.h" 47 #include "link/hwss/link_hwss_dpia.h" 48 #include "link/hwss/link_hwss_hpo_dp.h" 49 50 #if defined(CONFIG_DRM_AMD_DC_SI) 51 #include "dce60/dce60_resource.h" 52 #endif 53 #include "dce80/dce80_resource.h" 54 #include "dce100/dce100_resource.h" 55 #include "dce110/dce110_resource.h" 56 #include "dce112/dce112_resource.h" 57 #include "dce120/dce120_resource.h" 58 #include "dcn10/dcn10_resource.h" 59 #include "dcn20/dcn20_resource.h" 60 #include "dcn21/dcn21_resource.h" 61 #include "dcn201/dcn201_resource.h" 62 #include "dcn30/dcn30_resource.h" 63 #include "dcn301/dcn301_resource.h" 64 #include "dcn302/dcn302_resource.h" 65 #include "dcn303/dcn303_resource.h" 66 #include "dcn31/dcn31_resource.h" 67 #include "dcn314/dcn314_resource.h" 68 #include "dcn315/dcn315_resource.h" 69 #include "dcn316/dcn316_resource.h" 70 #include "../dcn32/dcn32_resource.h" 71 #include "../dcn321/dcn321_resource.h" 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_DCN) 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 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 } 1451 } 1452 return -1; 1453 } 1454 1455 bool dc_add_plane_to_context( 1456 const struct dc *dc, 1457 struct dc_stream_state *stream, 1458 struct dc_plane_state *plane_state, 1459 struct dc_state *context) 1460 { 1461 int i; 1462 struct resource_pool *pool = dc->res_pool; 1463 struct pipe_ctx *head_pipe, *tail_pipe, *free_pipe; 1464 struct dc_stream_status *stream_status = NULL; 1465 struct pipe_ctx *prev_right_head = NULL; 1466 struct pipe_ctx *free_right_pipe = NULL; 1467 struct pipe_ctx *prev_left_head = NULL; 1468 1469 DC_LOGGER_INIT(stream->ctx->logger); 1470 for (i = 0; i < context->stream_count; i++) 1471 if (context->streams[i] == stream) { 1472 stream_status = &context->stream_status[i]; 1473 break; 1474 } 1475 if (stream_status == NULL) { 1476 dm_error("Existing stream not found; failed to attach surface!\n"); 1477 return false; 1478 } 1479 1480 1481 if (stream_status->plane_count == MAX_SURFACE_NUM) { 1482 dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n", 1483 plane_state, MAX_SURFACE_NUM); 1484 return false; 1485 } 1486 1487 head_pipe = resource_get_head_pipe_for_stream(&context->res_ctx, stream); 1488 1489 if (!head_pipe) { 1490 dm_error("Head pipe not found for stream_state %p !\n", stream); 1491 return false; 1492 } 1493 1494 /* retain new surface, but only once per stream */ 1495 dc_plane_state_retain(plane_state); 1496 1497 while (head_pipe) { 1498 free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe); 1499 1500 if (!free_pipe) { 1501 int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); 1502 if (pipe_idx >= 0) 1503 free_pipe = &context->res_ctx.pipe_ctx[pipe_idx]; 1504 } 1505 1506 if (!free_pipe) { 1507 dc_plane_state_release(plane_state); 1508 return false; 1509 } 1510 1511 free_pipe->plane_state = plane_state; 1512 1513 if (head_pipe != free_pipe) { 1514 tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe); 1515 ASSERT(tail_pipe); 1516 1517 /* ODM + window MPO, where MPO window is on right half only */ 1518 if (free_pipe->plane_state && 1519 (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2) && 1520 tail_pipe->next_odm_pipe) { 1521 1522 /* For ODM + window MPO, in 3 plane case, if we already have a MPO window on 1523 * the right side, then we will invalidate a 2nd one on the right side 1524 */ 1525 if (head_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) { 1526 dc_plane_state_release(plane_state); 1527 return false; 1528 } 1529 1530 DC_LOG_SCALER("%s - ODM + window MPO(right). free_pipe:%d tail_pipe->next_odm_pipe:%d\n", 1531 __func__, 1532 free_pipe->pipe_idx, 1533 tail_pipe->next_odm_pipe ? tail_pipe->next_odm_pipe->pipe_idx : -1); 1534 1535 /* 1536 * We want to avoid the case where the right side already has a pipe assigned to 1537 * it and is different from free_pipe ( which would cause trigger a pipe 1538 * reallocation ). 1539 * Check the old context to see if the right side already has a pipe allocated 1540 * - If not, continue to use free_pipe 1541 * - If the right side already has a pipe, use that pipe instead if its available 1542 */ 1543 1544 /* 1545 * We also want to avoid the case where with three plane ( 2 MPO videos ), we have 1546 * both videos on the left side so one of the videos is invalidated. Then we 1547 * move the invalidated video back to the right side. If the order of the plane 1548 * states is such that the right MPO plane is processed first, the free pipe 1549 * selected by the head will be the left MPO pipe. But since there was no right 1550 * MPO pipe, it will assign the free pipe to the right MPO pipe instead and 1551 * a pipe reallocation will occur. 1552 * Check the old context to see if the left side already has a pipe allocated 1553 * - If not, continue to use free_pipe 1554 * - If the left side is already using this pipe, then pick another pipe for right 1555 */ 1556 1557 prev_right_head = &dc->current_state->res_ctx.pipe_ctx[tail_pipe->next_odm_pipe->pipe_idx]; 1558 if ((prev_right_head->bottom_pipe) && 1559 (free_pipe->pipe_idx != prev_right_head->bottom_pipe->pipe_idx)) { 1560 free_right_pipe = acquire_free_pipe_for_head(context, pool, tail_pipe->next_odm_pipe); 1561 } else { 1562 prev_left_head = &dc->current_state->res_ctx.pipe_ctx[head_pipe->pipe_idx]; 1563 if ((prev_left_head->bottom_pipe) && 1564 (free_pipe->pipe_idx == prev_left_head->bottom_pipe->pipe_idx)) { 1565 free_right_pipe = acquire_free_pipe_for_head(context, pool, head_pipe); 1566 } 1567 } 1568 1569 if (free_right_pipe) { 1570 free_pipe->stream = NULL; 1571 memset(&free_pipe->stream_res, 0, sizeof(struct stream_resource)); 1572 memset(&free_pipe->plane_res, 0, sizeof(struct plane_resource)); 1573 free_pipe->plane_state = NULL; 1574 free_pipe->pipe_idx = 0; 1575 free_right_pipe->plane_state = plane_state; 1576 free_pipe = free_right_pipe; 1577 } 1578 1579 free_pipe->stream_res.tg = tail_pipe->next_odm_pipe->stream_res.tg; 1580 free_pipe->stream_res.abm = tail_pipe->next_odm_pipe->stream_res.abm; 1581 free_pipe->stream_res.opp = tail_pipe->next_odm_pipe->stream_res.opp; 1582 free_pipe->stream_res.stream_enc = tail_pipe->next_odm_pipe->stream_res.stream_enc; 1583 free_pipe->stream_res.audio = tail_pipe->next_odm_pipe->stream_res.audio; 1584 free_pipe->clock_source = tail_pipe->next_odm_pipe->clock_source; 1585 1586 free_pipe->top_pipe = tail_pipe->next_odm_pipe; 1587 tail_pipe->next_odm_pipe->bottom_pipe = free_pipe; 1588 } else if (free_pipe->plane_state && 1589 (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2) 1590 && head_pipe->next_odm_pipe) { 1591 1592 /* For ODM + window MPO, support 3 plane ( 2 MPO ) case. 1593 * Here we have a desktop ODM + left window MPO and a new MPO window appears 1594 * on the right side only. It fails the first case, because tail_pipe is the 1595 * left window MPO, so it has no next_odm_pipe. So in this scenario, we check 1596 * for head_pipe->next_odm_pipe instead 1597 */ 1598 DC_LOG_SCALER("%s - ODM + win MPO (left) + win MPO (right). free_pipe:%d head_pipe->next_odm:%d\n", 1599 __func__, 1600 free_pipe->pipe_idx, 1601 head_pipe->next_odm_pipe ? head_pipe->next_odm_pipe->pipe_idx : -1); 1602 1603 /* 1604 * We want to avoid the case where the right side already has a pipe assigned to 1605 * it and is different from free_pipe ( which would cause trigger a pipe 1606 * reallocation ). 1607 * Check the old context to see if the right side already has a pipe allocated 1608 * - If not, continue to use free_pipe 1609 * - If the right side already has a pipe, use that pipe instead if its available 1610 */ 1611 prev_right_head = &dc->current_state->res_ctx.pipe_ctx[head_pipe->next_odm_pipe->pipe_idx]; 1612 if ((prev_right_head->bottom_pipe) && 1613 (free_pipe->pipe_idx != prev_right_head->bottom_pipe->pipe_idx)) { 1614 free_right_pipe = acquire_free_pipe_for_head(context, pool, head_pipe->next_odm_pipe); 1615 if (free_right_pipe) { 1616 free_pipe->stream = NULL; 1617 memset(&free_pipe->stream_res, 0, sizeof(struct stream_resource)); 1618 memset(&free_pipe->plane_res, 0, sizeof(struct plane_resource)); 1619 free_pipe->plane_state = NULL; 1620 free_pipe->pipe_idx = 0; 1621 free_right_pipe->plane_state = plane_state; 1622 free_pipe = free_right_pipe; 1623 } 1624 } 1625 1626 free_pipe->stream_res.tg = head_pipe->next_odm_pipe->stream_res.tg; 1627 free_pipe->stream_res.abm = head_pipe->next_odm_pipe->stream_res.abm; 1628 free_pipe->stream_res.opp = head_pipe->next_odm_pipe->stream_res.opp; 1629 free_pipe->stream_res.stream_enc = head_pipe->next_odm_pipe->stream_res.stream_enc; 1630 free_pipe->stream_res.audio = head_pipe->next_odm_pipe->stream_res.audio; 1631 free_pipe->clock_source = head_pipe->next_odm_pipe->clock_source; 1632 1633 free_pipe->top_pipe = head_pipe->next_odm_pipe; 1634 head_pipe->next_odm_pipe->bottom_pipe = free_pipe; 1635 } else { 1636 1637 /* For ODM + window MPO, in 3 plane case, if we already have a MPO window on 1638 * the left side, then we will invalidate a 2nd one on the left side 1639 */ 1640 if (head_pipe->next_odm_pipe && tail_pipe->top_pipe) { 1641 dc_plane_state_release(plane_state); 1642 return false; 1643 } 1644 1645 free_pipe->stream_res.tg = tail_pipe->stream_res.tg; 1646 free_pipe->stream_res.abm = tail_pipe->stream_res.abm; 1647 free_pipe->stream_res.opp = tail_pipe->stream_res.opp; 1648 free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc; 1649 free_pipe->stream_res.audio = tail_pipe->stream_res.audio; 1650 free_pipe->clock_source = tail_pipe->clock_source; 1651 1652 free_pipe->top_pipe = tail_pipe; 1653 tail_pipe->bottom_pipe = free_pipe; 1654 1655 /* Connect MPO pipes together if MPO window is in the centre */ 1656 if (!(free_pipe->plane_state && 1657 (free_pipe->plane_state->clip_rect.x + free_pipe->plane_state->clip_rect.width <= 1658 free_pipe->stream->src.x + free_pipe->stream->src.width/2))) { 1659 if (!free_pipe->next_odm_pipe && 1660 tail_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) { 1661 free_pipe->next_odm_pipe = tail_pipe->next_odm_pipe->bottom_pipe; 1662 tail_pipe->next_odm_pipe->bottom_pipe->prev_odm_pipe = free_pipe; 1663 } 1664 if (!free_pipe->prev_odm_pipe && 1665 tail_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe->bottom_pipe) { 1666 free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe; 1667 tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_pipe; 1668 } 1669 } 1670 } 1671 } 1672 1673 /* ODM + window MPO, where MPO window is on left half only */ 1674 if (free_pipe->plane_state && 1675 (free_pipe->plane_state->clip_rect.x + free_pipe->plane_state->clip_rect.width <= 1676 free_pipe->stream->src.x + free_pipe->stream->src.width/2)) { 1677 DC_LOG_SCALER("%s - ODM + window MPO(left). free_pipe:%d\n", 1678 __func__, 1679 free_pipe->pipe_idx); 1680 break; 1681 } 1682 /* ODM + window MPO, where MPO window is on right half only */ 1683 if (free_pipe->plane_state && 1684 (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2)) { 1685 DC_LOG_SCALER("%s - ODM + window MPO(right). free_pipe:%d\n", 1686 __func__, 1687 free_pipe->pipe_idx); 1688 break; 1689 } 1690 1691 head_pipe = head_pipe->next_odm_pipe; 1692 } 1693 /* assign new surfaces*/ 1694 stream_status->plane_states[stream_status->plane_count] = plane_state; 1695 1696 stream_status->plane_count++; 1697 1698 return true; 1699 } 1700 1701 bool dc_remove_plane_from_context( 1702 const struct dc *dc, 1703 struct dc_stream_state *stream, 1704 struct dc_plane_state *plane_state, 1705 struct dc_state *context) 1706 { 1707 int i; 1708 struct dc_stream_status *stream_status = NULL; 1709 struct resource_pool *pool = dc->res_pool; 1710 1711 for (i = 0; i < context->stream_count; i++) 1712 if (context->streams[i] == stream) { 1713 stream_status = &context->stream_status[i]; 1714 break; 1715 } 1716 1717 if (stream_status == NULL) { 1718 dm_error("Existing stream not found; failed to remove plane.\n"); 1719 return false; 1720 } 1721 1722 /* release pipe for plane*/ 1723 for (i = pool->pipe_count - 1; i >= 0; i--) { 1724 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1725 1726 if (pipe_ctx->plane_state == plane_state) { 1727 if (pipe_ctx->top_pipe) 1728 pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe; 1729 1730 /* Second condition is to avoid setting NULL to top pipe 1731 * of tail pipe making it look like head pipe in subsequent 1732 * deletes 1733 */ 1734 if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe) 1735 pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe; 1736 1737 /* 1738 * For head pipe detach surfaces from pipe for tail 1739 * pipe just zero it out 1740 */ 1741 if (!pipe_ctx->top_pipe) 1742 pipe_ctx->plane_state = NULL; 1743 else 1744 memset(pipe_ctx, 0, sizeof(*pipe_ctx)); 1745 } 1746 } 1747 1748 1749 for (i = 0; i < stream_status->plane_count; i++) { 1750 if (stream_status->plane_states[i] == plane_state) { 1751 dc_plane_state_release(stream_status->plane_states[i]); 1752 break; 1753 } 1754 } 1755 1756 if (i == stream_status->plane_count) { 1757 dm_error("Existing plane_state not found; failed to detach it!\n"); 1758 return false; 1759 } 1760 1761 stream_status->plane_count--; 1762 1763 /* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */ 1764 for (; i < stream_status->plane_count; i++) 1765 stream_status->plane_states[i] = stream_status->plane_states[i + 1]; 1766 1767 stream_status->plane_states[stream_status->plane_count] = NULL; 1768 1769 return true; 1770 } 1771 1772 /** 1773 * dc_rem_all_planes_for_stream - Remove planes attached to the target stream. 1774 * 1775 * @dc: Current dc state. 1776 * @stream: Target stream, which we want to remove the attached plans. 1777 * @context: New context. 1778 * 1779 * Return: 1780 * Return true if DC was able to remove all planes from the target 1781 * stream, otherwise, return false. 1782 */ 1783 bool dc_rem_all_planes_for_stream( 1784 const struct dc *dc, 1785 struct dc_stream_state *stream, 1786 struct dc_state *context) 1787 { 1788 int i, old_plane_count; 1789 struct dc_stream_status *stream_status = NULL; 1790 struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 }; 1791 1792 for (i = 0; i < context->stream_count; i++) 1793 if (context->streams[i] == stream) { 1794 stream_status = &context->stream_status[i]; 1795 break; 1796 } 1797 1798 if (stream_status == NULL) { 1799 dm_error("Existing stream %p not found!\n", stream); 1800 return false; 1801 } 1802 1803 old_plane_count = stream_status->plane_count; 1804 1805 for (i = 0; i < old_plane_count; i++) 1806 del_planes[i] = stream_status->plane_states[i]; 1807 1808 for (i = 0; i < old_plane_count; i++) 1809 if (!dc_remove_plane_from_context(dc, stream, del_planes[i], context)) 1810 return false; 1811 1812 return true; 1813 } 1814 1815 static bool add_all_planes_for_stream( 1816 const struct dc *dc, 1817 struct dc_stream_state *stream, 1818 const struct dc_validation_set set[], 1819 int set_count, 1820 struct dc_state *context) 1821 { 1822 int i, j; 1823 1824 for (i = 0; i < set_count; i++) 1825 if (set[i].stream == stream) 1826 break; 1827 1828 if (i == set_count) { 1829 dm_error("Stream %p not found in set!\n", stream); 1830 return false; 1831 } 1832 1833 for (j = 0; j < set[i].plane_count; j++) 1834 if (!dc_add_plane_to_context(dc, stream, set[i].plane_states[j], context)) 1835 return false; 1836 1837 return true; 1838 } 1839 1840 bool dc_add_all_planes_for_stream( 1841 const struct dc *dc, 1842 struct dc_stream_state *stream, 1843 struct dc_plane_state * const *plane_states, 1844 int plane_count, 1845 struct dc_state *context) 1846 { 1847 struct dc_validation_set set; 1848 int i; 1849 1850 set.stream = stream; 1851 set.plane_count = plane_count; 1852 1853 for (i = 0; i < plane_count; i++) 1854 set.plane_states[i] = plane_states[i]; 1855 1856 return add_all_planes_for_stream(dc, stream, &set, 1, context); 1857 } 1858 1859 bool is_timing_changed(struct dc_stream_state *cur_stream, 1860 struct dc_stream_state *new_stream) 1861 { 1862 if (cur_stream == NULL) 1863 return true; 1864 1865 /* If output color space is changed, need to reprogram info frames */ 1866 if (cur_stream->output_color_space != new_stream->output_color_space) 1867 return true; 1868 1869 return memcmp( 1870 &cur_stream->timing, 1871 &new_stream->timing, 1872 sizeof(struct dc_crtc_timing)) != 0; 1873 } 1874 1875 static bool are_stream_backends_same( 1876 struct dc_stream_state *stream_a, struct dc_stream_state *stream_b) 1877 { 1878 if (stream_a == stream_b) 1879 return true; 1880 1881 if (stream_a == NULL || stream_b == NULL) 1882 return false; 1883 1884 if (is_timing_changed(stream_a, stream_b)) 1885 return false; 1886 1887 if (stream_a->signal != stream_b->signal) 1888 return false; 1889 1890 if (stream_a->dpms_off != stream_b->dpms_off) 1891 return false; 1892 1893 return true; 1894 } 1895 1896 /* 1897 * dc_is_stream_unchanged() - Compare two stream states for equivalence. 1898 * 1899 * Checks if there a difference between the two states 1900 * that would require a mode change. 1901 * 1902 * Does not compare cursor position or attributes. 1903 */ 1904 bool dc_is_stream_unchanged( 1905 struct dc_stream_state *old_stream, struct dc_stream_state *stream) 1906 { 1907 1908 if (!are_stream_backends_same(old_stream, stream)) 1909 return false; 1910 1911 if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param) 1912 return false; 1913 1914 /*compare audio info*/ 1915 if (memcmp(&old_stream->audio_info, &stream->audio_info, sizeof(stream->audio_info)) != 0) 1916 return false; 1917 1918 return true; 1919 } 1920 1921 /* 1922 * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams. 1923 */ 1924 bool dc_is_stream_scaling_unchanged(struct dc_stream_state *old_stream, 1925 struct dc_stream_state *stream) 1926 { 1927 if (old_stream == stream) 1928 return true; 1929 1930 if (old_stream == NULL || stream == NULL) 1931 return false; 1932 1933 if (memcmp(&old_stream->src, 1934 &stream->src, 1935 sizeof(struct rect)) != 0) 1936 return false; 1937 1938 if (memcmp(&old_stream->dst, 1939 &stream->dst, 1940 sizeof(struct rect)) != 0) 1941 return false; 1942 1943 return true; 1944 } 1945 1946 static void update_stream_engine_usage( 1947 struct resource_context *res_ctx, 1948 const struct resource_pool *pool, 1949 struct stream_encoder *stream_enc, 1950 bool acquired) 1951 { 1952 int i; 1953 1954 for (i = 0; i < pool->stream_enc_count; i++) { 1955 if (pool->stream_enc[i] == stream_enc) 1956 res_ctx->is_stream_enc_acquired[i] = acquired; 1957 } 1958 } 1959 1960 static void update_hpo_dp_stream_engine_usage( 1961 struct resource_context *res_ctx, 1962 const struct resource_pool *pool, 1963 struct hpo_dp_stream_encoder *hpo_dp_stream_enc, 1964 bool acquired) 1965 { 1966 int i; 1967 1968 for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { 1969 if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc) 1970 res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired; 1971 } 1972 } 1973 1974 static inline int find_acquired_hpo_dp_link_enc_for_link( 1975 const struct resource_context *res_ctx, 1976 const struct dc_link *link) 1977 { 1978 int i; 1979 1980 for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++) 1981 if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 && 1982 res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index) 1983 return i; 1984 1985 return -1; 1986 } 1987 1988 static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx, 1989 const struct resource_pool *pool) 1990 { 1991 int i; 1992 1993 for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++) 1994 if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0) 1995 break; 1996 1997 return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) && 1998 i < pool->hpo_dp_link_enc_count) ? i : -1; 1999 } 2000 2001 static inline void acquire_hpo_dp_link_enc( 2002 struct resource_context *res_ctx, 2003 unsigned int link_index, 2004 int enc_index) 2005 { 2006 res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index; 2007 res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1; 2008 } 2009 2010 static inline void retain_hpo_dp_link_enc( 2011 struct resource_context *res_ctx, 2012 int enc_index) 2013 { 2014 res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++; 2015 } 2016 2017 static inline void release_hpo_dp_link_enc( 2018 struct resource_context *res_ctx, 2019 int enc_index) 2020 { 2021 ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0); 2022 res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--; 2023 } 2024 2025 static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx, 2026 const struct resource_pool *pool, 2027 struct pipe_ctx *pipe_ctx, 2028 struct dc_stream_state *stream) 2029 { 2030 int enc_index; 2031 2032 enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); 2033 2034 if (enc_index >= 0) { 2035 retain_hpo_dp_link_enc(res_ctx, enc_index); 2036 } else { 2037 enc_index = find_free_hpo_dp_link_enc(res_ctx, pool); 2038 if (enc_index >= 0) 2039 acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index); 2040 } 2041 2042 if (enc_index >= 0) 2043 pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index]; 2044 2045 return pipe_ctx->link_res.hpo_dp_link_enc != NULL; 2046 } 2047 2048 static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx, 2049 struct pipe_ctx *pipe_ctx, 2050 struct dc_stream_state *stream) 2051 { 2052 int enc_index; 2053 2054 enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); 2055 2056 if (enc_index >= 0) { 2057 release_hpo_dp_link_enc(res_ctx, enc_index); 2058 pipe_ctx->link_res.hpo_dp_link_enc = NULL; 2059 } 2060 } 2061 2062 /* TODO: release audio object */ 2063 void update_audio_usage( 2064 struct resource_context *res_ctx, 2065 const struct resource_pool *pool, 2066 struct audio *audio, 2067 bool acquired) 2068 { 2069 int i; 2070 for (i = 0; i < pool->audio_count; i++) { 2071 if (pool->audios[i] == audio) 2072 res_ctx->is_audio_acquired[i] = acquired; 2073 } 2074 } 2075 2076 static int acquire_first_free_pipe( 2077 struct resource_context *res_ctx, 2078 const struct resource_pool *pool, 2079 struct dc_stream_state *stream) 2080 { 2081 int i; 2082 2083 for (i = 0; i < pool->pipe_count; i++) { 2084 if (!res_ctx->pipe_ctx[i].stream) { 2085 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; 2086 2087 pipe_ctx->stream_res.tg = pool->timing_generators[i]; 2088 pipe_ctx->plane_res.mi = pool->mis[i]; 2089 pipe_ctx->plane_res.hubp = pool->hubps[i]; 2090 pipe_ctx->plane_res.ipp = pool->ipps[i]; 2091 pipe_ctx->plane_res.xfm = pool->transforms[i]; 2092 pipe_ctx->plane_res.dpp = pool->dpps[i]; 2093 pipe_ctx->stream_res.opp = pool->opps[i]; 2094 if (pool->dpps[i]) 2095 pipe_ctx->plane_res.mpcc_inst = pool->dpps[i]->inst; 2096 pipe_ctx->pipe_idx = i; 2097 2098 if (i >= pool->timing_generator_count) { 2099 int tg_inst = pool->timing_generator_count - 1; 2100 2101 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; 2102 pipe_ctx->stream_res.opp = pool->opps[tg_inst]; 2103 } 2104 2105 pipe_ctx->stream = stream; 2106 return i; 2107 } 2108 } 2109 return -1; 2110 } 2111 2112 static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for_link( 2113 struct resource_context *res_ctx, 2114 const struct resource_pool *pool, 2115 struct dc_stream_state *stream) 2116 { 2117 int i; 2118 2119 for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { 2120 if (!res_ctx->is_hpo_dp_stream_enc_acquired[i] && 2121 pool->hpo_dp_stream_enc[i]) { 2122 2123 return pool->hpo_dp_stream_enc[i]; 2124 } 2125 } 2126 2127 return NULL; 2128 } 2129 2130 static struct audio *find_first_free_audio( 2131 struct resource_context *res_ctx, 2132 const struct resource_pool *pool, 2133 enum engine_id id, 2134 enum dce_version dc_version) 2135 { 2136 int i, available_audio_count; 2137 2138 available_audio_count = pool->audio_count; 2139 2140 for (i = 0; i < available_audio_count; i++) { 2141 if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) { 2142 /*we have enough audio endpoint, find the matching inst*/ 2143 if (id != i) 2144 continue; 2145 return pool->audios[i]; 2146 } 2147 } 2148 2149 /* use engine id to find free audio */ 2150 if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false)) { 2151 return pool->audios[id]; 2152 } 2153 /*not found the matching one, first come first serve*/ 2154 for (i = 0; i < available_audio_count; i++) { 2155 if (res_ctx->is_audio_acquired[i] == false) { 2156 return pool->audios[i]; 2157 } 2158 } 2159 return NULL; 2160 } 2161 2162 /* 2163 * dc_add_stream_to_ctx() - Add a new dc_stream_state to a dc_state. 2164 */ 2165 enum dc_status dc_add_stream_to_ctx( 2166 struct dc *dc, 2167 struct dc_state *new_ctx, 2168 struct dc_stream_state *stream) 2169 { 2170 enum dc_status res; 2171 DC_LOGGER_INIT(dc->ctx->logger); 2172 2173 if (new_ctx->stream_count >= dc->res_pool->timing_generator_count) { 2174 DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream); 2175 return DC_ERROR_UNEXPECTED; 2176 } 2177 2178 new_ctx->streams[new_ctx->stream_count] = stream; 2179 dc_stream_retain(stream); 2180 new_ctx->stream_count++; 2181 2182 res = dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream); 2183 if (res != DC_OK) 2184 DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res); 2185 2186 return res; 2187 } 2188 2189 /* 2190 * dc_remove_stream_from_ctx() - Remove a stream from a dc_state. 2191 */ 2192 enum dc_status dc_remove_stream_from_ctx( 2193 struct dc *dc, 2194 struct dc_state *new_ctx, 2195 struct dc_stream_state *stream) 2196 { 2197 int i; 2198 struct dc_context *dc_ctx = dc->ctx; 2199 struct pipe_ctx *del_pipe = resource_get_head_pipe_for_stream(&new_ctx->res_ctx, stream); 2200 struct pipe_ctx *odm_pipe; 2201 2202 if (!del_pipe) { 2203 DC_ERROR("Pipe not found for stream %p !\n", stream); 2204 return DC_ERROR_UNEXPECTED; 2205 } 2206 2207 odm_pipe = del_pipe->next_odm_pipe; 2208 2209 /* Release primary pipe */ 2210 ASSERT(del_pipe->stream_res.stream_enc); 2211 update_stream_engine_usage( 2212 &new_ctx->res_ctx, 2213 dc->res_pool, 2214 del_pipe->stream_res.stream_enc, 2215 false); 2216 2217 if (link_is_dp_128b_132b_signal(del_pipe)) { 2218 update_hpo_dp_stream_engine_usage( 2219 &new_ctx->res_ctx, dc->res_pool, 2220 del_pipe->stream_res.hpo_dp_stream_enc, 2221 false); 2222 remove_hpo_dp_link_enc_from_ctx(&new_ctx->res_ctx, del_pipe, del_pipe->stream); 2223 } 2224 2225 if (del_pipe->stream_res.audio) 2226 update_audio_usage( 2227 &new_ctx->res_ctx, 2228 dc->res_pool, 2229 del_pipe->stream_res.audio, 2230 false); 2231 2232 resource_unreference_clock_source(&new_ctx->res_ctx, 2233 dc->res_pool, 2234 del_pipe->clock_source); 2235 2236 if (dc->res_pool->funcs->remove_stream_from_ctx) 2237 dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream); 2238 2239 while (odm_pipe) { 2240 struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe; 2241 2242 memset(odm_pipe, 0, sizeof(*odm_pipe)); 2243 odm_pipe = next_odm_pipe; 2244 } 2245 memset(del_pipe, 0, sizeof(*del_pipe)); 2246 2247 for (i = 0; i < new_ctx->stream_count; i++) 2248 if (new_ctx->streams[i] == stream) 2249 break; 2250 2251 if (new_ctx->streams[i] != stream) { 2252 DC_ERROR("Context doesn't have stream %p !\n", stream); 2253 return DC_ERROR_UNEXPECTED; 2254 } 2255 2256 dc_stream_release(new_ctx->streams[i]); 2257 new_ctx->stream_count--; 2258 2259 /* Trim back arrays */ 2260 for (; i < new_ctx->stream_count; i++) { 2261 new_ctx->streams[i] = new_ctx->streams[i + 1]; 2262 new_ctx->stream_status[i] = new_ctx->stream_status[i + 1]; 2263 } 2264 2265 new_ctx->streams[new_ctx->stream_count] = NULL; 2266 memset( 2267 &new_ctx->stream_status[new_ctx->stream_count], 2268 0, 2269 sizeof(new_ctx->stream_status[0])); 2270 2271 return DC_OK; 2272 } 2273 2274 static struct dc_stream_state *find_pll_sharable_stream( 2275 struct dc_stream_state *stream_needs_pll, 2276 struct dc_state *context) 2277 { 2278 int i; 2279 2280 for (i = 0; i < context->stream_count; i++) { 2281 struct dc_stream_state *stream_has_pll = context->streams[i]; 2282 2283 /* We are looking for non dp, non virtual stream */ 2284 if (resource_are_streams_timing_synchronizable( 2285 stream_needs_pll, stream_has_pll) 2286 && !dc_is_dp_signal(stream_has_pll->signal) 2287 && stream_has_pll->link->connector_signal 2288 != SIGNAL_TYPE_VIRTUAL) 2289 return stream_has_pll; 2290 2291 } 2292 2293 return NULL; 2294 } 2295 2296 static int get_norm_pix_clk(const struct dc_crtc_timing *timing) 2297 { 2298 uint32_t pix_clk = timing->pix_clk_100hz; 2299 uint32_t normalized_pix_clk = pix_clk; 2300 2301 if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) 2302 pix_clk /= 2; 2303 if (timing->pixel_encoding != PIXEL_ENCODING_YCBCR422) { 2304 switch (timing->display_color_depth) { 2305 case COLOR_DEPTH_666: 2306 case COLOR_DEPTH_888: 2307 normalized_pix_clk = pix_clk; 2308 break; 2309 case COLOR_DEPTH_101010: 2310 normalized_pix_clk = (pix_clk * 30) / 24; 2311 break; 2312 case COLOR_DEPTH_121212: 2313 normalized_pix_clk = (pix_clk * 36) / 24; 2314 break; 2315 case COLOR_DEPTH_161616: 2316 normalized_pix_clk = (pix_clk * 48) / 24; 2317 break; 2318 default: 2319 ASSERT(0); 2320 break; 2321 } 2322 } 2323 return normalized_pix_clk; 2324 } 2325 2326 static void calculate_phy_pix_clks(struct dc_stream_state *stream) 2327 { 2328 /* update actual pixel clock on all streams */ 2329 if (dc_is_hdmi_signal(stream->signal)) 2330 stream->phy_pix_clk = get_norm_pix_clk( 2331 &stream->timing) / 10; 2332 else 2333 stream->phy_pix_clk = 2334 stream->timing.pix_clk_100hz / 10; 2335 2336 if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) 2337 stream->phy_pix_clk *= 2; 2338 } 2339 2340 static int acquire_resource_from_hw_enabled_state( 2341 struct resource_context *res_ctx, 2342 const struct resource_pool *pool, 2343 struct dc_stream_state *stream) 2344 { 2345 struct dc_link *link = stream->link; 2346 unsigned int i, inst, tg_inst = 0; 2347 uint32_t numPipes = 1; 2348 uint32_t id_src[4] = {0}; 2349 2350 /* Check for enabled DIG to identify enabled display */ 2351 if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) 2352 return -1; 2353 2354 inst = link->link_enc->funcs->get_dig_frontend(link->link_enc); 2355 2356 if (inst == ENGINE_ID_UNKNOWN) 2357 return -1; 2358 2359 for (i = 0; i < pool->stream_enc_count; i++) { 2360 if (pool->stream_enc[i]->id == inst) { 2361 tg_inst = pool->stream_enc[i]->funcs->dig_source_otg( 2362 pool->stream_enc[i]); 2363 break; 2364 } 2365 } 2366 2367 // tg_inst not found 2368 if (i == pool->stream_enc_count) 2369 return -1; 2370 2371 if (tg_inst >= pool->timing_generator_count) 2372 return -1; 2373 2374 if (!res_ctx->pipe_ctx[tg_inst].stream) { 2375 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst]; 2376 2377 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; 2378 id_src[0] = tg_inst; 2379 2380 if (pipe_ctx->stream_res.tg->funcs->get_optc_source) 2381 pipe_ctx->stream_res.tg->funcs->get_optc_source(pipe_ctx->stream_res.tg, 2382 &numPipes, &id_src[0], &id_src[1]); 2383 2384 if (id_src[0] == 0xf && id_src[1] == 0xf) { 2385 id_src[0] = tg_inst; 2386 numPipes = 1; 2387 } 2388 2389 for (i = 0; i < numPipes; i++) { 2390 //Check if src id invalid 2391 if (id_src[i] == 0xf) 2392 return -1; 2393 2394 pipe_ctx = &res_ctx->pipe_ctx[id_src[i]]; 2395 2396 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; 2397 pipe_ctx->plane_res.mi = pool->mis[id_src[i]]; 2398 pipe_ctx->plane_res.hubp = pool->hubps[id_src[i]]; 2399 pipe_ctx->plane_res.ipp = pool->ipps[id_src[i]]; 2400 pipe_ctx->plane_res.xfm = pool->transforms[id_src[i]]; 2401 pipe_ctx->plane_res.dpp = pool->dpps[id_src[i]]; 2402 pipe_ctx->stream_res.opp = pool->opps[id_src[i]]; 2403 2404 if (pool->dpps[id_src[i]]) { 2405 pipe_ctx->plane_res.mpcc_inst = pool->dpps[id_src[i]]->inst; 2406 2407 if (pool->mpc->funcs->read_mpcc_state) { 2408 struct mpcc_state s = {0}; 2409 2410 pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s); 2411 2412 if (s.dpp_id < MAX_MPCC) 2413 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id = 2414 s.dpp_id; 2415 2416 if (s.bot_mpcc_id < MAX_MPCC) 2417 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot = 2418 &pool->mpc->mpcc_array[s.bot_mpcc_id]; 2419 2420 if (s.opp_id < MAX_OPP) 2421 pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id; 2422 } 2423 } 2424 pipe_ctx->pipe_idx = id_src[i]; 2425 2426 if (id_src[i] >= pool->timing_generator_count) { 2427 id_src[i] = pool->timing_generator_count - 1; 2428 2429 pipe_ctx->stream_res.tg = pool->timing_generators[id_src[i]]; 2430 pipe_ctx->stream_res.opp = pool->opps[id_src[i]]; 2431 } 2432 2433 pipe_ctx->stream = stream; 2434 } 2435 2436 if (numPipes == 2) { 2437 stream->apply_boot_odm_mode = dm_odm_combine_policy_2to1; 2438 res_ctx->pipe_ctx[id_src[0]].next_odm_pipe = &res_ctx->pipe_ctx[id_src[1]]; 2439 res_ctx->pipe_ctx[id_src[0]].prev_odm_pipe = NULL; 2440 res_ctx->pipe_ctx[id_src[1]].next_odm_pipe = NULL; 2441 res_ctx->pipe_ctx[id_src[1]].prev_odm_pipe = &res_ctx->pipe_ctx[id_src[0]]; 2442 } else 2443 stream->apply_boot_odm_mode = dm_odm_combine_mode_disabled; 2444 2445 return id_src[0]; 2446 } 2447 2448 return -1; 2449 } 2450 2451 static void mark_seamless_boot_stream( 2452 const struct dc *dc, 2453 struct dc_stream_state *stream) 2454 { 2455 struct dc_bios *dcb = dc->ctx->dc_bios; 2456 2457 if (dc->config.allow_seamless_boot_optimization && 2458 !dcb->funcs->is_accelerated_mode(dcb)) { 2459 if (dc_validate_boot_timing(dc, stream->sink, &stream->timing)) 2460 stream->apply_seamless_boot_optimization = true; 2461 } 2462 } 2463 2464 enum dc_status resource_map_pool_resources( 2465 const struct dc *dc, 2466 struct dc_state *context, 2467 struct dc_stream_state *stream) 2468 { 2469 const struct resource_pool *pool = dc->res_pool; 2470 int i; 2471 struct dc_context *dc_ctx = dc->ctx; 2472 struct pipe_ctx *pipe_ctx = NULL; 2473 int pipe_idx = -1; 2474 2475 calculate_phy_pix_clks(stream); 2476 2477 mark_seamless_boot_stream(dc, stream); 2478 2479 if (stream->apply_seamless_boot_optimization) { 2480 pipe_idx = acquire_resource_from_hw_enabled_state( 2481 &context->res_ctx, 2482 pool, 2483 stream); 2484 if (pipe_idx < 0) 2485 /* hw resource was assigned to other stream */ 2486 stream->apply_seamless_boot_optimization = false; 2487 } 2488 2489 if (pipe_idx < 0) 2490 /* acquire new resources */ 2491 pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream); 2492 2493 if (pipe_idx < 0) 2494 pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); 2495 2496 if (pipe_idx < 0 || context->res_ctx.pipe_ctx[pipe_idx].stream_res.tg == NULL) 2497 return DC_NO_CONTROLLER_RESOURCE; 2498 2499 pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; 2500 2501 pipe_ctx->stream_res.stream_enc = 2502 dc->res_pool->funcs->find_first_free_match_stream_enc_for_link( 2503 &context->res_ctx, pool, stream); 2504 2505 if (!pipe_ctx->stream_res.stream_enc) 2506 return DC_NO_STREAM_ENC_RESOURCE; 2507 2508 update_stream_engine_usage( 2509 &context->res_ctx, pool, 2510 pipe_ctx->stream_res.stream_enc, 2511 true); 2512 2513 /* Allocate DP HPO Stream Encoder based on signal, hw capabilities 2514 * and link settings 2515 */ 2516 if (dc_is_dp_signal(stream->signal)) { 2517 if (!link_decide_link_settings(stream, &pipe_ctx->link_config.dp_link_settings)) 2518 return DC_FAIL_DP_LINK_BANDWIDTH; 2519 if (link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) { 2520 pipe_ctx->stream_res.hpo_dp_stream_enc = 2521 find_first_free_match_hpo_dp_stream_enc_for_link( 2522 &context->res_ctx, pool, stream); 2523 2524 if (!pipe_ctx->stream_res.hpo_dp_stream_enc) 2525 return DC_NO_STREAM_ENC_RESOURCE; 2526 2527 update_hpo_dp_stream_engine_usage( 2528 &context->res_ctx, pool, 2529 pipe_ctx->stream_res.hpo_dp_stream_enc, 2530 true); 2531 if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, pool, pipe_ctx, stream)) 2532 return DC_NO_LINK_ENC_RESOURCE; 2533 } 2534 } 2535 2536 /* TODO: Add check if ASIC support and EDID audio */ 2537 if (!stream->converter_disable_audio && 2538 dc_is_audio_capable_signal(pipe_ctx->stream->signal) && 2539 stream->audio_info.mode_count && stream->audio_info.flags.all) { 2540 pipe_ctx->stream_res.audio = find_first_free_audio( 2541 &context->res_ctx, pool, pipe_ctx->stream_res.stream_enc->id, dc_ctx->dce_version); 2542 2543 /* 2544 * Audio assigned in order first come first get. 2545 * There are asics which has number of audio 2546 * resources less then number of pipes 2547 */ 2548 if (pipe_ctx->stream_res.audio) 2549 update_audio_usage(&context->res_ctx, pool, 2550 pipe_ctx->stream_res.audio, true); 2551 } 2552 2553 /* Add ABM to the resource if on EDP */ 2554 if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) { 2555 if (pool->abm) 2556 pipe_ctx->stream_res.abm = pool->abm; 2557 else 2558 pipe_ctx->stream_res.abm = pool->multiple_abms[pipe_ctx->stream_res.tg->inst]; 2559 } 2560 2561 for (i = 0; i < context->stream_count; i++) 2562 if (context->streams[i] == stream) { 2563 context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst; 2564 context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->stream_enc_inst; 2565 context->stream_status[i].audio_inst = 2566 pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1; 2567 2568 return DC_OK; 2569 } 2570 2571 DC_ERROR("Stream %p not found in new ctx!\n", stream); 2572 return DC_ERROR_UNEXPECTED; 2573 } 2574 2575 /** 2576 * dc_resource_state_copy_construct_current() - Creates a new dc_state from existing state 2577 * 2578 * @dc: copy out of dc->current_state 2579 * @dst_ctx: copy into this 2580 * 2581 * This function makes a shallow copy of the current DC state and increments 2582 * refcounts on existing streams and planes. 2583 */ 2584 void dc_resource_state_copy_construct_current( 2585 const struct dc *dc, 2586 struct dc_state *dst_ctx) 2587 { 2588 dc_resource_state_copy_construct(dc->current_state, dst_ctx); 2589 } 2590 2591 2592 void dc_resource_state_construct( 2593 const struct dc *dc, 2594 struct dc_state *dst_ctx) 2595 { 2596 dst_ctx->clk_mgr = dc->clk_mgr; 2597 2598 /* Initialise DIG link encoder resource tracking variables. */ 2599 link_enc_cfg_init(dc, dst_ctx); 2600 } 2601 2602 2603 bool dc_resource_is_dsc_encoding_supported(const struct dc *dc) 2604 { 2605 if (dc->res_pool == NULL) 2606 return false; 2607 2608 return dc->res_pool->res_cap->num_dsc > 0; 2609 } 2610 2611 static bool planes_changed_for_existing_stream(struct dc_state *context, 2612 struct dc_stream_state *stream, 2613 const struct dc_validation_set set[], 2614 int set_count) 2615 { 2616 int i, j; 2617 struct dc_stream_status *stream_status = NULL; 2618 2619 for (i = 0; i < context->stream_count; i++) { 2620 if (context->streams[i] == stream) { 2621 stream_status = &context->stream_status[i]; 2622 break; 2623 } 2624 } 2625 2626 if (!stream_status) 2627 ASSERT(0); 2628 2629 for (i = 0; i < set_count; i++) 2630 if (set[i].stream == stream) 2631 break; 2632 2633 if (i == set_count) 2634 ASSERT(0); 2635 2636 if (set[i].plane_count != stream_status->plane_count) 2637 return true; 2638 2639 for (j = 0; j < set[i].plane_count; j++) 2640 if (set[i].plane_states[j] != stream_status->plane_states[j]) 2641 return true; 2642 2643 return false; 2644 } 2645 2646 /** 2647 * dc_validate_with_context - Validate and update the potential new stream in the context object 2648 * 2649 * @dc: Used to get the current state status 2650 * @set: An array of dc_validation_set with all the current streams reference 2651 * @set_count: Total of streams 2652 * @context: New context 2653 * @fast_validate: Enable or disable fast validation 2654 * 2655 * This function updates the potential new stream in the context object. It 2656 * creates multiple lists for the add, remove, and unchanged streams. In 2657 * particular, if the unchanged streams have a plane that changed, it is 2658 * necessary to remove all planes from the unchanged streams. In summary, this 2659 * function is responsible for validating the new context. 2660 * 2661 * Return: 2662 * In case of success, return DC_OK (1), otherwise, return a DC error. 2663 */ 2664 enum dc_status dc_validate_with_context(struct dc *dc, 2665 const struct dc_validation_set set[], 2666 int set_count, 2667 struct dc_state *context, 2668 bool fast_validate) 2669 { 2670 struct dc_stream_state *unchanged_streams[MAX_PIPES] = { 0 }; 2671 struct dc_stream_state *del_streams[MAX_PIPES] = { 0 }; 2672 struct dc_stream_state *add_streams[MAX_PIPES] = { 0 }; 2673 int old_stream_count = context->stream_count; 2674 enum dc_status res = DC_ERROR_UNEXPECTED; 2675 int unchanged_streams_count = 0; 2676 int del_streams_count = 0; 2677 int add_streams_count = 0; 2678 bool found = false; 2679 int i, j, k; 2680 2681 DC_LOGGER_INIT(dc->ctx->logger); 2682 2683 /* First build a list of streams to be remove from current context */ 2684 for (i = 0; i < old_stream_count; i++) { 2685 struct dc_stream_state *stream = context->streams[i]; 2686 2687 for (j = 0; j < set_count; j++) { 2688 if (stream == set[j].stream) { 2689 found = true; 2690 break; 2691 } 2692 } 2693 2694 if (!found) 2695 del_streams[del_streams_count++] = stream; 2696 2697 found = false; 2698 } 2699 2700 /* Second, build a list of new streams */ 2701 for (i = 0; i < set_count; i++) { 2702 struct dc_stream_state *stream = set[i].stream; 2703 2704 for (j = 0; j < old_stream_count; j++) { 2705 if (stream == context->streams[j]) { 2706 found = true; 2707 break; 2708 } 2709 } 2710 2711 if (!found) 2712 add_streams[add_streams_count++] = stream; 2713 2714 found = false; 2715 } 2716 2717 /* Build a list of unchanged streams which is necessary for handling 2718 * planes change such as added, removed, and updated. 2719 */ 2720 for (i = 0; i < set_count; i++) { 2721 /* Check if stream is part of the delete list */ 2722 for (j = 0; j < del_streams_count; j++) { 2723 if (set[i].stream == del_streams[j]) { 2724 found = true; 2725 break; 2726 } 2727 } 2728 2729 if (!found) { 2730 /* Check if stream is part of the add list */ 2731 for (j = 0; j < add_streams_count; j++) { 2732 if (set[i].stream == add_streams[j]) { 2733 found = true; 2734 break; 2735 } 2736 } 2737 } 2738 2739 if (!found) 2740 unchanged_streams[unchanged_streams_count++] = set[i].stream; 2741 2742 found = false; 2743 } 2744 2745 /* Remove all planes for unchanged streams if planes changed */ 2746 for (i = 0; i < unchanged_streams_count; i++) { 2747 if (planes_changed_for_existing_stream(context, 2748 unchanged_streams[i], 2749 set, 2750 set_count)) { 2751 if (!dc_rem_all_planes_for_stream(dc, 2752 unchanged_streams[i], 2753 context)) { 2754 res = DC_FAIL_DETACH_SURFACES; 2755 goto fail; 2756 } 2757 } 2758 } 2759 2760 /* Remove all planes for removed streams and then remove the streams */ 2761 for (i = 0; i < del_streams_count; i++) { 2762 /* Need to cpy the dwb data from the old stream in order to efc to work */ 2763 if (del_streams[i]->num_wb_info > 0) { 2764 for (j = 0; j < add_streams_count; j++) { 2765 if (del_streams[i]->sink == add_streams[j]->sink) { 2766 add_streams[j]->num_wb_info = del_streams[i]->num_wb_info; 2767 for (k = 0; k < del_streams[i]->num_wb_info; k++) 2768 add_streams[j]->writeback_info[k] = del_streams[i]->writeback_info[k]; 2769 } 2770 } 2771 } 2772 2773 if (!dc_rem_all_planes_for_stream(dc, del_streams[i], context)) { 2774 res = DC_FAIL_DETACH_SURFACES; 2775 goto fail; 2776 } 2777 2778 res = dc_remove_stream_from_ctx(dc, context, del_streams[i]); 2779 if (res != DC_OK) 2780 goto fail; 2781 } 2782 2783 /* Swap seamless boot stream to pipe 0 (if needed) to ensure pipe_ctx 2784 * matches. This may change in the future if seamless_boot_stream can be 2785 * multiple. 2786 */ 2787 for (i = 0; i < add_streams_count; i++) { 2788 mark_seamless_boot_stream(dc, add_streams[i]); 2789 if (add_streams[i]->apply_seamless_boot_optimization && i != 0) { 2790 struct dc_stream_state *temp = add_streams[0]; 2791 2792 add_streams[0] = add_streams[i]; 2793 add_streams[i] = temp; 2794 break; 2795 } 2796 } 2797 2798 /* Add new streams and then add all planes for the new stream */ 2799 for (i = 0; i < add_streams_count; i++) { 2800 calculate_phy_pix_clks(add_streams[i]); 2801 res = dc_add_stream_to_ctx(dc, context, add_streams[i]); 2802 if (res != DC_OK) 2803 goto fail; 2804 2805 if (!add_all_planes_for_stream(dc, add_streams[i], set, set_count, context)) { 2806 res = DC_FAIL_ATTACH_SURFACES; 2807 goto fail; 2808 } 2809 } 2810 2811 /* Add all planes for unchanged streams if planes changed */ 2812 for (i = 0; i < unchanged_streams_count; i++) { 2813 if (planes_changed_for_existing_stream(context, 2814 unchanged_streams[i], 2815 set, 2816 set_count)) { 2817 if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, set_count, context)) { 2818 res = DC_FAIL_ATTACH_SURFACES; 2819 goto fail; 2820 } 2821 } 2822 } 2823 2824 res = dc_validate_global_state(dc, context, fast_validate); 2825 2826 fail: 2827 if (res != DC_OK) 2828 DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n", 2829 __func__, 2830 res); 2831 2832 return res; 2833 } 2834 2835 /** 2836 * dc_validate_global_state() - Determine if hardware can support a given state 2837 * 2838 * @dc: dc struct for this driver 2839 * @new_ctx: state to be validated 2840 * @fast_validate: set to true if only yes/no to support matters 2841 * 2842 * Checks hardware resource availability and bandwidth requirement. 2843 * 2844 * Return: 2845 * DC_OK if the result can be programmed. Otherwise, an error code. 2846 */ 2847 enum dc_status dc_validate_global_state( 2848 struct dc *dc, 2849 struct dc_state *new_ctx, 2850 bool fast_validate) 2851 { 2852 enum dc_status result = DC_ERROR_UNEXPECTED; 2853 int i, j; 2854 2855 if (!new_ctx) 2856 return DC_ERROR_UNEXPECTED; 2857 2858 if (dc->res_pool->funcs->validate_global) { 2859 result = dc->res_pool->funcs->validate_global(dc, new_ctx); 2860 if (result != DC_OK) 2861 return result; 2862 } 2863 2864 for (i = 0; i < new_ctx->stream_count; i++) { 2865 struct dc_stream_state *stream = new_ctx->streams[i]; 2866 2867 for (j = 0; j < dc->res_pool->pipe_count; j++) { 2868 struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[j]; 2869 2870 if (pipe_ctx->stream != stream) 2871 continue; 2872 2873 if (dc->res_pool->funcs->patch_unknown_plane_state && 2874 pipe_ctx->plane_state && 2875 pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) { 2876 result = dc->res_pool->funcs->patch_unknown_plane_state(pipe_ctx->plane_state); 2877 if (result != DC_OK) 2878 return result; 2879 } 2880 2881 /* Switch to dp clock source only if there is 2882 * no non dp stream that shares the same timing 2883 * with the dp stream. 2884 */ 2885 if (dc_is_dp_signal(pipe_ctx->stream->signal) && 2886 !find_pll_sharable_stream(stream, new_ctx)) { 2887 2888 resource_unreference_clock_source( 2889 &new_ctx->res_ctx, 2890 dc->res_pool, 2891 pipe_ctx->clock_source); 2892 2893 pipe_ctx->clock_source = dc->res_pool->dp_clock_source; 2894 resource_reference_clock_source( 2895 &new_ctx->res_ctx, 2896 dc->res_pool, 2897 pipe_ctx->clock_source); 2898 } 2899 } 2900 } 2901 2902 result = resource_build_scaling_params_for_context(dc, new_ctx); 2903 2904 if (result == DC_OK) 2905 if (!dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, fast_validate)) 2906 result = DC_FAIL_BANDWIDTH_VALIDATE; 2907 2908 /* 2909 * Only update link encoder to stream assignment after bandwidth validation passed. 2910 * TODO: Split out assignment and validation. 2911 */ 2912 if (result == DC_OK && dc->res_pool->funcs->link_encs_assign && fast_validate == false) 2913 dc->res_pool->funcs->link_encs_assign( 2914 dc, new_ctx, new_ctx->streams, new_ctx->stream_count); 2915 2916 return result; 2917 } 2918 2919 static void patch_gamut_packet_checksum( 2920 struct dc_info_packet *gamut_packet) 2921 { 2922 /* For gamut we recalc checksum */ 2923 if (gamut_packet->valid) { 2924 uint8_t chk_sum = 0; 2925 uint8_t *ptr; 2926 uint8_t i; 2927 2928 /*start of the Gamut data. */ 2929 ptr = &gamut_packet->sb[3]; 2930 2931 for (i = 0; i <= gamut_packet->sb[1]; i++) 2932 chk_sum += ptr[i]; 2933 2934 gamut_packet->sb[2] = (uint8_t) (0x100 - chk_sum); 2935 } 2936 } 2937 2938 static void set_avi_info_frame( 2939 struct dc_info_packet *info_packet, 2940 struct pipe_ctx *pipe_ctx) 2941 { 2942 struct dc_stream_state *stream = pipe_ctx->stream; 2943 enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; 2944 uint32_t pixel_encoding = 0; 2945 enum scanning_type scan_type = SCANNING_TYPE_NODATA; 2946 enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA; 2947 bool itc = false; 2948 uint8_t itc_value = 0; 2949 uint8_t cn0_cn1 = 0; 2950 unsigned int cn0_cn1_value = 0; 2951 uint8_t *check_sum = NULL; 2952 uint8_t byte_index = 0; 2953 union hdmi_info_packet hdmi_info; 2954 union display_content_support support = {0}; 2955 unsigned int vic = pipe_ctx->stream->timing.vic; 2956 unsigned int rid = pipe_ctx->stream->timing.rid; 2957 unsigned int fr_ind = pipe_ctx->stream->timing.fr_index; 2958 enum dc_timing_3d_format format; 2959 2960 memset(&hdmi_info, 0, sizeof(union hdmi_info_packet)); 2961 2962 color_space = pipe_ctx->stream->output_color_space; 2963 if (color_space == COLOR_SPACE_UNKNOWN) 2964 color_space = (stream->timing.pixel_encoding == PIXEL_ENCODING_RGB) ? 2965 COLOR_SPACE_SRGB:COLOR_SPACE_YCBCR709; 2966 2967 /* Initialize header */ 2968 hdmi_info.bits.header.info_frame_type = HDMI_INFOFRAME_TYPE_AVI; 2969 /* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall 2970 * not be used in HDMI 2.0 (Section 10.1) */ 2971 hdmi_info.bits.header.version = 2; 2972 hdmi_info.bits.header.length = HDMI_AVI_INFOFRAME_SIZE; 2973 2974 /* 2975 * IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built 2976 * according to HDMI 2.0 spec (Section 10.1) 2977 */ 2978 2979 switch (stream->timing.pixel_encoding) { 2980 case PIXEL_ENCODING_YCBCR422: 2981 pixel_encoding = 1; 2982 break; 2983 2984 case PIXEL_ENCODING_YCBCR444: 2985 pixel_encoding = 2; 2986 break; 2987 case PIXEL_ENCODING_YCBCR420: 2988 pixel_encoding = 3; 2989 break; 2990 2991 case PIXEL_ENCODING_RGB: 2992 default: 2993 pixel_encoding = 0; 2994 } 2995 2996 /* Y0_Y1_Y2 : The pixel encoding */ 2997 /* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */ 2998 hdmi_info.bits.Y0_Y1_Y2 = pixel_encoding; 2999 3000 /* A0 = 1 Active Format Information valid */ 3001 hdmi_info.bits.A0 = ACTIVE_FORMAT_VALID; 3002 3003 /* B0, B1 = 3; Bar info data is valid */ 3004 hdmi_info.bits.B0_B1 = BAR_INFO_BOTH_VALID; 3005 3006 hdmi_info.bits.SC0_SC1 = PICTURE_SCALING_UNIFORM; 3007 3008 /* S0, S1 : Underscan / Overscan */ 3009 /* TODO: un-hardcode scan type */ 3010 scan_type = SCANNING_TYPE_UNDERSCAN; 3011 hdmi_info.bits.S0_S1 = scan_type; 3012 3013 /* C0, C1 : Colorimetry */ 3014 if (color_space == COLOR_SPACE_YCBCR709 || 3015 color_space == COLOR_SPACE_YCBCR709_LIMITED) 3016 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709; 3017 else if (color_space == COLOR_SPACE_YCBCR601 || 3018 color_space == COLOR_SPACE_YCBCR601_LIMITED) 3019 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU601; 3020 else { 3021 hdmi_info.bits.C0_C1 = COLORIMETRY_NO_DATA; 3022 } 3023 if (color_space == COLOR_SPACE_2020_RGB_FULLRANGE || 3024 color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE || 3025 color_space == COLOR_SPACE_2020_YCBCR) { 3026 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR; 3027 hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; 3028 } else if (color_space == COLOR_SPACE_ADOBERGB) { 3029 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB; 3030 hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; 3031 } 3032 3033 if (pixel_encoding && color_space == COLOR_SPACE_2020_YCBCR && 3034 stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) { 3035 hdmi_info.bits.EC0_EC2 = 0; 3036 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709; 3037 } 3038 3039 /* TODO: un-hardcode aspect ratio */ 3040 aspect = stream->timing.aspect_ratio; 3041 3042 switch (aspect) { 3043 case ASPECT_RATIO_4_3: 3044 case ASPECT_RATIO_16_9: 3045 hdmi_info.bits.M0_M1 = aspect; 3046 break; 3047 3048 case ASPECT_RATIO_NO_DATA: 3049 case ASPECT_RATIO_64_27: 3050 case ASPECT_RATIO_256_135: 3051 default: 3052 hdmi_info.bits.M0_M1 = 0; 3053 } 3054 3055 /* Active Format Aspect ratio - same as Picture Aspect Ratio. */ 3056 hdmi_info.bits.R0_R3 = ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE; 3057 3058 /* TODO: un-hardcode cn0_cn1 and itc */ 3059 3060 cn0_cn1 = 0; 3061 cn0_cn1_value = 0; 3062 3063 itc = true; 3064 itc_value = 1; 3065 3066 support = stream->content_support; 3067 3068 if (itc) { 3069 if (!support.bits.valid_content_type) { 3070 cn0_cn1_value = 0; 3071 } else { 3072 if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GRAPHICS) { 3073 if (support.bits.graphics_content == 1) { 3074 cn0_cn1_value = 0; 3075 } 3076 } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_PHOTO) { 3077 if (support.bits.photo_content == 1) { 3078 cn0_cn1_value = 1; 3079 } else { 3080 cn0_cn1_value = 0; 3081 itc_value = 0; 3082 } 3083 } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_CINEMA) { 3084 if (support.bits.cinema_content == 1) { 3085 cn0_cn1_value = 2; 3086 } else { 3087 cn0_cn1_value = 0; 3088 itc_value = 0; 3089 } 3090 } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GAME) { 3091 if (support.bits.game_content == 1) { 3092 cn0_cn1_value = 3; 3093 } else { 3094 cn0_cn1_value = 0; 3095 itc_value = 0; 3096 } 3097 } 3098 } 3099 hdmi_info.bits.CN0_CN1 = cn0_cn1_value; 3100 hdmi_info.bits.ITC = itc_value; 3101 } 3102 3103 if (stream->qs_bit == 1) { 3104 if (color_space == COLOR_SPACE_SRGB || 3105 color_space == COLOR_SPACE_2020_RGB_FULLRANGE) 3106 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_FULL_RANGE; 3107 else if (color_space == COLOR_SPACE_SRGB_LIMITED || 3108 color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE) 3109 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_LIMITED_RANGE; 3110 else 3111 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE; 3112 } else 3113 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE; 3114 3115 /* TODO : We should handle YCC quantization */ 3116 /* but we do not have matrix calculation */ 3117 hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE; 3118 3119 ///VIC 3120 if (pipe_ctx->stream->timing.hdmi_vic != 0) 3121 vic = 0; 3122 format = stream->timing.timing_3d_format; 3123 /*todo, add 3DStereo support*/ 3124 if (format != TIMING_3D_FORMAT_NONE) { 3125 // Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled 3126 switch (pipe_ctx->stream->timing.hdmi_vic) { 3127 case 1: 3128 vic = 95; 3129 break; 3130 case 2: 3131 vic = 94; 3132 break; 3133 case 3: 3134 vic = 93; 3135 break; 3136 case 4: 3137 vic = 98; 3138 break; 3139 default: 3140 break; 3141 } 3142 } 3143 /* If VIC >= 128, the Source shall use AVI InfoFrame Version 3*/ 3144 hdmi_info.bits.VIC0_VIC7 = vic; 3145 if (vic >= 128) 3146 hdmi_info.bits.header.version = 3; 3147 /* If (C1, C0)=(1, 1) and (EC2, EC1, EC0)=(1, 1, 1), 3148 * the Source shall use 20 AVI InfoFrame Version 4 3149 */ 3150 if (hdmi_info.bits.C0_C1 == COLORIMETRY_EXTENDED && 3151 hdmi_info.bits.EC0_EC2 == COLORIMETRYEX_RESERVED) { 3152 hdmi_info.bits.header.version = 4; 3153 hdmi_info.bits.header.length = 14; 3154 } 3155 3156 if (rid != 0 && fr_ind != 0) { 3157 hdmi_info.bits.header.version = 5; 3158 hdmi_info.bits.header.length = 15; 3159 3160 hdmi_info.bits.FR0_FR3 = fr_ind & 0xF; 3161 hdmi_info.bits.FR4 = (fr_ind >> 4) & 0x1; 3162 hdmi_info.bits.RID0_RID5 = rid; 3163 } 3164 3165 /* pixel repetition 3166 * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel 3167 * repetition start from 1 */ 3168 hdmi_info.bits.PR0_PR3 = 0; 3169 3170 /* Bar Info 3171 * barTop: Line Number of End of Top Bar. 3172 * barBottom: Line Number of Start of Bottom Bar. 3173 * barLeft: Pixel Number of End of Left Bar. 3174 * barRight: Pixel Number of Start of Right Bar. */ 3175 hdmi_info.bits.bar_top = stream->timing.v_border_top; 3176 hdmi_info.bits.bar_bottom = (stream->timing.v_total 3177 - stream->timing.v_border_bottom + 1); 3178 hdmi_info.bits.bar_left = stream->timing.h_border_left; 3179 hdmi_info.bits.bar_right = (stream->timing.h_total 3180 - stream->timing.h_border_right + 1); 3181 3182 /* Additional Colorimetry Extension 3183 * Used in conduction with C0-C1 and EC0-EC2 3184 * 0 = DCI-P3 RGB (D65) 3185 * 1 = DCI-P3 RGB (theater) 3186 */ 3187 hdmi_info.bits.ACE0_ACE3 = 0; 3188 3189 /* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */ 3190 check_sum = &hdmi_info.packet_raw_data.sb[0]; 3191 3192 *check_sum = HDMI_INFOFRAME_TYPE_AVI + hdmi_info.bits.header.length + hdmi_info.bits.header.version; 3193 3194 for (byte_index = 1; byte_index <= hdmi_info.bits.header.length; byte_index++) 3195 *check_sum += hdmi_info.packet_raw_data.sb[byte_index]; 3196 3197 /* one byte complement */ 3198 *check_sum = (uint8_t) (0x100 - *check_sum); 3199 3200 /* Store in hw_path_mode */ 3201 info_packet->hb0 = hdmi_info.packet_raw_data.hb0; 3202 info_packet->hb1 = hdmi_info.packet_raw_data.hb1; 3203 info_packet->hb2 = hdmi_info.packet_raw_data.hb2; 3204 3205 for (byte_index = 0; byte_index < sizeof(hdmi_info.packet_raw_data.sb); byte_index++) 3206 info_packet->sb[byte_index] = hdmi_info.packet_raw_data.sb[byte_index]; 3207 3208 info_packet->valid = true; 3209 } 3210 3211 static void set_vendor_info_packet( 3212 struct dc_info_packet *info_packet, 3213 struct dc_stream_state *stream) 3214 { 3215 /* SPD info packet for FreeSync */ 3216 3217 /* Check if Freesync is supported. Return if false. If true, 3218 * set the corresponding bit in the info packet 3219 */ 3220 if (!stream->vsp_infopacket.valid) 3221 return; 3222 3223 *info_packet = stream->vsp_infopacket; 3224 } 3225 3226 static void set_spd_info_packet( 3227 struct dc_info_packet *info_packet, 3228 struct dc_stream_state *stream) 3229 { 3230 /* SPD info packet for FreeSync */ 3231 3232 /* Check if Freesync is supported. Return if false. If true, 3233 * set the corresponding bit in the info packet 3234 */ 3235 if (!stream->vrr_infopacket.valid) 3236 return; 3237 3238 *info_packet = stream->vrr_infopacket; 3239 } 3240 3241 static void set_hdr_static_info_packet( 3242 struct dc_info_packet *info_packet, 3243 struct dc_stream_state *stream) 3244 { 3245 /* HDR Static Metadata info packet for HDR10 */ 3246 3247 if (!stream->hdr_static_metadata.valid || 3248 stream->use_dynamic_meta) 3249 return; 3250 3251 *info_packet = stream->hdr_static_metadata; 3252 } 3253 3254 static void set_vsc_info_packet( 3255 struct dc_info_packet *info_packet, 3256 struct dc_stream_state *stream) 3257 { 3258 if (!stream->vsc_infopacket.valid) 3259 return; 3260 3261 *info_packet = stream->vsc_infopacket; 3262 } 3263 static void set_hfvs_info_packet( 3264 struct dc_info_packet *info_packet, 3265 struct dc_stream_state *stream) 3266 { 3267 if (!stream->hfvsif_infopacket.valid) 3268 return; 3269 3270 *info_packet = stream->hfvsif_infopacket; 3271 } 3272 3273 static void adaptive_sync_override_dp_info_packets_sdp_line_num( 3274 const struct dc_crtc_timing *timing, 3275 struct enc_sdp_line_num *sdp_line_num, 3276 struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param) 3277 { 3278 uint32_t asic_blank_start = 0; 3279 uint32_t asic_blank_end = 0; 3280 uint32_t v_update = 0; 3281 3282 const struct dc_crtc_timing *tg = timing; 3283 3284 /* blank_start = frame end - front porch */ 3285 asic_blank_start = tg->v_total - tg->v_front_porch; 3286 3287 /* blank_end = blank_start - active */ 3288 asic_blank_end = (asic_blank_start - tg->v_border_bottom - 3289 tg->v_addressable - tg->v_border_top); 3290 3291 if (pipe_dlg_param->vstartup_start > asic_blank_end) { 3292 v_update = (tg->v_total - (pipe_dlg_param->vstartup_start - asic_blank_end)); 3293 sdp_line_num->adaptive_sync_line_num_valid = true; 3294 sdp_line_num->adaptive_sync_line_num = (tg->v_total - v_update - 1); 3295 } else { 3296 sdp_line_num->adaptive_sync_line_num_valid = false; 3297 sdp_line_num->adaptive_sync_line_num = 0; 3298 } 3299 } 3300 3301 static void set_adaptive_sync_info_packet( 3302 struct dc_info_packet *info_packet, 3303 const struct dc_stream_state *stream, 3304 struct encoder_info_frame *info_frame, 3305 struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param) 3306 { 3307 if (!stream->adaptive_sync_infopacket.valid) 3308 return; 3309 3310 adaptive_sync_override_dp_info_packets_sdp_line_num( 3311 &stream->timing, 3312 &info_frame->sdp_line_num, 3313 pipe_dlg_param); 3314 3315 *info_packet = stream->adaptive_sync_infopacket; 3316 } 3317 3318 static void set_vtem_info_packet( 3319 struct dc_info_packet *info_packet, 3320 struct dc_stream_state *stream) 3321 { 3322 if (!stream->vtem_infopacket.valid) 3323 return; 3324 3325 *info_packet = stream->vtem_infopacket; 3326 } 3327 3328 void dc_resource_state_destruct(struct dc_state *context) 3329 { 3330 int i, j; 3331 3332 for (i = 0; i < context->stream_count; i++) { 3333 for (j = 0; j < context->stream_status[i].plane_count; j++) 3334 dc_plane_state_release( 3335 context->stream_status[i].plane_states[j]); 3336 3337 context->stream_status[i].plane_count = 0; 3338 dc_stream_release(context->streams[i]); 3339 context->streams[i] = NULL; 3340 } 3341 context->stream_count = 0; 3342 } 3343 3344 void dc_resource_state_copy_construct( 3345 const struct dc_state *src_ctx, 3346 struct dc_state *dst_ctx) 3347 { 3348 int i, j; 3349 struct kref refcount = dst_ctx->refcount; 3350 3351 *dst_ctx = *src_ctx; 3352 3353 for (i = 0; i < MAX_PIPES; i++) { 3354 struct pipe_ctx *cur_pipe = &dst_ctx->res_ctx.pipe_ctx[i]; 3355 3356 if (cur_pipe->top_pipe) 3357 cur_pipe->top_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx]; 3358 3359 if (cur_pipe->bottom_pipe) 3360 cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx]; 3361 3362 if (cur_pipe->next_odm_pipe) 3363 cur_pipe->next_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx]; 3364 3365 if (cur_pipe->prev_odm_pipe) 3366 cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx]; 3367 } 3368 3369 for (i = 0; i < dst_ctx->stream_count; i++) { 3370 dc_stream_retain(dst_ctx->streams[i]); 3371 for (j = 0; j < dst_ctx->stream_status[i].plane_count; j++) 3372 dc_plane_state_retain( 3373 dst_ctx->stream_status[i].plane_states[j]); 3374 } 3375 3376 /* context refcount should not be overridden */ 3377 dst_ctx->refcount = refcount; 3378 3379 } 3380 3381 struct clock_source *dc_resource_find_first_free_pll( 3382 struct resource_context *res_ctx, 3383 const struct resource_pool *pool) 3384 { 3385 int i; 3386 3387 for (i = 0; i < pool->clk_src_count; ++i) { 3388 if (res_ctx->clock_source_ref_count[i] == 0) 3389 return pool->clock_sources[i]; 3390 } 3391 3392 return NULL; 3393 } 3394 3395 void resource_build_info_frame(struct pipe_ctx *pipe_ctx) 3396 { 3397 enum signal_type signal = SIGNAL_TYPE_NONE; 3398 struct encoder_info_frame *info = &pipe_ctx->stream_res.encoder_info_frame; 3399 3400 /* default all packets to invalid */ 3401 info->avi.valid = false; 3402 info->gamut.valid = false; 3403 info->vendor.valid = false; 3404 info->spd.valid = false; 3405 info->hdrsmd.valid = false; 3406 info->vsc.valid = false; 3407 info->hfvsif.valid = false; 3408 info->vtem.valid = false; 3409 info->adaptive_sync.valid = false; 3410 signal = pipe_ctx->stream->signal; 3411 3412 /* HDMi and DP have different info packets*/ 3413 if (dc_is_hdmi_signal(signal)) { 3414 set_avi_info_frame(&info->avi, pipe_ctx); 3415 3416 set_vendor_info_packet(&info->vendor, pipe_ctx->stream); 3417 set_hfvs_info_packet(&info->hfvsif, pipe_ctx->stream); 3418 set_vtem_info_packet(&info->vtem, pipe_ctx->stream); 3419 3420 set_spd_info_packet(&info->spd, pipe_ctx->stream); 3421 3422 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream); 3423 3424 } else if (dc_is_dp_signal(signal)) { 3425 set_vsc_info_packet(&info->vsc, pipe_ctx->stream); 3426 3427 set_spd_info_packet(&info->spd, pipe_ctx->stream); 3428 3429 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream); 3430 set_adaptive_sync_info_packet(&info->adaptive_sync, 3431 pipe_ctx->stream, 3432 info, 3433 &pipe_ctx->pipe_dlg_param); 3434 } 3435 3436 patch_gamut_packet_checksum(&info->gamut); 3437 } 3438 3439 enum dc_status resource_map_clock_resources( 3440 const struct dc *dc, 3441 struct dc_state *context, 3442 struct dc_stream_state *stream) 3443 { 3444 /* acquire new resources */ 3445 const struct resource_pool *pool = dc->res_pool; 3446 struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream( 3447 &context->res_ctx, stream); 3448 3449 if (!pipe_ctx) 3450 return DC_ERROR_UNEXPECTED; 3451 3452 if (dc_is_dp_signal(pipe_ctx->stream->signal) 3453 || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL) 3454 pipe_ctx->clock_source = pool->dp_clock_source; 3455 else { 3456 pipe_ctx->clock_source = NULL; 3457 3458 if (!dc->config.disable_disp_pll_sharing) 3459 pipe_ctx->clock_source = resource_find_used_clk_src_for_sharing( 3460 &context->res_ctx, 3461 pipe_ctx); 3462 3463 if (pipe_ctx->clock_source == NULL) 3464 pipe_ctx->clock_source = 3465 dc_resource_find_first_free_pll( 3466 &context->res_ctx, 3467 pool); 3468 } 3469 3470 if (pipe_ctx->clock_source == NULL) 3471 return DC_NO_CLOCK_SOURCE_RESOURCE; 3472 3473 resource_reference_clock_source( 3474 &context->res_ctx, pool, 3475 pipe_ctx->clock_source); 3476 3477 return DC_OK; 3478 } 3479 3480 /* 3481 * Note: We need to disable output if clock sources change, 3482 * since bios does optimization and doesn't apply if changing 3483 * PHY when not already disabled. 3484 */ 3485 bool pipe_need_reprogram( 3486 struct pipe_ctx *pipe_ctx_old, 3487 struct pipe_ctx *pipe_ctx) 3488 { 3489 if (!pipe_ctx_old->stream) 3490 return false; 3491 3492 if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink) 3493 return true; 3494 3495 if (pipe_ctx_old->stream->signal != pipe_ctx->stream->signal) 3496 return true; 3497 3498 if (pipe_ctx_old->stream_res.audio != pipe_ctx->stream_res.audio) 3499 return true; 3500 3501 if (pipe_ctx_old->clock_source != pipe_ctx->clock_source 3502 && pipe_ctx_old->stream != pipe_ctx->stream) 3503 return true; 3504 3505 if (pipe_ctx_old->stream_res.stream_enc != pipe_ctx->stream_res.stream_enc) 3506 return true; 3507 3508 if (is_timing_changed(pipe_ctx_old->stream, pipe_ctx->stream)) 3509 return true; 3510 3511 if (pipe_ctx_old->stream->dpms_off != pipe_ctx->stream->dpms_off) 3512 return true; 3513 3514 if (false == pipe_ctx_old->stream->link->link_state_valid && 3515 false == pipe_ctx_old->stream->dpms_off) 3516 return true; 3517 3518 if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc) 3519 return true; 3520 3521 if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc) 3522 return true; 3523 if (pipe_ctx_old->link_res.hpo_dp_link_enc != pipe_ctx->link_res.hpo_dp_link_enc) 3524 return true; 3525 3526 /* DIG link encoder resource assignment for stream changed. */ 3527 if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) { 3528 bool need_reprogram = false; 3529 struct dc *dc = pipe_ctx_old->stream->ctx->dc; 3530 struct link_encoder *link_enc_prev = 3531 link_enc_cfg_get_link_enc_used_by_stream_current(dc, pipe_ctx_old->stream); 3532 3533 if (link_enc_prev != pipe_ctx->stream->link_enc) 3534 need_reprogram = true; 3535 3536 return need_reprogram; 3537 } 3538 3539 return false; 3540 } 3541 3542 void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream, 3543 struct bit_depth_reduction_params *fmt_bit_depth) 3544 { 3545 enum dc_dither_option option = stream->dither_option; 3546 enum dc_pixel_encoding pixel_encoding = 3547 stream->timing.pixel_encoding; 3548 3549 memset(fmt_bit_depth, 0, sizeof(*fmt_bit_depth)); 3550 3551 if (option == DITHER_OPTION_DEFAULT) { 3552 switch (stream->timing.display_color_depth) { 3553 case COLOR_DEPTH_666: 3554 option = DITHER_OPTION_SPATIAL6; 3555 break; 3556 case COLOR_DEPTH_888: 3557 option = DITHER_OPTION_SPATIAL8; 3558 break; 3559 case COLOR_DEPTH_101010: 3560 option = DITHER_OPTION_SPATIAL10; 3561 break; 3562 default: 3563 option = DITHER_OPTION_DISABLE; 3564 } 3565 } 3566 3567 if (option == DITHER_OPTION_DISABLE) 3568 return; 3569 3570 if (option == DITHER_OPTION_TRUN6) { 3571 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; 3572 fmt_bit_depth->flags.TRUNCATE_DEPTH = 0; 3573 } else if (option == DITHER_OPTION_TRUN8 || 3574 option == DITHER_OPTION_TRUN8_SPATIAL6 || 3575 option == DITHER_OPTION_TRUN8_FM6) { 3576 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; 3577 fmt_bit_depth->flags.TRUNCATE_DEPTH = 1; 3578 } else if (option == DITHER_OPTION_TRUN10 || 3579 option == DITHER_OPTION_TRUN10_SPATIAL6 || 3580 option == DITHER_OPTION_TRUN10_SPATIAL8 || 3581 option == DITHER_OPTION_TRUN10_FM8 || 3582 option == DITHER_OPTION_TRUN10_FM6 || 3583 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { 3584 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; 3585 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2; 3586 } 3587 3588 /* special case - Formatter can only reduce by 4 bits at most. 3589 * When reducing from 12 to 6 bits, 3590 * HW recommends we use trunc with round mode 3591 * (if we did nothing, trunc to 10 bits would be used) 3592 * note that any 12->10 bit reduction is ignored prior to DCE8, 3593 * as the input was 10 bits. 3594 */ 3595 if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM || 3596 option == DITHER_OPTION_SPATIAL6 || 3597 option == DITHER_OPTION_FM6) { 3598 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; 3599 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2; 3600 fmt_bit_depth->flags.TRUNCATE_MODE = 1; 3601 } 3602 3603 /* spatial dither 3604 * note that spatial modes 1-3 are never used 3605 */ 3606 if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM || 3607 option == DITHER_OPTION_SPATIAL6 || 3608 option == DITHER_OPTION_TRUN10_SPATIAL6 || 3609 option == DITHER_OPTION_TRUN8_SPATIAL6) { 3610 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1; 3611 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 0; 3612 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1; 3613 fmt_bit_depth->flags.RGB_RANDOM = 3614 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0; 3615 } else if (option == DITHER_OPTION_SPATIAL8_FRAME_RANDOM || 3616 option == DITHER_OPTION_SPATIAL8 || 3617 option == DITHER_OPTION_SPATIAL8_FM6 || 3618 option == DITHER_OPTION_TRUN10_SPATIAL8 || 3619 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { 3620 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1; 3621 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 1; 3622 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1; 3623 fmt_bit_depth->flags.RGB_RANDOM = 3624 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0; 3625 } else if (option == DITHER_OPTION_SPATIAL10_FRAME_RANDOM || 3626 option == DITHER_OPTION_SPATIAL10 || 3627 option == DITHER_OPTION_SPATIAL10_FM8 || 3628 option == DITHER_OPTION_SPATIAL10_FM6) { 3629 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1; 3630 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 2; 3631 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1; 3632 fmt_bit_depth->flags.RGB_RANDOM = 3633 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0; 3634 } 3635 3636 if (option == DITHER_OPTION_SPATIAL6 || 3637 option == DITHER_OPTION_SPATIAL8 || 3638 option == DITHER_OPTION_SPATIAL10) { 3639 fmt_bit_depth->flags.FRAME_RANDOM = 0; 3640 } else { 3641 fmt_bit_depth->flags.FRAME_RANDOM = 1; 3642 } 3643 3644 ////////////////////// 3645 //// temporal dither 3646 ////////////////////// 3647 if (option == DITHER_OPTION_FM6 || 3648 option == DITHER_OPTION_SPATIAL8_FM6 || 3649 option == DITHER_OPTION_SPATIAL10_FM6 || 3650 option == DITHER_OPTION_TRUN10_FM6 || 3651 option == DITHER_OPTION_TRUN8_FM6 || 3652 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { 3653 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1; 3654 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 0; 3655 } else if (option == DITHER_OPTION_FM8 || 3656 option == DITHER_OPTION_SPATIAL10_FM8 || 3657 option == DITHER_OPTION_TRUN10_FM8) { 3658 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1; 3659 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 1; 3660 } else if (option == DITHER_OPTION_FM10) { 3661 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1; 3662 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 2; 3663 } 3664 3665 fmt_bit_depth->pixel_encoding = pixel_encoding; 3666 } 3667 3668 enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream) 3669 { 3670 struct dc_link *link = stream->link; 3671 struct timing_generator *tg = dc->res_pool->timing_generators[0]; 3672 enum dc_status res = DC_OK; 3673 3674 calculate_phy_pix_clks(stream); 3675 3676 if (!tg->funcs->validate_timing(tg, &stream->timing)) 3677 res = DC_FAIL_CONTROLLER_VALIDATE; 3678 3679 if (res == DC_OK) { 3680 if (link->ep_type == DISPLAY_ENDPOINT_PHY && 3681 !link->link_enc->funcs->validate_output_with_stream( 3682 link->link_enc, stream)) 3683 res = DC_FAIL_ENC_VALIDATE; 3684 } 3685 3686 /* TODO: validate audio ASIC caps, encoder */ 3687 3688 if (res == DC_OK) 3689 res = dc_link_validate_mode_timing(stream, 3690 link, 3691 &stream->timing); 3692 3693 return res; 3694 } 3695 3696 enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state) 3697 { 3698 enum dc_status res = DC_OK; 3699 3700 /* check if surface has invalid dimensions */ 3701 if (plane_state->src_rect.width == 0 || plane_state->src_rect.height == 0 || 3702 plane_state->dst_rect.width == 0 || plane_state->dst_rect.height == 0) 3703 return DC_FAIL_SURFACE_VALIDATE; 3704 3705 /* TODO For now validates pixel format only */ 3706 if (dc->res_pool->funcs->validate_plane) 3707 return dc->res_pool->funcs->validate_plane(plane_state, &dc->caps); 3708 3709 return res; 3710 } 3711 3712 unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format) 3713 { 3714 switch (format) { 3715 case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS: 3716 return 8; 3717 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: 3718 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: 3719 return 12; 3720 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: 3721 case SURFACE_PIXEL_FORMAT_GRPH_RGB565: 3722 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: 3723 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: 3724 return 16; 3725 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: 3726 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: 3727 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: 3728 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: 3729 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS: 3730 case SURFACE_PIXEL_FORMAT_GRPH_RGBE: 3731 case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA: 3732 return 32; 3733 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: 3734 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: 3735 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: 3736 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: 3737 return 64; 3738 default: 3739 ASSERT_CRITICAL(false); 3740 return -1; 3741 } 3742 } 3743 static unsigned int get_max_audio_sample_rate(struct audio_mode *modes) 3744 { 3745 if (modes) { 3746 if (modes->sample_rates.rate.RATE_192) 3747 return 192000; 3748 if (modes->sample_rates.rate.RATE_176_4) 3749 return 176400; 3750 if (modes->sample_rates.rate.RATE_96) 3751 return 96000; 3752 if (modes->sample_rates.rate.RATE_88_2) 3753 return 88200; 3754 if (modes->sample_rates.rate.RATE_48) 3755 return 48000; 3756 if (modes->sample_rates.rate.RATE_44_1) 3757 return 44100; 3758 if (modes->sample_rates.rate.RATE_32) 3759 return 32000; 3760 } 3761 /*original logic when no audio info*/ 3762 return 441000; 3763 } 3764 3765 void get_audio_check(struct audio_info *aud_modes, 3766 struct audio_check *audio_chk) 3767 { 3768 unsigned int i; 3769 unsigned int max_sample_rate = 0; 3770 3771 if (aud_modes) { 3772 audio_chk->audio_packet_type = 0x2;/*audio sample packet AP = .25 for layout0, 1 for layout1*/ 3773 3774 audio_chk->max_audiosample_rate = 0; 3775 for (i = 0; i < aud_modes->mode_count; i++) { 3776 max_sample_rate = get_max_audio_sample_rate(&aud_modes->modes[i]); 3777 if (audio_chk->max_audiosample_rate < max_sample_rate) 3778 audio_chk->max_audiosample_rate = max_sample_rate; 3779 /*dts takes the same as type 2: AP = 0.25*/ 3780 } 3781 /*check which one take more bandwidth*/ 3782 if (audio_chk->max_audiosample_rate > 192000) 3783 audio_chk->audio_packet_type = 0x9;/*AP =1*/ 3784 audio_chk->acat = 0;/*not support*/ 3785 } 3786 } 3787 3788 static struct hpo_dp_link_encoder *get_temp_hpo_dp_link_enc( 3789 const struct resource_context *res_ctx, 3790 const struct resource_pool *const pool, 3791 const struct dc_link *link) 3792 { 3793 struct hpo_dp_link_encoder *hpo_dp_link_enc = NULL; 3794 int enc_index; 3795 3796 enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, link); 3797 3798 if (enc_index < 0) 3799 enc_index = find_free_hpo_dp_link_enc(res_ctx, pool); 3800 3801 if (enc_index >= 0) 3802 hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index]; 3803 3804 return hpo_dp_link_enc; 3805 } 3806 3807 bool get_temp_dp_link_res(struct dc_link *link, 3808 struct link_resource *link_res, 3809 struct dc_link_settings *link_settings) 3810 { 3811 const struct dc *dc = link->dc; 3812 const struct resource_context *res_ctx = &dc->current_state->res_ctx; 3813 3814 memset(link_res, 0, sizeof(*link_res)); 3815 3816 if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) { 3817 link_res->hpo_dp_link_enc = get_temp_hpo_dp_link_enc(res_ctx, 3818 dc->res_pool, link); 3819 if (!link_res->hpo_dp_link_enc) 3820 return false; 3821 } 3822 return true; 3823 } 3824 3825 void reset_syncd_pipes_from_disabled_pipes(struct dc *dc, 3826 struct dc_state *context) 3827 { 3828 int i, j; 3829 struct pipe_ctx *pipe_ctx_old, *pipe_ctx, *pipe_ctx_syncd; 3830 3831 /* If pipe backend is reset, need to reset pipe syncd status */ 3832 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3833 pipe_ctx_old = &dc->current_state->res_ctx.pipe_ctx[i]; 3834 pipe_ctx = &context->res_ctx.pipe_ctx[i]; 3835 3836 if (!pipe_ctx_old->stream) 3837 continue; 3838 3839 if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) 3840 continue; 3841 3842 if (!pipe_ctx->stream || 3843 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { 3844 3845 /* Reset all the syncd pipes from the disabled pipe */ 3846 for (j = 0; j < dc->res_pool->pipe_count; j++) { 3847 pipe_ctx_syncd = &context->res_ctx.pipe_ctx[j]; 3848 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_syncd) == pipe_ctx_old->pipe_idx) || 3849 !IS_PIPE_SYNCD_VALID(pipe_ctx_syncd)) 3850 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_syncd, j); 3851 } 3852 } 3853 } 3854 } 3855 3856 void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc, 3857 struct dc_state *context, 3858 uint8_t disabled_master_pipe_idx) 3859 { 3860 int i; 3861 struct pipe_ctx *pipe_ctx, *pipe_ctx_check; 3862 3863 pipe_ctx = &context->res_ctx.pipe_ctx[disabled_master_pipe_idx]; 3864 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx) != disabled_master_pipe_idx) || 3865 !IS_PIPE_SYNCD_VALID(pipe_ctx)) 3866 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx, disabled_master_pipe_idx); 3867 3868 /* for the pipe disabled, check if any slave pipe exists and assert */ 3869 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3870 pipe_ctx_check = &context->res_ctx.pipe_ctx[i]; 3871 3872 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_check) == disabled_master_pipe_idx) && 3873 IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx)) { 3874 struct pipe_ctx *first_pipe = pipe_ctx_check; 3875 3876 while (first_pipe->prev_odm_pipe) 3877 first_pipe = first_pipe->prev_odm_pipe; 3878 /* When ODM combine is enabled, this case is expected. If the disabled pipe 3879 * is part of the ODM tree, then we should not print an error. 3880 * */ 3881 if (first_pipe->pipe_idx == disabled_master_pipe_idx) 3882 continue; 3883 3884 DC_ERR("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n", 3885 i, disabled_master_pipe_idx); 3886 } 3887 } 3888 } 3889 3890 void reset_sync_context_for_pipe(const struct dc *dc, 3891 struct dc_state *context, 3892 uint8_t pipe_idx) 3893 { 3894 int i; 3895 struct pipe_ctx *pipe_ctx_reset; 3896 3897 /* reset the otg sync context for the pipe and its slave pipes if any */ 3898 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3899 pipe_ctx_reset = &context->res_ctx.pipe_ctx[i]; 3900 3901 if (((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_reset) == pipe_idx) && 3902 IS_PIPE_SYNCD_VALID(pipe_ctx_reset)) || (i == pipe_idx)) 3903 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_reset, i); 3904 } 3905 } 3906 3907 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter) 3908 { 3909 /* TODO - get transmitter to phy idx mapping from DMUB */ 3910 uint8_t phy_idx = transmitter - TRANSMITTER_UNIPHY_A; 3911 3912 if (dc->ctx->dce_version == DCN_VERSION_3_1 && 3913 dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { 3914 switch (transmitter) { 3915 case TRANSMITTER_UNIPHY_A: 3916 phy_idx = 0; 3917 break; 3918 case TRANSMITTER_UNIPHY_B: 3919 phy_idx = 1; 3920 break; 3921 case TRANSMITTER_UNIPHY_C: 3922 phy_idx = 5; 3923 break; 3924 case TRANSMITTER_UNIPHY_D: 3925 phy_idx = 6; 3926 break; 3927 case TRANSMITTER_UNIPHY_E: 3928 phy_idx = 4; 3929 break; 3930 default: 3931 phy_idx = 0; 3932 break; 3933 } 3934 } 3935 3936 return phy_idx; 3937 } 3938 3939 const struct link_hwss *get_link_hwss(const struct dc_link *link, 3940 const struct link_resource *link_res) 3941 { 3942 /* Link_hwss is only accessible by getter function instead of accessing 3943 * by pointers in dc with the intent to protect against breaking polymorphism. 3944 */ 3945 if (can_use_hpo_dp_link_hwss(link, link_res)) 3946 /* TODO: some assumes that if decided link settings is 128b/132b 3947 * channel coding format hpo_dp_link_enc should be used. 3948 * Others believe that if hpo_dp_link_enc is available in link 3949 * resource then hpo_dp_link_enc must be used. This bound between 3950 * hpo_dp_link_enc != NULL and decided link settings is loosely coupled 3951 * with a premise that both hpo_dp_link_enc pointer and decided link 3952 * settings are determined based on single policy function like 3953 * "decide_link_settings" from upper layer. This "convention" 3954 * cannot be maintained and enforced at current level. 3955 * Therefore a refactor is due so we can enforce a strong bound 3956 * between those two parameters at this level. 3957 * 3958 * To put it simple, we want to make enforcement at low level so that 3959 * we will not return link hwss if caller plans to do 8b/10b 3960 * with an hpo encoder. Or we can return a very dummy one that doesn't 3961 * do work for all functions 3962 */ 3963 return get_hpo_dp_link_hwss(); 3964 else if (can_use_dpia_link_hwss(link, link_res)) 3965 return get_dpia_link_hwss(); 3966 else if (can_use_dio_link_hwss(link, link_res)) 3967 return get_dio_link_hwss(); 3968 else 3969 return get_virtual_link_hwss(); 3970 } 3971 3972 bool is_h_timing_divisible_by_2(struct dc_stream_state *stream) 3973 { 3974 bool divisible = false; 3975 uint16_t h_blank_start = 0; 3976 uint16_t h_blank_end = 0; 3977 3978 if (stream) { 3979 h_blank_start = stream->timing.h_total - stream->timing.h_front_porch; 3980 h_blank_end = h_blank_start - stream->timing.h_addressable; 3981 3982 /* HTOTAL, Hblank start/end, and Hsync start/end all must be 3983 * divisible by 2 in order for the horizontal timing params 3984 * to be considered divisible by 2. Hsync start is always 0. 3985 */ 3986 divisible = (stream->timing.h_total % 2 == 0) && 3987 (h_blank_start % 2 == 0) && 3988 (h_blank_end % 2 == 0) && 3989 (stream->timing.h_sync_width % 2 == 0); 3990 } 3991 return divisible; 3992 } 3993 3994 bool dc_resource_acquire_secondary_pipe_for_mpc_odm( 3995 const struct dc *dc, 3996 struct dc_state *state, 3997 struct pipe_ctx *pri_pipe, 3998 struct pipe_ctx *sec_pipe, 3999 bool odm) 4000 { 4001 int pipe_idx = sec_pipe->pipe_idx; 4002 struct pipe_ctx *sec_top, *sec_bottom, *sec_next, *sec_prev; 4003 const struct resource_pool *pool = dc->res_pool; 4004 4005 sec_top = sec_pipe->top_pipe; 4006 sec_bottom = sec_pipe->bottom_pipe; 4007 sec_next = sec_pipe->next_odm_pipe; 4008 sec_prev = sec_pipe->prev_odm_pipe; 4009 4010 *sec_pipe = *pri_pipe; 4011 4012 sec_pipe->top_pipe = sec_top; 4013 sec_pipe->bottom_pipe = sec_bottom; 4014 sec_pipe->next_odm_pipe = sec_next; 4015 sec_pipe->prev_odm_pipe = sec_prev; 4016 4017 sec_pipe->pipe_idx = pipe_idx; 4018 sec_pipe->plane_res.mi = pool->mis[pipe_idx]; 4019 sec_pipe->plane_res.hubp = pool->hubps[pipe_idx]; 4020 sec_pipe->plane_res.ipp = pool->ipps[pipe_idx]; 4021 sec_pipe->plane_res.xfm = pool->transforms[pipe_idx]; 4022 sec_pipe->plane_res.dpp = pool->dpps[pipe_idx]; 4023 sec_pipe->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst; 4024 sec_pipe->stream_res.dsc = NULL; 4025 if (odm) { 4026 if (!sec_pipe->top_pipe) 4027 sec_pipe->stream_res.opp = pool->opps[pipe_idx]; 4028 else 4029 sec_pipe->stream_res.opp = sec_pipe->top_pipe->stream_res.opp; 4030 if (sec_pipe->stream->timing.flags.DSC == 1) { 4031 #if defined(CONFIG_DRM_AMD_DC_DCN) 4032 dcn20_acquire_dsc(dc, &state->res_ctx, &sec_pipe->stream_res.dsc, pipe_idx); 4033 #endif 4034 ASSERT(sec_pipe->stream_res.dsc); 4035 if (sec_pipe->stream_res.dsc == NULL) 4036 return false; 4037 } 4038 #if defined(CONFIG_DRM_AMD_DC_DCN) 4039 dcn20_build_mapped_resource(dc, state, sec_pipe->stream); 4040 #endif 4041 } 4042 4043 return true; 4044 } 4045 4046 enum dc_status update_dp_encoder_resources_for_test_harness(const struct dc *dc, 4047 struct dc_state *context, 4048 struct pipe_ctx *pipe_ctx) 4049 { 4050 if (link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) { 4051 if (pipe_ctx->stream_res.hpo_dp_stream_enc == NULL) { 4052 pipe_ctx->stream_res.hpo_dp_stream_enc = 4053 find_first_free_match_hpo_dp_stream_enc_for_link( 4054 &context->res_ctx, dc->res_pool, pipe_ctx->stream); 4055 4056 if (!pipe_ctx->stream_res.hpo_dp_stream_enc) 4057 return DC_NO_STREAM_ENC_RESOURCE; 4058 4059 update_hpo_dp_stream_engine_usage( 4060 &context->res_ctx, dc->res_pool, 4061 pipe_ctx->stream_res.hpo_dp_stream_enc, 4062 true); 4063 } 4064 4065 if (pipe_ctx->link_res.hpo_dp_link_enc == NULL) { 4066 if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, dc->res_pool, pipe_ctx, pipe_ctx->stream)) 4067 return DC_NO_LINK_ENC_RESOURCE; 4068 } 4069 } else { 4070 if (pipe_ctx->stream_res.hpo_dp_stream_enc) { 4071 update_hpo_dp_stream_engine_usage( 4072 &context->res_ctx, dc->res_pool, 4073 pipe_ctx->stream_res.hpo_dp_stream_enc, 4074 false); 4075 pipe_ctx->stream_res.hpo_dp_stream_enc = NULL; 4076 } 4077 if (pipe_ctx->link_res.hpo_dp_link_enc) 4078 remove_hpo_dp_link_enc_from_ctx(&context->res_ctx, pipe_ctx, pipe_ctx->stream); 4079 } 4080 4081 return DC_OK; 4082 } 4083 4084