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 #if defined(CONFIG_DRM_AMD_DC_FP)
37 #include "dml2/dml2_wrapper.h"
38 #include "dml2/dml2_internal_types.h"
39 #endif
40
41 #define DC_LOGGER \
42 dc->ctx->logger
43 #define DC_LOGGER_INIT(logger)
44
45 /* Private dc_state helper functions */
dc_state_track_phantom_stream(struct dc_state * state,struct dc_stream_state * phantom_stream)46 static bool dc_state_track_phantom_stream(struct dc_state *state,
47 struct dc_stream_state *phantom_stream)
48 {
49 if (state->phantom_stream_count >= MAX_PHANTOM_PIPES)
50 return false;
51
52 state->phantom_streams[state->phantom_stream_count++] = phantom_stream;
53
54 return true;
55 }
56
dc_state_untrack_phantom_stream(struct dc_state * state,struct dc_stream_state * phantom_stream)57 static bool dc_state_untrack_phantom_stream(struct dc_state *state, struct dc_stream_state *phantom_stream)
58 {
59 bool res = false;
60 int i;
61
62 /* first find phantom stream in the dc_state */
63 for (i = 0; i < state->phantom_stream_count; i++) {
64 if (state->phantom_streams[i] == phantom_stream) {
65 state->phantom_streams[i] = NULL;
66 res = true;
67 break;
68 }
69 }
70
71 /* failed to find stream in state */
72 if (!res)
73 return res;
74
75 /* trim back phantom streams */
76 state->phantom_stream_count--;
77 for (; i < state->phantom_stream_count; i++)
78 state->phantom_streams[i] = state->phantom_streams[i + 1];
79
80 return res;
81 }
82
dc_state_is_phantom_stream_tracked(struct dc_state * state,struct dc_stream_state * phantom_stream)83 static bool dc_state_is_phantom_stream_tracked(struct dc_state *state, struct dc_stream_state *phantom_stream)
84 {
85 int i;
86
87 for (i = 0; i < state->phantom_stream_count; i++) {
88 if (state->phantom_streams[i] == phantom_stream)
89 return true;
90 }
91
92 return false;
93 }
94
dc_state_track_phantom_plane(struct dc_state * state,struct dc_plane_state * phantom_plane)95 static bool dc_state_track_phantom_plane(struct dc_state *state,
96 struct dc_plane_state *phantom_plane)
97 {
98 if (state->phantom_plane_count >= MAX_PHANTOM_PIPES)
99 return false;
100
101 state->phantom_planes[state->phantom_plane_count++] = phantom_plane;
102
103 return true;
104 }
105
dc_state_untrack_phantom_plane(struct dc_state * state,struct dc_plane_state * phantom_plane)106 static bool dc_state_untrack_phantom_plane(struct dc_state *state, struct dc_plane_state *phantom_plane)
107 {
108 bool res = false;
109 int i;
110
111 /* first find phantom plane in the dc_state */
112 for (i = 0; i < state->phantom_plane_count; i++) {
113 if (state->phantom_planes[i] == phantom_plane) {
114 state->phantom_planes[i] = NULL;
115 res = true;
116 break;
117 }
118 }
119
120 /* failed to find plane in state */
121 if (!res)
122 return res;
123
124 /* trim back phantom planes */
125 state->phantom_plane_count--;
126 for (; i < state->phantom_plane_count; i++)
127 state->phantom_planes[i] = state->phantom_planes[i + 1];
128
129 return res;
130 }
131
dc_state_is_phantom_plane_tracked(struct dc_state * state,struct dc_plane_state * phantom_plane)132 static bool dc_state_is_phantom_plane_tracked(struct dc_state *state, struct dc_plane_state *phantom_plane)
133 {
134 int i;
135
136 for (i = 0; i < state->phantom_plane_count; i++) {
137 if (state->phantom_planes[i] == phantom_plane)
138 return true;
139 }
140
141 return false;
142 }
143
dc_state_copy_internal(struct dc_state * dst_state,struct dc_state * src_state)144 static void dc_state_copy_internal(struct dc_state *dst_state, struct dc_state *src_state)
145 {
146 int i, j;
147
148 memcpy(dst_state, src_state, sizeof(struct dc_state));
149
150 for (i = 0; i < MAX_PIPES; i++) {
151 struct pipe_ctx *cur_pipe = &dst_state->res_ctx.pipe_ctx[i];
152
153 if (cur_pipe->top_pipe)
154 cur_pipe->top_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx];
155
156 if (cur_pipe->bottom_pipe)
157 cur_pipe->bottom_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];
158
159 if (cur_pipe->prev_odm_pipe)
160 cur_pipe->prev_odm_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx];
161
162 if (cur_pipe->next_odm_pipe)
163 cur_pipe->next_odm_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx];
164 }
165
166 /* retain phantoms */
167 for (i = 0; i < dst_state->phantom_stream_count; i++)
168 dc_stream_retain(dst_state->phantom_streams[i]);
169
170 for (i = 0; i < dst_state->phantom_plane_count; i++)
171 dc_plane_state_retain(dst_state->phantom_planes[i]);
172
173 /* retain streams and planes */
174 for (i = 0; i < dst_state->stream_count; i++) {
175 dc_stream_retain(dst_state->streams[i]);
176 for (j = 0; j < dst_state->stream_status[i].plane_count; j++)
177 dc_plane_state_retain(
178 dst_state->stream_status[i].plane_states[j]);
179 }
180
181 }
182
init_state(struct dc * dc,struct dc_state * state)183 static void init_state(struct dc *dc, struct dc_state *state)
184 {
185 /* Each context must have their own instance of VBA and in order to
186 * initialize and obtain IP and SOC the base DML instance from DC is
187 * initially copied into every context
188 */
189 memcpy(&state->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib));
190 }
191
192 /* Public dc_state functions */
dc_state_create(struct dc * dc,struct dc_state_create_params * params)193 struct dc_state *dc_state_create(struct dc *dc, struct dc_state_create_params *params)
194 {
195 struct dc_state *state;
196 #ifdef CONFIG_DRM_AMD_DC_FP
197 struct dml2_configuration_options *dml2_opt = &dc->dml2_tmp;
198
199 memcpy(dml2_opt, &dc->dml2_options, sizeof(dc->dml2_options));
200 #endif
201
202 state = kvzalloc(sizeof(struct dc_state), GFP_KERNEL);
203
204 if (!state)
205 return NULL;
206
207 init_state(dc, state);
208 dc_state_construct(dc, state);
209 state->power_source = params ? params->power_source : DC_POWER_SOURCE_AC;
210
211 #ifdef CONFIG_DRM_AMD_DC_FP
212 if (dc->debug.using_dml2) {
213 dml2_opt->use_clock_dc_limits = false;
214 if (!dml2_create(dc, dml2_opt, &state->bw_ctx.dml2)) {
215 dc_state_release(state);
216 return NULL;
217 }
218
219 dml2_opt->use_clock_dc_limits = true;
220 if (!dml2_create(dc, dml2_opt, &state->bw_ctx.dml2_dc_power_source)) {
221 dc_state_release(state);
222 return NULL;
223 }
224 }
225 #endif
226
227 kref_init(&state->refcount);
228
229 return state;
230 }
231
dc_state_copy(struct dc_state * dst_state,struct dc_state * src_state)232 void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state)
233 {
234 struct kref refcount = dst_state->refcount;
235 #ifdef CONFIG_DRM_AMD_DC_FP
236 struct dml2_context *dst_dml2 = dst_state->bw_ctx.dml2;
237 struct dml2_context *dst_dml2_dc_power_source = dst_state->bw_ctx.dml2_dc_power_source;
238 #endif
239
240 dc_state_copy_internal(dst_state, src_state);
241
242 #ifdef CONFIG_DRM_AMD_DC_FP
243 dst_state->bw_ctx.dml2 = dst_dml2;
244 if (src_state->bw_ctx.dml2)
245 dml2_copy(dst_state->bw_ctx.dml2, src_state->bw_ctx.dml2);
246
247 dst_state->bw_ctx.dml2_dc_power_source = dst_dml2_dc_power_source;
248 if (src_state->bw_ctx.dml2_dc_power_source)
249 dml2_copy(dst_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source);
250 #endif
251
252 /* context refcount should not be overridden */
253 dst_state->refcount = refcount;
254 }
255
dc_state_create_copy(struct dc_state * src_state)256 struct dc_state *dc_state_create_copy(struct dc_state *src_state)
257 {
258 struct dc_state *new_state;
259
260 new_state = kvmalloc(sizeof(struct dc_state),
261 GFP_KERNEL);
262 if (!new_state)
263 return NULL;
264
265 dc_state_copy_internal(new_state, src_state);
266
267 #ifdef CONFIG_DRM_AMD_DC_FP
268 if (src_state->bw_ctx.dml2 &&
269 !dml2_create_copy(&new_state->bw_ctx.dml2, src_state->bw_ctx.dml2)) {
270 dc_state_release(new_state);
271 return NULL;
272 }
273
274 if (src_state->bw_ctx.dml2_dc_power_source &&
275 !dml2_create_copy(&new_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source)) {
276 dc_state_release(new_state);
277 return NULL;
278 }
279 #endif
280
281 kref_init(&new_state->refcount);
282
283 return new_state;
284 }
285
dc_state_copy_current(struct dc * dc,struct dc_state * dst_state)286 void dc_state_copy_current(struct dc *dc, struct dc_state *dst_state)
287 {
288 dc_state_copy(dst_state, dc->current_state);
289 }
290
dc_state_create_current_copy(struct dc * dc)291 struct dc_state *dc_state_create_current_copy(struct dc *dc)
292 {
293 return dc_state_create_copy(dc->current_state);
294 }
295
dc_state_construct(struct dc * dc,struct dc_state * state)296 void dc_state_construct(struct dc *dc, struct dc_state *state)
297 {
298 state->clk_mgr = dc->clk_mgr;
299
300 /* Initialise DIG link encoder resource tracking variables. */
301 if (dc->res_pool)
302 link_enc_cfg_init(dc, state);
303 }
304
dc_state_destruct(struct dc_state * state)305 void dc_state_destruct(struct dc_state *state)
306 {
307 int i, j;
308
309 for (i = 0; i < state->stream_count; i++) {
310 for (j = 0; j < state->stream_status[i].plane_count; j++)
311 dc_plane_state_release(
312 state->stream_status[i].plane_states[j]);
313
314 state->stream_status[i].plane_count = 0;
315 dc_stream_release(state->streams[i]);
316 state->streams[i] = NULL;
317 }
318 state->stream_count = 0;
319
320 /* release tracked phantoms */
321 for (i = 0; i < state->phantom_stream_count; i++) {
322 dc_stream_release(state->phantom_streams[i]);
323 state->phantom_streams[i] = NULL;
324 }
325 state->phantom_stream_count = 0;
326
327 for (i = 0; i < state->phantom_plane_count; i++) {
328 dc_plane_state_release(state->phantom_planes[i]);
329 state->phantom_planes[i] = NULL;
330 }
331 state->phantom_plane_count = 0;
332
333 state->stream_mask = 0;
334 memset(&state->res_ctx, 0, sizeof(state->res_ctx));
335 memset(&state->pp_display_cfg, 0, sizeof(state->pp_display_cfg));
336 memset(&state->dcn_bw_vars, 0, sizeof(state->dcn_bw_vars));
337 state->clk_mgr = NULL;
338 memset(&state->bw_ctx.bw, 0, sizeof(state->bw_ctx.bw));
339 memset(state->block_sequence, 0, sizeof(state->block_sequence));
340 state->block_sequence_steps = 0;
341 memset(state->dc_dmub_cmd, 0, sizeof(state->dc_dmub_cmd));
342 state->dmub_cmd_count = 0;
343 memset(&state->perf_params, 0, sizeof(state->perf_params));
344 }
345
dc_state_retain(struct dc_state * state)346 void dc_state_retain(struct dc_state *state)
347 {
348 kref_get(&state->refcount);
349 }
350
dc_state_free(struct kref * kref)351 static void dc_state_free(struct kref *kref)
352 {
353 struct dc_state *state = container_of(kref, struct dc_state, refcount);
354
355 dc_state_destruct(state);
356
357 #ifdef CONFIG_DRM_AMD_DC_FP
358 dml2_destroy(state->bw_ctx.dml2);
359 state->bw_ctx.dml2 = 0;
360
361 dml2_destroy(state->bw_ctx.dml2_dc_power_source);
362 state->bw_ctx.dml2_dc_power_source = 0;
363 #endif
364
365 kvfree(state);
366 }
367
dc_state_release(struct dc_state * state)368 void dc_state_release(struct dc_state *state)
369 {
370 if (state != NULL)
371 kref_put(&state->refcount, dc_state_free);
372 }
373 /*
374 * dc_state_add_stream() - Add a new dc_stream_state to a dc_state.
375 */
dc_state_add_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * stream)376 enum dc_status dc_state_add_stream(
377 const struct dc *dc,
378 struct dc_state *state,
379 struct dc_stream_state *stream)
380 {
381 enum dc_status res;
382
383 DC_LOGGER_INIT(dc->ctx->logger);
384
385 if (state->stream_count >= dc->res_pool->timing_generator_count) {
386 DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream);
387 return DC_ERROR_UNEXPECTED;
388 }
389
390 state->streams[state->stream_count] = stream;
391 dc_stream_retain(stream);
392 state->stream_count++;
393
394 res = resource_add_otg_master_for_stream_output(
395 state, dc->res_pool, stream);
396 if (res != DC_OK)
397 DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res);
398
399 return res;
400 }
401
402 /*
403 * dc_state_remove_stream() - Remove a stream from a dc_state.
404 */
dc_state_remove_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * stream)405 enum dc_status dc_state_remove_stream(
406 const struct dc *dc,
407 struct dc_state *state,
408 struct dc_stream_state *stream)
409 {
410 int i;
411 struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream(
412 &state->res_ctx, stream);
413
414 if (!del_pipe) {
415 dm_error("Pipe not found for stream %p !\n", stream);
416 return DC_ERROR_UNEXPECTED;
417 }
418
419 resource_update_pipes_for_stream_with_slice_count(state,
420 dc->current_state, dc->res_pool, stream, 1);
421 resource_remove_otg_master_for_stream_output(
422 state, dc->res_pool, stream);
423
424 for (i = 0; i < state->stream_count; i++)
425 if (state->streams[i] == stream)
426 break;
427
428 if (state->streams[i] != stream) {
429 dm_error("Context doesn't have stream %p !\n", stream);
430 return DC_ERROR_UNEXPECTED;
431 }
432
433 dc_stream_release(state->streams[i]);
434 state->stream_count--;
435
436 /* Trim back arrays */
437 for (; i < state->stream_count; i++) {
438 state->streams[i] = state->streams[i + 1];
439 state->stream_status[i] = state->stream_status[i + 1];
440 }
441
442 state->streams[state->stream_count] = NULL;
443 memset(
444 &state->stream_status[state->stream_count],
445 0,
446 sizeof(state->stream_status[0]));
447
448 return DC_OK;
449 }
450
remove_mpc_combine_for_stream(const struct dc * dc,struct dc_state * new_ctx,const struct dc_state * cur_ctx,struct dc_stream_status * status)451 static void remove_mpc_combine_for_stream(const struct dc *dc,
452 struct dc_state *new_ctx,
453 const struct dc_state *cur_ctx,
454 struct dc_stream_status *status)
455 {
456 int i;
457
458 for (i = 0; i < status->plane_count; i++)
459 resource_update_pipes_for_plane_with_slice_count(
460 new_ctx, cur_ctx, dc->res_pool,
461 status->plane_states[i], 1);
462 }
463
dc_state_add_plane(const struct dc * dc,struct dc_stream_state * stream,struct dc_plane_state * plane_state,struct dc_state * state)464 bool dc_state_add_plane(
465 const struct dc *dc,
466 struct dc_stream_state *stream,
467 struct dc_plane_state *plane_state,
468 struct dc_state *state)
469 {
470 struct resource_pool *pool = dc->res_pool;
471 struct pipe_ctx *otg_master_pipe;
472 struct dc_stream_status *stream_status = NULL;
473 bool added = false;
474 int odm_slice_count;
475 int i;
476
477 stream_status = dc_state_get_stream_status(state, stream);
478 otg_master_pipe = resource_get_otg_master_for_stream(
479 &state->res_ctx, stream);
480 if (stream_status == NULL) {
481 dm_error("Existing stream not found; failed to attach surface!\n");
482 goto out;
483 } else if (stream_status->plane_count == MAX_SURFACE_NUM) {
484 dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n",
485 plane_state, MAX_SURFACE_NUM);
486 goto out;
487 } else if (!otg_master_pipe) {
488 goto out;
489 }
490
491 added = resource_append_dpp_pipes_for_plane_composition(state,
492 dc->current_state, pool, otg_master_pipe, plane_state);
493
494 if (!added) {
495 /* try to remove MPC combine to free up pipes */
496 for (i = 0; i < state->stream_count; i++)
497 remove_mpc_combine_for_stream(dc, state,
498 dc->current_state,
499 &state->stream_status[i]);
500 added = resource_append_dpp_pipes_for_plane_composition(state,
501 dc->current_state, pool,
502 otg_master_pipe, plane_state);
503 }
504
505 if (!added) {
506 /* try to decrease ODM slice count gradually to free up pipes */
507 odm_slice_count = resource_get_odm_slice_count(otg_master_pipe);
508 for (i = odm_slice_count - 1; i > 0; i--) {
509 resource_update_pipes_for_stream_with_slice_count(state,
510 dc->current_state, dc->res_pool, stream,
511 i);
512 added = resource_append_dpp_pipes_for_plane_composition(
513 state,
514 dc->current_state, pool,
515 otg_master_pipe, plane_state);
516 if (added)
517 break;
518 }
519 }
520
521 if (added) {
522 stream_status->plane_states[stream_status->plane_count] =
523 plane_state;
524 stream_status->plane_count++;
525 dc_plane_state_retain(plane_state);
526 }
527
528 out:
529 return added;
530 }
531
dc_state_remove_plane(const struct dc * dc,struct dc_stream_state * stream,struct dc_plane_state * plane_state,struct dc_state * state)532 bool dc_state_remove_plane(
533 const struct dc *dc,
534 struct dc_stream_state *stream,
535 struct dc_plane_state *plane_state,
536 struct dc_state *state)
537 {
538 int i;
539 struct dc_stream_status *stream_status = NULL;
540 struct resource_pool *pool = dc->res_pool;
541
542 if (!plane_state)
543 return true;
544
545 for (i = 0; i < state->stream_count; i++)
546 if (state->streams[i] == stream) {
547 stream_status = &state->stream_status[i];
548 break;
549 }
550
551 if (stream_status == NULL) {
552 dm_error("Existing stream not found; failed to remove plane.\n");
553 return false;
554 }
555
556 resource_remove_dpp_pipes_for_plane_composition(
557 state, pool, plane_state);
558
559 for (i = 0; i < stream_status->plane_count; i++) {
560 if (stream_status->plane_states[i] == plane_state) {
561 dc_plane_state_release(stream_status->plane_states[i]);
562 break;
563 }
564 }
565
566 if (i == stream_status->plane_count) {
567 dm_error("Existing plane_state not found; failed to detach it!\n");
568 return false;
569 }
570
571 stream_status->plane_count--;
572
573 /* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */
574 for (; i < stream_status->plane_count; i++)
575 stream_status->plane_states[i] = stream_status->plane_states[i + 1];
576
577 stream_status->plane_states[stream_status->plane_count] = NULL;
578
579 return true;
580 }
581
582 /**
583 * dc_state_rem_all_planes_for_stream - Remove planes attached to the target stream.
584 *
585 * @dc: Current dc state.
586 * @stream: Target stream, which we want to remove the attached plans.
587 * @state: context from which the planes are to be removed.
588 *
589 * Return:
590 * Return true if DC was able to remove all planes from the target
591 * stream, otherwise, return false.
592 */
dc_state_rem_all_planes_for_stream(const struct dc * dc,struct dc_stream_state * stream,struct dc_state * state)593 bool dc_state_rem_all_planes_for_stream(
594 const struct dc *dc,
595 struct dc_stream_state *stream,
596 struct dc_state *state)
597 {
598 int i, old_plane_count;
599 struct dc_stream_status *stream_status = NULL;
600 struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 };
601
602 for (i = 0; i < state->stream_count; i++)
603 if (state->streams[i] == stream) {
604 stream_status = &state->stream_status[i];
605 break;
606 }
607
608 if (stream_status == NULL) {
609 dm_error("Existing stream %p not found!\n", stream);
610 return false;
611 }
612
613 old_plane_count = stream_status->plane_count;
614
615 for (i = 0; i < old_plane_count; i++)
616 del_planes[i] = stream_status->plane_states[i];
617
618 for (i = 0; i < old_plane_count; i++)
619 if (!dc_state_remove_plane(dc, stream, del_planes[i], state))
620 return false;
621
622 return true;
623 }
624
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)625 bool dc_state_add_all_planes_for_stream(
626 const struct dc *dc,
627 struct dc_stream_state *stream,
628 struct dc_plane_state * const *plane_states,
629 int plane_count,
630 struct dc_state *state)
631 {
632 int i;
633 bool result = true;
634
635 for (i = 0; i < plane_count; i++)
636 if (!dc_state_add_plane(dc, stream, plane_states[i], state)) {
637 result = false;
638 break;
639 }
640
641 return result;
642 }
643
644 /* Private dc_state functions */
645
646 /**
647 * dc_state_get_stream_status - Get stream status from given dc state
648 * @state: DC state to find the stream status in
649 * @stream: The stream to get the stream status for
650 *
651 * The given stream is expected to exist in the given dc state. Otherwise, NULL
652 * will be returned.
653 */
dc_state_get_stream_status(struct dc_state * state,const struct dc_stream_state * stream)654 struct dc_stream_status *dc_state_get_stream_status(
655 struct dc_state *state,
656 const struct dc_stream_state *stream)
657 {
658 uint8_t i;
659
660 if (state == NULL)
661 return NULL;
662
663 for (i = 0; i < state->stream_count; i++) {
664 if (stream == state->streams[i])
665 return &state->stream_status[i];
666 }
667
668 return NULL;
669 }
670
dc_state_get_pipe_subvp_type(const struct dc_state * state,const struct pipe_ctx * pipe_ctx)671 enum mall_stream_type dc_state_get_pipe_subvp_type(const struct dc_state *state,
672 const struct pipe_ctx *pipe_ctx)
673 {
674 return dc_state_get_stream_subvp_type(state, pipe_ctx->stream);
675 }
676
dc_state_get_stream_subvp_type(const struct dc_state * state,const struct dc_stream_state * stream)677 enum mall_stream_type dc_state_get_stream_subvp_type(const struct dc_state *state,
678 const struct dc_stream_state *stream)
679 {
680 int i;
681
682 enum mall_stream_type type = SUBVP_NONE;
683
684 for (i = 0; i < state->stream_count; i++) {
685 if (state->streams[i] == stream) {
686 type = state->stream_status[i].mall_stream_config.type;
687 break;
688 }
689 }
690
691 return type;
692 }
693
dc_state_get_paired_subvp_stream(const struct dc_state * state,const struct dc_stream_state * stream)694 struct dc_stream_state *dc_state_get_paired_subvp_stream(const struct dc_state *state,
695 const struct dc_stream_state *stream)
696 {
697 int i;
698
699 struct dc_stream_state *paired_stream = NULL;
700
701 for (i = 0; i < state->stream_count; i++) {
702 if (state->streams[i] == stream) {
703 paired_stream = state->stream_status[i].mall_stream_config.paired_stream;
704 break;
705 }
706 }
707
708 return paired_stream;
709 }
710
dc_state_create_phantom_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * main_stream)711 struct dc_stream_state *dc_state_create_phantom_stream(const struct dc *dc,
712 struct dc_state *state,
713 struct dc_stream_state *main_stream)
714 {
715 struct dc_stream_state *phantom_stream;
716
717 DC_LOGGER_INIT(dc->ctx->logger);
718
719 phantom_stream = dc_create_stream_for_sink(main_stream->sink);
720
721 if (!phantom_stream) {
722 DC_LOG_ERROR("Failed to allocate phantom stream.\n");
723 return NULL;
724 }
725
726 /* track phantom stream in dc_state */
727 dc_state_track_phantom_stream(state, phantom_stream);
728
729 phantom_stream->is_phantom = true;
730 phantom_stream->signal = SIGNAL_TYPE_VIRTUAL;
731 phantom_stream->dpms_off = true;
732
733 return phantom_stream;
734 }
735
dc_state_release_phantom_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * phantom_stream)736 void dc_state_release_phantom_stream(const struct dc *dc,
737 struct dc_state *state,
738 struct dc_stream_state *phantom_stream)
739 {
740 DC_LOGGER_INIT(dc->ctx->logger);
741
742 if (!dc_state_untrack_phantom_stream(state, phantom_stream)) {
743 DC_LOG_ERROR("Failed to free phantom stream %p in dc state %p.\n", phantom_stream, state);
744 return;
745 }
746
747 dc_stream_release(phantom_stream);
748 }
749
dc_state_create_phantom_plane(const struct dc * dc,struct dc_state * state,struct dc_plane_state * main_plane)750 struct dc_plane_state *dc_state_create_phantom_plane(const struct dc *dc,
751 struct dc_state *state,
752 struct dc_plane_state *main_plane)
753 {
754 struct dc_plane_state *phantom_plane = dc_create_plane_state(dc);
755
756 DC_LOGGER_INIT(dc->ctx->logger);
757
758 if (!phantom_plane) {
759 DC_LOG_ERROR("Failed to allocate phantom plane.\n");
760 return NULL;
761 }
762
763 /* track phantom inside dc_state */
764 dc_state_track_phantom_plane(state, phantom_plane);
765
766 phantom_plane->is_phantom = true;
767
768 return phantom_plane;
769 }
770
dc_state_release_phantom_plane(const struct dc * dc,struct dc_state * state,struct dc_plane_state * phantom_plane)771 void dc_state_release_phantom_plane(const struct dc *dc,
772 struct dc_state *state,
773 struct dc_plane_state *phantom_plane)
774 {
775 DC_LOGGER_INIT(dc->ctx->logger);
776
777 if (!dc_state_untrack_phantom_plane(state, phantom_plane)) {
778 DC_LOG_ERROR("Failed to free phantom plane %p in dc state %p.\n", phantom_plane, state);
779 return;
780 }
781
782 dc_plane_state_release(phantom_plane);
783 }
784
785 /* 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)786 enum dc_status dc_state_add_phantom_stream(const struct dc *dc,
787 struct dc_state *state,
788 struct dc_stream_state *phantom_stream,
789 struct dc_stream_state *main_stream)
790 {
791 struct dc_stream_status *main_stream_status;
792 struct dc_stream_status *phantom_stream_status;
793 enum dc_status res = dc_state_add_stream(dc, state, phantom_stream);
794
795 /* check if stream is tracked */
796 if (res == DC_OK && !dc_state_is_phantom_stream_tracked(state, phantom_stream)) {
797 /* stream must be tracked if added to state */
798 dc_state_track_phantom_stream(state, phantom_stream);
799 }
800
801 /* setup subvp meta */
802 main_stream_status = dc_state_get_stream_status(state, main_stream);
803 if (main_stream_status) {
804 main_stream_status->mall_stream_config.type = SUBVP_MAIN;
805 main_stream_status->mall_stream_config.paired_stream = phantom_stream;
806 }
807
808 phantom_stream_status = dc_state_get_stream_status(state, phantom_stream);
809 if (phantom_stream_status) {
810 phantom_stream_status->mall_stream_config.type = SUBVP_PHANTOM;
811 phantom_stream_status->mall_stream_config.paired_stream = main_stream;
812 }
813
814 return res;
815 }
816
dc_state_remove_phantom_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * phantom_stream)817 enum dc_status dc_state_remove_phantom_stream(const struct dc *dc,
818 struct dc_state *state,
819 struct dc_stream_state *phantom_stream)
820 {
821 struct dc_stream_status *main_stream_status = NULL;
822 struct dc_stream_status *phantom_stream_status;
823
824 /* reset subvp meta */
825 phantom_stream_status = dc_state_get_stream_status(state, phantom_stream);
826 if (phantom_stream_status) {
827 main_stream_status = dc_state_get_stream_status(state, phantom_stream_status->mall_stream_config.paired_stream);
828 phantom_stream_status->mall_stream_config.type = SUBVP_NONE;
829 phantom_stream_status->mall_stream_config.paired_stream = NULL;
830 }
831
832 if (main_stream_status) {
833 main_stream_status->mall_stream_config.type = SUBVP_NONE;
834 main_stream_status->mall_stream_config.paired_stream = NULL;
835 }
836
837 /* remove stream from state */
838 return dc_state_remove_stream(dc, state, phantom_stream);
839 }
840
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)841 bool dc_state_add_phantom_plane(
842 const struct dc *dc,
843 struct dc_stream_state *phantom_stream,
844 struct dc_plane_state *phantom_plane,
845 struct dc_state *state)
846 {
847 bool res = dc_state_add_plane(dc, phantom_stream, phantom_plane, state);
848
849 /* check if stream is tracked */
850 if (res && !dc_state_is_phantom_plane_tracked(state, phantom_plane)) {
851 /* stream must be tracked if added to state */
852 dc_state_track_phantom_plane(state, phantom_plane);
853 }
854
855 return res;
856 }
857
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)858 bool dc_state_remove_phantom_plane(
859 const struct dc *dc,
860 struct dc_stream_state *phantom_stream,
861 struct dc_plane_state *phantom_plane,
862 struct dc_state *state)
863 {
864 return dc_state_remove_plane(dc, phantom_stream, phantom_plane, state);
865 }
866
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)867 bool dc_state_rem_all_phantom_planes_for_stream(
868 const struct dc *dc,
869 struct dc_stream_state *phantom_stream,
870 struct dc_state *state,
871 bool should_release_planes)
872 {
873 int i, old_plane_count;
874 struct dc_stream_status *stream_status = NULL;
875 struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 };
876
877 for (i = 0; i < state->stream_count; i++)
878 if (state->streams[i] == phantom_stream) {
879 stream_status = &state->stream_status[i];
880 break;
881 }
882
883 if (stream_status == NULL) {
884 dm_error("Existing stream %p not found!\n", phantom_stream);
885 return false;
886 }
887
888 old_plane_count = stream_status->plane_count;
889
890 for (i = 0; i < old_plane_count; i++)
891 del_planes[i] = stream_status->plane_states[i];
892
893 for (i = 0; i < old_plane_count; i++) {
894 if (!dc_state_remove_plane(dc, phantom_stream, del_planes[i], state))
895 return false;
896 if (should_release_planes)
897 dc_state_release_phantom_plane(dc, state, del_planes[i]);
898 }
899
900 return true;
901 }
902
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)903 bool dc_state_add_all_phantom_planes_for_stream(
904 const struct dc *dc,
905 struct dc_stream_state *phantom_stream,
906 struct dc_plane_state * const *phantom_planes,
907 int plane_count,
908 struct dc_state *state)
909 {
910 return dc_state_add_all_planes_for_stream(dc, phantom_stream, phantom_planes, plane_count, state);
911 }
912
dc_state_remove_phantom_streams_and_planes(const struct dc * dc,struct dc_state * state)913 bool dc_state_remove_phantom_streams_and_planes(
914 const struct dc *dc,
915 struct dc_state *state)
916 {
917 int i;
918 bool removed_phantom = false;
919 struct dc_stream_state *phantom_stream = NULL;
920
921 for (i = 0; i < dc->res_pool->pipe_count; i++) {
922 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i];
923
924 if (pipe->plane_state && pipe->stream && dc_state_get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) {
925 phantom_stream = pipe->stream;
926
927 dc_state_rem_all_phantom_planes_for_stream(dc, phantom_stream, state, false);
928 dc_state_remove_phantom_stream(dc, state, phantom_stream);
929 removed_phantom = true;
930 }
931 }
932 return removed_phantom;
933 }
934
dc_state_release_phantom_streams_and_planes(const struct dc * dc,struct dc_state * state)935 void dc_state_release_phantom_streams_and_planes(
936 const struct dc *dc,
937 struct dc_state *state)
938 {
939 int i;
940
941 for (i = 0; i < state->phantom_stream_count; i++)
942 dc_state_release_phantom_stream(dc, state, state->phantom_streams[i]);
943
944 for (i = 0; i < state->phantom_plane_count; i++)
945 dc_state_release_phantom_plane(dc, state, state->phantom_planes[i]);
946 }
947
dc_state_get_stream_from_id(const struct dc_state * state,unsigned int id)948 struct dc_stream_state *dc_state_get_stream_from_id(const struct dc_state *state, unsigned int id)
949 {
950 struct dc_stream_state *stream = NULL;
951 int i;
952
953 for (i = 0; i < state->stream_count; i++) {
954 if (state->streams[i] && state->streams[i]->stream_id == id) {
955 stream = state->streams[i];
956 break;
957 }
958 }
959
960 return stream;
961 }
962
dc_state_is_fams2_in_use(const struct dc * dc,const struct dc_state * state)963 bool dc_state_is_fams2_in_use(
964 const struct dc *dc,
965 const struct dc_state *state)
966 {
967 bool is_fams2_in_use = false;
968
969 if (state)
970 is_fams2_in_use |= state->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable;
971
972 if (dc->current_state)
973 is_fams2_in_use |= dc->current_state->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable;
974
975 return is_fams2_in_use;
976 }
977