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