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