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/dml2_wrapper.h"
39 #include "dml2/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(sizeof(struct dc_state), GFP_KERNEL);
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 (!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(sizeof(struct dc_state),
255 GFP_KERNEL);
256 if (!new_state)
257 return NULL;
258
259 dc_state_copy_internal(new_state, src_state);
260
261 #ifdef CONFIG_DRM_AMD_DC_FP
262 new_state->bw_ctx.dml2 = NULL;
263 new_state->bw_ctx.dml2_dc_power_source = NULL;
264
265 if (src_state->bw_ctx.dml2 &&
266 !dml2_create_copy(&new_state->bw_ctx.dml2, src_state->bw_ctx.dml2)) {
267 dc_state_release(new_state);
268 return NULL;
269 }
270
271 if (src_state->bw_ctx.dml2_dc_power_source &&
272 !dml2_create_copy(&new_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source)) {
273 dc_state_release(new_state);
274 return NULL;
275 }
276 #endif
277
278 kref_init(&new_state->refcount);
279
280 return new_state;
281 }
282
dc_state_copy_current(struct dc * dc,struct dc_state * dst_state)283 void dc_state_copy_current(struct dc *dc, struct dc_state *dst_state)
284 {
285 dc_state_copy(dst_state, dc->current_state);
286 }
287
dc_state_create_current_copy(struct dc * dc)288 struct dc_state *dc_state_create_current_copy(struct dc *dc)
289 {
290 return dc_state_create_copy(dc->current_state);
291 }
292
dc_state_construct(struct dc * dc,struct dc_state * state)293 void dc_state_construct(struct dc *dc, struct dc_state *state)
294 {
295 state->clk_mgr = dc->clk_mgr;
296
297 /* Initialise DIG link encoder resource tracking variables. */
298 if (dc->res_pool)
299 link_enc_cfg_init(dc, state);
300 }
301
dc_state_destruct(struct dc_state * state)302 void dc_state_destruct(struct dc_state *state)
303 {
304 int i, j;
305
306 for (i = 0; i < state->stream_count; i++) {
307 for (j = 0; j < state->stream_status[i].plane_count; j++)
308 dc_plane_state_release(
309 state->stream_status[i].plane_states[j]);
310
311 state->stream_status[i].plane_count = 0;
312 dc_stream_release(state->streams[i]);
313 state->streams[i] = NULL;
314 }
315 state->stream_count = 0;
316
317 /* release tracked phantoms */
318 for (i = 0; i < state->phantom_stream_count; i++) {
319 dc_stream_release(state->phantom_streams[i]);
320 state->phantom_streams[i] = NULL;
321 }
322 state->phantom_stream_count = 0;
323
324 for (i = 0; i < state->phantom_plane_count; i++) {
325 dc_plane_state_release(state->phantom_planes[i]);
326 state->phantom_planes[i] = NULL;
327 }
328 state->phantom_plane_count = 0;
329
330 state->stream_mask = 0;
331 memset(&state->res_ctx, 0, sizeof(state->res_ctx));
332 memset(&state->pp_display_cfg, 0, sizeof(state->pp_display_cfg));
333 memset(&state->dcn_bw_vars, 0, sizeof(state->dcn_bw_vars));
334 state->clk_mgr = NULL;
335 memset(&state->bw_ctx.bw, 0, sizeof(state->bw_ctx.bw));
336 memset(state->block_sequence, 0, sizeof(state->block_sequence));
337 state->block_sequence_steps = 0;
338 memset(state->dc_dmub_cmd, 0, sizeof(state->dc_dmub_cmd));
339 state->dmub_cmd_count = 0;
340 memset(&state->perf_params, 0, sizeof(state->perf_params));
341 }
342
dc_state_retain(struct dc_state * state)343 void dc_state_retain(struct dc_state *state)
344 {
345 kref_get(&state->refcount);
346 }
347
dc_state_free(struct kref * kref)348 static void dc_state_free(struct kref *kref)
349 {
350 struct dc_state *state = container_of(kref, struct dc_state, refcount);
351
352 dc_state_destruct(state);
353
354 #ifdef CONFIG_DRM_AMD_DC_FP
355 dml2_destroy(state->bw_ctx.dml2);
356 state->bw_ctx.dml2 = 0;
357
358 dml2_destroy(state->bw_ctx.dml2_dc_power_source);
359 state->bw_ctx.dml2_dc_power_source = 0;
360 #endif
361
362 kvfree(state);
363 }
364
dc_state_release(struct dc_state * state)365 void dc_state_release(struct dc_state *state)
366 {
367 if (state != NULL)
368 kref_put(&state->refcount, dc_state_free);
369 }
370 /*
371 * dc_state_add_stream() - Add a new dc_stream_state to a dc_state.
372 */
dc_state_add_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * stream)373 enum dc_status dc_state_add_stream(
374 const struct dc *dc,
375 struct dc_state *state,
376 struct dc_stream_state *stream)
377 {
378 enum dc_status res;
379
380 DC_LOGGER_INIT(dc->ctx->logger);
381
382 if (state->stream_count >= dc->res_pool->timing_generator_count) {
383 DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream);
384 return DC_ERROR_UNEXPECTED;
385 }
386
387 state->streams[state->stream_count] = stream;
388 dc_stream_retain(stream);
389 state->stream_count++;
390
391 res = resource_add_otg_master_for_stream_output(
392 state, dc->res_pool, stream);
393 if (res != DC_OK)
394 DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res);
395
396 return res;
397 }
398
399 /*
400 * dc_state_remove_stream() - Remove a stream from a dc_state.
401 */
dc_state_remove_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * stream)402 enum dc_status dc_state_remove_stream(
403 const struct dc *dc,
404 struct dc_state *state,
405 struct dc_stream_state *stream)
406 {
407 int i;
408 struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream(
409 &state->res_ctx, stream);
410
411 if (!del_pipe) {
412 dm_error("Pipe not found for stream %p !\n", stream);
413 return DC_ERROR_UNEXPECTED;
414 }
415
416 resource_update_pipes_for_stream_with_slice_count(state,
417 dc->current_state, dc->res_pool, stream, 1);
418 resource_remove_otg_master_for_stream_output(
419 state, dc->res_pool, stream);
420
421 for (i = 0; i < state->stream_count; i++)
422 if (state->streams[i] == stream)
423 break;
424
425 if (state->streams[i] != stream) {
426 dm_error("Context doesn't have stream %p !\n", stream);
427 return DC_ERROR_UNEXPECTED;
428 }
429
430 dc_stream_release_3dlut_for_stream(dc, stream);
431
432 dc_stream_release(state->streams[i]);
433 state->stream_count--;
434
435 /* Trim back arrays */
436 for (; i < state->stream_count; i++) {
437 state->streams[i] = state->streams[i + 1];
438 state->stream_status[i] = state->stream_status[i + 1];
439 }
440
441 state->streams[state->stream_count] = NULL;
442 memset(
443 &state->stream_status[state->stream_count],
444 0,
445 sizeof(state->stream_status[0]));
446
447 return DC_OK;
448 }
449
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)450 static void remove_mpc_combine_for_stream(const struct dc *dc,
451 struct dc_state *new_ctx,
452 const struct dc_state *cur_ctx,
453 struct dc_stream_status *status)
454 {
455 int i;
456
457 for (i = 0; i < status->plane_count; i++)
458 resource_update_pipes_for_plane_with_slice_count(
459 new_ctx, cur_ctx, dc->res_pool,
460 status->plane_states[i], 1);
461 }
462
dc_state_add_plane(const struct dc * dc,struct dc_stream_state * stream,struct dc_plane_state * plane_state,struct dc_state * state)463 bool dc_state_add_plane(
464 const struct dc *dc,
465 struct dc_stream_state *stream,
466 struct dc_plane_state *plane_state,
467 struct dc_state *state)
468 {
469 struct resource_pool *pool = dc->res_pool;
470 struct pipe_ctx *otg_master_pipe;
471 struct dc_stream_status *stream_status = NULL;
472 bool added = false;
473 int odm_slice_count;
474 int i;
475
476 stream_status = dc_state_get_stream_status(state, stream);
477 otg_master_pipe = resource_get_otg_master_for_stream(
478 &state->res_ctx, stream);
479 if (stream_status == NULL) {
480 dm_error("Existing stream not found; failed to attach surface!\n");
481 goto out;
482 } else if (stream_status->plane_count == MAX_SURFACES) {
483 dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n",
484 plane_state, MAX_SURFACES);
485 goto out;
486 } else if (!otg_master_pipe) {
487 goto out;
488 }
489
490 added = resource_append_dpp_pipes_for_plane_composition(state,
491 dc->current_state, pool, otg_master_pipe, plane_state);
492
493 if (!added) {
494 /* try to remove MPC combine to free up pipes */
495 for (i = 0; i < state->stream_count; i++)
496 remove_mpc_combine_for_stream(dc, state,
497 dc->current_state,
498 &state->stream_status[i]);
499 added = resource_append_dpp_pipes_for_plane_composition(state,
500 dc->current_state, pool,
501 otg_master_pipe, plane_state);
502 }
503
504 if (!added) {
505 /* try to decrease ODM slice count gradually to free up pipes */
506 odm_slice_count = resource_get_odm_slice_count(otg_master_pipe);
507 for (i = odm_slice_count - 1; i > 0; i--) {
508 resource_update_pipes_for_stream_with_slice_count(state,
509 dc->current_state, dc->res_pool, stream,
510 i);
511 added = resource_append_dpp_pipes_for_plane_composition(
512 state,
513 dc->current_state, pool,
514 otg_master_pipe, plane_state);
515 if (added)
516 break;
517 }
518 }
519
520 if (added) {
521 stream_status->plane_states[stream_status->plane_count] =
522 plane_state;
523 stream_status->plane_count++;
524 dc_plane_state_retain(plane_state);
525 }
526
527 out:
528 return added;
529 }
530
dc_state_remove_plane(const struct dc * dc,struct dc_stream_state * stream,struct dc_plane_state * plane_state,struct dc_state * state)531 bool dc_state_remove_plane(
532 const struct dc *dc,
533 struct dc_stream_state *stream,
534 struct dc_plane_state *plane_state,
535 struct dc_state *state)
536 {
537 int i;
538 struct dc_stream_status *stream_status = NULL;
539 struct resource_pool *pool = dc->res_pool;
540
541 if (!plane_state)
542 return true;
543
544 for (i = 0; i < state->stream_count; i++)
545 if (state->streams[i] == stream) {
546 stream_status = &state->stream_status[i];
547 break;
548 }
549
550 if (stream_status == NULL) {
551 dm_error("Existing stream not found; failed to remove plane.\n");
552 return false;
553 }
554
555 resource_remove_dpp_pipes_for_plane_composition(
556 state, pool, plane_state);
557
558 for (i = 0; i < stream_status->plane_count; i++) {
559 if (stream_status->plane_states[i] == plane_state) {
560 dc_plane_state_release(stream_status->plane_states[i]);
561 break;
562 }
563 }
564
565 if (i == stream_status->plane_count) {
566 dm_error("Existing plane_state not found; failed to detach it!\n");
567 return false;
568 }
569
570 stream_status->plane_count--;
571
572 /* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */
573 for (; i < stream_status->plane_count; i++)
574 stream_status->plane_states[i] = stream_status->plane_states[i + 1];
575
576 stream_status->plane_states[stream_status->plane_count] = NULL;
577
578 return true;
579 }
580
581 /**
582 * dc_state_rem_all_planes_for_stream - Remove planes attached to the target stream.
583 *
584 * @dc: Current dc state.
585 * @stream: Target stream, which we want to remove the attached plans.
586 * @state: context from which the planes are to be removed.
587 *
588 * Return:
589 * Return true if DC was able to remove all planes from the target
590 * stream, otherwise, return false.
591 */
dc_state_rem_all_planes_for_stream(const struct dc * dc,struct dc_stream_state * stream,struct dc_state * state)592 bool dc_state_rem_all_planes_for_stream(
593 const struct dc *dc,
594 struct dc_stream_state *stream,
595 struct dc_state *state)
596 {
597 int i, old_plane_count;
598 struct dc_stream_status *stream_status = NULL;
599 struct dc_plane_state *del_planes[MAX_SURFACES] = { 0 };
600
601 for (i = 0; i < state->stream_count; i++)
602 if (state->streams[i] == stream) {
603 stream_status = &state->stream_status[i];
604 break;
605 }
606
607 if (stream_status == NULL) {
608 dm_error("Existing stream %p not found!\n", stream);
609 return false;
610 }
611
612 old_plane_count = stream_status->plane_count;
613
614 for (i = 0; i < old_plane_count; i++)
615 del_planes[i] = stream_status->plane_states[i];
616
617 for (i = 0; i < old_plane_count; i++)
618 if (!dc_state_remove_plane(dc, stream, del_planes[i], state))
619 return false;
620
621 return true;
622 }
623
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)624 bool dc_state_add_all_planes_for_stream(
625 const struct dc *dc,
626 struct dc_stream_state *stream,
627 struct dc_plane_state * const *plane_states,
628 int plane_count,
629 struct dc_state *state)
630 {
631 int i;
632 bool result = true;
633
634 for (i = 0; i < plane_count; i++)
635 if (!dc_state_add_plane(dc, stream, plane_states[i], state)) {
636 result = false;
637 break;
638 }
639
640 return result;
641 }
642
643 /* Private dc_state functions */
644
645 /**
646 * dc_state_get_stream_status - Get stream status from given dc state
647 * @state: DC state to find the stream status in
648 * @stream: The stream to get the stream status for
649 *
650 * The given stream is expected to exist in the given dc state. Otherwise, NULL
651 * will be returned.
652 */
dc_state_get_stream_status(struct dc_state * state,const struct dc_stream_state * stream)653 struct dc_stream_status *dc_state_get_stream_status(
654 struct dc_state *state,
655 const struct dc_stream_state *stream)
656 {
657 uint8_t i;
658
659 if (state == NULL)
660 return NULL;
661
662 for (i = 0; i < state->stream_count; i++) {
663 if (stream == state->streams[i])
664 return &state->stream_status[i];
665 }
666
667 return NULL;
668 }
669
dc_state_get_pipe_subvp_type(const struct dc_state * state,const struct pipe_ctx * pipe_ctx)670 enum mall_stream_type dc_state_get_pipe_subvp_type(const struct dc_state *state,
671 const struct pipe_ctx *pipe_ctx)
672 {
673 return dc_state_get_stream_subvp_type(state, pipe_ctx->stream);
674 }
675
dc_state_get_stream_subvp_type(const struct dc_state * state,const struct dc_stream_state * stream)676 enum mall_stream_type dc_state_get_stream_subvp_type(const struct dc_state *state,
677 const struct dc_stream_state *stream)
678 {
679 int i;
680
681 enum mall_stream_type type = SUBVP_NONE;
682
683 for (i = 0; i < state->stream_count; i++) {
684 if (state->streams[i] == stream) {
685 type = state->stream_status[i].mall_stream_config.type;
686 break;
687 }
688 }
689
690 return type;
691 }
692
dc_state_get_paired_subvp_stream(const struct dc_state * state,const struct dc_stream_state * stream)693 struct dc_stream_state *dc_state_get_paired_subvp_stream(const struct dc_state *state,
694 const struct dc_stream_state *stream)
695 {
696 int i;
697
698 struct dc_stream_state *paired_stream = NULL;
699
700 for (i = 0; i < state->stream_count; i++) {
701 if (state->streams[i] == stream) {
702 paired_stream = state->stream_status[i].mall_stream_config.paired_stream;
703 break;
704 }
705 }
706
707 return paired_stream;
708 }
709
dc_state_create_phantom_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * main_stream)710 struct dc_stream_state *dc_state_create_phantom_stream(const struct dc *dc,
711 struct dc_state *state,
712 struct dc_stream_state *main_stream)
713 {
714 struct dc_stream_state *phantom_stream;
715
716 DC_LOGGER_INIT(dc->ctx->logger);
717
718 phantom_stream = dc_create_stream_for_sink(main_stream->sink);
719
720 if (!phantom_stream) {
721 DC_LOG_ERROR("Failed to allocate phantom stream.\n");
722 return NULL;
723 }
724
725 /* track phantom stream in dc_state */
726 dc_state_track_phantom_stream(state, phantom_stream);
727
728 phantom_stream->is_phantom = true;
729 phantom_stream->signal = SIGNAL_TYPE_VIRTUAL;
730 phantom_stream->dpms_off = true;
731
732 return phantom_stream;
733 }
734
dc_state_release_phantom_stream(const struct dc * dc,struct dc_state * state,struct dc_stream_state * phantom_stream)735 void dc_state_release_phantom_stream(const struct dc *dc,
736 struct dc_state *state,
737 struct dc_stream_state *phantom_stream)
738 {
739 DC_LOGGER_INIT(dc->ctx->logger);
740
741 if (!dc_state_untrack_phantom_stream(state, phantom_stream)) {
742 DC_LOG_ERROR("Failed to free phantom stream %p in dc state %p.\n", phantom_stream, state);
743 return;
744 }
745
746 dc_stream_release(phantom_stream);
747 }
748
dc_state_create_phantom_plane(const struct dc * dc,struct dc_state * state,struct dc_plane_state * main_plane)749 struct dc_plane_state *dc_state_create_phantom_plane(const struct dc *dc,
750 struct dc_state *state,
751 struct dc_plane_state *main_plane)
752 {
753 struct dc_plane_state *phantom_plane = dc_create_plane_state(dc);
754
755 DC_LOGGER_INIT(dc->ctx->logger);
756
757 if (!phantom_plane) {
758 DC_LOG_ERROR("Failed to allocate phantom plane.\n");
759 return NULL;
760 }
761
762 /* track phantom inside dc_state */
763 dc_state_track_phantom_plane(state, phantom_plane);
764
765 phantom_plane->is_phantom = true;
766
767 return phantom_plane;
768 }
769
dc_state_release_phantom_plane(const struct dc * dc,struct dc_state * state,struct dc_plane_state * phantom_plane)770 void dc_state_release_phantom_plane(const struct dc *dc,
771 struct dc_state *state,
772 struct dc_plane_state *phantom_plane)
773 {
774 DC_LOGGER_INIT(dc->ctx->logger);
775
776 if (!dc_state_untrack_phantom_plane(state, phantom_plane)) {
777 DC_LOG_ERROR("Failed to free phantom plane %p in dc state %p.\n", phantom_plane, state);
778 return;
779 }
780
781 dc_plane_state_release(phantom_plane);
782 }
783
784 /* 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)785 enum dc_status dc_state_add_phantom_stream(const struct dc *dc,
786 struct dc_state *state,
787 struct dc_stream_state *phantom_stream,
788 struct dc_stream_state *main_stream)
789 {
790 struct dc_stream_status *main_stream_status;
791 struct dc_stream_status *phantom_stream_status;
792 enum dc_status res = dc_state_add_stream(dc, state, phantom_stream);
793
794 /* check if stream is tracked */
795 if (res == DC_OK && !dc_state_is_phantom_stream_tracked(state, phantom_stream)) {
796 /* stream must be tracked if added to state */
797 dc_state_track_phantom_stream(state, phantom_stream);
798 }
799
800 /* setup subvp meta */
801 main_stream_status = dc_state_get_stream_status(state, main_stream);
802 if (main_stream_status) {
803 main_stream_status->mall_stream_config.type = SUBVP_MAIN;
804 main_stream_status->mall_stream_config.paired_stream = phantom_stream;
805 }
806
807 phantom_stream_status = dc_state_get_stream_status(state, phantom_stream);
808 if (phantom_stream_status) {
809 phantom_stream_status->mall_stream_config.type = SUBVP_PHANTOM;
810 phantom_stream_status->mall_stream_config.paired_stream = main_stream;
811 phantom_stream_status->mall_stream_config.subvp_limit_cursor_size = false;
812 phantom_stream_status->mall_stream_config.cursor_size_limit_subvp = false;
813 }
814
815 dc_state_set_stream_subvp_cursor_limit(main_stream, state, true);
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_SURFACES] = { 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 unsigned int phantom_count;
943 struct dc_stream_state *phantom_streams[MAX_PHANTOM_PIPES];
944 struct dc_plane_state *phantom_planes[MAX_PHANTOM_PIPES];
945 int i;
946
947 phantom_count = state->phantom_stream_count;
948 memcpy(phantom_streams, state->phantom_streams, sizeof(struct dc_stream_state *) * MAX_PHANTOM_PIPES);
949 for (i = 0; i < phantom_count; i++)
950 dc_state_release_phantom_stream(dc, state, phantom_streams[i]);
951
952 phantom_count = state->phantom_plane_count;
953 memcpy(phantom_planes, state->phantom_planes, sizeof(struct dc_plane_state *) * MAX_PHANTOM_PIPES);
954 for (i = 0; i < phantom_count; i++)
955 dc_state_release_phantom_plane(dc, state, phantom_planes[i]);
956 }
957
dc_state_get_stream_from_id(const struct dc_state * state,unsigned int id)958 struct dc_stream_state *dc_state_get_stream_from_id(const struct dc_state *state, unsigned int id)
959 {
960 struct dc_stream_state *stream = NULL;
961 int i;
962
963 for (i = 0; i < state->stream_count; i++) {
964 if (state->streams[i] && state->streams[i]->stream_id == id) {
965 stream = state->streams[i];
966 break;
967 }
968 }
969
970 return stream;
971 }
972
dc_state_is_fams2_in_use(const struct dc * dc,const struct dc_state * state)973 bool dc_state_is_fams2_in_use(
974 const struct dc *dc,
975 const struct dc_state *state)
976 {
977 bool is_fams2_in_use = false;
978
979 if (state)
980 is_fams2_in_use |= state->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable;
981
982 if (dc->current_state)
983 is_fams2_in_use |= dc->current_state->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable;
984
985 return is_fams2_in_use;
986 }
987
dc_state_set_stream_subvp_cursor_limit(const struct dc_stream_state * stream,struct dc_state * state,bool limit)988 void dc_state_set_stream_subvp_cursor_limit(const struct dc_stream_state *stream,
989 struct dc_state *state,
990 bool limit)
991 {
992 struct dc_stream_status *stream_status;
993
994 stream_status = dc_state_get_stream_status(state, stream);
995
996 if (stream_status) {
997 stream_status->mall_stream_config.subvp_limit_cursor_size = limit;
998 }
999 }
1000
dc_state_get_stream_subvp_cursor_limit(const struct dc_stream_state * stream,struct dc_state * state)1001 bool dc_state_get_stream_subvp_cursor_limit(const struct dc_stream_state *stream,
1002 struct dc_state *state)
1003 {
1004 bool limit = false;
1005
1006 struct dc_stream_status *stream_status;
1007
1008 stream_status = dc_state_get_stream_status(state, stream);
1009
1010 if (stream_status) {
1011 limit = stream_status->mall_stream_config.subvp_limit_cursor_size;
1012 }
1013
1014 return limit;
1015 }
1016
dc_state_set_stream_cursor_subvp_limit(const struct dc_stream_state * stream,struct dc_state * state,bool limit)1017 void dc_state_set_stream_cursor_subvp_limit(const struct dc_stream_state *stream,
1018 struct dc_state *state,
1019 bool limit)
1020 {
1021 struct dc_stream_status *stream_status;
1022
1023 stream_status = dc_state_get_stream_status(state, stream);
1024
1025 if (stream_status) {
1026 stream_status->mall_stream_config.cursor_size_limit_subvp = limit;
1027 }
1028 }
1029
dc_state_get_stream_cursor_subvp_limit(const struct dc_stream_state * stream,struct dc_state * state)1030 bool dc_state_get_stream_cursor_subvp_limit(const struct dc_stream_state *stream,
1031 struct dc_state *state)
1032 {
1033 bool limit = false;
1034
1035 struct dc_stream_status *stream_status;
1036
1037 stream_status = dc_state_get_stream_status(state, stream);
1038
1039 if (stream_status) {
1040 limit = stream_status->mall_stream_config.cursor_size_limit_subvp;
1041 }
1042
1043 return limit;
1044 }
1045
dc_state_can_clear_stream_cursor_subvp_limit(const struct dc_stream_state * stream,struct dc_state * state)1046 bool dc_state_can_clear_stream_cursor_subvp_limit(const struct dc_stream_state *stream,
1047 struct dc_state *state)
1048 {
1049 bool can_clear_limit = false;
1050
1051 struct dc_stream_status *stream_status;
1052
1053 stream_status = dc_state_get_stream_status(state, stream);
1054
1055 if (stream_status) {
1056 can_clear_limit = dc_state_get_stream_cursor_subvp_limit(stream, state) &&
1057 (stream_status->mall_stream_config.type == SUBVP_PHANTOM ||
1058 stream->hw_cursor_req ||
1059 !stream_status->mall_stream_config.subvp_limit_cursor_size ||
1060 !stream->cursor_position.enable ||
1061 dc_stream_check_cursor_attributes(stream, state, &stream->cursor_attributes));
1062 }
1063
1064 return can_clear_limit;
1065 }
1066
dc_state_is_subvp_in_use(struct dc_state * state)1067 bool dc_state_is_subvp_in_use(struct dc_state *state)
1068 {
1069 uint32_t i;
1070
1071 for (i = 0; i < state->stream_count; i++) {
1072 if (dc_state_get_stream_subvp_type(state, state->streams[i]) != SUBVP_NONE)
1073 return true;
1074 }
1075
1076 return false;
1077 }
1078