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 */ 44static 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 55static 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 81static 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 93static 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 104static 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 130static 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 142static 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 181static 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 */ 191struct 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 212void 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 231struct 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 255void dc_state_copy_current(struct dc *dc, struct dc_state *dst_state) 256{ 257 dc_state_copy(dst_state, dc->current_state); 258} 259 260struct dc_state *dc_state_create_current_copy(struct dc *dc) 261{ 262 return dc_state_create_copy(dc->current_state); 263} 264 265void 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 274void 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 316void dc_state_retain(struct dc_state *state) 317{ 318 kref_get(&state->refcount); 319} 320 321static 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 335void dc_state_release(struct dc_state *state) 336{ 337 if (state != NULL) 338 kref_put(&state->refcount, dc_state_free); 339} 340/* 341 * dc_state_add_stream() - Add a new dc_stream_state to a dc_state. 342 */ 343enum dc_status dc_state_add_stream( 344 struct dc *dc, 345 struct dc_state *state, 346 struct dc_stream_state *stream) 347{ 348 enum dc_status res; 349 350 DC_LOGGER_INIT(dc->ctx->logger); 351 352 if (state->stream_count >= dc->res_pool->timing_generator_count) { 353 DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream); 354 return DC_ERROR_UNEXPECTED; 355 } 356 357 state->streams[state->stream_count] = stream; 358 dc_stream_retain(stream); 359 state->stream_count++; 360 361 res = resource_add_otg_master_for_stream_output( 362 state, dc->res_pool, stream); 363 if (res != DC_OK) 364 DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res); 365 366 return res; 367} 368 369/* 370 * dc_state_remove_stream() - Remove a stream from a dc_state. 371 */ 372enum dc_status dc_state_remove_stream( 373 struct dc *dc, 374 struct dc_state *state, 375 struct dc_stream_state *stream) 376{ 377 int i; 378 struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream( 379 &state->res_ctx, stream); 380 381 if (!del_pipe) { 382 dm_error("Pipe not found for stream %p !\n", stream); 383 return DC_ERROR_UNEXPECTED; 384 } 385 386 resource_update_pipes_for_stream_with_slice_count(state, 387 dc->current_state, dc->res_pool, stream, 1); 388 resource_remove_otg_master_for_stream_output( 389 state, dc->res_pool, stream); 390 391 for (i = 0; i < state->stream_count; i++) 392 if (state->streams[i] == stream) 393 break; 394 395 if (state->streams[i] != stream) { 396 dm_error("Context doesn't have stream %p !\n", stream); 397 return DC_ERROR_UNEXPECTED; 398 } 399 400 dc_stream_release(state->streams[i]); 401 state->stream_count--; 402 403 /* Trim back arrays */ 404 for (; i < state->stream_count; i++) { 405 state->streams[i] = state->streams[i + 1]; 406 state->stream_status[i] = state->stream_status[i + 1]; 407 } 408 409 state->streams[state->stream_count] = NULL; 410 memset( 411 &state->stream_status[state->stream_count], 412 0, 413 sizeof(state->stream_status[0])); 414 415 return DC_OK; 416} 417 418bool dc_state_add_plane( 419 const struct dc *dc, 420 struct dc_stream_state *stream, 421 struct dc_plane_state *plane_state, 422 struct dc_state *state) 423{ 424 struct resource_pool *pool = dc->res_pool; 425 struct pipe_ctx *otg_master_pipe; 426 struct dc_stream_status *stream_status = NULL; 427 bool added = false; 428 429 stream_status = dc_state_get_stream_status(state, stream); 430 if (stream_status == NULL) { 431 dm_error("Existing stream not found; failed to attach surface!\n"); 432 goto out; 433 } else if (stream_status->plane_count == MAX_SURFACE_NUM) { 434 dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n", 435 plane_state, MAX_SURFACE_NUM); 436 goto out; 437 } 438 439 if (stream_status->plane_count == 0 && dc->config.enable_windowed_mpo_odm) 440 /* ODM combine could prevent us from supporting more planes 441 * we will reset ODM slice count back to 1 when all planes have 442 * been removed to maximize the amount of planes supported when 443 * new planes are added. 444 */ 445 resource_update_pipes_for_stream_with_slice_count( 446 state, dc->current_state, dc->res_pool, stream, 1); 447 448 otg_master_pipe = resource_get_otg_master_for_stream( 449 &state->res_ctx, stream); 450 if (otg_master_pipe) 451 added = resource_append_dpp_pipes_for_plane_composition(state, 452 dc->current_state, pool, otg_master_pipe, plane_state); 453 454 if (added) { 455 stream_status->plane_states[stream_status->plane_count] = 456 plane_state; 457 stream_status->plane_count++; 458 dc_plane_state_retain(plane_state); 459 } 460 461out: 462 return added; 463} 464 465bool dc_state_remove_plane( 466 const struct dc *dc, 467 struct dc_stream_state *stream, 468 struct dc_plane_state *plane_state, 469 struct dc_state *state) 470{ 471 int i; 472 struct dc_stream_status *stream_status = NULL; 473 struct resource_pool *pool = dc->res_pool; 474 475 if (!plane_state) 476 return true; 477 478 for (i = 0; i < state->stream_count; i++) 479 if (state->streams[i] == stream) { 480 stream_status = &state->stream_status[i]; 481 break; 482 } 483 484 if (stream_status == NULL) { 485 dm_error("Existing stream not found; failed to remove plane.\n"); 486 return false; 487 } 488 489 resource_remove_dpp_pipes_for_plane_composition( 490 state, pool, plane_state); 491 492 for (i = 0; i < stream_status->plane_count; i++) { 493 if (stream_status->plane_states[i] == plane_state) { 494 dc_plane_state_release(stream_status->plane_states[i]); 495 break; 496 } 497 } 498 499 if (i == stream_status->plane_count) { 500 dm_error("Existing plane_state not found; failed to detach it!\n"); 501 return false; 502 } 503 504 stream_status->plane_count--; 505 506 /* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */ 507 for (; i < stream_status->plane_count; i++) 508 stream_status->plane_states[i] = stream_status->plane_states[i + 1]; 509 510 stream_status->plane_states[stream_status->plane_count] = NULL; 511 512 if (stream_status->plane_count == 0 && dc->config.enable_windowed_mpo_odm) 513 /* ODM combine could prevent us from supporting more planes 514 * we will reset ODM slice count back to 1 when all planes have 515 * been removed to maximize the amount of planes supported when 516 * new planes are added. 517 */ 518 resource_update_pipes_for_stream_with_slice_count( 519 state, dc->current_state, dc->res_pool, stream, 1); 520 521 return true; 522} 523 524/** 525 * dc_state_rem_all_planes_for_stream - Remove planes attached to the target stream. 526 * 527 * @dc: Current dc state. 528 * @stream: Target stream, which we want to remove the attached plans. 529 * @state: context from which the planes are to be removed. 530 * 531 * Return: 532 * Return true if DC was able to remove all planes from the target 533 * stream, otherwise, return false. 534 */ 535bool dc_state_rem_all_planes_for_stream( 536 const struct dc *dc, 537 struct dc_stream_state *stream, 538 struct dc_state *state) 539{ 540 int i, old_plane_count; 541 struct dc_stream_status *stream_status = NULL; 542 struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 }; 543 544 for (i = 0; i < state->stream_count; i++) 545 if (state->streams[i] == stream) { 546 stream_status = &state->stream_status[i]; 547 break; 548 } 549 550 if (stream_status == NULL) { 551 dm_error("Existing stream %p not found!\n", stream); 552 return false; 553 } 554 555 old_plane_count = stream_status->plane_count; 556 557 for (i = 0; i < old_plane_count; i++) 558 del_planes[i] = stream_status->plane_states[i]; 559 560 for (i = 0; i < old_plane_count; i++) 561 if (!dc_state_remove_plane(dc, stream, del_planes[i], state)) 562 return false; 563 564 return true; 565} 566 567bool dc_state_add_all_planes_for_stream( 568 const struct dc *dc, 569 struct dc_stream_state *stream, 570 struct dc_plane_state * const *plane_states, 571 int plane_count, 572 struct dc_state *state) 573{ 574 int i; 575 bool result = true; 576 577 for (i = 0; i < plane_count; i++) 578 if (!dc_state_add_plane(dc, stream, plane_states[i], state)) { 579 result = false; 580 break; 581 } 582 583 return result; 584} 585 586/* Private dc_state functions */ 587 588/** 589 * dc_state_get_stream_status - Get stream status from given dc state 590 * @state: DC state to find the stream status in 591 * @stream: The stream to get the stream status for 592 * 593 * The given stream is expected to exist in the given dc state. Otherwise, NULL 594 * will be returned. 595 */ 596struct dc_stream_status *dc_state_get_stream_status( 597 struct dc_state *state, 598 struct dc_stream_state *stream) 599{ 600 uint8_t i; 601 602 if (state == NULL) 603 return NULL; 604 605 for (i = 0; i < state->stream_count; i++) { 606 if (stream == state->streams[i]) 607 return &state->stream_status[i]; 608 } 609 610 return NULL; 611} 612 613enum mall_stream_type dc_state_get_pipe_subvp_type(const struct dc_state *state, 614 const struct pipe_ctx *pipe_ctx) 615{ 616 return dc_state_get_stream_subvp_type(state, pipe_ctx->stream); 617} 618 619enum mall_stream_type dc_state_get_stream_subvp_type(const struct dc_state *state, 620 const struct dc_stream_state *stream) 621{ 622 int i; 623 624 enum mall_stream_type type = SUBVP_NONE; 625 626 for (i = 0; i < state->stream_count; i++) { 627 if (state->streams[i] == stream) { 628 type = state->stream_status[i].mall_stream_config.type; 629 break; 630 } 631 } 632 633 return type; 634} 635 636struct dc_stream_state *dc_state_get_paired_subvp_stream(const struct dc_state *state, 637 const struct dc_stream_state *stream) 638{ 639 int i; 640 641 struct dc_stream_state *paired_stream = NULL; 642 643 for (i = 0; i < state->stream_count; i++) { 644 if (state->streams[i] == stream) { 645 paired_stream = state->stream_status[i].mall_stream_config.paired_stream; 646 break; 647 } 648 } 649 650 return paired_stream; 651} 652 653struct dc_stream_state *dc_state_create_phantom_stream(const struct dc *dc, 654 struct dc_state *state, 655 struct dc_stream_state *main_stream) 656{ 657 struct dc_stream_state *phantom_stream; 658 659 DC_LOGGER_INIT(dc->ctx->logger); 660 661 phantom_stream = dc_create_stream_for_sink(main_stream->sink); 662 663 if (!phantom_stream) { 664 DC_LOG_ERROR("Failed to allocate phantom stream.\n"); 665 return NULL; 666 } 667 668 /* track phantom stream in dc_state */ 669 dc_state_track_phantom_stream(state, phantom_stream); 670 671 phantom_stream->is_phantom = true; 672 phantom_stream->signal = SIGNAL_TYPE_VIRTUAL; 673 phantom_stream->dpms_off = true; 674 675 return phantom_stream; 676} 677 678void dc_state_release_phantom_stream(const struct dc *dc, 679 struct dc_state *state, 680 struct dc_stream_state *phantom_stream) 681{ 682 DC_LOGGER_INIT(dc->ctx->logger); 683 684 if (!dc_state_untrack_phantom_stream(state, phantom_stream)) { 685 DC_LOG_ERROR("Failed to free phantom stream %p in dc state %p.\n", phantom_stream, state); 686 return; 687 } 688 689 dc_stream_release(phantom_stream); 690} 691 692struct dc_plane_state *dc_state_create_phantom_plane(struct dc *dc, 693 struct dc_state *state, 694 struct dc_plane_state *main_plane) 695{ 696 struct dc_plane_state *phantom_plane = dc_create_plane_state(dc); 697 698 DC_LOGGER_INIT(dc->ctx->logger); 699 700 if (!phantom_plane) { 701 DC_LOG_ERROR("Failed to allocate phantom plane.\n"); 702 return NULL; 703 } 704 705 /* track phantom inside dc_state */ 706 dc_state_track_phantom_plane(state, phantom_plane); 707 708 phantom_plane->is_phantom = true; 709 710 return phantom_plane; 711} 712 713void dc_state_release_phantom_plane(const struct dc *dc, 714 struct dc_state *state, 715 struct dc_plane_state *phantom_plane) 716{ 717 DC_LOGGER_INIT(dc->ctx->logger); 718 719 if (!dc_state_untrack_phantom_plane(state, phantom_plane)) { 720 DC_LOG_ERROR("Failed to free phantom plane %p in dc state %p.\n", phantom_plane, state); 721 return; 722 } 723 724 dc_plane_state_release(phantom_plane); 725} 726 727/* add phantom streams to context and generate correct meta inside dc_state */ 728enum dc_status dc_state_add_phantom_stream(struct dc *dc, 729 struct dc_state *state, 730 struct dc_stream_state *phantom_stream, 731 struct dc_stream_state *main_stream) 732{ 733 struct dc_stream_status *main_stream_status; 734 struct dc_stream_status *phantom_stream_status; 735 enum dc_status res = dc_state_add_stream(dc, state, phantom_stream); 736 737 /* check if stream is tracked */ 738 if (res == DC_OK && !dc_state_is_phantom_stream_tracked(state, phantom_stream)) { 739 /* stream must be tracked if added to state */ 740 dc_state_track_phantom_stream(state, phantom_stream); 741 } 742 743 /* setup subvp meta */ 744 main_stream_status = dc_state_get_stream_status(state, main_stream); 745 phantom_stream_status = dc_state_get_stream_status(state, phantom_stream); 746 phantom_stream_status->mall_stream_config.type = SUBVP_PHANTOM; 747 phantom_stream_status->mall_stream_config.paired_stream = main_stream; 748 main_stream_status->mall_stream_config.type = SUBVP_MAIN; 749 main_stream_status->mall_stream_config.paired_stream = phantom_stream; 750 751 return res; 752} 753 754enum dc_status dc_state_remove_phantom_stream(struct dc *dc, 755 struct dc_state *state, 756 struct dc_stream_state *phantom_stream) 757{ 758 struct dc_stream_status *main_stream_status; 759 struct dc_stream_status *phantom_stream_status; 760 761 /* reset subvp meta */ 762 phantom_stream_status = dc_state_get_stream_status(state, phantom_stream); 763 main_stream_status = dc_state_get_stream_status(state, phantom_stream_status->mall_stream_config.paired_stream); 764 phantom_stream_status->mall_stream_config.type = SUBVP_NONE; 765 phantom_stream_status->mall_stream_config.paired_stream = NULL; 766 if (main_stream_status) { 767 main_stream_status->mall_stream_config.type = SUBVP_NONE; 768 main_stream_status->mall_stream_config.paired_stream = NULL; 769 } 770 771 /* remove stream from state */ 772 return dc_state_remove_stream(dc, state, phantom_stream); 773} 774 775bool dc_state_add_phantom_plane( 776 const struct dc *dc, 777 struct dc_stream_state *phantom_stream, 778 struct dc_plane_state *phantom_plane, 779 struct dc_state *state) 780{ 781 bool res = dc_state_add_plane(dc, phantom_stream, phantom_plane, state); 782 783 /* check if stream is tracked */ 784 if (res && !dc_state_is_phantom_plane_tracked(state, phantom_plane)) { 785 /* stream must be tracked if added to state */ 786 dc_state_track_phantom_plane(state, phantom_plane); 787 } 788 789 return res; 790} 791 792bool dc_state_remove_phantom_plane( 793 const struct dc *dc, 794 struct dc_stream_state *phantom_stream, 795 struct dc_plane_state *phantom_plane, 796 struct dc_state *state) 797{ 798 return dc_state_remove_plane(dc, phantom_stream, phantom_plane, state); 799} 800 801bool dc_state_rem_all_phantom_planes_for_stream( 802 const struct dc *dc, 803 struct dc_stream_state *phantom_stream, 804 struct dc_state *state, 805 bool should_release_planes) 806{ 807 int i, old_plane_count; 808 struct dc_stream_status *stream_status = NULL; 809 struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 }; 810 811 for (i = 0; i < state->stream_count; i++) 812 if (state->streams[i] == phantom_stream) { 813 stream_status = &state->stream_status[i]; 814 break; 815 } 816 817 if (stream_status == NULL) { 818 dm_error("Existing stream %p not found!\n", phantom_stream); 819 return false; 820 } 821 822 old_plane_count = stream_status->plane_count; 823 824 for (i = 0; i < old_plane_count; i++) 825 del_planes[i] = stream_status->plane_states[i]; 826 827 for (i = 0; i < old_plane_count; i++) { 828 if (!dc_state_remove_plane(dc, phantom_stream, del_planes[i], state)) 829 return false; 830 if (should_release_planes) 831 dc_state_release_phantom_plane(dc, state, del_planes[i]); 832 } 833 834 return true; 835} 836 837bool dc_state_add_all_phantom_planes_for_stream( 838 const struct dc *dc, 839 struct dc_stream_state *phantom_stream, 840 struct dc_plane_state * const *phantom_planes, 841 int plane_count, 842 struct dc_state *state) 843{ 844 return dc_state_add_all_planes_for_stream(dc, phantom_stream, phantom_planes, plane_count, state); 845} 846 847bool dc_state_remove_phantom_streams_and_planes( 848 struct dc *dc, 849 struct dc_state *state) 850{ 851 int i; 852 bool removed_phantom = false; 853 struct dc_stream_state *phantom_stream = NULL; 854 855 for (i = 0; i < dc->res_pool->pipe_count; i++) { 856 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; 857 858 if (pipe->plane_state && pipe->stream && dc_state_get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) { 859 phantom_stream = pipe->stream; 860 861 dc_state_rem_all_phantom_planes_for_stream(dc, phantom_stream, state, false); 862 dc_state_remove_phantom_stream(dc, state, phantom_stream); 863 removed_phantom = true; 864 } 865 } 866 return removed_phantom; 867} 868 869void dc_state_release_phantom_streams_and_planes( 870 struct dc *dc, 871 struct dc_state *state) 872{ 873 int i; 874 875 for (i = 0; i < state->phantom_stream_count; i++) 876 dc_state_release_phantom_stream(dc, state, state->phantom_streams[i]); 877 878 for (i = 0; i < state->phantom_plane_count; i++) 879 dc_state_release_phantom_plane(dc, state, state->phantom_planes[i]); 880} 881