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