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