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