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