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,struct dc_state_create_params * params)191 struct dc_state *dc_state_create(struct dc *dc, struct dc_state_create_params *params)
192 {
193 #ifdef CONFIG_DRM_AMD_DC_FP
194 struct dml2_configuration_options *dml2_opt = &dc->dml2_options;
195 #endif
196 struct dc_state *state = kvzalloc(sizeof(struct dc_state),
197 GFP_KERNEL);
198
199 if (!state)
200 return NULL;
201
202 init_state(dc, state);
203 dc_state_construct(dc, state);
204 state->power_source = params ? params->power_source : DC_POWER_SOURCE_AC;
205
206 #ifdef CONFIG_DRM_AMD_DC_FP
207 if (dc->debug.using_dml2) {
208 dml2_opt->use_clock_dc_limits = false;
209 dml2_create(dc, dml2_opt, &state->bw_ctx.dml2);
210
211 dml2_opt->use_clock_dc_limits = true;
212 dml2_create(dc, dml2_opt, &state->bw_ctx.dml2_dc_power_source);
213 }
214 #endif
215
216 kref_init(&state->refcount);
217
218 return state;
219 }
220
dc_state_copy(struct dc_state * dst_state,struct dc_state * src_state)221 void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state)
222 {
223 struct kref refcount = dst_state->refcount;
224 #ifdef CONFIG_DRM_AMD_DC_FP
225 struct dml2_context *dst_dml2 = dst_state->bw_ctx.dml2;
226 struct dml2_context *dst_dml2_dc_power_source = dst_state->bw_ctx.dml2_dc_power_source;
227 #endif
228
229 dc_state_copy_internal(dst_state, src_state);
230
231 #ifdef CONFIG_DRM_AMD_DC_FP
232 dst_state->bw_ctx.dml2 = dst_dml2;
233 if (src_state->bw_ctx.dml2)
234 dml2_copy(dst_state->bw_ctx.dml2, src_state->bw_ctx.dml2);
235
236 dst_state->bw_ctx.dml2_dc_power_source = dst_dml2_dc_power_source;
237 if (src_state->bw_ctx.dml2_dc_power_source)
238 dml2_copy(dst_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source);
239 #endif
240
241 /* context refcount should not be overridden */
242 dst_state->refcount = refcount;
243 }
244
dc_state_create_copy(struct dc_state * src_state)245 struct dc_state *dc_state_create_copy(struct dc_state *src_state)
246 {
247 struct dc_state *new_state;
248
249 new_state = kvmalloc(sizeof(struct dc_state),
250 GFP_KERNEL);
251 if (!new_state)
252 return NULL;
253
254 dc_state_copy_internal(new_state, src_state);
255
256 #ifdef CONFIG_DRM_AMD_DC_FP
257 if (src_state->bw_ctx.dml2 &&
258 !dml2_create_copy(&new_state->bw_ctx.dml2, src_state->bw_ctx.dml2)) {
259 dc_state_release(new_state);
260 return NULL;
261 }
262
263 if (src_state->bw_ctx.dml2_dc_power_source &&
264 !dml2_create_copy(&new_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source)) {
265 dc_state_release(new_state);
266 return NULL;
267 }
268 #endif
269
270 kref_init(&new_state->refcount);
271
272 return new_state;
273 }
274
dc_state_copy_current(struct dc * dc,struct dc_state * dst_state)275 void dc_state_copy_current(struct dc *dc, struct dc_state *dst_state)
276 {
277 dc_state_copy(dst_state, dc->current_state);
278 }
279
dc_state_create_current_copy(struct dc * dc)280 struct dc_state *dc_state_create_current_copy(struct dc *dc)
281 {
282 return dc_state_create_copy(dc->current_state);
283 }
284
dc_state_construct(struct dc * dc,struct dc_state * state)285 void dc_state_construct(struct dc *dc, struct dc_state *state)
286 {
287 state->clk_mgr = dc->clk_mgr;
288
289 /* Initialise DIG link encoder resource tracking variables. */
290 if (dc->res_pool)
291 link_enc_cfg_init(dc, state);
292 }
293
dc_state_destruct(struct dc_state * state)294 void dc_state_destruct(struct dc_state *state)
295 {
296 int i, j;
297
298 for (i = 0; i < state->stream_count; i++) {
299 for (j = 0; j < state->stream_status[i].plane_count; j++)
300 dc_plane_state_release(
301 state->stream_status[i].plane_states[j]);
302
303 state->stream_status[i].plane_count = 0;
304 dc_stream_release(state->streams[i]);
305 state->streams[i] = NULL;
306 }
307 state->stream_count = 0;
308
309 /* release tracked phantoms */
310 for (i = 0; i < state->phantom_stream_count; i++) {
311 dc_stream_release(state->phantom_streams[i]);
312 state->phantom_streams[i] = NULL;
313 }
314 state->phantom_stream_count = 0;
315
316 for (i = 0; i < state->phantom_plane_count; i++) {
317 dc_plane_state_release(state->phantom_planes[i]);
318 state->phantom_planes[i] = NULL;
319 }
320 state->phantom_plane_count = 0;
321
322 state->stream_mask = 0;
323 memset(&state->res_ctx, 0, sizeof(state->res_ctx));
324 memset(&state->pp_display_cfg, 0, sizeof(state->pp_display_cfg));
325 memset(&state->dcn_bw_vars, 0, sizeof(state->dcn_bw_vars));
326 state->clk_mgr = NULL;
327 memset(&state->bw_ctx.bw, 0, sizeof(state->bw_ctx.bw));
328 memset(state->block_sequence, 0, sizeof(state->block_sequence));
329 state->block_sequence_steps = 0;
330 memset(state->dc_dmub_cmd, 0, sizeof(state->dc_dmub_cmd));
331 state->dmub_cmd_count = 0;
332 memset(&state->perf_params, 0, sizeof(state->perf_params));
333 }
334
dc_state_retain(struct dc_state * state)335 void dc_state_retain(struct dc_state *state)
336 {
337 kref_get(&state->refcount);
338 }
339
dc_state_free(struct kref * kref)340 static void dc_state_free(struct kref *kref)
341 {
342 struct dc_state *state = container_of(kref, struct dc_state, refcount);
343
344 dc_state_destruct(state);
345
346 #ifdef CONFIG_DRM_AMD_DC_FP
347 dml2_destroy(state->bw_ctx.dml2);
348 state->bw_ctx.dml2 = 0;
349
350 dml2_destroy(state->bw_ctx.dml2_dc_power_source);
351 state->bw_ctx.dml2_dc_power_source = 0;
352 #endif
353
354 kvfree(state);
355 }
356
dc_state_release(struct dc_state * state)357 void dc_state_release(struct dc_state *state)
358 {
359 if (state != NULL)
360 kref_put(&state->refcount, dc_state_free);
361 }
362 /*
363 * dc_state_add_stream() - Add a new dc_stream_state to a dc_state.
364 */
dc_state_add_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * stream)365 enum dc_status dc_state_add_stream(
366 const struct dc *dc,
367 struct dc_state *state,
368 struct dc_stream_state *stream)
369 {
370 enum dc_status res;
371
372 DC_LOGGER_INIT(dc->ctx->logger);
373
374 if (state->stream_count >= dc->res_pool->timing_generator_count) {
375 DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream);
376 return DC_ERROR_UNEXPECTED;
377 }
378
379 state->streams[state->stream_count] = stream;
380 dc_stream_retain(stream);
381 state->stream_count++;
382
383 res = resource_add_otg_master_for_stream_output(
384 state, dc->res_pool, stream);
385 if (res != DC_OK)
386 DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res);
387
388 return res;
389 }
390
391 /*
392 * dc_state_remove_stream() - Remove a stream from a dc_state.
393 */
dc_state_remove_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * stream)394 enum dc_status dc_state_remove_stream(
395 const struct dc *dc,
396 struct dc_state *state,
397 struct dc_stream_state *stream)
398 {
399 int i;
400 struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream(
401 &state->res_ctx, stream);
402
403 if (!del_pipe) {
404 dm_error("Pipe not found for stream %p !\n", stream);
405 return DC_ERROR_UNEXPECTED;
406 }
407
408 resource_update_pipes_for_stream_with_slice_count(state,
409 dc->current_state, dc->res_pool, stream, 1);
410 resource_remove_otg_master_for_stream_output(
411 state, dc->res_pool, stream);
412
413 for (i = 0; i < state->stream_count; i++)
414 if (state->streams[i] == stream)
415 break;
416
417 if (state->streams[i] != stream) {
418 dm_error("Context doesn't have stream %p !\n", stream);
419 return DC_ERROR_UNEXPECTED;
420 }
421
422 dc_stream_release(state->streams[i]);
423 state->stream_count--;
424
425 /* Trim back arrays */
426 for (; i < state->stream_count; i++) {
427 state->streams[i] = state->streams[i + 1];
428 state->stream_status[i] = state->stream_status[i + 1];
429 }
430
431 state->streams[state->stream_count] = NULL;
432 memset(
433 &state->stream_status[state->stream_count],
434 0,
435 sizeof(state->stream_status[0]));
436
437 return DC_OK;
438 }
439
dc_state_add_plane(const struct dc * dc,struct dc_stream_state * stream,struct dc_plane_state * plane_state,struct dc_state * state)440 bool dc_state_add_plane(
441 const struct dc *dc,
442 struct dc_stream_state *stream,
443 struct dc_plane_state *plane_state,
444 struct dc_state *state)
445 {
446 struct resource_pool *pool = dc->res_pool;
447 struct pipe_ctx *otg_master_pipe;
448 struct dc_stream_status *stream_status = NULL;
449 bool added = false;
450
451 stream_status = dc_state_get_stream_status(state, stream);
452 if (stream_status == NULL) {
453 dm_error("Existing stream not found; failed to attach surface!\n");
454 goto out;
455 } else if (stream_status->plane_count == MAX_SURFACE_NUM) {
456 dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n",
457 plane_state, MAX_SURFACE_NUM);
458 goto out;
459 }
460
461 if (stream_status->plane_count == 0 && dc->config.enable_windowed_mpo_odm)
462 /* ODM combine could prevent us from supporting more planes
463 * we will reset ODM slice count back to 1 when all planes have
464 * been removed to maximize the amount of planes supported when
465 * new planes are added.
466 */
467 resource_update_pipes_for_stream_with_slice_count(
468 state, dc->current_state, dc->res_pool, stream, 1);
469
470 otg_master_pipe = resource_get_otg_master_for_stream(
471 &state->res_ctx, stream);
472 if (otg_master_pipe)
473 added = resource_append_dpp_pipes_for_plane_composition(state,
474 dc->current_state, pool, otg_master_pipe, plane_state);
475
476 if (added) {
477 stream_status->plane_states[stream_status->plane_count] =
478 plane_state;
479 stream_status->plane_count++;
480 dc_plane_state_retain(plane_state);
481 }
482
483 out:
484 return added;
485 }
486
dc_state_remove_plane(const struct dc * dc,struct dc_stream_state * stream,struct dc_plane_state * plane_state,struct dc_state * state)487 bool dc_state_remove_plane(
488 const struct dc *dc,
489 struct dc_stream_state *stream,
490 struct dc_plane_state *plane_state,
491 struct dc_state *state)
492 {
493 int i;
494 struct dc_stream_status *stream_status = NULL;
495 struct resource_pool *pool = dc->res_pool;
496
497 if (!plane_state)
498 return true;
499
500 for (i = 0; i < state->stream_count; i++)
501 if (state->streams[i] == stream) {
502 stream_status = &state->stream_status[i];
503 break;
504 }
505
506 if (stream_status == NULL) {
507 dm_error("Existing stream not found; failed to remove plane.\n");
508 return false;
509 }
510
511 resource_remove_dpp_pipes_for_plane_composition(
512 state, pool, plane_state);
513
514 for (i = 0; i < stream_status->plane_count; i++) {
515 if (stream_status->plane_states[i] == plane_state) {
516 dc_plane_state_release(stream_status->plane_states[i]);
517 break;
518 }
519 }
520
521 if (i == stream_status->plane_count) {
522 dm_error("Existing plane_state not found; failed to detach it!\n");
523 return false;
524 }
525
526 stream_status->plane_count--;
527
528 /* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */
529 for (; i < stream_status->plane_count; i++)
530 stream_status->plane_states[i] = stream_status->plane_states[i + 1];
531
532 stream_status->plane_states[stream_status->plane_count] = NULL;
533
534 if (stream_status->plane_count == 0 && dc->config.enable_windowed_mpo_odm)
535 /* ODM combine could prevent us from supporting more planes
536 * we will reset ODM slice count back to 1 when all planes have
537 * been removed to maximize the amount of planes supported when
538 * new planes are added.
539 */
540 resource_update_pipes_for_stream_with_slice_count(
541 state, dc->current_state, dc->res_pool, stream, 1);
542
543 return true;
544 }
545
546 /**
547 * dc_state_rem_all_planes_for_stream - Remove planes attached to the target stream.
548 *
549 * @dc: Current dc state.
550 * @stream: Target stream, which we want to remove the attached plans.
551 * @state: context from which the planes are to be removed.
552 *
553 * Return:
554 * Return true if DC was able to remove all planes from the target
555 * stream, otherwise, return false.
556 */
dc_state_rem_all_planes_for_stream(const struct dc * dc,struct dc_stream_state * stream,struct dc_state * state)557 bool dc_state_rem_all_planes_for_stream(
558 const struct dc *dc,
559 struct dc_stream_state *stream,
560 struct dc_state *state)
561 {
562 int i, old_plane_count;
563 struct dc_stream_status *stream_status = NULL;
564 struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 };
565
566 for (i = 0; i < state->stream_count; i++)
567 if (state->streams[i] == stream) {
568 stream_status = &state->stream_status[i];
569 break;
570 }
571
572 if (stream_status == NULL) {
573 dm_error("Existing stream %p not found!\n", stream);
574 return false;
575 }
576
577 old_plane_count = stream_status->plane_count;
578
579 for (i = 0; i < old_plane_count; i++)
580 del_planes[i] = stream_status->plane_states[i];
581
582 for (i = 0; i < old_plane_count; i++)
583 if (!dc_state_remove_plane(dc, stream, del_planes[i], state))
584 return false;
585
586 return true;
587 }
588
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)589 bool dc_state_add_all_planes_for_stream(
590 const struct dc *dc,
591 struct dc_stream_state *stream,
592 struct dc_plane_state * const *plane_states,
593 int plane_count,
594 struct dc_state *state)
595 {
596 int i;
597 bool result = true;
598
599 for (i = 0; i < plane_count; i++)
600 if (!dc_state_add_plane(dc, stream, plane_states[i], state)) {
601 result = false;
602 break;
603 }
604
605 return result;
606 }
607
608 /* Private dc_state functions */
609
610 /**
611 * dc_state_get_stream_status - Get stream status from given dc state
612 * @state: DC state to find the stream status in
613 * @stream: The stream to get the stream status for
614 *
615 * The given stream is expected to exist in the given dc state. Otherwise, NULL
616 * will be returned.
617 */
dc_state_get_stream_status(struct dc_state * state,const struct dc_stream_state * stream)618 struct dc_stream_status *dc_state_get_stream_status(
619 struct dc_state *state,
620 const struct dc_stream_state *stream)
621 {
622 uint8_t i;
623
624 if (state == NULL)
625 return NULL;
626
627 for (i = 0; i < state->stream_count; i++) {
628 if (stream == state->streams[i])
629 return &state->stream_status[i];
630 }
631
632 return NULL;
633 }
634
dc_state_get_pipe_subvp_type(const struct dc_state * state,const struct pipe_ctx * pipe_ctx)635 enum mall_stream_type dc_state_get_pipe_subvp_type(const struct dc_state *state,
636 const struct pipe_ctx *pipe_ctx)
637 {
638 return dc_state_get_stream_subvp_type(state, pipe_ctx->stream);
639 }
640
dc_state_get_stream_subvp_type(const struct dc_state * state,const struct dc_stream_state * stream)641 enum mall_stream_type dc_state_get_stream_subvp_type(const struct dc_state *state,
642 const struct dc_stream_state *stream)
643 {
644 int i;
645
646 enum mall_stream_type type = SUBVP_NONE;
647
648 for (i = 0; i < state->stream_count; i++) {
649 if (state->streams[i] == stream) {
650 type = state->stream_status[i].mall_stream_config.type;
651 break;
652 }
653 }
654
655 return type;
656 }
657
dc_state_get_paired_subvp_stream(const struct dc_state * state,const struct dc_stream_state * stream)658 struct dc_stream_state *dc_state_get_paired_subvp_stream(const struct dc_state *state,
659 const struct dc_stream_state *stream)
660 {
661 int i;
662
663 struct dc_stream_state *paired_stream = NULL;
664
665 for (i = 0; i < state->stream_count; i++) {
666 if (state->streams[i] == stream) {
667 paired_stream = state->stream_status[i].mall_stream_config.paired_stream;
668 break;
669 }
670 }
671
672 return paired_stream;
673 }
674
dc_state_create_phantom_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * main_stream)675 struct dc_stream_state *dc_state_create_phantom_stream(const struct dc *dc,
676 struct dc_state *state,
677 struct dc_stream_state *main_stream)
678 {
679 struct dc_stream_state *phantom_stream;
680
681 DC_LOGGER_INIT(dc->ctx->logger);
682
683 phantom_stream = dc_create_stream_for_sink(main_stream->sink);
684
685 if (!phantom_stream) {
686 DC_LOG_ERROR("Failed to allocate phantom stream.\n");
687 return NULL;
688 }
689
690 /* track phantom stream in dc_state */
691 dc_state_track_phantom_stream(state, phantom_stream);
692
693 phantom_stream->is_phantom = true;
694 phantom_stream->signal = SIGNAL_TYPE_VIRTUAL;
695 phantom_stream->dpms_off = true;
696
697 return phantom_stream;
698 }
699
dc_state_release_phantom_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * phantom_stream)700 void dc_state_release_phantom_stream(const struct dc *dc,
701 struct dc_state *state,
702 struct dc_stream_state *phantom_stream)
703 {
704 DC_LOGGER_INIT(dc->ctx->logger);
705
706 if (!dc_state_untrack_phantom_stream(state, phantom_stream)) {
707 DC_LOG_ERROR("Failed to free phantom stream %p in dc state %p.\n", phantom_stream, state);
708 return;
709 }
710
711 dc_stream_release(phantom_stream);
712 }
713
dc_state_create_phantom_plane(const struct dc * dc,struct dc_state * state,struct dc_plane_state * main_plane)714 struct dc_plane_state *dc_state_create_phantom_plane(const struct dc *dc,
715 struct dc_state *state,
716 struct dc_plane_state *main_plane)
717 {
718 struct dc_plane_state *phantom_plane = dc_create_plane_state(dc);
719
720 DC_LOGGER_INIT(dc->ctx->logger);
721
722 if (!phantom_plane) {
723 DC_LOG_ERROR("Failed to allocate phantom plane.\n");
724 return NULL;
725 }
726
727 /* track phantom inside dc_state */
728 dc_state_track_phantom_plane(state, phantom_plane);
729
730 phantom_plane->is_phantom = true;
731
732 return phantom_plane;
733 }
734
dc_state_release_phantom_plane(const struct dc * dc,struct dc_state * state,struct dc_plane_state * phantom_plane)735 void dc_state_release_phantom_plane(const struct dc *dc,
736 struct dc_state *state,
737 struct dc_plane_state *phantom_plane)
738 {
739 DC_LOGGER_INIT(dc->ctx->logger);
740
741 if (!dc_state_untrack_phantom_plane(state, phantom_plane)) {
742 DC_LOG_ERROR("Failed to free phantom plane %p in dc state %p.\n", phantom_plane, state);
743 return;
744 }
745
746 dc_plane_state_release(phantom_plane);
747 }
748
749 /* add phantom streams to context and generate correct meta inside dc_state */
dc_state_add_phantom_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * phantom_stream,struct dc_stream_state * main_stream)750 enum dc_status dc_state_add_phantom_stream(const struct dc *dc,
751 struct dc_state *state,
752 struct dc_stream_state *phantom_stream,
753 struct dc_stream_state *main_stream)
754 {
755 struct dc_stream_status *main_stream_status;
756 struct dc_stream_status *phantom_stream_status;
757 enum dc_status res = dc_state_add_stream(dc, state, phantom_stream);
758
759 /* check if stream is tracked */
760 if (res == DC_OK && !dc_state_is_phantom_stream_tracked(state, phantom_stream)) {
761 /* stream must be tracked if added to state */
762 dc_state_track_phantom_stream(state, phantom_stream);
763 }
764
765 /* setup subvp meta */
766 main_stream_status = dc_state_get_stream_status(state, main_stream);
767 phantom_stream_status = dc_state_get_stream_status(state, phantom_stream);
768 phantom_stream_status->mall_stream_config.type = SUBVP_PHANTOM;
769 phantom_stream_status->mall_stream_config.paired_stream = main_stream;
770 main_stream_status->mall_stream_config.type = SUBVP_MAIN;
771 main_stream_status->mall_stream_config.paired_stream = phantom_stream;
772
773 return res;
774 }
775
dc_state_remove_phantom_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * phantom_stream)776 enum dc_status dc_state_remove_phantom_stream(const struct dc *dc,
777 struct dc_state *state,
778 struct dc_stream_state *phantom_stream)
779 {
780 struct dc_stream_status *main_stream_status;
781 struct dc_stream_status *phantom_stream_status;
782
783 /* reset subvp meta */
784 phantom_stream_status = dc_state_get_stream_status(state, phantom_stream);
785 main_stream_status = dc_state_get_stream_status(state, phantom_stream_status->mall_stream_config.paired_stream);
786 phantom_stream_status->mall_stream_config.type = SUBVP_NONE;
787 phantom_stream_status->mall_stream_config.paired_stream = NULL;
788 if (main_stream_status) {
789 main_stream_status->mall_stream_config.type = SUBVP_NONE;
790 main_stream_status->mall_stream_config.paired_stream = NULL;
791 }
792
793 /* remove stream from state */
794 return dc_state_remove_stream(dc, state, phantom_stream);
795 }
796
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)797 bool dc_state_add_phantom_plane(
798 const struct dc *dc,
799 struct dc_stream_state *phantom_stream,
800 struct dc_plane_state *phantom_plane,
801 struct dc_state *state)
802 {
803 bool res = dc_state_add_plane(dc, phantom_stream, phantom_plane, state);
804
805 /* check if stream is tracked */
806 if (res && !dc_state_is_phantom_plane_tracked(state, phantom_plane)) {
807 /* stream must be tracked if added to state */
808 dc_state_track_phantom_plane(state, phantom_plane);
809 }
810
811 return res;
812 }
813
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)814 bool dc_state_remove_phantom_plane(
815 const struct dc *dc,
816 struct dc_stream_state *phantom_stream,
817 struct dc_plane_state *phantom_plane,
818 struct dc_state *state)
819 {
820 return dc_state_remove_plane(dc, phantom_stream, phantom_plane, state);
821 }
822
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)823 bool dc_state_rem_all_phantom_planes_for_stream(
824 const struct dc *dc,
825 struct dc_stream_state *phantom_stream,
826 struct dc_state *state,
827 bool should_release_planes)
828 {
829 int i, old_plane_count;
830 struct dc_stream_status *stream_status = NULL;
831 struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 };
832
833 for (i = 0; i < state->stream_count; i++)
834 if (state->streams[i] == phantom_stream) {
835 stream_status = &state->stream_status[i];
836 break;
837 }
838
839 if (stream_status == NULL) {
840 dm_error("Existing stream %p not found!\n", phantom_stream);
841 return false;
842 }
843
844 old_plane_count = stream_status->plane_count;
845
846 for (i = 0; i < old_plane_count; i++)
847 del_planes[i] = stream_status->plane_states[i];
848
849 for (i = 0; i < old_plane_count; i++) {
850 if (!dc_state_remove_plane(dc, phantom_stream, del_planes[i], state))
851 return false;
852 if (should_release_planes)
853 dc_state_release_phantom_plane(dc, state, del_planes[i]);
854 }
855
856 return true;
857 }
858
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)859 bool dc_state_add_all_phantom_planes_for_stream(
860 const struct dc *dc,
861 struct dc_stream_state *phantom_stream,
862 struct dc_plane_state * const *phantom_planes,
863 int plane_count,
864 struct dc_state *state)
865 {
866 return dc_state_add_all_planes_for_stream(dc, phantom_stream, phantom_planes, plane_count, state);
867 }
868
dc_state_remove_phantom_streams_and_planes(const struct dc * dc,struct dc_state * state)869 bool dc_state_remove_phantom_streams_and_planes(
870 const struct dc *dc,
871 struct dc_state *state)
872 {
873 int i;
874 bool removed_phantom = false;
875 struct dc_stream_state *phantom_stream = NULL;
876
877 for (i = 0; i < dc->res_pool->pipe_count; i++) {
878 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i];
879
880 if (pipe->plane_state && pipe->stream && dc_state_get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) {
881 phantom_stream = pipe->stream;
882
883 dc_state_rem_all_phantom_planes_for_stream(dc, phantom_stream, state, false);
884 dc_state_remove_phantom_stream(dc, state, phantom_stream);
885 removed_phantom = true;
886 }
887 }
888 return removed_phantom;
889 }
890
dc_state_release_phantom_streams_and_planes(const struct dc * dc,struct dc_state * state)891 void dc_state_release_phantom_streams_and_planes(
892 const struct dc *dc,
893 struct dc_state *state)
894 {
895 int i;
896
897 for (i = 0; i < state->phantom_stream_count; i++)
898 dc_state_release_phantom_stream(dc, state, state->phantom_streams[i]);
899
900 for (i = 0; i < state->phantom_plane_count; i++)
901 dc_state_release_phantom_plane(dc, state, state->phantom_planes[i]);
902 }
903
dc_state_get_stream_from_id(const struct dc_state * state,unsigned int id)904 struct dc_stream_state *dc_state_get_stream_from_id(const struct dc_state *state, unsigned int id)
905 {
906 struct dc_stream_state *stream = NULL;
907 int i;
908
909 for (i = 0; i < state->stream_count; i++) {
910 if (state->streams[i] && state->streams[i]->stream_id == id) {
911 stream = state->streams[i];
912 break;
913 }
914 }
915
916 return stream;
917 }
918
919