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