1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2024 Advanced Micro Devices, Inc.
4 
5 
6 #include "dml2_internal_types.h"
7 #include "dml_top.h"
8 #include "dml2_core_dcn4_calcs.h"
9 #include "dml2_internal_shared_types.h"
10 #include "dml21_utils.h"
11 #include "dml21_translation_helper.h"
12 #include "dml2_dc_resource_mgmt.h"
13 
14 static bool dml21_allocate_memory(struct dml2_context **dml_ctx)
15 {
16 	*dml_ctx = (struct dml2_context *)kzalloc(sizeof(struct dml2_context), GFP_KERNEL);
17 	if (!(*dml_ctx))
18 		return false;
19 
20 	(*dml_ctx)->v21.dml_init.dml2_instance = (struct dml2_instance *)kzalloc(sizeof(struct dml2_instance), GFP_KERNEL);
21 	if (!((*dml_ctx)->v21.dml_init.dml2_instance))
22 		return false;
23 
24 	(*dml_ctx)->v21.mode_support.dml2_instance = (*dml_ctx)->v21.dml_init.dml2_instance;
25 	(*dml_ctx)->v21.mode_programming.dml2_instance = (*dml_ctx)->v21.dml_init.dml2_instance;
26 
27 	(*dml_ctx)->v21.mode_support.display_config = &(*dml_ctx)->v21.display_config;
28 	(*dml_ctx)->v21.mode_programming.display_config = (*dml_ctx)->v21.mode_support.display_config;
29 
30 	(*dml_ctx)->v21.mode_programming.programming = (struct dml2_display_cfg_programming *)kzalloc(sizeof(struct dml2_display_cfg_programming), GFP_KERNEL);
31 	if (!((*dml_ctx)->v21.mode_programming.programming))
32 		return false;
33 
34 	return true;
35 }
36 
37 static void dml21_apply_debug_options(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config)
38 {
39 	bool disable_fams2;
40 	struct dml2_pmo_options *pmo_options = &dml_ctx->v21.dml_init.options.pmo_options;
41 
42 	/* ODM options */
43 	pmo_options->disable_dyn_odm = !config->minimize_dispclk_using_odm;
44 	pmo_options->disable_dyn_odm_for_multi_stream = true;
45 	pmo_options->disable_dyn_odm_for_stream_with_svp = true;
46 
47 	/* UCLK P-State options */
48 	if (in_dc->debug.dml21_force_pstate_method) {
49 		dml_ctx->config.pmo.force_pstate_method_enable = true;
50 		dml_ctx->config.pmo.force_pstate_method_value = in_dc->debug.dml21_force_pstate_method_value;
51 	} else {
52 		dml_ctx->config.pmo.force_pstate_method_enable = false;
53 	}
54 
55 	pmo_options->disable_vblank = ((in_dc->debug.dml21_disable_pstate_method_mask >> 1) & 1);
56 
57 	/* NOTE: DRR and SubVP Require FAMS2 */
58 	disable_fams2 = !in_dc->debug.fams2_config.bits.enable;
59 	pmo_options->disable_svp = ((in_dc->debug.dml21_disable_pstate_method_mask >> 2) & 1) ||
60 			in_dc->debug.force_disable_subvp ||
61 			disable_fams2;
62 	pmo_options->disable_drr_fixed = ((in_dc->debug.dml21_disable_pstate_method_mask >> 3) & 1) ||
63 			disable_fams2;
64 	pmo_options->disable_drr_var = ((in_dc->debug.dml21_disable_pstate_method_mask >> 4) & 1) ||
65 			disable_fams2;
66 	pmo_options->disable_fams2 = disable_fams2;
67 
68 	pmo_options->disable_drr_var_when_var_active = in_dc->debug.disable_fams_gaming;
69 }
70 
71 static void dml21_init(const struct dc *in_dc, struct dml2_context **dml_ctx, const struct dml2_configuration_options *config)
72 {
73 	switch (in_dc->ctx->dce_version) {
74 	case DCN_VERSION_4_01:
75 	case DCN_VERSION_3_2:	// TODO : Temporary for N-1 validation. Remove this after N-1 validation phase is complete.
76 		(*dml_ctx)->v21.dml_init.options.project_id = dml2_project_dcn4x_stage2_auto_drr_svp;
77 		break;
78 	default:
79 		(*dml_ctx)->v21.dml_init.options.project_id = dml2_project_invalid;
80 	}
81 
82 	(*dml_ctx)->architecture = dml2_architecture_21;
83 
84 	/* Store configuration options */
85 	(*dml_ctx)->config = *config;
86 
87 	/*Initialize SOCBB and DCNIP params */
88 	dml21_initialize_soc_bb_params(&(*dml_ctx)->v21.dml_init, config, in_dc);
89 	dml21_initialize_ip_params(&(*dml_ctx)->v21.dml_init, config, in_dc);
90 	dml21_apply_soc_bb_overrides(&(*dml_ctx)->v21.dml_init, config, in_dc);
91 
92 	/* apply debug overrides */
93 	dml21_apply_debug_options(in_dc, *dml_ctx, config);
94 
95 	/*Initialize DML21 instance */
96 	dml2_initialize_instance(&(*dml_ctx)->v21.dml_init);
97 }
98 
99 bool dml21_create(const struct dc *in_dc, struct dml2_context **dml_ctx, const struct dml2_configuration_options *config)
100 {
101 	/* Allocate memory for initializing DML21 instance */
102 	if (!dml21_allocate_memory(dml_ctx))
103 		return false;
104 
105 	dml21_init(in_dc, dml_ctx, config);
106 
107 	return true;
108 }
109 
110 static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_state *context, struct resource_context *out_new_hw_state,
111 	struct dml2_context *in_ctx, unsigned int pipe_cnt)
112 {
113 	unsigned int dml_prog_idx = 0, dc_pipe_index = 0, num_dpps_required = 0;
114 	struct dml2_per_plane_programming *pln_prog = NULL;
115 	struct dml2_per_stream_programming *stream_prog = NULL;
116 	struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__];
117 	struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0};
118 	int num_pipes;
119 
120 	context->bw_ctx.bw.dcn.clk.dppclk_khz = 0;
121 
122 	/* copy global DCHUBBUB arbiter registers */
123 	memcpy(&context->bw_ctx.bw.dcn.arb_regs, &in_ctx->v21.mode_programming.programming->global_regs.arb_regs, sizeof(struct dml2_display_arb_regs));
124 
125 	/* legacy only */
126 	context->bw_ctx.bw.dcn.compbuf_size_kb = (int)in_ctx->v21.mode_programming.programming->global_regs.arb_regs.compbuf_size * 64;
127 
128 	context->bw_ctx.bw.dcn.mall_ss_size_bytes = 0;
129 	context->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes = 0;
130 	context->bw_ctx.bw.dcn.mall_subvp_size_bytes = 0;
131 
132 	for (dml_prog_idx = 0; dml_prog_idx < DML2_MAX_PLANES; dml_prog_idx++) {
133 		pln_prog = &in_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx];
134 
135 		if (!pln_prog->plane_descriptor)
136 			continue;
137 
138 		stream_prog = &in_ctx->v21.mode_programming.programming->stream_programming[pln_prog->plane_descriptor->stream_index];
139 		num_dpps_required = pln_prog->num_dpps_required;
140 
141 		if (num_dpps_required == 0) {
142 			continue;
143 		}
144 		num_pipes = dml21_find_dc_pipes_for_plane(dc, context, in_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx);
145 
146 		if (num_pipes <= 0)
147 			continue;
148 
149 		/* program each pipe */
150 		for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
151 			dml21_program_dc_pipe(in_ctx, context, dc_main_pipes[dc_pipe_index], pln_prog, stream_prog);
152 
153 			if (pln_prog->phantom_plane.valid) {
154 				dml21_program_dc_pipe(in_ctx, context, dc_phantom_pipes[dc_pipe_index], pln_prog, stream_prog);
155 			}
156 		}
157 	}
158 
159 	/* assign global clocks */
160 	context->bw_ctx.bw.dcn.clk.bw_dppclk_khz = context->bw_ctx.bw.dcn.clk.dppclk_khz;
161 	context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz;
162 	if (in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values > 1) {
163 		context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz =
164 			in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values] * 1000;
165 	} else {
166 		context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[0] * 1000;
167 	}
168 
169 	if (in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values > 1) {
170 		context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz =
171 			in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values] * 1000;
172 	} else {
173 		context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[0] * 1000;
174 	}
175 
176 	/* get global mall allocation */
177 	if (dc->res_pool->funcs->calculate_mall_ways_from_bytes) {
178 		context->bw_ctx.bw.dcn.clk.num_ways = dc->res_pool->funcs->calculate_mall_ways_from_bytes(dc, context->bw_ctx.bw.dcn.mall_subvp_size_bytes);
179 	} else {
180 		context->bw_ctx.bw.dcn.clk.num_ways = 0;
181 	}
182 }
183 
184 static bool dml21_mode_check_and_programming(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx)
185 {
186 	bool result = false;
187 	struct dml2_build_mode_programming_in_out *mode_programming = &dml_ctx->v21.mode_programming;
188 
189 	memset(&dml_ctx->v21.display_config, 0, sizeof(struct dml2_display_cfg));
190 	memset(&dml_ctx->v21.dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping));
191 	memset(&dml_ctx->v21.mode_programming.dml2_instance->scratch.build_mode_programming_locals.mode_programming_params, 0, sizeof(struct dml2_core_mode_programming_in_out));
192 
193 	if (!context || context->stream_count == 0)
194 		return true;
195 
196 	/* scrub phantom's from current dc_state */
197 	dml_ctx->config.svp_pstate.callbacks.remove_phantom_streams_and_planes(in_dc, context);
198 	dml_ctx->config.svp_pstate.callbacks.release_phantom_streams_and_planes(in_dc, context);
199 
200 	/* Populate stream, plane mappings and other fields in display config. */
201 	result = dml21_map_dc_state_into_dml_display_cfg(in_dc, context, dml_ctx);
202 	if (!result)
203 		return false;
204 
205 	result = dml2_build_mode_programming(mode_programming);
206 	if (!result)
207 		return false;
208 
209 	/* Check and map HW resources */
210 	if (result && !dml_ctx->config.skip_hw_state_mapping) {
211 		dml21_map_hw_resources(dml_ctx);
212 		dml2_map_dc_pipes(dml_ctx, context, NULL, &dml_ctx->v21.dml_to_dc_pipe_mapping, in_dc->current_state);
213 		/* if subvp phantoms are present, expand them into dc context */
214 		dml21_handle_phantom_streams_planes(in_dc, context, dml_ctx);
215 	}
216 
217 	/* Copy DML CLK, WM and REG outputs to bandwidth context */
218 	if (result && !dml_ctx->config.skip_hw_state_mapping) {
219 		dml21_calculate_rq_and_dlg_params(in_dc, context, &context->res_ctx, dml_ctx, in_dc->res_pool->pipe_count);
220 		dml21_copy_clocks_to_dc_state(dml_ctx, context);
221 		dml21_extract_watermark_sets(in_dc, &context->bw_ctx.bw.dcn.watermarks, dml_ctx);
222 		if (in_dc->ctx->dce_version == DCN_VERSION_3_2) {
223 			dml21_extract_legacy_watermark_set(in_dc, &context->bw_ctx.bw.dcn.watermarks.a, DML2_DCHUB_WATERMARK_SET_A, dml_ctx);
224 			dml21_extract_legacy_watermark_set(in_dc, &context->bw_ctx.bw.dcn.watermarks.b, DML2_DCHUB_WATERMARK_SET_A, dml_ctx);
225 			dml21_extract_legacy_watermark_set(in_dc, &context->bw_ctx.bw.dcn.watermarks.c, DML2_DCHUB_WATERMARK_SET_A, dml_ctx);
226 			dml21_extract_legacy_watermark_set(in_dc, &context->bw_ctx.bw.dcn.watermarks.d, DML2_DCHUB_WATERMARK_SET_A, dml_ctx);
227 		}
228 
229 		dml21_build_fams2_programming(in_dc, context, dml_ctx);
230 	}
231 
232 	return true;
233 }
234 
235 static bool dml21_check_mode_support(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx)
236 {
237 	bool is_supported = false;
238 	struct dml2_initialize_instance_in_out *dml_init = &dml_ctx->v21.dml_init;
239 	struct dml2_check_mode_supported_in_out *mode_support = &dml_ctx->v21.mode_support;
240 
241 	memset(&dml_ctx->v21.display_config, 0, sizeof(struct dml2_display_cfg));
242 	memset(&dml_ctx->v21.dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping));
243 	memset(&dml_ctx->v21.mode_programming.dml2_instance->scratch.check_mode_supported_locals.mode_support_params, 0, sizeof(struct dml2_core_mode_support_in_out));
244 
245 	if (!context || context->stream_count == 0)
246 		return true;
247 
248 	/* Scrub phantom's from current dc_state */
249 	dml_ctx->config.svp_pstate.callbacks.remove_phantom_streams_and_planes(in_dc, context);
250 	dml_ctx->config.svp_pstate.callbacks.release_phantom_streams_and_planes(in_dc, context);
251 
252 	mode_support->dml2_instance = dml_init->dml2_instance;
253 	dml21_map_dc_state_into_dml_display_cfg(in_dc, context, dml_ctx);
254 	is_supported = dml2_check_mode_supported(mode_support);
255 	if (!is_supported)
256 		return false;
257 
258 	return true;
259 }
260 
261 bool dml21_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx, bool fast_validate)
262 {
263 	bool out = false;
264 
265 	/* Use dml_validate_only for fast_validate path */
266 	if (fast_validate) {
267 		out = dml21_check_mode_support(in_dc, context, dml_ctx);
268 	} else
269 		out = dml21_mode_check_and_programming(in_dc, context, dml_ctx);
270 	return out;
271 }
272 
273 void dml21_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx)
274 {
275 	unsigned int num_pipes, dml_prog_idx, dml_phantom_prog_idx, dc_pipe_index;
276 	struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__];
277 	struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0};
278 
279 	struct dml2_per_plane_programming *pln_prog = NULL;
280 	struct dml2_plane_mcache_configuration_descriptor *mcache_config = NULL;
281 	struct prepare_mcache_programming_locals *l = &dml_ctx->v21.scratch.prepare_mcache_locals;
282 
283 	if (context->stream_count == 0) {
284 		return;
285 	}
286 
287 	memset(&l->build_mcache_programming_params, 0, sizeof(struct dml2_build_mcache_programming_in_out));
288 	l->build_mcache_programming_params.dml2_instance = dml_ctx->v21.dml_init.dml2_instance;
289 
290 	/* phantom's start after main planes */
291 	dml_phantom_prog_idx = dml_ctx->v21.mode_programming.programming->display_config.num_planes;
292 
293 	/* Build mcache programming parameters per plane per pipe */
294 	for (dml_prog_idx = 0; dml_prog_idx < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_prog_idx++) {
295 		pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx];
296 
297 		mcache_config = &l->build_mcache_programming_params.mcache_configurations[dml_prog_idx];
298 		memset(mcache_config, 0, sizeof(struct dml2_plane_mcache_configuration_descriptor));
299 		mcache_config->plane_descriptor = pln_prog->plane_descriptor;
300 		mcache_config->mcache_allocation = &context->bw_ctx.bw.dcn.mcache_allocations[dml_prog_idx];
301 		mcache_config->num_pipes = pln_prog->num_dpps_required;
302 		l->build_mcache_programming_params.num_configurations++;
303 
304 		if (pln_prog->num_dpps_required == 0) {
305 			continue;
306 		}
307 
308 		num_pipes = dml21_find_dc_pipes_for_plane(in_dc, context, dml_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx);
309 
310 		if (num_pipes <= 0 ||
311 				dc_main_pipes[0]->stream == NULL ||
312 				dc_main_pipes[0]->plane_state == NULL)
313 			continue;
314 
315 		/* get config for each pipe */
316 		for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
317 			ASSERT(dc_main_pipes[dc_pipe_index]);
318 			dml21_get_pipe_mcache_config(context, dc_main_pipes[dc_pipe_index], pln_prog, &mcache_config->pipe_configurations[dc_pipe_index]);
319 		}
320 
321 		/* get config for each phantom pipe */
322 		if (pln_prog->phantom_plane.valid) {
323 			mcache_config = &l->build_mcache_programming_params.mcache_configurations[dml_phantom_prog_idx];
324 			memset(mcache_config, 0, sizeof(struct dml2_plane_mcache_configuration_descriptor));
325 			mcache_config->plane_descriptor = pln_prog->plane_descriptor;
326 			mcache_config->mcache_allocation = &context->bw_ctx.bw.dcn.mcache_allocations[dml_phantom_prog_idx];
327 			mcache_config->num_pipes = pln_prog->num_dpps_required;
328 			l->build_mcache_programming_params.num_configurations++;
329 
330 			for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
331 				ASSERT(dc_phantom_pipes[dc_pipe_index]);
332 				dml21_get_pipe_mcache_config(context, dc_phantom_pipes[dc_pipe_index], pln_prog, &mcache_config->pipe_configurations[dc_pipe_index]);
333 			}
334 
335 			/* increment phantom index */
336 			dml_phantom_prog_idx++;
337 		}
338 	}
339 
340 	/* Call to generate mcache programming per plane per pipe for the given display configuration */
341 	dml2_build_mcache_programming(&l->build_mcache_programming_params);
342 
343 	/* get per plane per pipe mcache programming */
344 	for (dml_prog_idx = 0; dml_prog_idx < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_prog_idx++) {
345 		pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx];
346 
347 		num_pipes = dml21_find_dc_pipes_for_plane(in_dc, context, dml_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx);
348 
349 		if (num_pipes <= 0 ||
350 				dc_main_pipes[0]->stream == NULL ||
351 				dc_main_pipes[0]->plane_state == NULL)
352 			continue;
353 
354 		/* get config for each pipe */
355 		for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
356 			ASSERT(dc_main_pipes[dc_pipe_index]);
357 			if (l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_prog_idx][dc_pipe_index]) {
358 				memcpy(&dc_main_pipes[dc_pipe_index]->mcache_regs,
359 						l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_prog_idx][dc_pipe_index],
360 						sizeof(struct dml2_hubp_pipe_mcache_regs));
361 			}
362 		}
363 
364 		/* get config for each phantom pipe */
365 		if (pln_prog->phantom_plane.valid) {
366 			for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
367 				ASSERT(dc_phantom_pipes[dc_pipe_index]);
368 				if (l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_phantom_prog_idx][dc_pipe_index]) {
369 					memcpy(&dc_phantom_pipes[dc_pipe_index]->mcache_regs,
370 							l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_phantom_prog_idx][dc_pipe_index],
371 							sizeof(struct dml2_hubp_pipe_mcache_regs));
372 				}
373 			}
374 			/* increment phantom index */
375 			dml_phantom_prog_idx++;
376 		}
377 	}
378 }
379 
380 void dml21_copy(struct dml2_context *dst_dml_ctx,
381 	struct dml2_context *src_dml_ctx)
382 {
383 	/* Preserve references to internals */
384 	struct dml2_instance *dst_dml2_instance = dst_dml_ctx->v21.dml_init.dml2_instance;
385 	struct dml2_display_cfg_programming *dst_dml2_programming = dst_dml_ctx->v21.mode_programming.programming;
386 
387 	/* Copy context */
388 	memcpy(dst_dml_ctx, src_dml_ctx, sizeof(struct dml2_context));
389 
390 	/* Copy Internals */
391 	memcpy(dst_dml2_instance, src_dml_ctx->v21.dml_init.dml2_instance, sizeof(struct dml2_instance));
392 	memcpy(dst_dml2_programming, src_dml_ctx->v21.mode_programming.programming, sizeof(struct dml2_display_cfg_programming));
393 
394 	/* Restore references to internals */
395 	dst_dml_ctx->v21.dml_init.dml2_instance = dst_dml2_instance;
396 
397 	dst_dml_ctx->v21.mode_support.dml2_instance = dst_dml2_instance;
398 	dst_dml_ctx->v21.mode_programming.dml2_instance = dst_dml2_instance;
399 
400 	dst_dml_ctx->v21.mode_support.display_config = &dst_dml_ctx->v21.display_config;
401 	dst_dml_ctx->v21.mode_programming.display_config = dst_dml_ctx->v21.mode_support.display_config;
402 
403 	dst_dml_ctx->v21.mode_programming.programming = dst_dml2_programming;
404 
405 	/* need to initialize copied instance for internal references to be correct */
406 	dml2_initialize_instance(&dst_dml_ctx->v21.dml_init);
407 }
408 
409 bool dml21_create_copy(struct dml2_context **dst_dml_ctx,
410 	struct dml2_context *src_dml_ctx)
411 {
412 	/* Allocate memory for initializing DML21 instance */
413 	if (!dml21_allocate_memory(dst_dml_ctx))
414 		return false;
415 
416 	dml21_copy(*dst_dml_ctx, src_dml_ctx);
417 
418 	return true;
419 }
420 
421 void dml21_reinit(const struct dc *in_dc, struct dml2_context **dml_ctx, const struct dml2_configuration_options *config)
422 {
423 	dml21_init(in_dc, dml_ctx, config);
424 }
425 
426