xref: /linux/drivers/gpu/drm/amd/display/dc/core/dc_state.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
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