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