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