1 /* Copyright 2021 Advanced Micro Devices, Inc. All rights reserved. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a 4 * copy of this software and associated documentation files (the "Software"), 5 * to deal in the Software without restriction, including without limitation 6 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 * and/or sell copies of the Software, and to permit persons to whom the 8 * Software is furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 17 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 18 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 19 * OTHER DEALINGS IN THE SOFTWARE. 20 * 21 * Authors: AMD 22 * 23 */ 24 25 #include "link_enc_cfg.h" 26 #include "resource.h" 27 #include "dc_link_dp.h" 28 29 /* Check whether stream is supported by DIG link encoders. */ 30 static bool is_dig_link_enc_stream(struct dc_stream_state *stream) 31 { 32 bool is_dig_stream = false; 33 struct link_encoder *link_enc = NULL; 34 int i; 35 36 /* Loop over created link encoder objects. */ 37 if (stream) { 38 for (i = 0; i < stream->ctx->dc->res_pool->res_cap->num_dig_link_enc; i++) { 39 link_enc = stream->ctx->dc->res_pool->link_encoders[i]; 40 41 /* Need to check link signal type rather than stream signal type which may not 42 * yet match. 43 */ 44 if (link_enc && ((uint32_t)stream->link->connector_signal & link_enc->output_signals)) { 45 if (dc_is_dp_signal(stream->signal)) { 46 /* DIGs do not support DP2.0 streams with 128b/132b encoding. */ 47 struct dc_link_settings link_settings = {0}; 48 49 decide_link_settings(stream, &link_settings); 50 if ((link_settings.link_rate >= LINK_RATE_LOW) && 51 link_settings.link_rate <= LINK_RATE_HIGH3) { 52 is_dig_stream = true; 53 break; 54 } 55 } else { 56 is_dig_stream = true; 57 break; 58 } 59 } 60 } 61 } 62 return is_dig_stream; 63 } 64 65 static struct link_enc_assignment get_assignment(struct dc *dc, int i) 66 { 67 struct link_enc_assignment assignment; 68 69 if (dc->current_state->res_ctx.link_enc_cfg_ctx.mode == LINK_ENC_CFG_TRANSIENT) 70 assignment = dc->current_state->res_ctx.link_enc_cfg_ctx.transient_assignments[i]; 71 else /* LINK_ENC_CFG_STEADY */ 72 assignment = dc->current_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; 73 74 return assignment; 75 } 76 77 /* Return stream using DIG link encoder resource. NULL if unused. */ 78 static struct dc_stream_state *get_stream_using_link_enc( 79 struct dc_state *state, 80 enum engine_id eng_id) 81 { 82 struct dc_stream_state *stream = NULL; 83 int i; 84 85 for (i = 0; i < state->stream_count; i++) { 86 struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; 87 88 if ((assignment.valid == true) && (assignment.eng_id == eng_id)) { 89 stream = state->streams[i]; 90 break; 91 } 92 } 93 94 return stream; 95 } 96 97 static void remove_link_enc_assignment( 98 struct dc_state *state, 99 struct dc_stream_state *stream, 100 enum engine_id eng_id) 101 { 102 int eng_idx; 103 int i; 104 105 if (eng_id != ENGINE_ID_UNKNOWN) { 106 eng_idx = eng_id - ENGINE_ID_DIGA; 107 108 /* stream ptr of stream in dc_state used to update correct entry in 109 * link_enc_assignments table. 110 */ 111 for (i = 0; i < MAX_PIPES; i++) { 112 struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; 113 114 if (assignment.valid && assignment.stream == stream) { 115 state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].valid = false; 116 /* Only add link encoder back to availability pool if not being 117 * used by any other stream (i.e. removing SST stream or last MST stream). 118 */ 119 if (get_stream_using_link_enc(state, eng_id) == NULL) 120 state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] = eng_id; 121 122 stream->link_enc = NULL; 123 state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].eng_id = ENGINE_ID_UNKNOWN; 124 state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].stream = NULL; 125 break; 126 } 127 } 128 } 129 } 130 131 static void add_link_enc_assignment( 132 struct dc_state *state, 133 struct dc_stream_state *stream, 134 enum engine_id eng_id) 135 { 136 int eng_idx; 137 int i; 138 139 if (eng_id != ENGINE_ID_UNKNOWN) { 140 eng_idx = eng_id - ENGINE_ID_DIGA; 141 142 /* stream ptr of stream in dc_state used to update correct entry in 143 * link_enc_assignments table. 144 */ 145 for (i = 0; i < state->stream_count; i++) { 146 if (stream == state->streams[i]) { 147 state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i] = (struct link_enc_assignment){ 148 .valid = true, 149 .ep_id = (struct display_endpoint_id) { 150 .link_id = stream->link->link_id, 151 .ep_type = stream->link->ep_type}, 152 .eng_id = eng_id, 153 .stream = stream}; 154 dc_stream_retain(stream); 155 state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] = ENGINE_ID_UNKNOWN; 156 stream->link_enc = stream->ctx->dc->res_pool->link_encoders[eng_idx]; 157 break; 158 } 159 } 160 161 /* Attempted to add an encoder assignment for a stream not in dc_state. */ 162 ASSERT(i != state->stream_count); 163 } 164 } 165 166 /* Return first available DIG link encoder. */ 167 static enum engine_id find_first_avail_link_enc( 168 const struct dc_context *ctx, 169 const struct dc_state *state) 170 { 171 enum engine_id eng_id = ENGINE_ID_UNKNOWN; 172 int i; 173 174 for (i = 0; i < ctx->dc->res_pool->res_cap->num_dig_link_enc; i++) { 175 eng_id = state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i]; 176 if (eng_id != ENGINE_ID_UNKNOWN) 177 break; 178 } 179 180 return eng_id; 181 } 182 183 /* Check for availability of link encoder eng_id. */ 184 static bool is_avail_link_enc(struct dc_state *state, enum engine_id eng_id, struct dc_stream_state *stream) 185 { 186 bool is_avail = false; 187 int eng_idx = eng_id - ENGINE_ID_DIGA; 188 189 /* An encoder is available if it is still in the availability pool. */ 190 if (eng_id != ENGINE_ID_UNKNOWN && state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] != ENGINE_ID_UNKNOWN) { 191 is_avail = true; 192 } else { 193 struct dc_stream_state *stream_assigned = NULL; 194 195 /* MST streams share the same link and should share the same encoder. 196 * If a stream that has already been assigned a link encoder uses as the 197 * same link as the stream checking for availability, it is an MST stream 198 * and should use the same link encoder. 199 */ 200 stream_assigned = get_stream_using_link_enc(state, eng_id); 201 if (stream_assigned && stream != stream_assigned && stream->link == stream_assigned->link) 202 is_avail = true; 203 } 204 205 return is_avail; 206 } 207 208 /* Test for display_endpoint_id equality. */ 209 static bool are_ep_ids_equal(struct display_endpoint_id *lhs, struct display_endpoint_id *rhs) 210 { 211 bool are_equal = false; 212 213 if (lhs->link_id.id == rhs->link_id.id && 214 lhs->link_id.enum_id == rhs->link_id.enum_id && 215 lhs->link_id.type == rhs->link_id.type && 216 lhs->ep_type == rhs->ep_type) 217 are_equal = true; 218 219 return are_equal; 220 } 221 222 static struct link_encoder *get_link_enc_used_by_link( 223 struct dc_state *state, 224 const struct dc_link *link) 225 { 226 struct link_encoder *link_enc = NULL; 227 struct display_endpoint_id ep_id; 228 int i; 229 230 ep_id = (struct display_endpoint_id) { 231 .link_id = link->link_id, 232 .ep_type = link->ep_type}; 233 234 for (i = 0; i < MAX_PIPES; i++) { 235 struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; 236 237 if (assignment.valid == true && are_ep_ids_equal(&assignment.ep_id, &ep_id)) 238 link_enc = link->dc->res_pool->link_encoders[assignment.eng_id - ENGINE_ID_DIGA]; 239 } 240 241 return link_enc; 242 } 243 /* Clear all link encoder assignments. */ 244 static void clear_enc_assignments(const struct dc *dc, struct dc_state *state) 245 { 246 int i; 247 248 for (i = 0; i < MAX_PIPES; i++) { 249 state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].valid = false; 250 state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].eng_id = ENGINE_ID_UNKNOWN; 251 if (state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].stream != NULL) { 252 dc_stream_release(state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].stream); 253 state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].stream = NULL; 254 } 255 } 256 257 for (i = 0; i < dc->res_pool->res_cap->num_dig_link_enc; i++) { 258 if (dc->res_pool->link_encoders[i]) 259 state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i] = (enum engine_id) i; 260 else 261 state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i] = ENGINE_ID_UNKNOWN; 262 } 263 } 264 265 void link_enc_cfg_init( 266 const struct dc *dc, 267 struct dc_state *state) 268 { 269 clear_enc_assignments(dc, state); 270 271 state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY; 272 } 273 274 void link_enc_cfg_link_encs_assign( 275 struct dc *dc, 276 struct dc_state *state, 277 struct dc_stream_state *streams[], 278 uint8_t stream_count) 279 { 280 enum engine_id eng_id = ENGINE_ID_UNKNOWN; 281 int i; 282 int j; 283 284 ASSERT(state->stream_count == stream_count); 285 286 /* Release DIG link encoder resources before running assignment algorithm. */ 287 for (i = 0; i < dc->current_state->stream_count; i++) 288 dc->res_pool->funcs->link_enc_unassign(state, dc->current_state->streams[i]); 289 290 for (i = 0; i < MAX_PIPES; i++) 291 ASSERT(state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].valid == false); 292 293 /* (a) Assign DIG link encoders to physical (unmappable) endpoints first. */ 294 for (i = 0; i < stream_count; i++) { 295 struct dc_stream_state *stream = streams[i]; 296 297 /* Skip stream if not supported by DIG link encoder. */ 298 if (!is_dig_link_enc_stream(stream)) 299 continue; 300 301 /* Physical endpoints have a fixed mapping to DIG link encoders. */ 302 if (!stream->link->is_dig_mapping_flexible) { 303 eng_id = stream->link->eng_id; 304 add_link_enc_assignment(state, stream, eng_id); 305 } 306 } 307 308 /* (b) Retain previous assignments for mappable endpoints if encoders still available. */ 309 eng_id = ENGINE_ID_UNKNOWN; 310 311 if (state != dc->current_state) { 312 struct dc_state *prev_state = dc->current_state; 313 314 for (i = 0; i < stream_count; i++) { 315 struct dc_stream_state *stream = state->streams[i]; 316 317 /* Skip stream if not supported by DIG link encoder. */ 318 if (!is_dig_link_enc_stream(stream)) 319 continue; 320 321 if (!stream->link->is_dig_mapping_flexible) 322 continue; 323 324 for (j = 0; j < prev_state->stream_count; j++) { 325 struct dc_stream_state *prev_stream = prev_state->streams[j]; 326 327 if (stream == prev_stream && stream->link == prev_stream->link && 328 prev_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j].valid) { 329 eng_id = prev_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j].eng_id; 330 if (is_avail_link_enc(state, eng_id, stream)) 331 add_link_enc_assignment(state, stream, eng_id); 332 } 333 } 334 } 335 } 336 337 /* (c) Then assign encoders to remaining mappable endpoints. */ 338 eng_id = ENGINE_ID_UNKNOWN; 339 340 for (i = 0; i < stream_count; i++) { 341 struct dc_stream_state *stream = streams[i]; 342 343 /* Skip stream if not supported by DIG link encoder. */ 344 if (!is_dig_link_enc_stream(stream)) { 345 ASSERT(stream->link->is_dig_mapping_flexible != true); 346 continue; 347 } 348 349 /* Mappable endpoints have a flexible mapping to DIG link encoders. */ 350 if (stream->link->is_dig_mapping_flexible) { 351 struct link_encoder *link_enc = NULL; 352 353 /* Skip if encoder assignment retained in step (b) above. */ 354 if (stream->link_enc) 355 continue; 356 357 /* For MST, multiple streams will share the same link / display 358 * endpoint. These streams should use the same link encoder 359 * assigned to that endpoint. 360 */ 361 link_enc = get_link_enc_used_by_link(state, stream->link); 362 if (link_enc == NULL) 363 eng_id = find_first_avail_link_enc(stream->ctx, state); 364 else 365 eng_id = link_enc->preferred_engine; 366 add_link_enc_assignment(state, stream, eng_id); 367 } 368 } 369 370 link_enc_cfg_validate(dc, state); 371 372 /* Update transient assignments. */ 373 for (i = 0; i < MAX_PIPES; i++) { 374 dc->current_state->res_ctx.link_enc_cfg_ctx.transient_assignments[i] = 375 state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; 376 } 377 378 /* Current state mode will be set to steady once this state committed. */ 379 state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY; 380 } 381 382 void link_enc_cfg_link_enc_unassign( 383 struct dc_state *state, 384 struct dc_stream_state *stream) 385 { 386 enum engine_id eng_id = ENGINE_ID_UNKNOWN; 387 388 /* Only DIG link encoders. */ 389 if (!is_dig_link_enc_stream(stream)) 390 return; 391 392 if (stream->link_enc) 393 eng_id = stream->link_enc->preferred_engine; 394 395 remove_link_enc_assignment(state, stream, eng_id); 396 } 397 398 bool link_enc_cfg_is_transmitter_mappable( 399 struct dc *dc, 400 struct link_encoder *link_enc) 401 { 402 bool is_mappable = false; 403 enum engine_id eng_id = link_enc->preferred_engine; 404 struct dc_stream_state *stream = link_enc_cfg_get_stream_using_link_enc(dc, eng_id); 405 406 if (stream) 407 is_mappable = stream->link->is_dig_mapping_flexible; 408 409 return is_mappable; 410 } 411 412 struct dc_stream_state *link_enc_cfg_get_stream_using_link_enc( 413 struct dc *dc, 414 enum engine_id eng_id) 415 { 416 struct dc_stream_state *stream = NULL; 417 int i; 418 419 for (i = 0; i < MAX_PIPES; i++) { 420 struct link_enc_assignment assignment = get_assignment(dc, i); 421 422 if ((assignment.valid == true) && (assignment.eng_id == eng_id)) { 423 stream = assignment.stream; 424 break; 425 } 426 } 427 428 return stream; 429 } 430 431 struct dc_link *link_enc_cfg_get_link_using_link_enc( 432 struct dc *dc, 433 enum engine_id eng_id) 434 { 435 struct dc_link *link = NULL; 436 struct dc_stream_state *stream = NULL; 437 438 stream = link_enc_cfg_get_stream_using_link_enc(dc, eng_id); 439 440 if (stream) 441 link = stream->link; 442 443 // dm_output_to_console("%s: No link using DIG(%d).\n", __func__, eng_id); 444 return link; 445 } 446 447 struct link_encoder *link_enc_cfg_get_link_enc_used_by_link( 448 struct dc *dc, 449 const struct dc_link *link) 450 { 451 struct link_encoder *link_enc = NULL; 452 struct display_endpoint_id ep_id; 453 int i; 454 455 ep_id = (struct display_endpoint_id) { 456 .link_id = link->link_id, 457 .ep_type = link->ep_type}; 458 459 for (i = 0; i < MAX_PIPES; i++) { 460 struct link_enc_assignment assignment = get_assignment(dc, i); 461 462 if (assignment.valid == true && are_ep_ids_equal(&assignment.ep_id, &ep_id)) { 463 link_enc = link->dc->res_pool->link_encoders[assignment.eng_id - ENGINE_ID_DIGA]; 464 break; 465 } 466 } 467 468 return link_enc; 469 } 470 471 struct link_encoder *link_enc_cfg_get_next_avail_link_enc(struct dc *dc) 472 { 473 struct link_encoder *link_enc = NULL; 474 enum engine_id encs_assigned[MAX_DIG_LINK_ENCODERS]; 475 int i; 476 477 for (i = 0; i < MAX_DIG_LINK_ENCODERS; i++) 478 encs_assigned[i] = ENGINE_ID_UNKNOWN; 479 480 /* Add assigned encoders to list. */ 481 for (i = 0; i < MAX_PIPES; i++) { 482 struct link_enc_assignment assignment = get_assignment(dc, i); 483 484 if (assignment.valid) 485 encs_assigned[assignment.eng_id - ENGINE_ID_DIGA] = assignment.eng_id; 486 } 487 488 for (i = 0; i < dc->res_pool->res_cap->num_dig_link_enc; i++) { 489 if (encs_assigned[i] == ENGINE_ID_UNKNOWN) { 490 link_enc = dc->res_pool->link_encoders[i]; 491 break; 492 } 493 } 494 495 return link_enc; 496 } 497 498 struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream( 499 struct dc *dc, 500 const struct dc_stream_state *stream) 501 { 502 struct link_encoder *link_enc; 503 504 link_enc = link_enc_cfg_get_link_enc_used_by_link(dc, stream->link); 505 506 return link_enc; 507 } 508 509 bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id, struct dc_link *link) 510 { 511 bool is_avail = true; 512 int i; 513 514 /* An encoder is not available if it has already been assigned to a different endpoint. */ 515 for (i = 0; i < MAX_PIPES; i++) { 516 struct link_enc_assignment assignment = get_assignment(dc, i); 517 struct display_endpoint_id ep_id = (struct display_endpoint_id) { 518 .link_id = link->link_id, 519 .ep_type = link->ep_type}; 520 521 if (assignment.valid && assignment.eng_id == eng_id && !are_ep_ids_equal(&ep_id, &assignment.ep_id)) { 522 is_avail = false; 523 break; 524 } 525 } 526 527 return is_avail; 528 } 529 530 bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state) 531 { 532 bool is_valid = false; 533 bool valid_entries = true; 534 bool valid_stream_ptrs = true; 535 bool valid_uniqueness = true; 536 bool valid_avail = true; 537 bool valid_streams = true; 538 int i, j; 539 uint8_t valid_count = 0; 540 uint8_t dig_stream_count = 0; 541 int matching_stream_ptrs = 0; 542 int eng_ids_per_ep_id[MAX_PIPES] = {0}; 543 int valid_bitmap = 0; 544 545 /* (1) No. valid entries same as stream count. */ 546 for (i = 0; i < MAX_PIPES; i++) { 547 struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; 548 549 if (assignment.valid) 550 valid_count++; 551 552 if (is_dig_link_enc_stream(state->streams[i])) 553 dig_stream_count++; 554 } 555 if (valid_count != dig_stream_count) 556 valid_entries = false; 557 558 /* (2) Matching stream ptrs. */ 559 for (i = 0; i < MAX_PIPES; i++) { 560 struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; 561 562 if (assignment.valid) { 563 if (assignment.stream == state->streams[i]) 564 matching_stream_ptrs++; 565 else 566 valid_stream_ptrs = false; 567 } 568 } 569 570 /* (3) Each endpoint assigned unique encoder. */ 571 for (i = 0; i < MAX_PIPES; i++) { 572 struct link_enc_assignment assignment_i = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; 573 574 if (assignment_i.valid) { 575 struct display_endpoint_id ep_id_i = assignment_i.ep_id; 576 577 eng_ids_per_ep_id[i]++; 578 for (j = 0; j < MAX_PIPES; j++) { 579 struct link_enc_assignment assignment_j = 580 state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j]; 581 582 if (j == i) 583 continue; 584 585 if (assignment_j.valid) { 586 struct display_endpoint_id ep_id_j = assignment_j.ep_id; 587 588 if (are_ep_ids_equal(&ep_id_i, &ep_id_j) && 589 assignment_i.eng_id != assignment_j.eng_id) { 590 valid_uniqueness = false; 591 eng_ids_per_ep_id[i]++; 592 } 593 } 594 } 595 } 596 } 597 598 /* (4) Assigned encoders not in available pool. */ 599 for (i = 0; i < MAX_PIPES; i++) { 600 struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; 601 602 if (assignment.valid) { 603 for (j = 0; j < dc->res_pool->res_cap->num_dig_link_enc; j++) { 604 if (state->res_ctx.link_enc_cfg_ctx.link_enc_avail[j] == assignment.eng_id) { 605 valid_avail = false; 606 break; 607 } 608 } 609 } 610 } 611 612 /* (5) All streams have valid link encoders. */ 613 for (i = 0; i < state->stream_count; i++) { 614 struct dc_stream_state *stream = state->streams[i]; 615 616 if (is_dig_link_enc_stream(stream) && stream->link_enc == NULL) { 617 valid_streams = false; 618 break; 619 } 620 } 621 622 is_valid = valid_entries && valid_stream_ptrs && valid_uniqueness && valid_avail && valid_streams; 623 ASSERT(is_valid); 624 625 if (is_valid == false) { 626 valid_bitmap = 627 (valid_entries & 0x1) | 628 ((valid_stream_ptrs & 0x1) << 1) | 629 ((valid_uniqueness & 0x1) << 2) | 630 ((valid_avail & 0x1) << 3) | 631 ((valid_streams & 0x1) << 4); 632 dm_error("Invalid link encoder assignments: 0x%x\n", valid_bitmap); 633 } 634 635 return is_valid; 636 } 637