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