2 * Copyright 2023 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
25 #include "core_types.h"
26 #include "core_status.h"
28 #include "dc_state_priv.h"
29 #include "dc_stream_priv.h"
30 #include "dc_plane_priv.h"
32 #include "dm_services.h"
34 #include "link_enc_cfg.h"
36 #include "dml2/dml2_wrapper.h"
37 #include "dml2/dml2_internal_types.h"
41 #define DC_LOGGER_INIT(logger)
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)
47 if (state->phantom_stream_count >= MAX_PHANTOM_PIPES)
50 state->phantom_streams[state->phantom_stream_count++] = phantom_stream;
55 static bool dc_state_untrack_phantom_stream(struct dc_state *state, struct dc_stream_state *phantom_stream)
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;
69 /* failed to find stream in state */
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];
81 static bool dc_state_is_phantom_stream_tracked(struct dc_state *state, struct dc_stream_state *phantom_stream)
85 for (i = 0; i < state->phantom_stream_count; i++) {
86 if (state->phantom_streams[i] == phantom_stream)
93 static bool dc_state_track_phantom_plane(struct dc_state *state,
94 struct dc_plane_state *phantom_plane)
96 if (state->phantom_plane_count >= MAX_PHANTOM_PIPES)
99 state->phantom_planes[state->phantom_plane_count++] = phantom_plane;
104 static bool dc_state_untrack_phantom_plane(struct dc_state *state, struct dc_plane_state *phantom_plane)
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;
118 /* failed to find plane in state */
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];
130 static bool dc_state_is_phantom_plane_tracked(struct dc_state *state, struct dc_plane_state *phantom_plane)
134 for (i = 0; i < state->phantom_plane_count; i++) {
135 if (state->phantom_planes[i] == phantom_plane)
142 static void dc_state_copy_internal(struct dc_state *dst_state, struct dc_state *src_state)
146 memcpy(dst_state, src_state, sizeof(struct dc_state));
148 for (i = 0; i < MAX_PIPES; i++) {
149 struct pipe_ctx *cur_pipe = &dst_state->res_ctx.pipe_ctx[i];
151 if (cur_pipe->top_pipe)
152 cur_pipe->top_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx];
154 if (cur_pipe->bottom_pipe)
155 cur_pipe->bottom_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];
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];
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];
164 /* retain phantoms */
165 for (i = 0; i < dst_state->phantom_stream_count; i++)
166 dc_stream_retain(dst_state->phantom_streams[i]);
168 for (i = 0; i < dst_state->phantom_plane_count; i++)
169 dc_plane_state_retain(dst_state->phantom_planes[i]);
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]);
181 static void init_state(struct dc *dc, struct dc_state *state)
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
187 memcpy(&state->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib));
190 /* Public dc_state functions */
191 struct dc_state *dc_state_create(struct dc *dc)
193 struct dc_state *state = kvzalloc(sizeof(struct dc_state),
199 init_state(dc, state);
200 dc_state_construct(dc, state);
202 #ifdef CONFIG_DRM_AMD_DC_FP
203 if (dc->debug.using_dml2)
204 dml2_create(dc, &dc->dml2_options, &state->bw_ctx.dml2);
207 kref_init(&state->refcount);
212 void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state)
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;
219 dc_state_copy_internal(dst_state, src_state);
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);
227 /* context refcount should not be overridden */
228 dst_state->refcount = refcount;
231 struct dc_state *dc_state_create_copy(struct dc_state *src_state)
233 struct dc_state *new_state;
235 new_state = kvmalloc(sizeof(struct dc_state),
240 dc_state_copy_internal(new_state, src_state);
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);
250 kref_init(&new_state->refcount);
255 void dc_state_copy_current(struct dc *dc, struct dc_state *dst_state)
257 dc_state_copy(dst_state, dc->current_state);
260 struct dc_state *dc_state_create_current_copy(struct dc *dc)
262 return dc_state_create_copy(dc->current_state);
265 void dc_state_construct(struct dc *dc, struct dc_state *state)
267 state->clk_mgr = dc->clk_mgr;
269 /* Initialise DIG link encoder resource tracking variables. */
271 link_enc_cfg_init(dc, state);
274 void dc_state_destruct(struct dc_state *state)
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]);
283 state->stream_status[i].plane_count = 0;
284 dc_stream_release(state->streams[i]);
285 state->streams[i] = NULL;
287 state->stream_count = 0;
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;
294 state->phantom_stream_count = 0;
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;
300 state->phantom_plane_count = 0;
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));
316 void dc_state_retain(struct dc_state *state)
318 kref_get(&state->refcount);
321 static void dc_state_free(struct kref *kref)
323 struct dc_state *state = container_of(kref, struct dc_state, refcount);
325 dc_state_destruct(state);
327 #ifdef CONFIG_DRM_AMD_DC_FP
328 dml2_destroy(state->bw_ctx.dml2);
329 state->bw_ctx.dml2 = 0;
335 void dc_state_release(struct dc_state *state)
338 kref_put(&state->refcount, dc_state_free);
341 * dc_state_add_stream() - Add a new dc_stream_state to a dc_state.
343 enum dc_status dc_state_add_stream(
345 struct dc_state *state,
346 struct dc_stream_state *stream)
350 DC_LOGGER_INIT(dc->ctx->logger);
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;
357 state->streams[state->stream_count] = stream;
358 dc_stream_retain(stream);
359 state->stream_count++;
361 res = resource_add_otg_master_for_stream_output(
362 state, dc->res_pool, stream);
364 DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res);
370 * dc_state_remove_stream() - Remove a stream from a dc_state.
372 enum dc_status dc_state_remove_stream(
374 struct dc_state *state,
375 struct dc_stream_state *stream)
378 struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream(
379 &state->res_ctx, stream);
382 dm_error("Pipe not found for stream %p !\n", stream);
383 return DC_ERROR_UNEXPECTED;
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);
391 for (i = 0; i < state->stream_count; i++)
392 if (state->streams[i] == stream)
395 if (state->streams[i] != stream) {
396 dm_error("Context doesn't have stream %p !\n", stream);
397 return DC_ERROR_UNEXPECTED;
400 dc_stream_release(state->streams[i]);
401 state->stream_count--;
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];
409 state->streams[state->stream_count] = NULL;
411 &state->stream_status[state->stream_count],
413 sizeof(state->stream_status[0]));
418 bool dc_state_add_plane(
420 struct dc_stream_state *stream,
421 struct dc_plane_state *plane_state,
422 struct dc_state *state)
424 struct resource_pool *pool = dc->res_pool;
425 struct pipe_ctx *otg_master_pipe;
426 struct dc_stream_status *stream_status = NULL;
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");
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);
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.
445 resource_update_pipes_for_stream_with_slice_count(
446 state, dc->current_state, dc->res_pool, stream, 1);
448 otg_master_pipe = resource_get_otg_master_for_stream(
449 &state->res_ctx, stream);
451 added = resource_append_dpp_pipes_for_plane_composition(state,
452 dc->current_state, pool, otg_master_pipe, plane_state);
455 stream_status->plane_states[stream_status->plane_count] =
457 stream_status->plane_count++;
458 dc_plane_state_retain(plane_state);
465 bool dc_state_remove_plane(
467 struct dc_stream_state *stream,
468 struct dc_plane_state *plane_state,
469 struct dc_state *state)
472 struct dc_stream_status *stream_status = NULL;
473 struct resource_pool *pool = dc->res_pool;
478 for (i = 0; i < state->stream_count; i++)
479 if (state->streams[i] == stream) {
480 stream_status = &state->stream_status[i];
484 if (stream_status == NULL) {
485 dm_error("Existing stream not found; failed to remove plane.\n");
489 resource_remove_dpp_pipes_for_plane_composition(
490 state, pool, plane_state);
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]);
499 if (i == stream_status->plane_count) {
500 dm_error("Existing plane_state not found; failed to detach it!\n");
504 stream_status->plane_count--;
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];
510 stream_status->plane_states[stream_status->plane_count] = NULL;
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.
518 resource_update_pipes_for_stream_with_slice_count(
519 state, dc->current_state, dc->res_pool, stream, 1);
525 * dc_state_rem_all_planes_for_stream - Remove planes attached to the target stream.
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.
532 * Return true if DC was able to remove all planes from the target
533 * stream, otherwise, return false.
535 bool dc_state_rem_all_planes_for_stream(
537 struct dc_stream_state *stream,
538 struct dc_state *state)
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 };
544 for (i = 0; i < state->stream_count; i++)
545 if (state->streams[i] == stream) {
546 stream_status = &state->stream_status[i];
550 if (stream_status == NULL) {
551 dm_error("Existing stream %p not found!\n", stream);
555 old_plane_count = stream_status->plane_count;
557 for (i = 0; i < old_plane_count; i++)
558 del_planes[i] = stream_status->plane_states[i];
560 for (i = 0; i < old_plane_count; i++)
561 if (!dc_state_remove_plane(dc, stream, del_planes[i], state))
567 bool dc_state_add_all_planes_for_stream(
569 struct dc_stream_state *stream,
570 struct dc_plane_state * const *plane_states,
572 struct dc_state *state)
577 for (i = 0; i < plane_count; i++)
578 if (!dc_state_add_plane(dc, stream, plane_states[i], state)) {
586 /* Private dc_state functions */
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
593 * The given stream is expected to exist in the given dc state. Otherwise, NULL
596 struct dc_stream_status *dc_state_get_stream_status(
597 struct dc_state *state,
598 struct dc_stream_state *stream)
605 for (i = 0; i < state->stream_count; i++) {
606 if (stream == state->streams[i])
607 return &state->stream_status[i];
613 enum mall_stream_type dc_state_get_pipe_subvp_type(const struct dc_state *state,
614 const struct pipe_ctx *pipe_ctx)
616 return dc_state_get_stream_subvp_type(state, pipe_ctx->stream);
619 enum mall_stream_type dc_state_get_stream_subvp_type(const struct dc_state *state,
620 const struct dc_stream_state *stream)
624 enum mall_stream_type type = SUBVP_NONE;
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;
636 struct dc_stream_state *dc_state_get_paired_subvp_stream(const struct dc_state *state,
637 const struct dc_stream_state *stream)
641 struct dc_stream_state *paired_stream = NULL;
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;
650 return paired_stream;
653 struct dc_stream_state *dc_state_create_phantom_stream(const struct dc *dc,
654 struct dc_state *state,
655 struct dc_stream_state *main_stream)
657 struct dc_stream_state *phantom_stream;
659 DC_LOGGER_INIT(dc->ctx->logger);
661 phantom_stream = dc_create_stream_for_sink(main_stream->sink);
663 if (!phantom_stream) {
664 DC_LOG_ERROR("Failed to allocate phantom stream.\n");
668 /* track phantom stream in dc_state */
669 dc_state_track_phantom_stream(state, phantom_stream);
671 phantom_stream->is_phantom = true;
672 phantom_stream->signal = SIGNAL_TYPE_VIRTUAL;
673 phantom_stream->dpms_off = true;
675 return phantom_stream;
678 void dc_state_release_phantom_stream(const struct dc *dc,
679 struct dc_state *state,
680 struct dc_stream_state *phantom_stream)
682 DC_LOGGER_INIT(dc->ctx->logger);
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);
689 dc_stream_release(phantom_stream);
692 struct dc_plane_state *dc_state_create_phantom_plane(struct dc *dc,
693 struct dc_state *state,
694 struct dc_plane_state *main_plane)
696 struct dc_plane_state *phantom_plane = dc_create_plane_state(dc);
698 DC_LOGGER_INIT(dc->ctx->logger);
700 if (!phantom_plane) {
701 DC_LOG_ERROR("Failed to allocate phantom plane.\n");
705 /* track phantom inside dc_state */
706 dc_state_track_phantom_plane(state, phantom_plane);
708 phantom_plane->is_phantom = true;
710 return phantom_plane;
713 void dc_state_release_phantom_plane(const struct dc *dc,
714 struct dc_state *state,
715 struct dc_plane_state *phantom_plane)
717 DC_LOGGER_INIT(dc->ctx->logger);
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);
724 dc_plane_state_release(phantom_plane);
727 /* add phantom streams to context and generate correct meta inside dc_state */
728 enum 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)
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);
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);
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;
754 enum dc_status dc_state_remove_phantom_stream(struct dc *dc,
755 struct dc_state *state,
756 struct dc_stream_state *phantom_stream)
758 struct dc_stream_status *main_stream_status;
759 struct dc_stream_status *phantom_stream_status;
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;
771 /* remove stream from state */
772 return dc_state_remove_stream(dc, state, phantom_stream);
775 bool dc_state_add_phantom_plane(
777 struct dc_stream_state *phantom_stream,
778 struct dc_plane_state *phantom_plane,
779 struct dc_state *state)
781 bool res = dc_state_add_plane(dc, phantom_stream, phantom_plane, state);
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);
792 bool dc_state_remove_phantom_plane(
794 struct dc_stream_state *phantom_stream,
795 struct dc_plane_state *phantom_plane,
796 struct dc_state *state)
798 return dc_state_remove_plane(dc, phantom_stream, phantom_plane, state);
801 bool dc_state_rem_all_phantom_planes_for_stream(
803 struct dc_stream_state *phantom_stream,
804 struct dc_state *state,
805 bool should_release_planes)
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 };
811 for (i = 0; i < state->stream_count; i++)
812 if (state->streams[i] == phantom_stream) {
813 stream_status = &state->stream_status[i];
817 if (stream_status == NULL) {
818 dm_error("Existing stream %p not found!\n", phantom_stream);
822 old_plane_count = stream_status->plane_count;
824 for (i = 0; i < old_plane_count; i++)
825 del_planes[i] = stream_status->plane_states[i];
827 for (i = 0; i < old_plane_count; i++) {
828 if (!dc_state_remove_plane(dc, phantom_stream, del_planes[i], state))
830 if (should_release_planes)
831 dc_state_release_phantom_plane(dc, state, del_planes[i]);
837 bool dc_state_add_all_phantom_planes_for_stream(
839 struct dc_stream_state *phantom_stream,
840 struct dc_plane_state * const *phantom_planes,
842 struct dc_state *state)
844 return dc_state_add_all_planes_for_stream(dc, phantom_stream, phantom_planes, plane_count, state);
847 bool dc_state_remove_phantom_streams_and_planes(
849 struct dc_state *state)
852 bool removed_phantom = false;
853 struct dc_stream_state *phantom_stream = NULL;
855 for (i = 0; i < dc->res_pool->pipe_count; i++) {
856 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i];
858 if (pipe->plane_state && pipe->stream && dc_state_get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) {
859 phantom_stream = pipe->stream;
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;
866 return removed_phantom;
869 void dc_state_release_phantom_streams_and_planes(
871 struct dc_state *state)
875 for (i = 0; i < state->phantom_stream_count; i++)
876 dc_state_release_phantom_stream(dc, state, state->phantom_streams[i]);
878 for (i = 0; i < state->phantom_plane_count; i++)
879 dc_state_release_phantom_plane(dc, state, state->phantom_planes[i]);