1 /* 2 * Copyright 2023 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 #include "core_types.h" 26 #include "core_status.h" 27 #include "dc_state.h" 28 #include "dc_state_priv.h" 29 #include "dc_stream_priv.h" 30 #include "dc_plane_priv.h" 31 32 #include "dm_services.h" 33 #include "resource.h" 34 #include "link_enc_cfg.h" 35 36 #include "dml2/dml2_wrapper.h" 37 #include "dml2/dml2_internal_types.h" 38 39 #define DC_LOGGER \ 40 dc->ctx->logger 41 #define DC_LOGGER_INIT(logger) 42 43 /* Private dc_state helper functions */ 44 static bool dc_state_track_phantom_stream(struct dc_state *state, 45 struct dc_stream_state *phantom_stream) 46 { 47 if (state->phantom_stream_count >= MAX_PHANTOM_PIPES) 48 return false; 49 50 state->phantom_streams[state->phantom_stream_count++] = phantom_stream; 51 52 return true; 53 } 54 55 static bool dc_state_untrack_phantom_stream(struct dc_state *state, struct dc_stream_state *phantom_stream) 56 { 57 bool res = false; 58 int i; 59 60 /* first find phantom stream in the dc_state */ 61 for (i = 0; i < state->phantom_stream_count; i++) { 62 if (state->phantom_streams[i] == phantom_stream) { 63 state->phantom_streams[i] = NULL; 64 res = true; 65 break; 66 } 67 } 68 69 /* failed to find stream in state */ 70 if (!res) 71 return res; 72 73 /* trim back phantom streams */ 74 state->phantom_stream_count--; 75 for (; i < state->phantom_stream_count; i++) 76 state->phantom_streams[i] = state->phantom_streams[i + 1]; 77 78 return res; 79 } 80 81 static bool dc_state_is_phantom_stream_tracked(struct dc_state *state, struct dc_stream_state *phantom_stream) 82 { 83 int i; 84 85 for (i = 0; i < state->phantom_stream_count; i++) { 86 if (state->phantom_streams[i] == phantom_stream) 87 return true; 88 } 89 90 return false; 91 } 92 93 static bool dc_state_track_phantom_plane(struct dc_state *state, 94 struct dc_plane_state *phantom_plane) 95 { 96 if (state->phantom_plane_count >= MAX_PHANTOM_PIPES) 97 return false; 98 99 state->phantom_planes[state->phantom_plane_count++] = phantom_plane; 100 101 return true; 102 } 103 104 static bool dc_state_untrack_phantom_plane(struct dc_state *state, struct dc_plane_state *phantom_plane) 105 { 106 bool res = false; 107 int i; 108 109 /* first find phantom plane in the dc_state */ 110 for (i = 0; i < state->phantom_plane_count; i++) { 111 if (state->phantom_planes[i] == phantom_plane) { 112 state->phantom_planes[i] = NULL; 113 res = true; 114 break; 115 } 116 } 117 118 /* failed to find plane in state */ 119 if (!res) 120 return res; 121 122 /* trim back phantom planes */ 123 state->phantom_plane_count--; 124 for (; i < state->phantom_plane_count; i++) 125 state->phantom_planes[i] = state->phantom_planes[i + 1]; 126 127 return res; 128 } 129 130 static bool dc_state_is_phantom_plane_tracked(struct dc_state *state, struct dc_plane_state *phantom_plane) 131 { 132 int i; 133 134 for (i = 0; i < state->phantom_plane_count; i++) { 135 if (state->phantom_planes[i] == phantom_plane) 136 return true; 137 } 138 139 return false; 140 } 141 142 static void dc_state_copy_internal(struct dc_state *dst_state, struct dc_state *src_state) 143 { 144 int i, j; 145 146 memcpy(dst_state, src_state, sizeof(struct dc_state)); 147 148 for (i = 0; i < MAX_PIPES; i++) { 149 struct pipe_ctx *cur_pipe = &dst_state->res_ctx.pipe_ctx[i]; 150 151 if (cur_pipe->top_pipe) 152 cur_pipe->top_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx]; 153 154 if (cur_pipe->bottom_pipe) 155 cur_pipe->bottom_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx]; 156 157 if (cur_pipe->prev_odm_pipe) 158 cur_pipe->prev_odm_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx]; 159 160 if (cur_pipe->next_odm_pipe) 161 cur_pipe->next_odm_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx]; 162 } 163 164 /* retain phantoms */ 165 for (i = 0; i < dst_state->phantom_stream_count; i++) 166 dc_stream_retain(dst_state->phantom_streams[i]); 167 168 for (i = 0; i < dst_state->phantom_plane_count; i++) 169 dc_plane_state_retain(dst_state->phantom_planes[i]); 170 171 /* retain streams and planes */ 172 for (i = 0; i < dst_state->stream_count; i++) { 173 dc_stream_retain(dst_state->streams[i]); 174 for (j = 0; j < dst_state->stream_status[i].plane_count; j++) 175 dc_plane_state_retain( 176 dst_state->stream_status[i].plane_states[j]); 177 } 178 179 } 180 181 static void init_state(struct dc *dc, struct dc_state *state) 182 { 183 /* Each context must have their own instance of VBA and in order to 184 * initialize and obtain IP and SOC the base DML instance from DC is 185 * initially copied into every context 186 */ 187 memcpy(&state->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib)); 188 } 189 190 /* Public dc_state functions */ 191 struct dc_state *dc_state_create(struct dc *dc) 192 { 193 struct dc_state *state = kvzalloc(sizeof(struct dc_state), 194 GFP_KERNEL); 195 196 if (!state) 197 return NULL; 198 199 init_state(dc, state); 200 dc_state_construct(dc, state); 201 202 #ifdef CONFIG_DRM_AMD_DC_FP 203 if (dc->debug.using_dml2) 204 dml2_create(dc, &dc->dml2_options, &state->bw_ctx.dml2); 205 #endif 206 207 kref_init(&state->refcount); 208 209 return state; 210 } 211 212 void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state) 213 { 214 struct kref refcount = dst_state->refcount; 215 #ifdef CONFIG_DRM_AMD_DC_FP 216 struct dml2_context *dst_dml2 = dst_state->bw_ctx.dml2; 217 #endif 218 219 dc_state_copy_internal(dst_state, src_state); 220 221 #ifdef CONFIG_DRM_AMD_DC_FP 222 dst_state->bw_ctx.dml2 = dst_dml2; 223 if (src_state->bw_ctx.dml2) 224 dml2_copy(dst_state->bw_ctx.dml2, src_state->bw_ctx.dml2); 225 #endif 226 227 /* context refcount should not be overridden */ 228 dst_state->refcount = refcount; 229 } 230 231 struct dc_state *dc_state_create_copy(struct dc_state *src_state) 232 { 233 struct dc_state *new_state; 234 235 new_state = kvmalloc(sizeof(struct dc_state), 236 GFP_KERNEL); 237 if (!new_state) 238 return NULL; 239 240 dc_state_copy_internal(new_state, src_state); 241 242 #ifdef CONFIG_DRM_AMD_DC_FP 243 if (src_state->bw_ctx.dml2 && 244 !dml2_create_copy(&new_state->bw_ctx.dml2, src_state->bw_ctx.dml2)) { 245 dc_state_release(new_state); 246 return NULL; 247 } 248 #endif 249 250 kref_init(&new_state->refcount); 251 252 return new_state; 253 } 254 255 void dc_state_copy_current(struct dc *dc, struct dc_state *dst_state) 256 { 257 dc_state_copy(dst_state, dc->current_state); 258 } 259 260 struct dc_state *dc_state_create_current_copy(struct dc *dc) 261 { 262 return dc_state_create_copy(dc->current_state); 263 } 264 265 void dc_state_construct(struct dc *dc, struct dc_state *state) 266 { 267 state->clk_mgr = dc->clk_mgr; 268 269 /* Initialise DIG link encoder resource tracking variables. */ 270 if (dc->res_pool) 271 link_enc_cfg_init(dc, state); 272 } 273 274 void dc_state_destruct(struct dc_state *state) 275 { 276 int i, j; 277 278 for (i = 0; i < state->stream_count; i++) { 279 for (j = 0; j < state->stream_status[i].plane_count; j++) 280 dc_plane_state_release( 281 state->stream_status[i].plane_states[j]); 282 283 state->stream_status[i].plane_count = 0; 284 dc_stream_release(state->streams[i]); 285 state->streams[i] = NULL; 286 } 287 state->stream_count = 0; 288 289 /* release tracked phantoms */ 290 for (i = 0; i < state->phantom_stream_count; i++) { 291 dc_stream_release(state->phantom_streams[i]); 292 state->phantom_streams[i] = NULL; 293 } 294 state->phantom_stream_count = 0; 295 296 for (i = 0; i < state->phantom_plane_count; i++) { 297 dc_plane_state_release(state->phantom_planes[i]); 298 state->phantom_planes[i] = NULL; 299 } 300 state->phantom_plane_count = 0; 301 302 state->stream_mask = 0; 303 memset(&state->res_ctx, 0, sizeof(state->res_ctx)); 304 memset(&state->pp_display_cfg, 0, sizeof(state->pp_display_cfg)); 305 memset(&state->dcn_bw_vars, 0, sizeof(state->dcn_bw_vars)); 306 state->clk_mgr = NULL; 307 memset(&state->bw_ctx.bw, 0, sizeof(state->bw_ctx.bw)); 308 memset(state->block_sequence, 0, sizeof(state->block_sequence)); 309 state->block_sequence_steps = 0; 310 memset(state->dc_dmub_cmd, 0, sizeof(state->dc_dmub_cmd)); 311 state->dmub_cmd_count = 0; 312 memset(&state->perf_params, 0, sizeof(state->perf_params)); 313 memset(&state->scratch, 0, sizeof(state->scratch)); 314 } 315 316 void dc_state_retain(struct dc_state *state) 317 { 318 kref_get(&state->refcount); 319 } 320 321 static void dc_state_free(struct kref *kref) 322 { 323 struct dc_state *state = container_of(kref, struct dc_state, refcount); 324 325 dc_state_destruct(state); 326 327 #ifdef CONFIG_DRM_AMD_DC_FP 328 dml2_destroy(state->bw_ctx.dml2); 329 state->bw_ctx.dml2 = 0; 330 #endif 331 332 kvfree(state); 333 } 334 335 void dc_state_release(struct dc_state *state) 336 { 337 kref_put(&state->refcount, dc_state_free); 338 } 339 /* 340 * dc_state_add_stream() - Add a new dc_stream_state to a dc_state. 341 */ 342 enum dc_status dc_state_add_stream( 343 struct dc *dc, 344 struct dc_state *state, 345 struct dc_stream_state *stream) 346 { 347 enum dc_status res; 348 349 DC_LOGGER_INIT(dc->ctx->logger); 350 351 if (state->stream_count >= dc->res_pool->timing_generator_count) { 352 DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream); 353 return DC_ERROR_UNEXPECTED; 354 } 355 356 state->streams[state->stream_count] = stream; 357 dc_stream_retain(stream); 358 state->stream_count++; 359 360 res = resource_add_otg_master_for_stream_output( 361 state, dc->res_pool, stream); 362 if (res != DC_OK) 363 DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res); 364 365 return res; 366 } 367 368 /* 369 * dc_state_remove_stream() - Remove a stream from a dc_state. 370 */ 371 enum dc_status dc_state_remove_stream( 372 struct dc *dc, 373 struct dc_state *state, 374 struct dc_stream_state *stream) 375 { 376 int i; 377 struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream( 378 &state->res_ctx, stream); 379 380 if (!del_pipe) { 381 dm_error("Pipe not found for stream %p !\n", stream); 382 return DC_ERROR_UNEXPECTED; 383 } 384 385 resource_update_pipes_for_stream_with_slice_count(state, 386 dc->current_state, dc->res_pool, stream, 1); 387 resource_remove_otg_master_for_stream_output( 388 state, dc->res_pool, stream); 389 390 for (i = 0; i < state->stream_count; i++) 391 if (state->streams[i] == stream) 392 break; 393 394 if (state->streams[i] != stream) { 395 dm_error("Context doesn't have stream %p !\n", stream); 396 return DC_ERROR_UNEXPECTED; 397 } 398 399 dc_stream_release(state->streams[i]); 400 state->stream_count--; 401 402 /* Trim back arrays */ 403 for (; i < state->stream_count; i++) { 404 state->streams[i] = state->streams[i + 1]; 405 state->stream_status[i] = state->stream_status[i + 1]; 406 } 407 408 state->streams[state->stream_count] = NULL; 409 memset( 410 &state->stream_status[state->stream_count], 411 0, 412 sizeof(state->stream_status[0])); 413 414 return DC_OK; 415 } 416 417 bool dc_state_add_plane( 418 const struct dc *dc, 419 struct dc_stream_state *stream, 420 struct dc_plane_state *plane_state, 421 struct dc_state *state) 422 { 423 struct resource_pool *pool = dc->res_pool; 424 struct pipe_ctx *otg_master_pipe; 425 struct dc_stream_status *stream_status = NULL; 426 bool added = false; 427 428 stream_status = dc_state_get_stream_status(state, stream); 429 if (stream_status == NULL) { 430 dm_error("Existing stream not found; failed to attach surface!\n"); 431 goto out; 432 } else if (stream_status->plane_count == MAX_SURFACE_NUM) { 433 dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n", 434 plane_state, MAX_SURFACE_NUM); 435 goto out; 436 } 437 438 otg_master_pipe = resource_get_otg_master_for_stream( 439 &state->res_ctx, stream); 440 if (otg_master_pipe) 441 added = resource_append_dpp_pipes_for_plane_composition(state, 442 dc->current_state, pool, otg_master_pipe, plane_state); 443 444 if (added) { 445 stream_status->plane_states[stream_status->plane_count] = 446 plane_state; 447 stream_status->plane_count++; 448 dc_plane_state_retain(plane_state); 449 } 450 451 out: 452 return added; 453 } 454 455 bool dc_state_remove_plane( 456 const struct dc *dc, 457 struct dc_stream_state *stream, 458 struct dc_plane_state *plane_state, 459 struct dc_state *state) 460 { 461 int i; 462 struct dc_stream_status *stream_status = NULL; 463 struct resource_pool *pool = dc->res_pool; 464 465 if (!plane_state) 466 return true; 467 468 for (i = 0; i < state->stream_count; i++) 469 if (state->streams[i] == stream) { 470 stream_status = &state->stream_status[i]; 471 break; 472 } 473 474 if (stream_status == NULL) { 475 dm_error("Existing stream not found; failed to remove plane.\n"); 476 return false; 477 } 478 479 resource_remove_dpp_pipes_for_plane_composition( 480 state, pool, plane_state); 481 482 for (i = 0; i < stream_status->plane_count; i++) { 483 if (stream_status->plane_states[i] == plane_state) { 484 dc_plane_state_release(stream_status->plane_states[i]); 485 break; 486 } 487 } 488 489 if (i == stream_status->plane_count) { 490 dm_error("Existing plane_state not found; failed to detach it!\n"); 491 return false; 492 } 493 494 stream_status->plane_count--; 495 496 /* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */ 497 for (; i < stream_status->plane_count; i++) 498 stream_status->plane_states[i] = stream_status->plane_states[i + 1]; 499 500 stream_status->plane_states[stream_status->plane_count] = NULL; 501 502 if (stream_status->plane_count == 0 && dc->config.enable_windowed_mpo_odm) 503 /* ODM combine could prevent us from supporting more planes 504 * we will reset ODM slice count back to 1 when all planes have 505 * been removed to maximize the amount of planes supported when 506 * new planes are added. 507 */ 508 resource_update_pipes_for_stream_with_slice_count( 509 state, dc->current_state, dc->res_pool, stream, 1); 510 511 return true; 512 } 513 514 /** 515 * dc_state_rem_all_planes_for_stream - Remove planes attached to the target stream. 516 * 517 * @dc: Current dc state. 518 * @stream: Target stream, which we want to remove the attached plans. 519 * @state: context from which the planes are to be removed. 520 * 521 * Return: 522 * Return true if DC was able to remove all planes from the target 523 * stream, otherwise, return false. 524 */ 525 bool dc_state_rem_all_planes_for_stream( 526 const struct dc *dc, 527 struct dc_stream_state *stream, 528 struct dc_state *state) 529 { 530 int i, old_plane_count; 531 struct dc_stream_status *stream_status = NULL; 532 struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 }; 533 534 for (i = 0; i < state->stream_count; i++) 535 if (state->streams[i] == stream) { 536 stream_status = &state->stream_status[i]; 537 break; 538 } 539 540 if (stream_status == NULL) { 541 dm_error("Existing stream %p not found!\n", stream); 542 return false; 543 } 544 545 old_plane_count = stream_status->plane_count; 546 547 for (i = 0; i < old_plane_count; i++) 548 del_planes[i] = stream_status->plane_states[i]; 549 550 for (i = 0; i < old_plane_count; i++) 551 if (!dc_state_remove_plane(dc, stream, del_planes[i], state)) 552 return false; 553 554 return true; 555 } 556 557 bool dc_state_add_all_planes_for_stream( 558 const struct dc *dc, 559 struct dc_stream_state *stream, 560 struct dc_plane_state * const *plane_states, 561 int plane_count, 562 struct dc_state *state) 563 { 564 int i; 565 bool result = true; 566 567 for (i = 0; i < plane_count; i++) 568 if (!dc_state_add_plane(dc, stream, plane_states[i], state)) { 569 result = false; 570 break; 571 } 572 573 return result; 574 } 575 576 /* Private dc_state functions */ 577 578 /** 579 * dc_state_get_stream_status - Get stream status from given dc state 580 * @state: DC state to find the stream status in 581 * @stream: The stream to get the stream status for 582 * 583 * The given stream is expected to exist in the given dc state. Otherwise, NULL 584 * will be returned. 585 */ 586 struct dc_stream_status *dc_state_get_stream_status( 587 struct dc_state *state, 588 struct dc_stream_state *stream) 589 { 590 uint8_t i; 591 592 if (state == NULL) 593 return NULL; 594 595 for (i = 0; i < state->stream_count; i++) { 596 if (stream == state->streams[i]) 597 return &state->stream_status[i]; 598 } 599 600 return NULL; 601 } 602 603 enum mall_stream_type dc_state_get_pipe_subvp_type(const struct dc_state *state, 604 const struct pipe_ctx *pipe_ctx) 605 { 606 return dc_state_get_stream_subvp_type(state, pipe_ctx->stream); 607 } 608 609 enum mall_stream_type dc_state_get_stream_subvp_type(const struct dc_state *state, 610 const struct dc_stream_state *stream) 611 { 612 int i; 613 614 enum mall_stream_type type = SUBVP_NONE; 615 616 for (i = 0; i < state->stream_count; i++) { 617 if (state->streams[i] == stream) { 618 type = state->stream_status[i].mall_stream_config.type; 619 break; 620 } 621 } 622 623 return type; 624 } 625 626 struct dc_stream_state *dc_state_get_paired_subvp_stream(const struct dc_state *state, 627 const struct dc_stream_state *stream) 628 { 629 int i; 630 631 struct dc_stream_state *paired_stream = NULL; 632 633 for (i = 0; i < state->stream_count; i++) { 634 if (state->streams[i] == stream) { 635 paired_stream = state->stream_status[i].mall_stream_config.paired_stream; 636 break; 637 } 638 } 639 640 return paired_stream; 641 } 642 643 struct dc_stream_state *dc_state_create_phantom_stream(const struct dc *dc, 644 struct dc_state *state, 645 struct dc_stream_state *main_stream) 646 { 647 struct dc_stream_state *phantom_stream; 648 649 DC_LOGGER_INIT(dc->ctx->logger); 650 651 phantom_stream = dc_create_stream_for_sink(main_stream->sink); 652 653 if (!phantom_stream) { 654 DC_LOG_ERROR("Failed to allocate phantom stream.\n"); 655 return NULL; 656 } 657 658 /* track phantom stream in dc_state */ 659 dc_state_track_phantom_stream(state, phantom_stream); 660 661 phantom_stream->is_phantom = true; 662 phantom_stream->signal = SIGNAL_TYPE_VIRTUAL; 663 phantom_stream->dpms_off = true; 664 665 return phantom_stream; 666 } 667 668 void dc_state_release_phantom_stream(const struct dc *dc, 669 struct dc_state *state, 670 struct dc_stream_state *phantom_stream) 671 { 672 DC_LOGGER_INIT(dc->ctx->logger); 673 674 if (!dc_state_untrack_phantom_stream(state, phantom_stream)) { 675 DC_LOG_ERROR("Failed to free phantom stream %p in dc state %p.\n", phantom_stream, state); 676 return; 677 } 678 679 dc_stream_release(phantom_stream); 680 } 681 682 struct dc_plane_state *dc_state_create_phantom_plane(struct dc *dc, 683 struct dc_state *state, 684 struct dc_plane_state *main_plane) 685 { 686 struct dc_plane_state *phantom_plane = dc_create_plane_state(dc); 687 688 DC_LOGGER_INIT(dc->ctx->logger); 689 690 if (!phantom_plane) { 691 DC_LOG_ERROR("Failed to allocate phantom plane.\n"); 692 return NULL; 693 } 694 695 /* track phantom inside dc_state */ 696 dc_state_track_phantom_plane(state, phantom_plane); 697 698 phantom_plane->is_phantom = true; 699 700 return phantom_plane; 701 } 702 703 void dc_state_release_phantom_plane(const struct dc *dc, 704 struct dc_state *state, 705 struct dc_plane_state *phantom_plane) 706 { 707 DC_LOGGER_INIT(dc->ctx->logger); 708 709 if (!dc_state_untrack_phantom_plane(state, phantom_plane)) { 710 DC_LOG_ERROR("Failed to free phantom plane %p in dc state %p.\n", phantom_plane, state); 711 return; 712 } 713 714 dc_plane_state_release(phantom_plane); 715 } 716 717 /* add phantom streams to context and generate correct meta inside dc_state */ 718 enum dc_status dc_state_add_phantom_stream(struct dc *dc, 719 struct dc_state *state, 720 struct dc_stream_state *phantom_stream, 721 struct dc_stream_state *main_stream) 722 { 723 struct dc_stream_status *main_stream_status; 724 struct dc_stream_status *phantom_stream_status; 725 enum dc_status res = dc_state_add_stream(dc, state, phantom_stream); 726 727 /* check if stream is tracked */ 728 if (res == DC_OK && !dc_state_is_phantom_stream_tracked(state, phantom_stream)) { 729 /* stream must be tracked if added to state */ 730 dc_state_track_phantom_stream(state, phantom_stream); 731 } 732 733 /* setup subvp meta */ 734 main_stream_status = dc_state_get_stream_status(state, main_stream); 735 phantom_stream_status = dc_state_get_stream_status(state, phantom_stream); 736 phantom_stream_status->mall_stream_config.type = SUBVP_PHANTOM; 737 phantom_stream_status->mall_stream_config.paired_stream = main_stream; 738 main_stream_status->mall_stream_config.type = SUBVP_MAIN; 739 main_stream_status->mall_stream_config.paired_stream = phantom_stream; 740 741 return res; 742 } 743 744 enum dc_status dc_state_remove_phantom_stream(struct dc *dc, 745 struct dc_state *state, 746 struct dc_stream_state *phantom_stream) 747 { 748 struct dc_stream_status *main_stream_status; 749 struct dc_stream_status *phantom_stream_status; 750 751 /* reset subvp meta */ 752 phantom_stream_status = dc_state_get_stream_status(state, phantom_stream); 753 main_stream_status = dc_state_get_stream_status(state, phantom_stream_status->mall_stream_config.paired_stream); 754 phantom_stream_status->mall_stream_config.type = SUBVP_NONE; 755 phantom_stream_status->mall_stream_config.paired_stream = NULL; 756 if (main_stream_status) { 757 main_stream_status->mall_stream_config.type = SUBVP_NONE; 758 main_stream_status->mall_stream_config.paired_stream = NULL; 759 } 760 761 /* remove stream from state */ 762 return dc_state_remove_stream(dc, state, phantom_stream); 763 } 764 765 bool dc_state_add_phantom_plane( 766 const struct dc *dc, 767 struct dc_stream_state *phantom_stream, 768 struct dc_plane_state *phantom_plane, 769 struct dc_state *state) 770 { 771 bool res = dc_state_add_plane(dc, phantom_stream, phantom_plane, state); 772 773 /* check if stream is tracked */ 774 if (res && !dc_state_is_phantom_plane_tracked(state, phantom_plane)) { 775 /* stream must be tracked if added to state */ 776 dc_state_track_phantom_plane(state, phantom_plane); 777 } 778 779 return res; 780 } 781 782 bool dc_state_remove_phantom_plane( 783 const struct dc *dc, 784 struct dc_stream_state *phantom_stream, 785 struct dc_plane_state *phantom_plane, 786 struct dc_state *state) 787 { 788 return dc_state_remove_plane(dc, phantom_stream, phantom_plane, state); 789 } 790 791 bool dc_state_rem_all_phantom_planes_for_stream( 792 const struct dc *dc, 793 struct dc_stream_state *phantom_stream, 794 struct dc_state *state, 795 bool should_release_planes) 796 { 797 int i, old_plane_count; 798 struct dc_stream_status *stream_status = NULL; 799 struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 }; 800 801 for (i = 0; i < state->stream_count; i++) 802 if (state->streams[i] == phantom_stream) { 803 stream_status = &state->stream_status[i]; 804 break; 805 } 806 807 if (stream_status == NULL) { 808 dm_error("Existing stream %p not found!\n", phantom_stream); 809 return false; 810 } 811 812 old_plane_count = stream_status->plane_count; 813 814 for (i = 0; i < old_plane_count; i++) 815 del_planes[i] = stream_status->plane_states[i]; 816 817 for (i = 0; i < old_plane_count; i++) { 818 if (!dc_state_remove_plane(dc, phantom_stream, del_planes[i], state)) 819 return false; 820 if (should_release_planes) 821 dc_state_release_phantom_plane(dc, state, del_planes[i]); 822 } 823 824 return true; 825 } 826 827 bool dc_state_add_all_phantom_planes_for_stream( 828 const struct dc *dc, 829 struct dc_stream_state *phantom_stream, 830 struct dc_plane_state * const *phantom_planes, 831 int plane_count, 832 struct dc_state *state) 833 { 834 return dc_state_add_all_planes_for_stream(dc, phantom_stream, phantom_planes, plane_count, state); 835 } 836 837 bool dc_state_remove_phantom_streams_and_planes( 838 struct dc *dc, 839 struct dc_state *state) 840 { 841 int i; 842 bool removed_phantom = false; 843 struct dc_stream_state *phantom_stream = NULL; 844 845 for (i = 0; i < dc->res_pool->pipe_count; i++) { 846 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; 847 848 if (pipe->plane_state && pipe->stream && dc_state_get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) { 849 phantom_stream = pipe->stream; 850 851 dc_state_rem_all_phantom_planes_for_stream(dc, phantom_stream, state, false); 852 dc_state_remove_phantom_stream(dc, state, phantom_stream); 853 removed_phantom = true; 854 } 855 } 856 return removed_phantom; 857 } 858 859 void dc_state_release_phantom_streams_and_planes( 860 struct dc *dc, 861 struct dc_state *state) 862 { 863 int i; 864 865 for (i = 0; i < state->phantom_stream_count; i++) 866 dc_state_release_phantom_stream(dc, state, state->phantom_streams[i]); 867 868 for (i = 0; i < state->phantom_plane_count; i++) 869 dc_state_release_phantom_plane(dc, state, state->phantom_planes[i]); 870 } 871