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