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