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