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