xref: /linux/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c (revision 92c4c9fdc838d3b41a996bb700ea64b9e78fc7ea)
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2024 Advanced Micro Devices, Inc.
4 
5 
6 #include "dml2_internal_shared_types.h"
7 #include "dml21_translation_helper.h"
8 #include "dml2_internal_types.h"
9 #include "dml21_utils.h"
10 #include "dml2_dc_resource_mgmt.h"
11 
12 #include "dml2_core_dcn4_calcs.h"
13 
dml21_helper_find_dml_pipe_idx_by_stream_id(struct dml2_context * ctx,unsigned int stream_id)14 int dml21_helper_find_dml_pipe_idx_by_stream_id(struct dml2_context *ctx, unsigned int stream_id)
15 {
16 	int i;
17 	for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) {
18 		if (ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id_valid[i] && ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id[i] == stream_id)
19 			return  i;
20 	}
21 
22 	return -1;
23 }
24 
dml21_find_dml_pipe_idx_by_plane_id(struct dml2_context * ctx,unsigned int plane_id)25 int dml21_find_dml_pipe_idx_by_plane_id(struct dml2_context *ctx, unsigned int plane_id)
26 {
27 	int i;
28 	for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) {
29 		if (ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id_valid[i] && ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id[i] == plane_id)
30 			return  i;
31 	}
32 
33 	return -1;
34 }
35 
dml21_get_plane_id(const struct dc_state * state,const struct dc_plane_state * plane,unsigned int * plane_id)36 bool dml21_get_plane_id(const struct dc_state *state, const struct dc_plane_state *plane, unsigned int *plane_id)
37 {
38 	int i, j;
39 
40 	if (!plane_id)
41 		return false;
42 
43 	for (i = 0; i < state->stream_count; i++) {
44 		for (j = 0; j < state->stream_status[i].plane_count; j++) {
45 			if (state->stream_status[i].plane_states[j] == plane) {
46 				*plane_id = (i << 16) | j;
47 				return true;
48 			}
49 		}
50 	}
51 
52 	return false;
53 }
54 
dml21_get_dc_plane_idx_from_plane_id(unsigned int plane_id)55 unsigned int dml21_get_dc_plane_idx_from_plane_id(unsigned int plane_id)
56 {
57 	return 0xffff & plane_id;
58 }
59 
find_valid_pipe_idx_for_stream_index(const struct dml2_context * dml_ctx,unsigned int * dml_pipe_idx,unsigned int stream_index)60 void find_valid_pipe_idx_for_stream_index(const struct dml2_context *dml_ctx, unsigned int *dml_pipe_idx, unsigned int stream_index)
61 {
62 	unsigned int i = 0;
63 
64 	for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) {
65 		if (dml_ctx->v21.mode_programming.programming->plane_programming[i].plane_descriptor->stream_index == stream_index) {
66 			*dml_pipe_idx = i;
67 			return;
68 		}
69 	}
70 }
71 
find_pipe_regs_idx(const struct dml2_context * dml_ctx,struct pipe_ctx * pipe,unsigned int * pipe_regs_idx)72 void find_pipe_regs_idx(const struct dml2_context *dml_ctx,
73 		struct pipe_ctx *pipe, unsigned int *pipe_regs_idx)
74 {
75 	struct pipe_ctx *opp_head = dml_ctx->config.callbacks.get_opp_head(pipe);
76 
77 	*pipe_regs_idx = dml_ctx->config.callbacks.get_odm_slice_index(opp_head);
78 
79 	if (pipe->plane_state)
80 		*pipe_regs_idx += dml_ctx->config.callbacks.get_mpc_slice_index(pipe);
81 }
82 
83 /* places pipe references into pipes arrays and returns number of pipes */
dml21_find_dc_pipes_for_plane(const struct dc * in_dc,struct dc_state * context,struct dml2_context * dml_ctx,struct pipe_ctx * dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__],struct pipe_ctx * dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__],int dml_plane_idx)84 int dml21_find_dc_pipes_for_plane(const struct dc *in_dc,
85 		struct dc_state *context,
86 		struct dml2_context *dml_ctx,
87 		struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__],
88 		struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__],
89 		int dml_plane_idx)
90 {
91 	(void)in_dc;
92 	unsigned int dml_stream_index;
93 	unsigned int main_stream_id;
94 	unsigned int dc_plane_index;
95 	struct dc_stream_state *dc_main_stream;
96 	struct dc_stream_status *dc_main_stream_status;
97 	struct dc_plane_state *dc_main_plane;
98 	struct dc_stream_state *dc_phantom_stream;
99 	struct dc_stream_status *dc_phantom_stream_status;
100 	struct dc_plane_state *dc_phantom_plane;
101 	int num_pipes = 0;
102 
103 	memset(dc_main_pipes, 0, sizeof(struct pipe_ctx *) * __DML2_WRAPPER_MAX_STREAMS_PLANES__);
104 	memset(dc_phantom_pipes, 0, sizeof(struct pipe_ctx *) * __DML2_WRAPPER_MAX_STREAMS_PLANES__);
105 
106 	dml_stream_index = dml_ctx->v21.mode_programming.programming->plane_programming[dml_plane_idx].plane_descriptor->stream_index;
107 	main_stream_id = dml_ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id[dml_stream_index];
108 
109 	dc_main_stream = dml_ctx->config.callbacks.get_stream_from_id(context, main_stream_id);
110 	dc_main_stream_status = dml_ctx->config.callbacks.get_stream_status(context, dc_main_stream);
111 	if (!dc_main_stream_status)
112 		return num_pipes;
113 
114 	/* find main plane based on id */
115 	dc_plane_index = dml21_get_dc_plane_idx_from_plane_id(dml_ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id[dml_plane_idx]);
116 	dc_main_plane = dc_main_stream_status->plane_states[dc_plane_index];
117 
118 	if (dc_main_plane) {
119 		num_pipes = dml_ctx->config.callbacks.get_dpp_pipes_for_plane(dc_main_plane, &context->res_ctx, dc_main_pipes);
120 	} else {
121 		/* stream was configured with dummy plane, so get pipes from opp head */
122 		struct pipe_ctx *otg_master_pipe = dml_ctx->config.callbacks.get_otg_master_for_stream(&context->res_ctx, dc_main_stream);
123 		if (otg_master_pipe != NULL)
124 			num_pipes = dml_ctx->config.callbacks.get_opp_heads_for_otg_master(otg_master_pipe, &context->res_ctx, dc_main_pipes);
125 	}
126 
127 	/* if phantom exists, find associated pipes */
128 	dc_phantom_stream = dml_ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, dc_main_stream);
129 	if (dc_phantom_stream && num_pipes > 0) {
130 		dc_phantom_stream_status = dml_ctx->config.callbacks.get_stream_status(context, dc_phantom_stream);
131 
132 		if (dc_phantom_stream_status) {
133 			/* phantom plane will have same index as main */
134 			dc_phantom_plane = dc_phantom_stream_status->plane_states[dc_plane_index];
135 
136 			if (dc_phantom_plane) {
137 				/* only care about phantom pipes if they contain the phantom plane */
138 				dml_ctx->config.callbacks.get_dpp_pipes_for_plane(dc_phantom_plane, &context->res_ctx, dc_phantom_pipes);
139 			}
140 		}
141 	}
142 
143 	return num_pipes;
144 }
145 
dml21_pipe_populate_global_sync(struct dml2_context * dml_ctx,struct dc_state * context,struct pipe_ctx * pipe_ctx,struct dml2_per_stream_programming * stream_programming)146 void dml21_pipe_populate_global_sync(struct dml2_context *dml_ctx,
147 	struct dc_state *context,
148 	struct pipe_ctx *pipe_ctx,
149 	struct dml2_per_stream_programming *stream_programming)
150 {
151 	union dml2_global_sync_programming *global_sync = &stream_programming->global_sync;
152 
153 	if (dml_ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) {
154 		/* phantom has its own global sync */
155 		global_sync = &stream_programming->phantom_stream.global_sync;
156 	}
157 
158 	memcpy(&pipe_ctx->global_sync,
159 		global_sync,
160 		sizeof(union dml2_global_sync_programming));
161 }
162 
dml21_populate_mall_allocation_size(struct dc_state * context,struct dml2_context * in_ctx,struct dml2_per_plane_programming * pln_prog,struct pipe_ctx * dc_pipe)163 void dml21_populate_mall_allocation_size(struct dc_state *context,
164 		struct dml2_context *in_ctx,
165 		struct dml2_per_plane_programming *pln_prog,
166 		struct pipe_ctx *dc_pipe)
167 {
168 
169 	/* Reuse MALL Allocation Sizes logic from dcn32_fpu.c */
170 	/* Count from active, top pipes per plane only. Only add mall_ss_size_bytes for each unique plane. */
171 	if (dc_pipe->stream && dc_pipe->plane_state &&
172 			(dc_pipe->top_pipe == NULL ||
173 			dc_pipe->plane_state != dc_pipe->top_pipe->plane_state) &&
174 			dc_pipe->prev_odm_pipe == NULL) {
175 		/* SS: all active surfaces stored in MALL */
176 		if (in_ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, dc_pipe) != SUBVP_PHANTOM) {
177 			dc_pipe->surface_size_in_mall_bytes = pln_prog->surface_size_mall_bytes;
178 			context->bw_ctx.bw.dcn.mall_ss_size_bytes += dc_pipe->surface_size_in_mall_bytes;
179 		} else {
180 			/* SUBVP: phantom surfaces only stored in MALL */
181 			dc_pipe->surface_size_in_mall_bytes = pln_prog->svp_size_mall_bytes;
182 			context->bw_ctx.bw.dcn.mall_subvp_size_bytes += dc_pipe->surface_size_in_mall_bytes;
183 		}
184 	}
185 }
186 
check_dp2p0_output_encoder(const struct pipe_ctx * pipe_ctx)187 bool check_dp2p0_output_encoder(const struct pipe_ctx *pipe_ctx)
188 {
189 	/* If this assert is hit then we have a link encoder dynamic management issue */
190 	ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true);
191 	return (pipe_ctx->stream_res.hpo_dp_stream_enc &&
192 		pipe_ctx->link_res.hpo_dp_link_enc &&
193 		dc_is_dp_signal(pipe_ctx->stream->signal));
194 }
195 
196 
is_sub_vp_enabled(struct dc * dc,struct dc_state * context)197 static bool is_sub_vp_enabled(struct dc *dc, struct dc_state *context)
198 {
199 	int i;
200 
201 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
202 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
203 
204 		if (pipe_ctx->stream && dc_state_get_paired_subvp_stream(context, pipe_ctx->stream) &&
205 							dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_MAIN) {
206 			return true;
207 		}
208 	}
209 	return false;
210 }
211 
212 
dml21_program_dc_pipe(struct dml2_context * dml_ctx,struct dc_state * context,struct pipe_ctx * pipe_ctx,struct dml2_per_plane_programming * pln_prog,struct dml2_per_stream_programming * stream_prog)213 void dml21_program_dc_pipe(struct dml2_context *dml_ctx, struct dc_state *context, struct pipe_ctx *pipe_ctx, struct dml2_per_plane_programming *pln_prog,
214 		struct dml2_per_stream_programming *stream_prog)
215 {
216 	unsigned int pipe_reg_index = 0;
217 
218 	dml21_pipe_populate_global_sync(dml_ctx, context, pipe_ctx, stream_prog);
219 	find_pipe_regs_idx(dml_ctx, pipe_ctx, &pipe_reg_index);
220 
221 	if (dml_ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) {
222 		memcpy(&pipe_ctx->hubp_regs, pln_prog->phantom_plane.pipe_regs[pipe_reg_index], sizeof(struct dml2_dchub_per_pipe_register_set));
223 		pipe_ctx->unbounded_req = false;
224 		pipe_ctx->det_buffer_size_kb = 0;
225 	} else {
226 		memcpy(&pipe_ctx->hubp_regs, pln_prog->pipe_regs[pipe_reg_index], sizeof(struct dml2_dchub_per_pipe_register_set));
227 		pipe_ctx->unbounded_req = pln_prog->pipe_regs[pipe_reg_index]->rq_regs.unbounded_request_enabled;
228 		pipe_ctx->det_buffer_size_kb = pln_prog->pipe_regs[pipe_reg_index]->det_size * 64;
229 	}
230 
231 	pipe_ctx->plane_res.bw.dppclk_khz = pln_prog->min_clocks.dcn4x.dppclk_khz;
232 	if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipe_ctx->plane_res.bw.dppclk_khz)
233 		context->bw_ctx.bw.dcn.clk.dppclk_khz = pipe_ctx->plane_res.bw.dppclk_khz;
234 
235 	dml21_populate_mall_allocation_size(context, dml_ctx, pln_prog, pipe_ctx);
236 
237 	bool sub_vp_enabled = is_sub_vp_enabled(pipe_ctx->stream->ctx->dc, context);
238 
239 	dml21_set_dc_p_state_type(pipe_ctx, stream_prog, sub_vp_enabled);
240 }
241 
dml21_add_phantom_stream(struct dml2_context * dml_ctx,const struct dc * dc,struct dc_state * context,struct dc_stream_state * main_stream,struct dml2_per_stream_programming * stream_programming)242 static struct dc_stream_state *dml21_add_phantom_stream(struct dml2_context *dml_ctx,
243 	const struct dc *dc,
244 	struct dc_state *context,
245 	struct dc_stream_state *main_stream,
246 	struct dml2_per_stream_programming *stream_programming)
247 {
248 	struct dc_stream_state *phantom_stream;
249 	struct dml2_stream_parameters *phantom_stream_descriptor = &stream_programming->phantom_stream.descriptor;
250 
251 	phantom_stream = dml_ctx->config.svp_pstate.callbacks.create_phantom_stream(dc, context, main_stream);
252 	if (!phantom_stream)
253 		return NULL;
254 
255 	/* copy details of phantom stream from main */
256 	memcpy(&phantom_stream->timing, &main_stream->timing, sizeof(phantom_stream->timing));
257 	memcpy(&phantom_stream->src, &main_stream->src, sizeof(phantom_stream->src));
258 	memcpy(&phantom_stream->dst, &main_stream->dst, sizeof(phantom_stream->dst));
259 
260 	/* modify timing for phantom */
261 	phantom_stream->timing.v_front_porch = phantom_stream_descriptor->timing.v_front_porch;
262 	phantom_stream->timing.v_addressable = phantom_stream_descriptor->timing.v_active;
263 	phantom_stream->timing.v_total = phantom_stream_descriptor->timing.v_total;
264 	phantom_stream->timing.flags.DSC = 0; // phantom always has DSC disabled
265 
266 	phantom_stream->dst.y = 0;
267 	phantom_stream->dst.height = stream_programming->phantom_stream.descriptor.timing.v_active;
268 
269 	phantom_stream->src.y = 0;
270 	phantom_stream->src.height = (double)phantom_stream_descriptor->timing.v_active * (double)main_stream->src.height / (double)main_stream->dst.height;
271 
272 	phantom_stream->use_dynamic_meta = false;
273 
274 	dml_ctx->config.svp_pstate.callbacks.add_phantom_stream(dc, context, phantom_stream, main_stream);
275 
276 	return phantom_stream;
277 }
278 
dml21_add_phantom_plane(struct dml2_context * dml_ctx,const struct dc * dc,struct dc_state * context,struct dc_stream_state * phantom_stream,struct dc_plane_state * main_plane,struct dml2_per_plane_programming * plane_programming)279 static struct dc_plane_state *dml21_add_phantom_plane(struct dml2_context *dml_ctx,
280 	const struct dc *dc,
281 	struct dc_state *context,
282 	struct dc_stream_state *phantom_stream,
283 	struct dc_plane_state *main_plane,
284 	struct dml2_per_plane_programming *plane_programming)
285 {
286 	(void)plane_programming;
287 	struct dc_plane_state *phantom_plane;
288 
289 	phantom_plane = dml_ctx->config.svp_pstate.callbacks.create_phantom_plane(dc, context, main_plane);
290 	if (!phantom_plane)
291 		return NULL;
292 
293 	phantom_plane->format = main_plane->format;
294 	phantom_plane->rotation = main_plane->rotation;
295 	phantom_plane->visible = main_plane->visible;
296 
297 	memcpy(&phantom_plane->address, &main_plane->address, sizeof(phantom_plane->address));
298 	memcpy(&phantom_plane->scaling_quality, &main_plane->scaling_quality,
299 		sizeof(phantom_plane->scaling_quality));
300 	memcpy(&phantom_plane->src_rect, &main_plane->src_rect, sizeof(phantom_plane->src_rect));
301 	memcpy(&phantom_plane->dst_rect, &main_plane->dst_rect, sizeof(phantom_plane->dst_rect));
302 	memcpy(&phantom_plane->clip_rect, &main_plane->clip_rect, sizeof(phantom_plane->clip_rect));
303 	memcpy(&phantom_plane->plane_size, &main_plane->plane_size,
304 		sizeof(phantom_plane->plane_size));
305 	memcpy(&phantom_plane->tiling_info, &main_plane->tiling_info,
306 		sizeof(phantom_plane->tiling_info));
307 	memcpy(&phantom_plane->dcc, &main_plane->dcc, sizeof(phantom_plane->dcc));
308 
309 	phantom_plane->format = main_plane->format;
310 	phantom_plane->rotation = main_plane->rotation;
311 	phantom_plane->visible = main_plane->visible;
312 
313 	/* Shadow pipe has small viewport. */
314 	phantom_plane->clip_rect.y = 0;
315 	phantom_plane->clip_rect.height = phantom_stream->src.height;
316 
317 	dml_ctx->config.svp_pstate.callbacks.add_phantom_plane(dc, phantom_stream, phantom_plane, context);
318 
319 	return phantom_plane;
320 }
321 
dml21_handle_phantom_streams_planes(const struct dc * dc,struct dc_state * context,struct dml2_context * dml_ctx)322 void dml21_handle_phantom_streams_planes(const struct dc *dc, struct dc_state *context, struct dml2_context *dml_ctx)
323 {
324 	unsigned int dml_stream_index, dml_plane_index, dc_plane_index;
325 	struct dc_stream_state *main_stream;
326 	struct dc_stream_status *main_stream_status;
327 	struct dc_stream_state *phantom_stream;
328 	struct dc_plane_state *main_plane;
329 	bool phantoms_added = false;
330 
331 	/* create phantom streams and planes and add to context */
332 	for (dml_stream_index = 0; dml_stream_index < dml_ctx->v21.mode_programming.programming->display_config.num_streams; dml_stream_index++) {
333 		/* iterate through DML streams looking for phantoms */
334 		if (dml_ctx->v21.mode_programming.programming->stream_programming[dml_stream_index].phantom_stream.enabled) {
335 			/* find associated dc stream */
336 			main_stream = dml_ctx->config.callbacks.get_stream_from_id(context,
337 					dml_ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id[dml_stream_index]);
338 
339 			main_stream_status = dml_ctx->config.callbacks.get_stream_status(context, main_stream);
340 
341 			if (!main_stream_status || main_stream_status->plane_count == 0)
342 				continue;
343 
344 			/* create phantom stream for subvp enabled stream */
345 			phantom_stream = dml21_add_phantom_stream(dml_ctx,
346 					dc,
347 					context,
348 					main_stream,
349 					&dml_ctx->v21.mode_programming.programming->stream_programming[dml_stream_index]);
350 
351 			if (!phantom_stream)
352 				continue;
353 
354 			/* iterate through DML planes associated with this stream */
355 			for (dml_plane_index = 0; dml_plane_index < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_plane_index++) {
356 				if (dml_ctx->v21.mode_programming.programming->plane_programming[dml_plane_index].plane_descriptor->stream_index == dml_stream_index) {
357 					/* find associated dc plane */
358 					dc_plane_index = dml21_get_dc_plane_idx_from_plane_id(dml_ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id[dml_plane_index]);
359 					main_plane = main_stream_status->plane_states[dc_plane_index];
360 
361 					/* create phantom planes for subvp enabled plane */
362 					dml21_add_phantom_plane(dml_ctx,
363 							dc,
364 							context,
365 							phantom_stream,
366 							main_plane,
367 							&dml_ctx->v21.mode_programming.programming->plane_programming[dml_plane_index]);
368 
369 					phantoms_added = true;
370 				}
371 			}
372 		}
373 	}
374 
375 	if (phantoms_added)
376 		dml2_map_dc_pipes(dml_ctx, context, NULL, &dml_ctx->v21.dml_to_dc_pipe_mapping, dc->current_state);
377 }
378 
379 
dml21_build_fams2_stream_programming_v2(const struct dc * dc,struct dc_state * context,struct dml2_context * dml_ctx)380 static unsigned int dml21_build_fams2_stream_programming_v2(const struct dc *dc,
381 		struct dc_state *context,
382 		struct dml2_context *dml_ctx)
383 {
384 	int dc_stream_idx, dc_plane_idx, dc_pipe_idx;
385 	unsigned int num_fams2_streams = 0;
386 
387 	for (dc_stream_idx = 0; dc_stream_idx < context->stream_count; dc_stream_idx++) {
388 		int dml_stream_idx;
389 		struct dc_stream_state *phantom_stream;
390 		struct dc_stream_status *phantom_status;
391 		enum fams2_stream_type type = 0;
392 
393 		union dmub_cmd_fams2_config *static_base_state = &context->bw_ctx.bw.dcn.fams2_stream_base_params[num_fams2_streams];
394 		union dmub_cmd_fams2_config *static_sub_state = &context->bw_ctx.bw.dcn.fams2_stream_sub_params[num_fams2_streams];
395 
396 		struct dc_stream_state *stream = context->streams[dc_stream_idx];
397 
398 		if (context->stream_status[dc_stream_idx].plane_count == 0 ||
399 				dml_ctx->config.svp_pstate.callbacks.get_stream_subvp_type(context, stream) == SUBVP_PHANTOM) {
400 			/* can ignore blanked or phantom streams */
401 			continue;
402 		}
403 
404 		dml_stream_idx = dml21_helper_find_dml_pipe_idx_by_stream_id(dml_ctx, stream->stream_id);
405 		if (dml_stream_idx < 0) {
406 			ASSERT(dml_stream_idx >= 0);
407 			continue;
408 		}
409 
410 		/* copy static state from PMO */
411 		memcpy(static_base_state,
412 				&dml_ctx->v21.mode_programming.programming->stream_programming[dml_stream_idx].fams2_base_params,
413 				sizeof(union dmub_cmd_fams2_config));
414 
415 		memcpy(static_sub_state,
416 				&dml_ctx->v21.mode_programming.programming->stream_programming[dml_stream_idx].fams2_sub_params,
417 				sizeof(union dmub_cmd_fams2_config));
418 
419 		switch (dc->debug.fams_version.minor) {
420 		case 1:
421 		default:
422 			type = static_base_state->stream_v1.base.type;
423 
424 			/* get information from context */
425 			ASSERT(context->stream_status[dc_stream_idx].plane_count >= 0 &&
426 					context->stream_status[dc_stream_idx].plane_count <= 0xFF);
427 			ASSERT(context->stream_status[dc_stream_idx].primary_otg_inst >= 0 &&
428 					context->stream_status[dc_stream_idx].primary_otg_inst <= 0xFF);
429 			static_base_state->stream_v1.base.num_planes = (uint8_t)context->stream_status[dc_stream_idx].plane_count;
430 			static_base_state->stream_v1.base.otg_inst = (uint8_t)context->stream_status[dc_stream_idx].primary_otg_inst;
431 
432 			/* populate pipe masks for planes */
433 			for (dc_plane_idx = 0; dc_plane_idx < context->stream_status[dc_stream_idx].plane_count; dc_plane_idx++) {
434 				for (dc_pipe_idx = 0; dc_pipe_idx < dc->res_pool->pipe_count; dc_pipe_idx++) {
435 					if (context->res_ctx.pipe_ctx[dc_pipe_idx].stream &&
436 							context->res_ctx.pipe_ctx[dc_pipe_idx].stream->stream_id == stream->stream_id &&
437 							context->res_ctx.pipe_ctx[dc_pipe_idx].plane_state == context->stream_status[dc_stream_idx].plane_states[dc_plane_idx]) {
438 						static_base_state->stream_v1.base.pipe_mask |= (1 << dc_pipe_idx);
439 						static_base_state->stream_v1.base.plane_pipe_masks[dc_plane_idx] |= (1 << dc_pipe_idx);
440 					}
441 				}
442 			}
443 		}
444 
445 
446 		/* get per method programming */
447 		switch (type) {
448 		case FAMS2_STREAM_TYPE_VBLANK:
449 		case FAMS2_STREAM_TYPE_VACTIVE:
450 		case FAMS2_STREAM_TYPE_DRR:
451 			break;
452 		case FAMS2_STREAM_TYPE_SUBVP:
453 			phantom_stream = dml_ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, stream);
454 			if (!phantom_stream)
455 				break;
456 
457 			phantom_status = dml_ctx->config.callbacks.get_stream_status(context, phantom_stream);
458 
459 			/* phantom status should always be present */
460 			ASSERT(phantom_status);
461 			if (!phantom_status)
462 				break;
463 
464 			switch (dc->debug.fams_version.minor) {
465 			case 1:
466 			default:
467 				ASSERT(phantom_status->primary_otg_inst >= 0 &&
468 						phantom_status->primary_otg_inst <= 0xFF);
469 				static_sub_state->stream_v1.sub_state.subvp.phantom_otg_inst = (uint8_t)phantom_status->primary_otg_inst;
470 
471 				/* populate pipe masks for phantom planes */
472 				for (dc_plane_idx = 0; dc_plane_idx < phantom_status->plane_count; dc_plane_idx++) {
473 					for (dc_pipe_idx = 0; dc_pipe_idx < dc->res_pool->pipe_count; dc_pipe_idx++) {
474 						if (context->res_ctx.pipe_ctx[dc_pipe_idx].stream &&
475 								context->res_ctx.pipe_ctx[dc_pipe_idx].stream->stream_id == phantom_stream->stream_id &&
476 								context->res_ctx.pipe_ctx[dc_pipe_idx].plane_state == phantom_status->plane_states[dc_plane_idx]) {
477 							switch (dc->debug.fams_version.minor) {
478 							case 1:
479 							default:
480 								static_sub_state->stream_v1.sub_state.subvp.phantom_pipe_mask |= (1 << dc_pipe_idx);
481 								static_sub_state->stream_v1.sub_state.subvp.phantom_plane_pipe_masks[dc_plane_idx] |= (1 << dc_pipe_idx);
482 							}
483 						}
484 					}
485 				}
486 			}
487 			break;
488 		default:
489 			ASSERT(false);
490 			break;
491 		}
492 
493 		num_fams2_streams++;
494 	}
495 
496 	return num_fams2_streams;
497 }
498 
dml21_build_fams2_programming(const struct dc * dc,struct dc_state * context,struct dml2_context * dml_ctx)499 void dml21_build_fams2_programming(const struct dc *dc,
500 		struct dc_state *context,
501 		struct dml2_context *dml_ctx)
502 {
503 	unsigned int num_fams2_streams = 0;
504 
505 	/* reset fams2 data */
506 	memset(&context->bw_ctx.bw.dcn.fams2_stream_base_params, 0, sizeof(union dmub_cmd_fams2_config) * DML2_MAX_PLANES);
507 	memset(&context->bw_ctx.bw.dcn.fams2_stream_sub_params, 0, sizeof(union dmub_cmd_fams2_config) * DML2_MAX_PLANES);
508 	memset(&context->bw_ctx.bw.dcn.fams2_stream_sub_params_v2, 0, sizeof(union dmub_fams2_stream_static_sub_state_v2) * DML2_MAX_PLANES);
509 	memset(&context->bw_ctx.bw.dcn.fams2_global_config, 0, sizeof(struct dmub_cmd_fams2_global_config));
510 
511 	if (dml_ctx->v21.mode_programming.programming->fams2_required ||
512 			dml_ctx->v21.mode_programming.programming->legacy_pstate_info_for_dmu) {
513 		if (dc->debug.fams_version.major == 2) {
514 			num_fams2_streams = dml21_build_fams2_stream_programming_v2(dc, context, dml_ctx);
515 		}
516 	}
517 
518 	if (num_fams2_streams > 0) {
519 		/* copy FAMS2 configuration */
520 		memcpy(&context->bw_ctx.bw.dcn.fams2_global_config,
521 				&dml_ctx->v21.mode_programming.programming->fams2_global_config,
522 				sizeof(struct dmub_cmd_fams2_global_config));
523 
524 		context->bw_ctx.bw.dcn.fams2_global_config.num_streams = num_fams2_streams;
525 	}
526 
527 	context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching =
528 			(context->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable != 0);
529 }
530 
dml21_is_plane1_enabled(enum dml2_source_format_class source_format)531 bool dml21_is_plane1_enabled(enum dml2_source_format_class source_format)
532 {
533 	return source_format >= dml2_420_8 && source_format <= dml2_rgbe_alpha;
534 }
535