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 
14 
15 int dml21_helper_find_dml_pipe_idx_by_stream_id(struct dml2_context *ctx, unsigned int stream_id)
16 {
17 	int i;
18 	for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) {
19 		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)
20 			return  i;
21 	}
22 
23 	return -1;
24 }
25 
26 int dml21_find_dml_pipe_idx_by_plane_id(struct dml2_context *ctx, unsigned int plane_id)
27 {
28 	int i;
29 	for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) {
30 		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)
31 			return  i;
32 	}
33 
34 	return -1;
35 }
36 
37 bool dml21_get_plane_id(const struct dc_state *state, const struct dc_plane_state *plane, unsigned int *plane_id)
38 {
39 	int i, j;
40 
41 	if (!plane_id)
42 		return false;
43 
44 	for (i = 0; i < state->stream_count; i++) {
45 		for (j = 0; j < state->stream_status[i].plane_count; j++) {
46 			if (state->stream_status[i].plane_states[j] == plane) {
47 				*plane_id = (i << 16) | j;
48 				return true;
49 			}
50 		}
51 	}
52 
53 	return false;
54 }
55 
56 unsigned int dml21_get_dc_plane_idx_from_plane_id(unsigned int plane_id)
57 {
58 	return 0xffff & plane_id;
59 }
60 
61 void find_valid_pipe_idx_for_stream_index(const struct dml2_context *dml_ctx, unsigned int *dml_pipe_idx, unsigned int stream_index)
62 {
63 	unsigned int i = 0;
64 
65 	for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) {
66 		if (dml_ctx->v21.mode_programming.programming->plane_programming[i].plane_descriptor->stream_index == stream_index) {
67 			*dml_pipe_idx = i;
68 			return;
69 		}
70 	}
71 }
72 
73 void find_pipe_regs_idx(const struct dml2_context *dml_ctx,
74 		struct pipe_ctx *pipe, unsigned int *pipe_regs_idx)
75 {
76 	struct pipe_ctx *opp_head = dml_ctx->config.callbacks.get_opp_head(pipe);
77 
78 	*pipe_regs_idx = dml_ctx->config.callbacks.get_odm_slice_index(opp_head);
79 
80 	if (pipe->plane_state)
81 		*pipe_regs_idx += dml_ctx->config.callbacks.get_mpc_slice_index(pipe);
82 }
83 
84 /* places pipe references into pipes arrays and returns number of pipes */
85 int dml21_find_dc_pipes_for_plane(const struct dc *in_dc,
86 		struct dc_state *context,
87 		struct dml2_context *dml_ctx,
88 		struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__],
89 		struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__],
90 		int dml_plane_idx)
91 {
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 
146 
147 void dml21_update_pipe_ctx_dchub_regs(struct dml2_display_rq_regs *rq_regs,
148 	struct dml2_display_dlg_regs *disp_dlg_regs,
149 	struct dml2_display_ttu_regs *disp_ttu_regs,
150 	struct pipe_ctx *out)
151 {
152 	memset(&out->rq_regs, 0, sizeof(out->rq_regs));
153 	out->rq_regs.rq_regs_l.chunk_size = rq_regs->rq_regs_l.chunk_size;
154 	out->rq_regs.rq_regs_l.min_chunk_size = rq_regs->rq_regs_l.min_chunk_size;
155 	//out->rq_regs.rq_regs_l.meta_chunk_size = rq_regs->rq_regs_l.meta_chunk_size;
156 	//out->rq_regs.rq_regs_l.min_meta_chunk_size = rq_regs->rq_regs_l.min_meta_chunk_size;
157 	out->rq_regs.rq_regs_l.dpte_group_size = rq_regs->rq_regs_l.dpte_group_size;
158 	out->rq_regs.rq_regs_l.mpte_group_size = rq_regs->rq_regs_l.mpte_group_size;
159 	out->rq_regs.rq_regs_l.swath_height = rq_regs->rq_regs_l.swath_height;
160 	out->rq_regs.rq_regs_l.pte_row_height_linear = rq_regs->rq_regs_l.pte_row_height_linear;
161 
162 	out->rq_regs.rq_regs_c.chunk_size = rq_regs->rq_regs_c.chunk_size;
163 	out->rq_regs.rq_regs_c.min_chunk_size = rq_regs->rq_regs_c.min_chunk_size;
164 	//out->rq_regs.rq_regs_c.meta_chunk_size = rq_regs->rq_regs_c.meta_chunk_size;
165 	//out->rq_regs.rq_regs_c.min_meta_chunk_size = rq_regs->rq_regs_c.min_meta_chunk_size;
166 	out->rq_regs.rq_regs_c.dpte_group_size = rq_regs->rq_regs_c.dpte_group_size;
167 	out->rq_regs.rq_regs_c.mpte_group_size = rq_regs->rq_regs_c.mpte_group_size;
168 	out->rq_regs.rq_regs_c.swath_height = rq_regs->rq_regs_c.swath_height;
169 	out->rq_regs.rq_regs_c.pte_row_height_linear = rq_regs->rq_regs_c.pte_row_height_linear;
170 
171 	out->rq_regs.drq_expansion_mode = rq_regs->drq_expansion_mode;
172 	out->rq_regs.prq_expansion_mode = rq_regs->prq_expansion_mode;
173 	//out->rq_regs.mrq_expansion_mode = rq_regs->mrq_expansion_mode;
174 	out->rq_regs.crq_expansion_mode = rq_regs->crq_expansion_mode;
175 	out->rq_regs.plane1_base_address = rq_regs->plane1_base_address;
176 	out->unbounded_req = rq_regs->unbounded_request_enabled;
177 
178 	memset(&out->dlg_regs, 0, sizeof(out->dlg_regs));
179 	out->dlg_regs.refcyc_h_blank_end = disp_dlg_regs->refcyc_h_blank_end;
180 	out->dlg_regs.dlg_vblank_end = disp_dlg_regs->dlg_vblank_end;
181 	out->dlg_regs.min_dst_y_next_start = disp_dlg_regs->min_dst_y_next_start;
182 	out->dlg_regs.refcyc_per_htotal = disp_dlg_regs->refcyc_per_htotal;
183 	out->dlg_regs.refcyc_x_after_scaler = disp_dlg_regs->refcyc_x_after_scaler;
184 	out->dlg_regs.dst_y_after_scaler = disp_dlg_regs->dst_y_after_scaler;
185 	out->dlg_regs.dst_y_prefetch = disp_dlg_regs->dst_y_prefetch;
186 	out->dlg_regs.dst_y_per_vm_vblank = disp_dlg_regs->dst_y_per_vm_vblank;
187 	out->dlg_regs.dst_y_per_row_vblank = disp_dlg_regs->dst_y_per_row_vblank;
188 	out->dlg_regs.dst_y_per_vm_flip = disp_dlg_regs->dst_y_per_vm_flip;
189 	out->dlg_regs.dst_y_per_row_flip = disp_dlg_regs->dst_y_per_row_flip;
190 	out->dlg_regs.ref_freq_to_pix_freq = disp_dlg_regs->ref_freq_to_pix_freq;
191 	out->dlg_regs.vratio_prefetch = disp_dlg_regs->vratio_prefetch;
192 	out->dlg_regs.vratio_prefetch_c = disp_dlg_regs->vratio_prefetch_c;
193 	out->dlg_regs.refcyc_per_tdlut_group = disp_dlg_regs->refcyc_per_tdlut_group;
194 	out->dlg_regs.refcyc_per_pte_group_vblank_l = disp_dlg_regs->refcyc_per_pte_group_vblank_l;
195 	out->dlg_regs.refcyc_per_pte_group_vblank_c = disp_dlg_regs->refcyc_per_pte_group_vblank_c;
196 	//out->dlg_regs.refcyc_per_meta_chunk_vblank_l = disp_dlg_regs->refcyc_per_meta_chunk_vblank_l;
197 	//out->dlg_regs.refcyc_per_meta_chunk_vblank_c = disp_dlg_regs->refcyc_per_meta_chunk_vblank_c;
198 	out->dlg_regs.refcyc_per_pte_group_flip_l = disp_dlg_regs->refcyc_per_pte_group_flip_l;
199 	out->dlg_regs.refcyc_per_pte_group_flip_c = disp_dlg_regs->refcyc_per_pte_group_flip_c;
200 	//out->dlg_regs.refcyc_per_meta_chunk_flip_l = disp_dlg_regs->refcyc_per_meta_chunk_flip_l;
201 	//out->dlg_regs.refcyc_per_meta_chunk_flip_c = disp_dlg_regs->refcyc_per_meta_chunk_flip_c;
202 	out->dlg_regs.dst_y_per_pte_row_nom_l = disp_dlg_regs->dst_y_per_pte_row_nom_l;
203 	out->dlg_regs.dst_y_per_pte_row_nom_c = disp_dlg_regs->dst_y_per_pte_row_nom_c;
204 	out->dlg_regs.refcyc_per_pte_group_nom_l = disp_dlg_regs->refcyc_per_pte_group_nom_l;
205 	out->dlg_regs.refcyc_per_pte_group_nom_c = disp_dlg_regs->refcyc_per_pte_group_nom_c;
206 	//out->dlg_regs.dst_y_per_meta_row_nom_l = disp_dlg_regs->dst_y_per_meta_row_nom_l;
207 	//out->dlg_regs.dst_y_per_meta_row_nom_c = disp_dlg_regs->dst_y_per_meta_row_nom_c;
208 	//out->dlg_regs.refcyc_per_meta_chunk_nom_l = disp_dlg_regs->refcyc_per_meta_chunk_nom_l;
209 	//out->dlg_regs.refcyc_per_meta_chunk_nom_c = disp_dlg_regs->refcyc_per_meta_chunk_nom_c;
210 	out->dlg_regs.refcyc_per_line_delivery_pre_l = disp_dlg_regs->refcyc_per_line_delivery_pre_l;
211 	out->dlg_regs.refcyc_per_line_delivery_pre_c = disp_dlg_regs->refcyc_per_line_delivery_pre_c;
212 	out->dlg_regs.refcyc_per_line_delivery_l = disp_dlg_regs->refcyc_per_line_delivery_l;
213 	out->dlg_regs.refcyc_per_line_delivery_c = disp_dlg_regs->refcyc_per_line_delivery_c;
214 	out->dlg_regs.refcyc_per_vm_group_vblank = disp_dlg_regs->refcyc_per_vm_group_vblank;
215 	out->dlg_regs.refcyc_per_vm_group_flip = disp_dlg_regs->refcyc_per_vm_group_flip;
216 	out->dlg_regs.refcyc_per_vm_req_vblank = disp_dlg_regs->refcyc_per_vm_req_vblank;
217 	out->dlg_regs.refcyc_per_vm_req_flip = disp_dlg_regs->refcyc_per_vm_req_flip;
218 	out->dlg_regs.dst_y_offset_cur0 = disp_dlg_regs->dst_y_offset_cur0;
219 	out->dlg_regs.chunk_hdl_adjust_cur0 = disp_dlg_regs->chunk_hdl_adjust_cur0;
220 	//out->dlg_regs.dst_y_offset_cur1 = disp_dlg_regs->dst_y_offset_cur1;
221 	//out->dlg_regs.chunk_hdl_adjust_cur1 = disp_dlg_regs->chunk_hdl_adjust_cur1;
222 	out->dlg_regs.vready_after_vcount0 = disp_dlg_regs->vready_after_vcount0;
223 	out->dlg_regs.dst_y_delta_drq_limit = disp_dlg_regs->dst_y_delta_drq_limit;
224 	out->dlg_regs.refcyc_per_vm_dmdata = disp_dlg_regs->refcyc_per_vm_dmdata;
225 	out->dlg_regs.dmdata_dl_delta = disp_dlg_regs->dmdata_dl_delta;
226 
227 	memset(&out->ttu_regs, 0, sizeof(out->ttu_regs));
228 	out->ttu_regs.qos_level_low_wm = disp_ttu_regs->qos_level_low_wm;
229 	out->ttu_regs.qos_level_high_wm = disp_ttu_regs->qos_level_high_wm;
230 	out->ttu_regs.min_ttu_vblank = disp_ttu_regs->min_ttu_vblank;
231 	out->ttu_regs.qos_level_flip = disp_ttu_regs->qos_level_flip;
232 	out->ttu_regs.refcyc_per_req_delivery_l = disp_ttu_regs->refcyc_per_req_delivery_l;
233 	out->ttu_regs.refcyc_per_req_delivery_c = disp_ttu_regs->refcyc_per_req_delivery_c;
234 	out->ttu_regs.refcyc_per_req_delivery_cur0 = disp_ttu_regs->refcyc_per_req_delivery_cur0;
235 	//out->ttu_regs.refcyc_per_req_delivery_cur1 = disp_ttu_regs->refcyc_per_req_delivery_cur1;
236 	out->ttu_regs.refcyc_per_req_delivery_pre_l = disp_ttu_regs->refcyc_per_req_delivery_pre_l;
237 	out->ttu_regs.refcyc_per_req_delivery_pre_c = disp_ttu_regs->refcyc_per_req_delivery_pre_c;
238 	out->ttu_regs.refcyc_per_req_delivery_pre_cur0 = disp_ttu_regs->refcyc_per_req_delivery_pre_cur0;
239 	//out->ttu_regs.refcyc_per_req_delivery_pre_cur1 = disp_ttu_regs->refcyc_per_req_delivery_pre_cur1;
240 	out->ttu_regs.qos_level_fixed_l = disp_ttu_regs->qos_level_fixed_l;
241 	out->ttu_regs.qos_level_fixed_c = disp_ttu_regs->qos_level_fixed_c;
242 	out->ttu_regs.qos_level_fixed_cur0 = disp_ttu_regs->qos_level_fixed_cur0;
243 	//out->ttu_regs.qos_level_fixed_cur1 = disp_ttu_regs->qos_level_fixed_cur1;
244 	out->ttu_regs.qos_ramp_disable_l = disp_ttu_regs->qos_ramp_disable_l;
245 	out->ttu_regs.qos_ramp_disable_c = disp_ttu_regs->qos_ramp_disable_c;
246 	out->ttu_regs.qos_ramp_disable_cur0 = disp_ttu_regs->qos_ramp_disable_cur0;
247 	//out->ttu_regs.qos_ramp_disable_cur1 = disp_ttu_regs->qos_ramp_disable_cur1;
248 }
249 
250 void dml21_populate_mall_allocation_size(struct dc_state *context,
251 		struct dml2_context *in_ctx,
252 		struct dml2_per_plane_programming *pln_prog,
253 		struct pipe_ctx *dc_pipe)
254 {
255 
256 	/* Reuse MALL Allocation Sizes logic from dcn32_fpu.c */
257 	/* Count from active, top pipes per plane only. Only add mall_ss_size_bytes for each unique plane. */
258 	if (dc_pipe->stream && dc_pipe->plane_state &&
259 			(dc_pipe->top_pipe == NULL ||
260 			dc_pipe->plane_state != dc_pipe->top_pipe->plane_state) &&
261 			dc_pipe->prev_odm_pipe == NULL) {
262 		/* SS: all active surfaces stored in MALL */
263 		if (in_ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, dc_pipe) != SUBVP_PHANTOM) {
264 			dc_pipe->surface_size_in_mall_bytes = pln_prog->surface_size_mall_bytes;
265 			context->bw_ctx.bw.dcn.mall_ss_size_bytes += dc_pipe->surface_size_in_mall_bytes;
266 		} else {
267 			/* SUBVP: phantom surfaces only stored in MALL */
268 			dc_pipe->surface_size_in_mall_bytes = pln_prog->svp_size_mall_bytes;
269 			context->bw_ctx.bw.dcn.mall_subvp_size_bytes += dc_pipe->surface_size_in_mall_bytes;
270 		}
271 	}
272 }
273 
274 bool check_dp2p0_output_encoder(const struct pipe_ctx *pipe_ctx)
275 {
276 	/* If this assert is hit then we have a link encoder dynamic management issue */
277 	ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true);
278 	return (pipe_ctx->stream_res.hpo_dp_stream_enc &&
279 		pipe_ctx->link_res.hpo_dp_link_enc &&
280 		dc_is_dp_signal(pipe_ctx->stream->signal));
281 }
282 
283 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,
284 		struct dml2_per_stream_programming *stream_prog)
285 {
286 	unsigned int pipe_reg_index = 0;
287 
288 	dml21_populate_pipe_ctx_dlg_params(dml_ctx, context, pipe_ctx, stream_prog);
289 	find_pipe_regs_idx(dml_ctx, pipe_ctx, &pipe_reg_index);
290 
291 	if (dml_ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) {
292 		memcpy(&pipe_ctx->hubp_regs, pln_prog->phantom_plane.pipe_regs[pipe_reg_index], sizeof(struct dml2_dchub_per_pipe_register_set));
293 		pipe_ctx->unbounded_req = false;
294 
295 		/* legacy only, should be removed later */
296 		dml21_update_pipe_ctx_dchub_regs(&pln_prog->phantom_plane.pipe_regs[pipe_reg_index]->rq_regs,
297 				&pln_prog->phantom_plane.pipe_regs[pipe_reg_index]->dlg_regs,
298 				&pln_prog->phantom_plane.pipe_regs[pipe_reg_index]->ttu_regs, pipe_ctx);
299 
300 		pipe_ctx->det_buffer_size_kb = 0;
301 	} else {
302 		memcpy(&pipe_ctx->hubp_regs, pln_prog->pipe_regs[pipe_reg_index], sizeof(struct dml2_dchub_per_pipe_register_set));
303 		pipe_ctx->unbounded_req = pln_prog->pipe_regs[pipe_reg_index]->rq_regs.unbounded_request_enabled;
304 
305 		/* legacy only, should be removed later */
306 		dml21_update_pipe_ctx_dchub_regs(&pln_prog->pipe_regs[pipe_reg_index]->rq_regs,
307 				&pln_prog->pipe_regs[pipe_reg_index]->dlg_regs,
308 				&pln_prog->pipe_regs[pipe_reg_index]->ttu_regs, pipe_ctx);
309 
310 		pipe_ctx->det_buffer_size_kb = pln_prog->pipe_regs[pipe_reg_index]->det_size * 64;
311 	}
312 
313 	pipe_ctx->plane_res.bw.dppclk_khz = pln_prog->min_clocks.dcn4.dppclk_khz;
314 	if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipe_ctx->plane_res.bw.dppclk_khz)
315 		context->bw_ctx.bw.dcn.clk.dppclk_khz = pipe_ctx->plane_res.bw.dppclk_khz;
316 
317 	dml21_populate_mall_allocation_size(context, dml_ctx, pln_prog, pipe_ctx);
318 	memcpy(&context->bw_ctx.bw.dcn.mcache_allocations[pipe_ctx->pipe_idx], &pln_prog->mcache_allocation, sizeof(struct dml2_mcache_surface_allocation));
319 }
320 
321 static struct dc_stream_state *dml21_add_phantom_stream(struct dml2_context *dml_ctx,
322 	const struct dc *dc,
323 	struct dc_state *context,
324 	struct dc_stream_state *main_stream,
325 	struct dml2_per_stream_programming *stream_programming)
326 {
327 	struct dc_stream_state *phantom_stream;
328 	struct dml2_stream_parameters *phantom_stream_descriptor = &stream_programming->phantom_stream.descriptor;
329 
330 	phantom_stream = dml_ctx->config.svp_pstate.callbacks.create_phantom_stream(dc, context, main_stream);
331 	if (!phantom_stream)
332 		return NULL;
333 
334 	/* copy details of phantom stream from main */
335 	memcpy(&phantom_stream->timing, &main_stream->timing, sizeof(phantom_stream->timing));
336 	memcpy(&phantom_stream->src, &main_stream->src, sizeof(phantom_stream->src));
337 	memcpy(&phantom_stream->dst, &main_stream->dst, sizeof(phantom_stream->dst));
338 
339 	/* modify timing for phantom */
340 	phantom_stream->timing.v_front_porch = phantom_stream_descriptor->timing.v_front_porch;
341 	phantom_stream->timing.v_addressable = phantom_stream_descriptor->timing.v_active;
342 	phantom_stream->timing.v_total = phantom_stream_descriptor->timing.v_total;
343 	phantom_stream->timing.flags.DSC = 0; // phantom always has DSC disabled
344 
345 	phantom_stream->dst.y = 0;
346 	phantom_stream->dst.height = stream_programming->phantom_stream.descriptor.timing.v_active;
347 
348 	phantom_stream->src.y = 0;
349 	phantom_stream->src.height = (double)phantom_stream_descriptor->timing.v_active * (double)main_stream->src.height / (double)main_stream->dst.height;
350 
351 	phantom_stream->use_dynamic_meta = false;
352 
353 	dml_ctx->config.svp_pstate.callbacks.add_phantom_stream(dc, context, phantom_stream, main_stream);
354 
355 	return phantom_stream;
356 }
357 
358 static struct dc_plane_state *dml21_add_phantom_plane(struct dml2_context *dml_ctx,
359 	const struct dc *dc,
360 	struct dc_state *context,
361 	struct dc_stream_state *phantom_stream,
362 	struct dc_plane_state *main_plane,
363 	struct dml2_per_plane_programming *plane_programming)
364 {
365 	struct dc_plane_state *phantom_plane;
366 
367 	phantom_plane = dml_ctx->config.svp_pstate.callbacks.create_phantom_plane(dc, context, main_plane);
368 	if (!phantom_plane)
369 		return NULL;
370 
371 	phantom_plane->format = main_plane->format;
372 	phantom_plane->rotation = main_plane->rotation;
373 	phantom_plane->visible = main_plane->visible;
374 
375 	memcpy(&phantom_plane->address, &main_plane->address, sizeof(phantom_plane->address));
376 	memcpy(&phantom_plane->scaling_quality, &main_plane->scaling_quality,
377 		sizeof(phantom_plane->scaling_quality));
378 	memcpy(&phantom_plane->src_rect, &main_plane->src_rect, sizeof(phantom_plane->src_rect));
379 	memcpy(&phantom_plane->dst_rect, &main_plane->dst_rect, sizeof(phantom_plane->dst_rect));
380 	memcpy(&phantom_plane->clip_rect, &main_plane->clip_rect, sizeof(phantom_plane->clip_rect));
381 	memcpy(&phantom_plane->plane_size, &main_plane->plane_size,
382 		sizeof(phantom_plane->plane_size));
383 	memcpy(&phantom_plane->tiling_info, &main_plane->tiling_info,
384 		sizeof(phantom_plane->tiling_info));
385 	memcpy(&phantom_plane->dcc, &main_plane->dcc, sizeof(phantom_plane->dcc));
386 
387 	phantom_plane->format = main_plane->format;
388 	phantom_plane->rotation = main_plane->rotation;
389 	phantom_plane->visible = main_plane->visible;
390 
391 	/* Shadow pipe has small viewport. */
392 	phantom_plane->clip_rect.y = 0;
393 	phantom_plane->clip_rect.height = phantom_stream->src.height;
394 
395 	dml_ctx->config.svp_pstate.callbacks.add_phantom_plane(dc, phantom_stream, phantom_plane, context);
396 
397 	return phantom_plane;
398 }
399 
400 void dml21_handle_phantom_streams_planes(const struct dc *dc, struct dc_state *context, struct dml2_context *dml_ctx)
401 {
402 	unsigned int dml_stream_index, dml_plane_index, dc_plane_index;
403 	struct dc_stream_state *main_stream;
404 	struct dc_stream_status *main_stream_status;
405 	struct dc_stream_state *phantom_stream;
406 	struct dc_plane_state *main_plane;
407 	bool phantoms_added = false;
408 
409 	/* create phantom streams and planes and add to context */
410 	for (dml_stream_index = 0; dml_stream_index < dml_ctx->v21.mode_programming.programming->display_config.num_streams; dml_stream_index++) {
411 		/* iterate through DML streams looking for phantoms */
412 		if (dml_ctx->v21.mode_programming.programming->stream_programming[dml_stream_index].phantom_stream.enabled) {
413 			/* find associated dc stream */
414 			main_stream = dml_ctx->config.callbacks.get_stream_from_id(context,
415 					dml_ctx->v21.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id[dml_stream_index]);
416 
417 			main_stream_status = dml_ctx->config.callbacks.get_stream_status(context, main_stream);
418 
419 			if (!main_stream_status || main_stream_status->plane_count == 0)
420 				continue;
421 
422 			/* create phantom stream for subvp enabled stream */
423 			phantom_stream = dml21_add_phantom_stream(dml_ctx,
424 					dc,
425 					context,
426 					main_stream,
427 					&dml_ctx->v21.mode_programming.programming->stream_programming[dml_stream_index]);
428 
429 			if (!phantom_stream)
430 				continue;
431 
432 			/* iterate through DML planes associated with this stream */
433 			for (dml_plane_index = 0; dml_plane_index < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_plane_index++) {
434 				if (dml_ctx->v21.mode_programming.programming->plane_programming[dml_plane_index].plane_descriptor->stream_index == dml_stream_index) {
435 					/* find associated dc plane */
436 					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]);
437 					main_plane = main_stream_status->plane_states[dc_plane_index];
438 
439 					/* create phantom planes for subvp enabled plane */
440 					dml21_add_phantom_plane(dml_ctx,
441 							dc,
442 							context,
443 							phantom_stream,
444 							main_plane,
445 							&dml_ctx->v21.mode_programming.programming->plane_programming[dml_plane_index]);
446 
447 					phantoms_added = true;
448 				}
449 			}
450 		}
451 	}
452 
453 	if (phantoms_added)
454 		dml2_map_dc_pipes(dml_ctx, context, NULL, &dml_ctx->v21.dml_to_dc_pipe_mapping, dc->current_state);
455 }
456 
457 void dml21_build_fams2_programming(const struct dc *dc,
458 		struct dc_state *context,
459 		struct dml2_context *dml_ctx)
460 {
461 	int i, j, k;
462 
463 	/* reset fams2 data */
464 	context->bw_ctx.bw.dcn.fams2_stream_count = 0;
465 	memset(&context->bw_ctx.bw.dcn.fams2_stream_params, 0, sizeof(struct dmub_fams2_stream_static_state) * DML2_MAX_PLANES);
466 
467 	if (!dml_ctx->v21.mode_programming.programming->fams2_required)
468 		return;
469 
470 	for (i = 0; i < context->stream_count; i++) {
471 		int dml_stream_idx;
472 		struct dc_stream_state *phantom_stream;
473 		struct dc_stream_status *phantom_status;
474 
475 		struct dmub_fams2_stream_static_state *static_state = &context->bw_ctx.bw.dcn.fams2_stream_params[context->bw_ctx.bw.dcn.fams2_stream_count];
476 
477 		struct dc_stream_state *stream = context->streams[i];
478 
479 		if (context->stream_status[i].plane_count == 0 ||
480 				dml_ctx->config.svp_pstate.callbacks.get_stream_subvp_type(context, stream) == SUBVP_PHANTOM) {
481 			/* can ignore blanked or phantom streams */
482 			continue;
483 		}
484 
485 		dml_stream_idx = dml21_helper_find_dml_pipe_idx_by_stream_id(dml_ctx, stream->stream_id);
486 		if (dml_stream_idx < 0) {
487 			ASSERT(dml_stream_idx >= 0);
488 			continue;
489 		}
490 
491 		/* copy static state from PMO */
492 		memcpy(static_state,
493 				&dml_ctx->v21.mode_programming.programming->stream_programming[dml_stream_idx].fams2_params,
494 				sizeof(struct dmub_fams2_stream_static_state));
495 
496 		/* get information from context */
497 		static_state->num_planes = context->stream_status[i].plane_count;
498 		static_state->otg_inst = context->stream_status[i].primary_otg_inst;
499 
500 		/* populate pipe masks for planes */
501 		for (j = 0; j < context->stream_status[i].plane_count; j++) {
502 			for (k = 0; k < dc->res_pool->pipe_count; k++) {
503 				if (context->res_ctx.pipe_ctx[k].stream &&
504 						context->res_ctx.pipe_ctx[k].stream->stream_id == stream->stream_id &&
505 						context->res_ctx.pipe_ctx[k].plane_state == context->stream_status[i].plane_states[j]) {
506 					static_state->pipe_mask |= (1 << k);
507 					static_state->plane_pipe_masks[j] |= (1 << k);
508 				}
509 			}
510 		}
511 
512 		/* get per method programming */
513 		switch (static_state->type) {
514 		case FAMS2_STREAM_TYPE_VBLANK:
515 		case FAMS2_STREAM_TYPE_VACTIVE:
516 		case FAMS2_STREAM_TYPE_DRR:
517 			break;
518 		case FAMS2_STREAM_TYPE_SUBVP:
519 			phantom_stream = dml_ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, stream);
520 			if (!phantom_stream)
521 				break;
522 
523 			phantom_status = dml_ctx->config.callbacks.get_stream_status(context, phantom_stream);
524 
525 			/* phantom status should always be present */
526 			ASSERT(phantom_status);
527 			static_state->sub_state.subvp.phantom_otg_inst = phantom_status->primary_otg_inst;
528 
529 			/* populate pipe masks for phantom planes */
530 			for (j = 0; j < phantom_status->plane_count; j++) {
531 				for (k = 0; k < dc->res_pool->pipe_count; k++) {
532 					if (context->res_ctx.pipe_ctx[k].stream &&
533 							context->res_ctx.pipe_ctx[k].stream->stream_id == phantom_stream->stream_id &&
534 							context->res_ctx.pipe_ctx[k].plane_state == phantom_status->plane_states[j]) {
535 						static_state->sub_state.subvp.phantom_pipe_mask |= (1 << k);
536 						static_state->sub_state.subvp.phantom_plane_pipe_masks[j] |= (1 << k);
537 					}
538 				}
539 			}
540 			break;
541 		default:
542 			ASSERT(false);
543 			break;
544 		}
545 
546 		context->bw_ctx.bw.dcn.fams2_stream_count++;
547 	}
548 
549 	context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = context->bw_ctx.bw.dcn.fams2_stream_count > 0;
550 }
551 
552 bool dml21_is_plane1_enabled(enum dml2_source_format_class source_format)
553 {
554 	return source_format >= dml2_420_8 && source_format <= dml2_rgbe_alpha;
555 }
556