FILE
dc_state.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpu/drm/amd/display/dc/core/dc_state.c
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 "dc_types.h" 26#include "core_types.h" 27#include "core_status.h" 28#include "dc_state.h" 29#include "dc_state_priv.h" 30#include "dc_stream_priv.h" 31#include "dc_plane_priv.h" 32 33#include "dm_services.h" 34#include "resource.h" 35#include "link_enc_cfg.h" 36 37#if defined(CONFIG_DRM_AMD_DC_FP) 38#include "dml2_0/dml2_wrapper.h" 39#include "dml2_0/dml2_internal_types.h" 40#endif 41 42#define DC_LOGGER \ 43 dc->ctx->logger 44#define DC_LOGGER_INIT(logger) 45 46/* Private dc_state helper functions */ 47static bool dc_state_track_phantom_stream(struct dc_state *state, 48 struct dc_stream_state *phantom_stream) 49{ 50 if (state->phantom_stream_count >= MAX_PHANTOM_PIPES) 51 return false; 52 53 state->phantom_streams[state->phantom_stream_count++] = phantom_stream; 54 55 return true; 56} 57 58static bool dc_state_untrack_phantom_stream(struct dc_state *state, struct dc_stream_state *phantom_stream) 59{ 60 bool res = false; 61 int i; 62 63 /* first find phantom stream in the dc_state */ 64 for (i = 0; i < state->phantom_stream_count; i++) { 65 if (state->phantom_streams[i] == phantom_stream) { 66 state->phantom_streams[i] = NULL; 67 res = true; 68 break; 69 } 70 } 71 72 /* failed to find stream in state */ 73 if (!res) 74 return res; 75 76 /* trim back phantom streams */ 77 state->phantom_stream_count--; 78 for (; i < state->phantom_stream_count; i++) 79 state->phantom_streams[i] = state->phantom_streams[i + 1]; 80 81 return res; 82} 83 84static bool dc_state_is_phantom_stream_tracked(struct dc_state *state, struct dc_stream_state *phantom_stream) 85{ 86 int i; 87 88 for (i = 0; i < state->phantom_stream_count; i++) { 89 if (state->phantom_streams[i] == phantom_stream) 90 return true; 91 } 92 93 return false; 94} 95 96static bool dc_state_track_phantom_plane(struct dc_state *state, 97 struct dc_plane_state *phantom_plane) 98{ 99 if (state->phantom_plane_count >= MAX_PHANTOM_PIPES) 100 return false; 101 102 state->phantom_planes[state->phantom_plane_count++] = phantom_plane; 103 104 return true; 105} 106 107static bool dc_state_untrack_phantom_plane(struct dc_state *state, struct dc_plane_state *phantom_plane) 108{ 109 bool res = false; 110 int i; 111 112 /* first find phantom plane in the dc_state */ 113 for (i = 0; i < state->phantom_plane_count; i++) { 114 if (state->phantom_planes[i] == phantom_plane) { 115 state->phantom_planes[i] = NULL; 116 res = true; 117 break; 118 } 119 } 120 121 /* failed to find plane in state */ 122 if (!res) 123 return res; 124 125 /* trim back phantom planes */ 126 state->phantom_plane_count--; 127 for (; i < state->phantom_plane_count; i++) 128 state->phantom_planes[i] = state->phantom_planes[i + 1]; 129 130 return res; 131} 132 133static bool dc_state_is_phantom_plane_tracked(struct dc_state *state, struct dc_plane_state *phantom_plane) 134{ 135 int i; 136 137 for (i = 0; i < state->phantom_plane_count; i++) { 138 if (state->phantom_planes[i] == phantom_plane) 139 return true; 140 } 141 142 return false; 143} 144 145static void dc_state_copy_internal(struct dc_state *dst_state, struct dc_state *src_state) 146{ 147 int i, j; 148 149 memcpy(dst_state, src_state, sizeof(struct dc_state)); 150 151 for (i = 0; i < MAX_PIPES; i++) { 152 struct pipe_ctx *cur_pipe = &dst_state->res_ctx.pipe_ctx[i]; 153 154 if (cur_pipe->top_pipe) 155 cur_pipe->top_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx]; 156 157 if (cur_pipe->bottom_pipe) 158 cur_pipe->bottom_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx]; 159 160 if (cur_pipe->prev_odm_pipe) 161 cur_pipe->prev_odm_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx]; 162 163 if (cur_pipe->next_odm_pipe) 164 cur_pipe->next_odm_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx]; 165 } 166 167 /* retain phantoms */ 168 for (i = 0; i < dst_state->phantom_stream_count; i++) 169 dc_stream_retain(dst_state->phantom_streams[i]); 170 171 for (i = 0; i < dst_state->phantom_plane_count; i++) 172 dc_plane_state_retain(dst_state->phantom_planes[i]); 173 174 /* retain streams and planes */ 175 for (i = 0; i < dst_state->stream_count; i++) { 176 dc_stream_retain(dst_state->streams[i]); 177 for (j = 0; j < dst_state->stream_status[i].plane_count; j++) 178 dc_plane_state_retain( 179 dst_state->stream_status[i].plane_states[j]); 180 } 181 182} 183 184static void init_state(struct dc *dc, struct dc_state *state) 185{ 186 /* Each context must have their own instance of VBA and in order to 187 * initialize and obtain IP and SOC the base DML instance from DC is 188 * initially copied into every context 189 */ 190 memcpy(&state->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib)); 191} 192 193/* Public dc_state functions */ 194struct dc_state *dc_state_create(struct dc *dc, struct dc_state_create_params *params) 195{ 196 struct dc_state *state; 197 198 state = kvzalloc(sizeof(struct dc_state), GFP_KERNEL); 199 200 if (!state) 201 return NULL; 202 203 init_state(dc, state); 204 dc_state_construct(dc, state); 205 state->power_source = params ? params->power_source : DC_POWER_SOURCE_AC; 206 207#ifdef CONFIG_DRM_AMD_DC_FP 208 if (dc->debug.using_dml2) { 209 if (!dml2_create(dc, &dc->dml2_options, &state->bw_ctx.dml2)) { 210 dc_state_release(state); 211 return NULL; 212 } 213 214 if (dc->caps.dcmode_power_limits_present && !dml2_create(dc, &dc->dml2_dc_power_options, &state->bw_ctx.dml2_dc_power_source)) { 215 dc_state_release(state); 216 return NULL; 217 } 218 } 219#endif 220 221 kref_init(&state->refcount); 222 223 return state; 224} 225 226void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state) 227{ 228 struct kref refcount = dst_state->refcount; 229#ifdef CONFIG_DRM_AMD_DC_FP 230 struct dml2_context *dst_dml2 = dst_state->bw_ctx.dml2; 231 struct dml2_context *dst_dml2_dc_power_source = dst_state->bw_ctx.dml2_dc_power_source; 232#endif 233 234 dc_state_copy_internal(dst_state, src_state); 235 236#ifdef CONFIG_DRM_AMD_DC_FP 237 dst_state->bw_ctx.dml2 = dst_dml2; 238 if (src_state->bw_ctx.dml2) 239 dml2_copy(dst_state->bw_ctx.dml2, src_state->bw_ctx.dml2); 240 241 dst_state->bw_ctx.dml2_dc_power_source = dst_dml2_dc_power_source; 242 if (src_state->bw_ctx.dml2_dc_power_source) 243 dml2_copy(dst_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source); 244#endif 245 246 /* context refcount should not be overridden */ 247 dst_state->refcount = refcount; 248} 249 250struct dc_state *dc_state_create_copy(struct dc_state *src_state) 251{ 252 struct dc_state *new_state; 253 254 new_state = kvmalloc(sizeof(struct dc_state), 255 GFP_KERNEL); 256 if (!new_state) 257 return NULL; 258 259 dc_state_copy_internal(new_state, src_state); 260 261#ifdef CONFIG_DRM_AMD_DC_FP 262 new_state->bw_ctx.dml2 = NULL; 263 new_state->bw_ctx.dml2_dc_power_source = NULL; 264 265 if (src_state->bw_ctx.dml2 && 266 !dml2_create_copy(&new_state->bw_ctx.dml2, src_state->bw_ctx.dml2)) { 267 dc_state_release(new_state); 268 return NULL; 269 } 270 271 if (src_state->bw_ctx.dml2_dc_power_source && 272 !dml2_create_copy(&new_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source)) { 273 dc_state_release(new_state); 274 return NULL; 275 } 276#endif 277 278 kref_init(&new_state->refcount); 279 280 return new_state; 281} 282 283void dc_state_copy_current(struct dc *dc, struct dc_state *dst_state) 284{ 285 dc_state_copy(dst_state, dc->current_state); 286} 287 288struct dc_state *dc_state_create_current_copy(struct dc *dc) 289{ 290 return dc_state_create_copy(dc->current_state); 291} 292 293void dc_state_construct(struct dc *dc, struct dc_state *state) 294{ 295 state->clk_mgr = dc->clk_mgr; 296 297 /* Initialise DIG link encoder resource tracking variables. */ 298 if (dc->res_pool) 299 link_enc_cfg_init(dc, state); 300} 301 302void dc_state_destruct(struct dc_state *state) 303{ 304 int i, j; 305 306 for (i = 0; i < state->stream_count; i++) { 307 for (j = 0; j < state->stream_status[i].plane_count; j++) 308 dc_plane_state_release( 309 state->stream_status[i].plane_states[j]); 310 311 state->stream_status[i].plane_count = 0; 312 dc_stream_release(state->streams[i]); 313 state->streams[i] = NULL; 314 } 315 state->stream_count = 0; 316 317 /* release tracked phantoms */ 318 for (i = 0; i < state->phantom_stream_count; i++) { 319 dc_stream_release(state->phantom_streams[i]); 320 state->phantom_streams[i] = NULL; 321 } 322 state->phantom_stream_count = 0; 323 324 for (i = 0; i < state->phantom_plane_count; i++) { 325 dc_plane_state_release(state->phantom_planes[i]); 326 state->phantom_planes[i] = NULL; 327 } 328 state->phantom_plane_count = 0; 329 330 state->stream_mask = 0; 331 memset(&state->res_ctx, 0, sizeof(state->res_ctx)); 332 memset(&state->pp_display_cfg, 0, sizeof(state->pp_display_cfg)); 333 memset(&state->dcn_bw_vars, 0, sizeof(state->dcn_bw_vars)); 334 state->clk_mgr = NULL; 335 memset(&state->bw_ctx.bw, 0, sizeof(state->bw_ctx.bw)); 336 memset(state->block_sequence, 0, sizeof(state->block_sequence)); 337 state->block_sequence_steps = 0; 338 memset(state->dc_dmub_cmd, 0, sizeof(state->dc_dmub_cmd)); 339 state->dmub_cmd_count = 0; 340 memset(&state->perf_params, 0, sizeof(state->perf_params)); 341} 342 343void dc_state_retain(struct dc_state *state) 344{ 345 kref_get(&state->refcount); 346} 347 348static void dc_state_free(struct kref *kref) 349{ 350 struct dc_state *state = container_of(kref, struct dc_state, refcount); 351 352 dc_state_destruct(state); 353 354#ifdef CONFIG_DRM_AMD_DC_FP 355 dml2_destroy(state->bw_ctx.dml2); 356 state->bw_ctx.dml2 = 0; 357 358 dml2_destroy(state->bw_ctx.dml2_dc_power_source); 359 state->bw_ctx.dml2_dc_power_source = 0; 360#endif 361 362 kvfree(state); 363} 364 365void dc_state_release(struct dc_state *state) 366{ 367 if (state != NULL) 368 kref_put(&state->refcount, dc_state_free); 369} 370/* 371 * dc_state_add_stream() - Add a new dc_stream_state to a dc_state. 372 */ 373enum dc_status dc_state_add_stream( 374 const struct dc *dc, 375 struct dc_state *state, 376 struct dc_stream_state *stream) 377{ 378 enum dc_status res; 379 380 DC_LOGGER_INIT(dc->ctx->logger); 381 382 if (state->stream_count >= dc->res_pool->timing_generator_count) { 383 DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream); 384 return DC_ERROR_UNEXPECTED; 385 } 386 387 state->streams[state->stream_count] = stream; 388 dc_stream_retain(stream); 389 state->stream_count++; 390 391 res = resource_add_otg_master_for_stream_output( 392 state, dc->res_pool, stream); 393 if (res != DC_OK) 394 DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res); 395 396 return res; 397} 398 399/* 400 * dc_state_remove_stream() - Remove a stream from a dc_state. 401 */ 402enum dc_status dc_state_remove_stream( 403 const struct dc *dc, 404 struct dc_state *state, 405 struct dc_stream_state *stream) 406{ 407 int i; 408 struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream( 409 &state->res_ctx, stream); 410 411 if (!del_pipe) { 412 dm_error("Pipe not found for stream %p !\n", stream); 413 return DC_ERROR_UNEXPECTED; 414 } 415 416 resource_update_pipes_for_stream_with_slice_count(state, 417 dc->current_state, dc->res_pool, stream, 1); 418 resource_remove_otg_master_for_stream_output( 419 state, dc->res_pool, stream); 420 421 for (i = 0; i < state->stream_count; i++) 422 if (state->streams[i] == stream) 423 break; 424 425 if (state->streams[i] != stream) { 426 dm_error("Context doesn't have stream %p !\n", stream); 427 return DC_ERROR_UNEXPECTED; 428 } 429 430 dc_stream_release_3dlut_for_stream(dc, stream); 431 432 dc_stream_release(state->streams[i]); 433 state->stream_count--; 434 435 /* Trim back arrays */ 436 for (; i < state->stream_count; i++) { 437 state->streams[i] = state->streams[i + 1]; 438 state->stream_status[i] = state->stream_status[i + 1]; 439 } 440 441 state->streams[state->stream_count] = NULL; 442 memset( 443 &state->stream_status[state->stream_count], 444 0, 445 sizeof(state->stream_status[0])); 446 447 return DC_OK; 448} 449 450static void remove_mpc_combine_for_stream(const struct dc *dc, 451 struct dc_state *new_ctx, 452 const struct dc_state *cur_ctx, 453 struct dc_stream_status *status) 454{ 455 int i; 456 457 for (i = 0; i < status->plane_count; i++) 458 resource_update_pipes_for_plane_with_slice_count( 459 new_ctx, cur_ctx, dc->res_pool, 460 status->plane_states[i], 1); 461} 462 463bool dc_state_add_plane( 464 const struct dc *dc, 465 struct dc_stream_state *stream, 466 struct dc_plane_state *plane_state, 467 struct dc_state *state) 468{ 469 struct resource_pool *pool = dc->res_pool; 470 struct pipe_ctx *otg_master_pipe; 471 struct dc_stream_status *stream_status = NULL; 472 bool added = false; 473 int odm_slice_count; 474 int i; 475 476 stream_status = dc_state_get_stream_status(state, stream); 477 otg_master_pipe = resource_get_otg_master_for_stream( 478 &state->res_ctx, stream); 479 if (stream_status == NULL) { 480 dm_error("Existing stream not found; failed to attach surface!\n"); 481 goto out; 482 } else if (stream_status->plane_count == MAX_SURFACES) { 483 dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n", 484 plane_state, MAX_SURFACES); 485 goto out; 486 } else if (!otg_master_pipe) { 487 goto out; 488 } 489 490 added = resource_append_dpp_pipes_for_plane_composition(state, 491 dc->current_state, pool, otg_master_pipe, plane_state); 492 493 if (!added) { 494 /* try to remove MPC combine to free up pipes */ 495 for (i = 0; i < state->stream_count; i++) 496 remove_mpc_combine_for_stream(dc, state, 497 dc->current_state, 498 &state->stream_status[i]); 499 added = resource_append_dpp_pipes_for_plane_composition(state, 500 dc->current_state, pool, 501 otg_master_pipe, plane_state); 502 } 503 504 if (!added) { 505 /* try to decrease ODM slice count gradually to free up pipes */ 506 odm_slice_count = resource_get_odm_slice_count(otg_master_pipe); 507 for (i = odm_slice_count - 1; i > 0; i--) { 508 resource_update_pipes_for_stream_with_slice_count(state, 509 dc->current_state, dc->res_pool, stream, 510 i); 511 added = resource_append_dpp_pipes_for_plane_composition( 512 state, 513 dc->current_state, pool, 514 otg_master_pipe, plane_state); 515 if (added) 516 break; 517 } 518 } 519 520 if (added) { 521 stream_status->plane_states[stream_status->plane_count] = 522 plane_state; 523 stream_status->plane_count++; 524 dc_plane_state_retain(plane_state); 525 } 526 527out: 528 return added; 529} 530 531bool dc_state_remove_plane( 532 const struct dc *dc, 533 struct dc_stream_state *stream, 534 struct dc_plane_state *plane_state, 535 struct dc_state *state) 536{ 537 int i; 538 struct dc_stream_status *stream_status = NULL; 539 struct resource_pool *pool = dc->res_pool; 540 541 if (!plane_state) 542 return true; 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 not found; failed to remove plane.\n"); 552 return false; 553 } 554 555 resource_remove_dpp_pipes_for_plane_composition( 556 state, pool, plane_state); 557 558 for (i = 0; i < stream_status->plane_count; i++) { 559 if (stream_status->plane_states[i] == plane_state) { 560 dc_plane_state_release(stream_status->plane_states[i]); 561 break; 562 } 563 } 564 565 if (i == stream_status->plane_count) { 566 dm_error("Existing plane_state not found; failed to detach it!\n"); 567 return false; 568 } 569 570 stream_status->plane_count--; 571 572 /* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */ 573 for (; i < stream_status->plane_count; i++) 574 stream_status->plane_states[i] = stream_status->plane_states[i + 1]; 575 576 stream_status->plane_states[stream_status->plane_count] = NULL; 577 578 return true; 579} 580 581/** 582 * dc_state_rem_all_planes_for_stream - Remove planes attached to the target stream. 583 * 584 * @dc: Current dc state. 585 * @stream: Target stream, which we want to remove the attached plans. 586 * @state: context from which the planes are to be removed. 587 * 588 * Return: 589 * Return true if DC was able to remove all planes from the target 590 * stream, otherwise, return false. 591 */ 592bool dc_state_rem_all_planes_for_stream( 593 const struct dc *dc, 594 struct dc_stream_state *stream, 595 struct dc_state *state) 596{ 597 int i, old_plane_count; 598 struct dc_stream_status *stream_status = NULL; 599 struct dc_plane_state *del_planes[MAX_SURFACES] = { 0 }; 600 601 for (i = 0; i < state->stream_count; i++) 602 if (state->streams[i] == stream) { 603 stream_status = &state->stream_status[i]; 604 break; 605 } 606 607 if (stream_status == NULL) { 608 dm_error("Existing stream %p not found!\n", stream); 609 return false; 610 } 611 612 old_plane_count = stream_status->plane_count; 613 614 for (i = 0; i < old_plane_count; i++) 615 del_planes[i] = stream_status->plane_states[i]; 616 617 for (i = 0; i < old_plane_count; i++) 618 if (!dc_state_remove_plane(dc, stream, del_planes[i], state)) 619 return false; 620 621 return true; 622} 623 624bool dc_state_add_all_planes_for_stream( 625 const struct dc *dc, 626 struct dc_stream_state *stream, 627 struct dc_plane_state * const *plane_states, 628 int plane_count, 629 struct dc_state *state) 630{ 631 int i; 632 bool result = true; 633 634 for (i = 0; i < plane_count; i++) 635 if (!dc_state_add_plane(dc, stream, plane_states[i], state)) { 636 result = false; 637 break; 638 } 639 640 return result; 641} 642 643/* Private dc_state functions */ 644 645/** 646 * dc_state_get_stream_status - Get stream status from given dc state 647 * @state: DC state to find the stream status in 648 * @stream: The stream to get the stream status for 649 * 650 * The given stream is expected to exist in the given dc state. Otherwise, NULL 651 * will be returned. 652 */ 653struct dc_stream_status *dc_state_get_stream_status( 654 struct dc_state *state, 655 const struct dc_stream_state *stream) 656{ 657 uint8_t i; 658 659 if (state == NULL) 660 return NULL; 661 662 for (i = 0; i < state->stream_count; i++) { 663 if (stream == state->streams[i]) 664 return &state->stream_status[i]; 665 } 666 667 return NULL; 668} 669 670enum mall_stream_type dc_state_get_pipe_subvp_type(const struct dc_state *state, 671 const struct pipe_ctx *pipe_ctx) 672{ 673 return dc_state_get_stream_subvp_type(state, pipe_ctx->stream); 674} 675 676enum mall_stream_type dc_state_get_stream_subvp_type(const struct dc_state *state, 677 const struct dc_stream_state *stream) 678{ 679 int i; 680 681 enum mall_stream_type type = SUBVP_NONE; 682 683 for (i = 0; i < state->stream_count; i++) { 684 if (state->streams[i] == stream) { 685 type = state->stream_status[i].mall_stream_config.type; 686 break; 687 } 688 } 689 690 return type; 691} 692 693struct dc_stream_state *dc_state_get_paired_subvp_stream(const struct dc_state *state, 694 const struct dc_stream_state *stream) 695{ 696 int i; 697 698 struct dc_stream_state *paired_stream = NULL; 699 700 for (i = 0; i < state->stream_count; i++) { 701 if (state->streams[i] == stream) { 702 paired_stream = state->stream_status[i].mall_stream_config.paired_stream; 703 break; 704 } 705 } 706 707 return paired_stream; 708} 709 710struct dc_stream_state *dc_state_create_phantom_stream(const struct dc *dc, 711 struct dc_state *state, 712 struct dc_stream_state *main_stream) 713{ 714 struct dc_stream_state *phantom_stream; 715 716 DC_LOGGER_INIT(dc->ctx->logger); 717 718 phantom_stream = dc_create_stream_for_sink(main_stream->sink); 719 720 if (!phantom_stream) { 721 DC_LOG_ERROR("Failed to allocate phantom stream.\n"); 722 return NULL; 723 } 724 725 /* track phantom stream in dc_state */ 726 dc_state_track_phantom_stream(state, phantom_stream); 727 728 phantom_stream->is_phantom = true; 729 phantom_stream->signal = SIGNAL_TYPE_VIRTUAL; 730 phantom_stream->dpms_off = true; 731 732 return phantom_stream; 733} 734 735void dc_state_release_phantom_stream(const struct dc *dc, 736 struct dc_state *state, 737 struct dc_stream_state *phantom_stream) 738{ 739 DC_LOGGER_INIT(dc->ctx->logger); 740 741 if (!dc_state_untrack_phantom_stream(state, phantom_stream)) { 742 DC_LOG_ERROR("Failed to free phantom stream %p in dc state %p.\n", phantom_stream, state); 743 return; 744 } 745 746 dc_stream_release(phantom_stream); 747} 748 749struct dc_plane_state *dc_state_create_phantom_plane(const struct dc *dc, 750 struct dc_state *state, 751 struct dc_plane_state *main_plane) 752{ 753 struct dc_plane_state *phantom_plane = dc_create_plane_state(dc); 754 755 DC_LOGGER_INIT(dc->ctx->logger); 756 757 if (!phantom_plane) { 758 DC_LOG_ERROR("Failed to allocate phantom plane.\n"); 759 return NULL; 760 } 761 762 /* track phantom inside dc_state */ 763 dc_state_track_phantom_plane(state, phantom_plane); 764 765 phantom_plane->is_phantom = true; 766 767 return phantom_plane; 768} 769 770void dc_state_release_phantom_plane(const struct dc *dc, 771 struct dc_state *state, 772 struct dc_plane_state *phantom_plane) 773{ 774 DC_LOGGER_INIT(dc->ctx->logger); 775 776 if (!dc_state_untrack_phantom_plane(state, phantom_plane)) { 777 DC_LOG_ERROR("Failed to free phantom plane %p in dc state %p.\n", phantom_plane, state); 778 return; 779 } 780 781 dc_plane_state_release(phantom_plane); 782} 783 784/* add phantom streams to context and generate correct meta inside dc_state */ 785enum dc_status dc_state_add_phantom_stream(const struct dc *dc, 786 struct dc_state *state, 787 struct dc_stream_state *phantom_stream, 788 struct dc_stream_state *main_stream) 789{ 790 struct dc_stream_status *main_stream_status; 791 struct dc_stream_status *phantom_stream_status; 792 enum dc_status res = dc_state_add_stream(dc, state, phantom_stream); 793 794 /* check if stream is tracked */ 795 if (res == DC_OK && !dc_state_is_phantom_stream_tracked(state, phantom_stream)) { 796 /* stream must be tracked if added to state */ 797 dc_state_track_phantom_stream(state, phantom_stream); 798 } 799 800 /* setup subvp meta */ 801 main_stream_status = dc_state_get_stream_status(state, main_stream); 802 if (main_stream_status) { 803 main_stream_status->mall_stream_config.type = SUBVP_MAIN; 804 main_stream_status->mall_stream_config.paired_stream = phantom_stream; 805 } 806 807 phantom_stream_status = dc_state_get_stream_status(state, phantom_stream); 808 if (phantom_stream_status) { 809 phantom_stream_status->mall_stream_config.type = SUBVP_PHANTOM; 810 phantom_stream_status->mall_stream_config.paired_stream = main_stream; 811 phantom_stream_status->mall_stream_config.subvp_limit_cursor_size = false; 812 phantom_stream_status->mall_stream_config.cursor_size_limit_subvp = false; 813 } 814 815 dc_state_set_stream_subvp_cursor_limit(main_stream, state, true); 816 817 return res; 818} 819 820enum dc_status dc_state_remove_phantom_stream(const struct dc *dc, 821 struct dc_state *state, 822 struct dc_stream_state *phantom_stream) 823{ 824 struct dc_stream_status *main_stream_status = NULL; 825 struct dc_stream_status *phantom_stream_status; 826 827 /* reset subvp meta */ 828 phantom_stream_status = dc_state_get_stream_status(state, phantom_stream); 829 if (phantom_stream_status) { 830 main_stream_status = dc_state_get_stream_status(state, phantom_stream_status->mall_stream_config.paired_stream); 831 phantom_stream_status->mall_stream_config.type = SUBVP_NONE; 832 phantom_stream_status->mall_stream_config.paired_stream = NULL; 833 } 834 835 if (main_stream_status) { 836 main_stream_status->mall_stream_config.type = SUBVP_NONE; 837 main_stream_status->mall_stream_config.paired_stream = NULL; 838 } 839 840 /* remove stream from state */ 841 return dc_state_remove_stream(dc, state, phantom_stream); 842} 843 844bool dc_state_add_phantom_plane( 845 const struct dc *dc, 846 struct dc_stream_state *phantom_stream, 847 struct dc_plane_state *phantom_plane, 848 struct dc_state *state) 849{ 850 bool res = dc_state_add_plane(dc, phantom_stream, phantom_plane, state); 851 852 /* check if stream is tracked */ 853 if (res && !dc_state_is_phantom_plane_tracked(state, phantom_plane)) { 854 /* stream must be tracked if added to state */ 855 dc_state_track_phantom_plane(state, phantom_plane); 856 } 857 858 return res; 859} 860 861bool dc_state_remove_phantom_plane( 862 const struct dc *dc, 863 struct dc_stream_state *phantom_stream, 864 struct dc_plane_state *phantom_plane, 865 struct dc_state *state) 866{ 867 return dc_state_remove_plane(dc, phantom_stream, phantom_plane, state); 868} 869 870bool dc_state_rem_all_phantom_planes_for_stream( 871 const struct dc *dc, 872 struct dc_stream_state *phantom_stream, 873 struct dc_state *state, 874 bool should_release_planes) 875{ 876 int i, old_plane_count; 877 struct dc_stream_status *stream_status = NULL; 878 struct dc_plane_state *del_planes[MAX_SURFACES] = { 0 }; 879 880 for (i = 0; i < state->stream_count; i++) 881 if (state->streams[i] == phantom_stream) { 882 stream_status = &state->stream_status[i]; 883 break; 884 } 885 886 if (stream_status == NULL) { 887 dm_error("Existing stream %p not found!\n", phantom_stream); 888 return false; 889 } 890 891 old_plane_count = stream_status->plane_count; 892 893 for (i = 0; i < old_plane_count; i++) 894 del_planes[i] = stream_status->plane_states[i]; 895 896 for (i = 0; i < old_plane_count; i++) { 897 if (!dc_state_remove_plane(dc, phantom_stream, del_planes[i], state)) 898 return false; 899 if (should_release_planes) 900 dc_state_release_phantom_plane(dc, state, del_planes[i]); 901 } 902 903 return true; 904} 905 906bool dc_state_add_all_phantom_planes_for_stream( 907 const struct dc *dc, 908 struct dc_stream_state *phantom_stream, 909 struct dc_plane_state * const *phantom_planes, 910 int plane_count, 911 struct dc_state *state) 912{ 913 return dc_state_add_all_planes_for_stream(dc, phantom_stream, phantom_planes, plane_count, state); 914} 915 916bool dc_state_remove_phantom_streams_and_planes( 917 const struct dc *dc, 918 struct dc_state *state) 919{ 920 int i; 921 bool removed_phantom = false; 922 struct dc_stream_state *phantom_stream = NULL; 923 924 for (i = 0; i < dc->res_pool->pipe_count; i++) { 925 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; 926 927 if (pipe->plane_state && pipe->stream && dc_state_get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) { 928 phantom_stream = pipe->stream; 929 930 dc_state_rem_all_phantom_planes_for_stream(dc, phantom_stream, state, false); 931 dc_state_remove_phantom_stream(dc, state, phantom_stream); 932 removed_phantom = true; 933 } 934 } 935 return removed_phantom; 936} 937 938void dc_state_release_phantom_streams_and_planes( 939 const struct dc *dc, 940 struct dc_state *state) 941{ 942 unsigned int phantom_count; 943 struct dc_stream_state *phantom_streams[MAX_PHANTOM_PIPES]; 944 struct dc_plane_state *phantom_planes[MAX_PHANTOM_PIPES]; 945 int i; 946 947 phantom_count = state->phantom_stream_count; 948 memcpy(phantom_streams, state->phantom_streams, sizeof(struct dc_stream_state *) * MAX_PHANTOM_PIPES); 949 for (i = 0; i < phantom_count; i++) 950 dc_state_release_phantom_stream(dc, state, phantom_streams[i]); 951 952 phantom_count = state->phantom_plane_count; 953 memcpy(phantom_planes, state->phantom_planes, sizeof(struct dc_plane_state *) * MAX_PHANTOM_PIPES); 954 for (i = 0; i < phantom_count; i++) 955 dc_state_release_phantom_plane(dc, state, phantom_planes[i]); 956} 957 958struct dc_stream_state *dc_state_get_stream_from_id(const struct dc_state *state, unsigned int id) 959{ 960 struct dc_stream_state *stream = NULL; 961 int i; 962 963 for (i = 0; i < state->stream_count; i++) { 964 if (state->streams[i] && state->streams[i]->stream_id == id) { 965 stream = state->streams[i]; 966 break; 967 } 968 } 969 970 return stream; 971} 972 973bool dc_state_is_fams2_in_use( 974 const struct dc *dc, 975 const struct dc_state *state) 976{ 977 bool is_fams2_in_use = false; 978 979 if (state) 980 is_fams2_in_use |= state->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable; 981 982 if (dc->current_state) 983 is_fams2_in_use |= dc->current_state->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable; 984 985 return is_fams2_in_use; 986} 987 988void dc_state_set_stream_subvp_cursor_limit(const struct dc_stream_state *stream, 989 struct dc_state *state, 990 bool limit) 991{ 992 struct dc_stream_status *stream_status; 993 994 stream_status = dc_state_get_stream_status(state, stream); 995 996 if (stream_status) { 997 stream_status->mall_stream_config.subvp_limit_cursor_size = limit; 998 } 999} 1000 1001bool dc_state_get_stream_subvp_cursor_limit(const struct dc_stream_state *stream, 1002 struct dc_state *state) 1003{ 1004 bool limit = false; 1005 1006 struct dc_stream_status *stream_status; 1007 1008 stream_status = dc_state_get_stream_status(state, stream); 1009 1010 if (stream_status) { 1011 limit = stream_status->mall_stream_config.subvp_limit_cursor_size; 1012 } 1013 1014 return limit; 1015} 1016 1017void dc_state_set_stream_cursor_subvp_limit(const struct dc_stream_state *stream, 1018 struct dc_state *state, 1019 bool limit) 1020{ 1021 struct dc_stream_status *stream_status; 1022 1023 stream_status = dc_state_get_stream_status(state, stream); 1024 1025 if (stream_status) { 1026 stream_status->mall_stream_config.cursor_size_limit_subvp = limit; 1027 } 1028} 1029 1030bool dc_state_get_stream_cursor_subvp_limit(const struct dc_stream_state *stream, 1031 struct dc_state *state) 1032{ 1033 bool limit = false; 1034 1035 struct dc_stream_status *stream_status; 1036 1037 stream_status = dc_state_get_stream_status(state, stream); 1038 1039 if (stream_status) { 1040 limit = stream_status->mall_stream_config.cursor_size_limit_subvp; 1041 } 1042 1043 return limit; 1044} 1045 1046bool dc_state_can_clear_stream_cursor_subvp_limit(const struct dc_stream_state *stream, 1047 struct dc_state *state) 1048{ 1049 bool can_clear_limit = false; 1050 1051 struct dc_stream_status *stream_status; 1052 1053 stream_status = dc_state_get_stream_status(state, stream); 1054 1055 if (stream_status) { 1056 can_clear_limit = dc_state_get_stream_cursor_subvp_limit(stream, state) && 1057 (stream_status->mall_stream_config.type == SUBVP_PHANTOM || 1058 stream->hw_cursor_req || 1059 !stream_status->mall_stream_config.subvp_limit_cursor_size || 1060 !stream->cursor_position.enable || 1061 dc_stream_check_cursor_attributes(stream, state, &stream->cursor_attributes)); 1062 } 1063 1064 return can_clear_limit; 1065} 1066 1067bool dc_state_is_subvp_in_use(struct dc_state *state) 1068{ 1069 uint32_t i; 1070 1071 for (i = 0; i < state->stream_count; i++) { 1072 if (dc_state_get_stream_subvp_type(state, state->streams[i]) != SUBVP_NONE) 1073 return true; 1074 } 1075 1076 return false; 1077}
~/
Read-only file preview.