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 */
dc_state_track_phantom_stream(struct dc_state * state,struct dc_stream_state * phantom_stream)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
dc_state_untrack_phantom_stream(struct dc_state * state,struct dc_stream_state * phantom_stream)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
dc_state_is_phantom_stream_tracked(struct dc_state * state,struct dc_stream_state * phantom_stream)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
dc_state_track_phantom_plane(struct dc_state * state,struct dc_plane_state * phantom_plane)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
dc_state_untrack_phantom_plane(struct dc_state * state,struct dc_plane_state * phantom_plane)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
dc_state_is_phantom_plane_tracked(struct dc_state * state,struct dc_plane_state * phantom_plane)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
dc_state_copy_internal(struct dc_state * dst_state,struct dc_state * src_state)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
init_state(struct dc * dc,struct dc_state * state)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 */
dc_state_create(struct dc * dc)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
dc_state_copy(struct dc_state * dst_state,struct dc_state * src_state)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
dc_state_create_copy(struct dc_state * src_state)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
dc_state_copy_current(struct dc * dc,struct dc_state * dst_state)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
dc_state_create_current_copy(struct dc * dc)260 struct dc_state *dc_state_create_current_copy(struct dc *dc)
261 {
262 return dc_state_create_copy(dc->current_state);
263 }
264
dc_state_construct(struct dc * dc,struct dc_state * state)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
dc_state_destruct(struct dc_state * state)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
dc_state_retain(struct dc_state * state)316 void dc_state_retain(struct dc_state *state)
317 {
318 kref_get(&state->refcount);
319 }
320
dc_state_free(struct kref * kref)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
dc_state_release(struct dc_state * state)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 */
dc_state_add_stream(struct dc * dc,struct dc_state * state,struct dc_stream_state * stream)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 */
dc_state_remove_stream(struct dc * dc,struct dc_state * state,struct dc_stream_state * stream)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
dc_state_add_plane(const struct dc * dc,struct dc_stream_state * stream,struct dc_plane_state * plane_state,struct dc_state * state)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
dc_state_remove_plane(const struct dc * dc,struct dc_stream_state * stream,struct dc_plane_state * plane_state,struct dc_state * state)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 */
dc_state_rem_all_planes_for_stream(const struct dc * dc,struct dc_stream_state * stream,struct dc_state * state)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
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)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 */
dc_state_get_stream_status(struct dc_state * state,struct dc_stream_state * stream)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
dc_state_get_pipe_subvp_type(const struct dc_state * state,const struct pipe_ctx * pipe_ctx)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
dc_state_get_stream_subvp_type(const struct dc_state * state,const struct dc_stream_state * stream)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
dc_state_get_paired_subvp_stream(const struct dc_state * state,const struct dc_stream_state * stream)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
dc_state_create_phantom_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * main_stream)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
dc_state_release_phantom_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * phantom_stream)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
dc_state_create_phantom_plane(struct dc * dc,struct dc_state * state,struct dc_plane_state * main_plane)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
dc_state_release_phantom_plane(const struct dc * dc,struct dc_state * state,struct dc_plane_state * phantom_plane)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 */
dc_state_add_phantom_stream(struct dc * dc,struct dc_state * state,struct dc_stream_state * phantom_stream,struct dc_stream_state * main_stream)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
dc_state_remove_phantom_stream(struct dc * dc,struct dc_state * state,struct dc_stream_state * phantom_stream)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
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)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
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)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
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)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
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)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
dc_state_remove_phantom_streams_and_planes(struct dc * dc,struct dc_state * state)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
dc_state_release_phantom_streams_and_planes(struct dc * dc,struct dc_state * state)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