1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2024 Advanced Micro Devices, Inc.
4 
5 #include "dml2_internal_shared_types.h"
6 #include "dml2_core_shared_types.h"
7 #include "dml2_core_dcn4.h"
8 #include "dml2_core_dcn4_calcs.h"
9 #include "dml2_debug.h"
10 #include "lib_float_math.h"
11 
12 struct dml2_core_ip_params core_dcn4_ip_caps_base = {
13 	// Hardcoded values for DCN3x
14 	.vblank_nom_default_us = 668,
15 	.remote_iommu_outstanding_translations = 256,
16 	.rob_buffer_size_kbytes = 128,
17 	.config_return_buffer_size_in_kbytes = 1280,
18 	.config_return_buffer_segment_size_in_kbytes = 64,
19 	.compressed_buffer_segment_size_in_kbytes = 64,
20 	.dpte_buffer_size_in_pte_reqs_luma = 68,
21 	.dpte_buffer_size_in_pte_reqs_chroma = 36,
22 	.pixel_chunk_size_kbytes = 8,
23 	.alpha_pixel_chunk_size_kbytes = 4,
24 	.min_pixel_chunk_size_bytes = 1024,
25 	.writeback_chunk_size_kbytes = 8,
26 	.line_buffer_size_bits = 1171920,
27 	.max_line_buffer_lines = 32,
28 	.writeback_interface_buffer_size_kbytes = 90,
29 	//Number of pipes after DCN Pipe harvesting
30 	.max_num_dpp = 4,
31 	.max_num_otg = 4,
32 	.max_num_wb = 1,
33 	.max_dchub_pscl_bw_pix_per_clk = 4,
34 	.max_pscl_lb_bw_pix_per_clk = 2,
35 	.max_lb_vscl_bw_pix_per_clk = 4,
36 	.max_vscl_hscl_bw_pix_per_clk = 4,
37 	.max_hscl_ratio = 6,
38 	.max_vscl_ratio = 6,
39 	.max_hscl_taps = 8,
40 	.max_vscl_taps = 8,
41 	.dispclk_ramp_margin_percent = 1,
42 	.dppclk_delay_subtotal = 47,
43 	.dppclk_delay_scl = 50,
44 	.dppclk_delay_scl_lb_only = 16,
45 	.dppclk_delay_cnvc_formatter = 28,
46 	.dppclk_delay_cnvc_cursor = 6,
47 	.cursor_buffer_size = 24,
48 	.cursor_chunk_size = 2,
49 	.dispclk_delay_subtotal = 125,
50 	.max_inter_dcn_tile_repeaters = 8,
51 	.writeback_max_hscl_ratio = 1,
52 	.writeback_max_vscl_ratio = 1,
53 	.writeback_min_hscl_ratio = 1,
54 	.writeback_min_vscl_ratio = 1,
55 	.writeback_max_hscl_taps = 1,
56 	.writeback_max_vscl_taps = 1,
57 	.writeback_line_buffer_buffer_size = 0,
58 	.num_dsc = 4,
59 	.maximum_dsc_bits_per_component = 12,
60 	.maximum_pixels_per_line_per_dsc_unit = 5760,
61 	.dsc422_native_support = true,
62 	.dcc_supported = true,
63 	.ptoi_supported = false,
64 
65 	.cursor_64bpp_support = true,
66 	.dynamic_metadata_vm_enabled = false,
67 
68 	.max_num_dp2p0_outputs = 4,
69 	.max_num_dp2p0_streams = 4,
70 	.imall_supported = 1,
71 	.max_flip_time_us = 80,
72 	.max_flip_time_lines = 32,
73 	.words_per_channel = 16,
74 
75 	.subvp_fw_processing_delay_us = 15,
76 	.subvp_pstate_allow_width_us = 20,
77 	.subvp_swath_height_margin_lines = 16,
78 };
79 
patch_ip_caps_with_explicit_ip_params(struct dml2_ip_capabilities * ip_caps,const struct dml2_core_ip_params * ip_params)80 static void patch_ip_caps_with_explicit_ip_params(struct dml2_ip_capabilities *ip_caps, const struct dml2_core_ip_params *ip_params)
81 {
82 	ip_caps->pipe_count = ip_params->max_num_dpp;
83 	ip_caps->otg_count = ip_params->max_num_otg;
84 	ip_caps->num_dsc = ip_params->num_dsc;
85 	ip_caps->max_num_dp2p0_streams = ip_params->max_num_dp2p0_streams;
86 	ip_caps->max_num_dp2p0_outputs = ip_params->max_num_dp2p0_outputs;
87 	ip_caps->max_num_hdmi_frl_outputs = ip_params->max_num_hdmi_frl_outputs;
88 	ip_caps->rob_buffer_size_kbytes = ip_params->rob_buffer_size_kbytes;
89 	ip_caps->config_return_buffer_size_in_kbytes = ip_params->config_return_buffer_size_in_kbytes;
90 	ip_caps->config_return_buffer_segment_size_in_kbytes = ip_params->config_return_buffer_segment_size_in_kbytes;
91 	ip_caps->meta_fifo_size_in_kentries = ip_params->meta_fifo_size_in_kentries;
92 	ip_caps->compressed_buffer_segment_size_in_kbytes = ip_params->compressed_buffer_segment_size_in_kbytes;
93 	ip_caps->cursor_buffer_size = ip_params->cursor_buffer_size;
94 	ip_caps->max_flip_time_us = ip_params->max_flip_time_us;
95 	ip_caps->max_flip_time_lines = ip_params->max_flip_time_lines;
96 	ip_caps->hostvm_mode = ip_params->hostvm_mode;
97 
98 	// FIXME_STAGE2: cleanup after adding all dv override to ip_caps
99 	ip_caps->subvp_drr_scheduling_margin_us = 100;
100 	ip_caps->subvp_prefetch_end_to_mall_start_us = 15;
101 	ip_caps->subvp_fw_processing_delay = 16;
102 
103 }
104 
patch_ip_params_with_ip_caps(struct dml2_core_ip_params * ip_params,const struct dml2_ip_capabilities * ip_caps)105 static void patch_ip_params_with_ip_caps(struct dml2_core_ip_params *ip_params, const struct dml2_ip_capabilities *ip_caps)
106 {
107 	ip_params->max_num_dpp = ip_caps->pipe_count;
108 	ip_params->max_num_otg = ip_caps->otg_count;
109 	ip_params->num_dsc = ip_caps->num_dsc;
110 	ip_params->max_num_dp2p0_streams = ip_caps->max_num_dp2p0_streams;
111 	ip_params->max_num_dp2p0_outputs = ip_caps->max_num_dp2p0_outputs;
112 	ip_params->max_num_hdmi_frl_outputs = ip_caps->max_num_hdmi_frl_outputs;
113 	ip_params->rob_buffer_size_kbytes = ip_caps->rob_buffer_size_kbytes;
114 	ip_params->config_return_buffer_size_in_kbytes = ip_caps->config_return_buffer_size_in_kbytes;
115 	ip_params->config_return_buffer_segment_size_in_kbytes = ip_caps->config_return_buffer_segment_size_in_kbytes;
116 	ip_params->meta_fifo_size_in_kentries = ip_caps->meta_fifo_size_in_kentries;
117 	ip_params->compressed_buffer_segment_size_in_kbytes = ip_caps->compressed_buffer_segment_size_in_kbytes;
118 	ip_params->cursor_buffer_size = ip_caps->cursor_buffer_size;
119 	ip_params->max_flip_time_us = ip_caps->max_flip_time_us;
120 	ip_params->max_flip_time_lines = ip_caps->max_flip_time_lines;
121 	ip_params->hostvm_mode = ip_caps->hostvm_mode;
122 }
123 
core_dcn4_initialize(struct dml2_core_initialize_in_out * in_out)124 bool core_dcn4_initialize(struct dml2_core_initialize_in_out *in_out)
125 {
126 	struct dml2_core_instance *core = in_out->instance;
127 
128 	if (!in_out->minimum_clock_table)
129 		return false;
130 	else
131 		core->minimum_clock_table = in_out->minimum_clock_table;
132 
133 	if (in_out->explicit_ip_bb && in_out->explicit_ip_bb_size > 0) {
134 		memcpy(&core->clean_me_up.mode_lib.ip, in_out->explicit_ip_bb, in_out->explicit_ip_bb_size);
135 
136 		// FIXME_STAGE2:
137 		// DV still uses stage1 ip_param_st for each variant, need to patch the ip_caps with ip_param info
138 		// Should move DV to use ip_caps but need move more overrides to ip_caps
139 		patch_ip_caps_with_explicit_ip_params(in_out->ip_caps, in_out->explicit_ip_bb);
140 		core->clean_me_up.mode_lib.ip.subvp_pstate_allow_width_us = core_dcn4_ip_caps_base.subvp_pstate_allow_width_us;
141 		core->clean_me_up.mode_lib.ip.subvp_fw_processing_delay_us = core_dcn4_ip_caps_base.subvp_pstate_allow_width_us;
142 		core->clean_me_up.mode_lib.ip.subvp_swath_height_margin_lines = core_dcn4_ip_caps_base.subvp_swath_height_margin_lines;
143 	} else {
144 		memcpy(&core->clean_me_up.mode_lib.ip, &core_dcn4_ip_caps_base, sizeof(struct dml2_core_ip_params));
145 		patch_ip_params_with_ip_caps(&core->clean_me_up.mode_lib.ip, in_out->ip_caps);
146 		core->clean_me_up.mode_lib.ip.imall_supported = false;
147 	}
148 
149 	memcpy(&core->clean_me_up.mode_lib.soc, in_out->soc_bb, sizeof(struct dml2_soc_bb));
150 	memcpy(&core->clean_me_up.mode_lib.ip_caps, in_out->ip_caps, sizeof(struct dml2_ip_capabilities));
151 
152 	return true;
153 }
154 
create_phantom_stream_from_main_stream(struct dml2_stream_parameters * phantom,const struct dml2_stream_parameters * main,const struct dml2_implicit_svp_meta * meta)155 static void create_phantom_stream_from_main_stream(struct dml2_stream_parameters *phantom, const struct dml2_stream_parameters *main,
156 	const struct dml2_implicit_svp_meta *meta)
157 {
158 	memcpy(phantom, main, sizeof(struct dml2_stream_parameters));
159 
160 	phantom->timing.v_total = meta->v_total;
161 	phantom->timing.v_active = meta->v_active;
162 	phantom->timing.v_front_porch = meta->v_front_porch;
163 	phantom->timing.v_blank_end = phantom->timing.v_total - phantom->timing.v_front_porch - phantom->timing.v_active;
164 	phantom->timing.vblank_nom = phantom->timing.v_total - phantom->timing.v_active;
165 	phantom->timing.drr_config.enabled = false;
166 }
167 
create_phantom_plane_from_main_plane(struct dml2_plane_parameters * phantom,const struct dml2_plane_parameters * main,const struct dml2_stream_parameters * phantom_stream,int phantom_stream_index,const struct dml2_stream_parameters * main_stream)168 static void create_phantom_plane_from_main_plane(struct dml2_plane_parameters *phantom, const struct dml2_plane_parameters *main,
169 	const struct dml2_stream_parameters *phantom_stream, int phantom_stream_index, const struct dml2_stream_parameters *main_stream)
170 {
171 	memcpy(phantom, main, sizeof(struct dml2_plane_parameters));
172 
173 	phantom->stream_index = phantom_stream_index;
174 	phantom->overrides.refresh_from_mall = dml2_refresh_from_mall_mode_override_force_disable;
175 	phantom->overrides.legacy_svp_config = dml2_svp_mode_override_phantom_pipe_no_data_return;
176 	phantom->composition.viewport.plane0.height = (long int unsigned) math_min2(math_ceil2(
177 		(double)main->composition.scaler_info.plane0.v_ratio * (double)phantom_stream->timing.v_active, 16.0),
178 		(double)main->composition.viewport.plane0.height);
179 	phantom->composition.viewport.plane1.height = (long int unsigned) math_min2(math_ceil2(
180 		(double)main->composition.scaler_info.plane1.v_ratio * (double)phantom_stream->timing.v_active, 16.0),
181 		(double)main->composition.viewport.plane1.height);
182 	phantom->immediate_flip = false;
183 	phantom->dynamic_meta_data.enable = false;
184 	phantom->cursor.num_cursors = 0;
185 	phantom->cursor.cursor_width = 0;
186 	phantom->tdlut.setup_for_tdlut = false;
187 }
188 
expand_implict_subvp(const struct display_configuation_with_meta * display_cfg,struct dml2_display_cfg * svp_expanded_display_cfg,struct dml2_core_scratch * scratch)189 static void expand_implict_subvp(const struct display_configuation_with_meta *display_cfg, struct dml2_display_cfg *svp_expanded_display_cfg,
190 	struct dml2_core_scratch *scratch)
191 {
192 	unsigned int stream_index, plane_index;
193 	const struct dml2_plane_parameters *main_plane;
194 	const struct dml2_stream_parameters *main_stream;
195 	const struct dml2_stream_parameters *phantom_stream;
196 
197 	memcpy(svp_expanded_display_cfg, &display_cfg->display_config, sizeof(struct dml2_display_cfg));
198 	memset(scratch->main_stream_index_from_svp_stream_index, 0, sizeof(int) * DML2_MAX_PLANES);
199 	memset(scratch->svp_stream_index_from_main_stream_index, 0, sizeof(int) * DML2_MAX_PLANES);
200 	memset(scratch->main_plane_index_to_phantom_plane_index, 0, sizeof(int) * DML2_MAX_PLANES);
201 
202 	if (!display_cfg->display_config.overrides.enable_subvp_implicit_pmo)
203 		return;
204 
205 	/* disable unbounded requesting for all planes until stage 3 has been performed */
206 	if (!display_cfg->stage3.performed) {
207 		svp_expanded_display_cfg->overrides.hw.force_unbounded_requesting.enable = true;
208 		svp_expanded_display_cfg->overrides.hw.force_unbounded_requesting.value = false;
209 	}
210 	// Create the phantom streams
211 	for (stream_index = 0; stream_index < display_cfg->display_config.num_streams; stream_index++) {
212 		main_stream = &display_cfg->display_config.stream_descriptors[stream_index];
213 		scratch->main_stream_index_from_svp_stream_index[stream_index] = stream_index;
214 		scratch->svp_stream_index_from_main_stream_index[stream_index] = stream_index;
215 
216 		if (display_cfg->stage3.stream_svp_meta[stream_index].valid) {
217 			// Create the phantom stream
218 			create_phantom_stream_from_main_stream(&svp_expanded_display_cfg->stream_descriptors[svp_expanded_display_cfg->num_streams],
219 				main_stream, &display_cfg->stage3.stream_svp_meta[stream_index]);
220 
221 			// Associate this phantom stream to the main stream
222 			scratch->main_stream_index_from_svp_stream_index[svp_expanded_display_cfg->num_streams] = stream_index;
223 			scratch->svp_stream_index_from_main_stream_index[stream_index] = svp_expanded_display_cfg->num_streams;
224 
225 			// Increment num streams
226 			svp_expanded_display_cfg->num_streams++;
227 		}
228 	}
229 
230 	// Create the phantom planes
231 	for (plane_index = 0; plane_index < display_cfg->display_config.num_planes; plane_index++) {
232 		main_plane = &display_cfg->display_config.plane_descriptors[plane_index];
233 
234 		if (display_cfg->stage3.stream_svp_meta[main_plane->stream_index].valid) {
235 			main_stream = &display_cfg->display_config.stream_descriptors[main_plane->stream_index];
236 			phantom_stream = &svp_expanded_display_cfg->stream_descriptors[scratch->svp_stream_index_from_main_stream_index[main_plane->stream_index]];
237 			create_phantom_plane_from_main_plane(&svp_expanded_display_cfg->plane_descriptors[svp_expanded_display_cfg->num_planes],
238 				main_plane, phantom_stream, scratch->svp_stream_index_from_main_stream_index[main_plane->stream_index], main_stream);
239 
240 			// Associate this phantom plane to the main plane
241 			scratch->phantom_plane_index_to_main_plane_index[svp_expanded_display_cfg->num_planes] = plane_index;
242 			scratch->main_plane_index_to_phantom_plane_index[plane_index] = svp_expanded_display_cfg->num_planes;
243 
244 			// Increment num planes
245 			svp_expanded_display_cfg->num_planes++;
246 
247 			// Adjust the main plane settings
248 			svp_expanded_display_cfg->plane_descriptors[plane_index].overrides.legacy_svp_config = dml2_svp_mode_override_main_pipe;
249 		}
250 	}
251 }
252 
pack_mode_programming_params_with_implicit_subvp(struct dml2_core_instance * core,const struct display_configuation_with_meta * display_cfg,const struct dml2_display_cfg * svp_expanded_display_cfg,struct dml2_display_cfg_programming * programming,struct dml2_core_scratch * scratch)253 static void pack_mode_programming_params_with_implicit_subvp(struct dml2_core_instance *core, const struct display_configuation_with_meta *display_cfg,
254 	const struct dml2_display_cfg *svp_expanded_display_cfg, struct dml2_display_cfg_programming *programming, struct dml2_core_scratch *scratch)
255 {
256 	unsigned int stream_index, plane_index, pipe_offset, stream_already_populated_mask, main_plane_index, mcache_index;
257 	unsigned int total_main_mcaches_required = 0;
258 	int total_pipe_regs_copied = 0;
259 	int dml_internal_pipe_index = 0;
260 	const struct dml2_plane_parameters *main_plane;
261 	const struct dml2_plane_parameters *phantom_plane;
262 	const struct dml2_stream_parameters *main_stream;
263 	const struct dml2_stream_parameters *phantom_stream;
264 
265 	// Copy the unexpanded display config to output
266 	memcpy(&programming->display_config, &display_cfg->display_config, sizeof(struct dml2_display_cfg));
267 
268 	// Set the global register values
269 	dml2_core_calcs_get_arb_params(&display_cfg->display_config, &core->clean_me_up.mode_lib, &programming->global_regs.arb_regs);
270 	// Get watermarks uses display config for ref clock override, so it doesn't matter whether we pass the pre or post expansion
271 	// display config
272 	dml2_core_calcs_get_watermarks(&display_cfg->display_config, &core->clean_me_up.mode_lib, &programming->global_regs.wm_regs[0]);
273 
274 	// Check if FAMS2 is required
275 	if (display_cfg->stage3.performed && display_cfg->stage3.success) {
276 		programming->fams2_required = display_cfg->stage3.fams2_required;
277 
278 		dml2_core_calcs_get_global_fams2_programming(&core->clean_me_up.mode_lib, display_cfg, &programming->fams2_global_config);
279 	}
280 
281 	// Only loop over all the main streams (the implicit svp streams will be packed as part of the main stream)
282 	for (stream_index = 0; stream_index < programming->display_config.num_streams; stream_index++) {
283 		main_stream = &svp_expanded_display_cfg->stream_descriptors[stream_index];
284 		phantom_stream = &svp_expanded_display_cfg->stream_descriptors[scratch->svp_stream_index_from_main_stream_index[stream_index]];
285 
286 		// Set the descriptor
287 		programming->stream_programming[stream_index].stream_descriptor = &programming->display_config.stream_descriptors[stream_index];
288 
289 		// Set the odm combine factor
290 		programming->stream_programming[stream_index].num_odms_required = display_cfg->mode_support_result.cfg_support_info.stream_support_info[stream_index].odms_used;
291 
292 		// Check if the stream has implicit SVP enabled
293 		if (main_stream != phantom_stream) {
294 			// If so, copy the phantom stream descriptor
295 			programming->stream_programming[stream_index].phantom_stream.enabled = true;
296 			memcpy(&programming->stream_programming[stream_index].phantom_stream.descriptor, phantom_stream, sizeof(struct dml2_stream_parameters));
297 		} else {
298 			programming->stream_programming[stream_index].phantom_stream.enabled = false;
299 		}
300 
301 		// Due to the way DML indexes data internally, it's easier to populate the rest of the display
302 		// stream programming in the next stage
303 	}
304 
305 	dml_internal_pipe_index = 0;
306 	total_pipe_regs_copied = 0;
307 	stream_already_populated_mask = 0x0;
308 
309 	// Loop over all main planes
310 	for (plane_index = 0; plane_index < programming->display_config.num_planes; plane_index++) {
311 		main_plane = &svp_expanded_display_cfg->plane_descriptors[plane_index];
312 
313 		// Set the descriptor
314 		programming->plane_programming[plane_index].plane_descriptor = &programming->display_config.plane_descriptors[plane_index];
315 
316 		// Set the mpc combine factor
317 		programming->plane_programming[plane_index].num_dpps_required = core->clean_me_up.mode_lib.mp.NoOfDPP[plane_index];
318 
319 		// Setup the appropriate p-state strategy
320 		if (display_cfg->stage3.performed && display_cfg->stage3.success) {
321 			programming->plane_programming[plane_index].uclk_pstate_support_method = display_cfg->stage3.pstate_switch_modes[plane_index];
322 		} else {
323 			programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_pstate_method_na;
324 		}
325 
326 		dml2_core_calcs_get_mall_allocation(&core->clean_me_up.mode_lib, &programming->plane_programming[plane_index].surface_size_mall_bytes, dml_internal_pipe_index);
327 
328 		memcpy(&programming->plane_programming[plane_index].mcache_allocation,
329 			&display_cfg->stage2.mcache_allocations[plane_index],
330 			sizeof(struct dml2_mcache_surface_allocation));
331 		total_main_mcaches_required += programming->plane_programming[plane_index].mcache_allocation.num_mcaches_plane0 +
332 			programming->plane_programming[plane_index].mcache_allocation.num_mcaches_plane1 -
333 			(programming->plane_programming[plane_index].mcache_allocation.last_slice_sharing.plane0_plane1 ? 1 : 0);
334 
335 		for (pipe_offset = 0; pipe_offset < programming->plane_programming[plane_index].num_dpps_required; pipe_offset++) {
336 			// Assign storage for this pipe's register values
337 			programming->plane_programming[plane_index].pipe_regs[pipe_offset] = &programming->pipe_regs[total_pipe_regs_copied];
338 			memset(programming->plane_programming[plane_index].pipe_regs[pipe_offset], 0, sizeof(struct dml2_dchub_per_pipe_register_set));
339 			total_pipe_regs_copied++;
340 
341 			// Populate the main plane regs
342 			dml2_core_calcs_get_pipe_regs(svp_expanded_display_cfg, &core->clean_me_up.mode_lib, programming->plane_programming[plane_index].pipe_regs[pipe_offset], dml_internal_pipe_index);
343 
344 			// Multiple planes can refer to the same stream index, so it's only necessary to populate it once
345 			if (!(stream_already_populated_mask & (0x1 << main_plane->stream_index))) {
346 				dml2_core_calcs_get_stream_programming(&core->clean_me_up.mode_lib, &programming->stream_programming[main_plane->stream_index], dml_internal_pipe_index);
347 
348 				programming->stream_programming[main_plane->stream_index].uclk_pstate_method = programming->plane_programming[plane_index].uclk_pstate_support_method;
349 
350 				/* unconditionally populate fams2 params */
351 				dml2_core_calcs_get_stream_fams2_programming(&core->clean_me_up.mode_lib,
352 					display_cfg,
353 					&programming->stream_programming[main_plane->stream_index].fams2_base_params,
354 					&programming->stream_programming[main_plane->stream_index].fams2_sub_params,
355 					programming->stream_programming[main_plane->stream_index].uclk_pstate_method,
356 					plane_index);
357 
358 				stream_already_populated_mask |= (0x1 << main_plane->stream_index);
359 			}
360 			dml_internal_pipe_index++;
361 		}
362 	}
363 
364 	for (plane_index = programming->display_config.num_planes; plane_index < svp_expanded_display_cfg->num_planes; plane_index++) {
365 		phantom_plane = &svp_expanded_display_cfg->plane_descriptors[plane_index];
366 		main_plane_index = scratch->phantom_plane_index_to_main_plane_index[plane_index];
367 		main_plane = &svp_expanded_display_cfg->plane_descriptors[main_plane_index];
368 
369 		programming->plane_programming[main_plane_index].phantom_plane.valid = true;
370 		memcpy(&programming->plane_programming[main_plane_index].phantom_plane.descriptor, phantom_plane, sizeof(struct dml2_plane_parameters));
371 
372 		dml2_core_calcs_get_mall_allocation(&core->clean_me_up.mode_lib, &programming->plane_programming[main_plane_index].svp_size_mall_bytes, dml_internal_pipe_index);
373 
374 		/* generate mcache allocation, phantoms use identical mcache configuration, but in the MALL set and unique mcache ID's beginning after all main ID's */
375 		memcpy(&programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation,
376 			&programming->plane_programming[main_plane_index].mcache_allocation,
377 			sizeof(struct dml2_mcache_surface_allocation));
378 		for (mcache_index = 0; mcache_index < programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.num_mcaches_plane0; mcache_index++) {
379 			programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.global_mcache_ids_plane0[mcache_index] += total_main_mcaches_required;
380 			programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.global_mcache_ids_mall_plane0[mcache_index] =
381 				programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.global_mcache_ids_plane0[mcache_index];
382 		}
383 		for (mcache_index = 0; mcache_index < programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.num_mcaches_plane1; mcache_index++) {
384 			programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.global_mcache_ids_plane1[mcache_index] += total_main_mcaches_required;
385 			programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.global_mcache_ids_mall_plane1[mcache_index] =
386 				programming->plane_programming[main_plane_index].phantom_plane.mcache_allocation.global_mcache_ids_plane1[mcache_index];
387 		}
388 
389 		for (pipe_offset = 0; pipe_offset < programming->plane_programming[main_plane_index].num_dpps_required; pipe_offset++) {
390 			// Assign storage for this pipe's register values
391 			programming->plane_programming[main_plane_index].phantom_plane.pipe_regs[pipe_offset] = &programming->pipe_regs[total_pipe_regs_copied];
392 			memset(programming->plane_programming[main_plane_index].phantom_plane.pipe_regs[pipe_offset], 0, sizeof(struct dml2_dchub_per_pipe_register_set));
393 			total_pipe_regs_copied++;
394 
395 			// Populate the phantom plane regs
396 			dml2_core_calcs_get_pipe_regs(svp_expanded_display_cfg, &core->clean_me_up.mode_lib, programming->plane_programming[main_plane_index].phantom_plane.pipe_regs[pipe_offset], dml_internal_pipe_index);
397 			// Populate the phantom stream specific programming
398 			if (!(stream_already_populated_mask & (0x1 << phantom_plane->stream_index))) {
399 				dml2_core_calcs_get_global_sync_programming(&core->clean_me_up.mode_lib, &programming->stream_programming[main_plane->stream_index].phantom_stream.global_sync, dml_internal_pipe_index);
400 
401 				stream_already_populated_mask |= (0x1 << phantom_plane->stream_index);
402 			}
403 
404 			dml_internal_pipe_index++;
405 		}
406 	}
407 }
408 
core_dcn4_mode_support(struct dml2_core_mode_support_in_out * in_out)409 bool core_dcn4_mode_support(struct dml2_core_mode_support_in_out *in_out)
410 {
411 	struct dml2_core_instance *core = (struct dml2_core_instance *)in_out->instance;
412 	struct dml2_core_mode_support_locals *l = &core->scratch.mode_support_locals;
413 
414 	bool result;
415 	unsigned int i, stream_index, stream_bitmask;
416 	int unsigned odm_count, num_odm_output_segments, dpp_count;
417 
418 	expand_implict_subvp(in_out->display_cfg, &l->svp_expanded_display_cfg, &core->scratch);
419 
420 	l->mode_support_ex_params.mode_lib = &core->clean_me_up.mode_lib;
421 	l->mode_support_ex_params.in_display_cfg = &l->svp_expanded_display_cfg;
422 	l->mode_support_ex_params.min_clk_table = in_out->min_clk_table;
423 	l->mode_support_ex_params.min_clk_index = in_out->min_clk_index;
424 	l->mode_support_ex_params.out_evaluation_info = &in_out->mode_support_result.cfg_support_info.clean_me_up.support_info;
425 
426 	result = dml2_core_calcs_mode_support_ex(&l->mode_support_ex_params);
427 
428 	in_out->mode_support_result.cfg_support_info.is_supported = result;
429 
430 	if (result) {
431 		in_out->mode_support_result.global.dispclk_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.RequiredDISPCLK * 1000);
432 		in_out->mode_support_result.global.dcfclk_deepsleep_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.dcfclk_deepsleep * 1000);
433 		in_out->mode_support_result.global.socclk_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.SOCCLK * 1000);
434 
435 		in_out->mode_support_result.global.fclk_pstate_supported = l->mode_support_ex_params.out_evaluation_info->global_fclk_change_supported;
436 		in_out->mode_support_result.global.uclk_pstate_supported = l->mode_support_ex_params.out_evaluation_info->global_dram_clock_change_supported;
437 
438 		in_out->mode_support_result.global.active.fclk_khz = (unsigned long)(core->clean_me_up.mode_lib.ms.FabricClock * 1000);
439 		in_out->mode_support_result.global.active.dcfclk_khz = (unsigned long)(core->clean_me_up.mode_lib.ms.DCFCLK * 1000);
440 
441 
442 		in_out->mode_support_result.global.svp_prefetch.fclk_khz = (unsigned long)core->clean_me_up.mode_lib.ms.FabricClock * 1000;
443 		in_out->mode_support_result.global.svp_prefetch.dcfclk_khz = (unsigned long)core->clean_me_up.mode_lib.ms.DCFCLK * 1000;
444 
445 		in_out->mode_support_result.global.active.average_bw_sdp_kbps = 0;
446 		in_out->mode_support_result.global.active.urgent_bw_dram_kbps = 0;
447 		in_out->mode_support_result.global.svp_prefetch.average_bw_sdp_kbps = 0;
448 		in_out->mode_support_result.global.svp_prefetch.urgent_bw_dram_kbps = 0;
449 
450 		in_out->mode_support_result.global.active.average_bw_sdp_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->avg_bandwidth_required[dml2_core_internal_soc_state_sys_active][dml2_core_internal_bw_sdp] * 1000), 1.0);
451 		in_out->mode_support_result.global.active.urgent_bw_sdp_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->urg_bandwidth_required_flip[dml2_core_internal_soc_state_sys_active][dml2_core_internal_bw_sdp] * 1000), 1.0);
452 		in_out->mode_support_result.global.svp_prefetch.average_bw_sdp_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->avg_bandwidth_required[dml2_core_internal_soc_state_svp_prefetch][dml2_core_internal_bw_sdp] * 1000), 1.0);
453 		in_out->mode_support_result.global.svp_prefetch.urgent_bw_sdp_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->urg_bandwidth_required_flip[dml2_core_internal_soc_state_svp_prefetch][dml2_core_internal_bw_sdp] * 1000), 1.0);
454 
455 		in_out->mode_support_result.global.active.average_bw_dram_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->avg_bandwidth_required[dml2_core_internal_soc_state_sys_active][dml2_core_internal_bw_dram] * 1000), 1.0);
456 		in_out->mode_support_result.global.active.urgent_bw_dram_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->urg_bandwidth_required_flip[dml2_core_internal_soc_state_sys_active][dml2_core_internal_bw_dram] * 1000), 1.0);
457 		in_out->mode_support_result.global.svp_prefetch.average_bw_dram_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->avg_bandwidth_required[dml2_core_internal_soc_state_svp_prefetch][dml2_core_internal_bw_dram] * 1000), 1.0);
458 		in_out->mode_support_result.global.svp_prefetch.urgent_bw_dram_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->urg_bandwidth_required_flip[dml2_core_internal_soc_state_svp_prefetch][dml2_core_internal_bw_dram] * 1000), 1.0);
459 		dml2_printf("DML::%s: in_out->mode_support_result.global.active.urgent_bw_sdp_kbps = %ld\n", __func__, in_out->mode_support_result.global.active.urgent_bw_sdp_kbps);
460 		dml2_printf("DML::%s: in_out->mode_support_result.global.svp_prefetch.urgent_bw_sdp_kbps = %ld\n", __func__, in_out->mode_support_result.global.svp_prefetch.urgent_bw_sdp_kbps);
461 		dml2_printf("DML::%s: in_out->mode_support_result.global.active.urgent_bw_dram_kbps = %ld\n", __func__, in_out->mode_support_result.global.active.urgent_bw_dram_kbps);
462 		dml2_printf("DML::%s: in_out->mode_support_result.global.svp_prefetch.urgent_bw_dram_kbps = %ld\n", __func__, in_out->mode_support_result.global.svp_prefetch.urgent_bw_dram_kbps);
463 
464 		for (i = 0; i < l->svp_expanded_display_cfg.num_planes; i++) {
465 			in_out->mode_support_result.per_plane[i].dppclk_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.RequiredDPPCLK[i] * 1000);
466 		}
467 
468 		stream_bitmask = 0;
469 		for (i = 0; i < l->svp_expanded_display_cfg.num_planes; i++) {
470 			odm_count = 1;
471 			dpp_count = l->mode_support_ex_params.out_evaluation_info->DPPPerSurface[i];
472 			num_odm_output_segments = 1;
473 
474 			switch (l->mode_support_ex_params.out_evaluation_info->ODMMode[i]) {
475 			case dml2_odm_mode_bypass:
476 				odm_count = 1;
477 				dpp_count = l->mode_support_ex_params.out_evaluation_info->DPPPerSurface[i];
478 				break;
479 			case dml2_odm_mode_combine_2to1:
480 				odm_count = 2;
481 				dpp_count = 2;
482 				break;
483 			case dml2_odm_mode_combine_3to1:
484 				odm_count = 3;
485 				dpp_count = 3;
486 				break;
487 			case dml2_odm_mode_combine_4to1:
488 				odm_count = 4;
489 				dpp_count = 4;
490 				break;
491 			case dml2_odm_mode_split_1to2:
492 			case dml2_odm_mode_mso_1to2:
493 				num_odm_output_segments = 2;
494 				break;
495 			case dml2_odm_mode_mso_1to4:
496 				num_odm_output_segments = 4;
497 				break;
498 			case dml2_odm_mode_auto:
499 			default:
500 				odm_count = 1;
501 				dpp_count = l->mode_support_ex_params.out_evaluation_info->DPPPerSurface[i];
502 				break;
503 			}
504 
505 			in_out->mode_support_result.cfg_support_info.plane_support_info[i].dpps_used = dpp_count;
506 
507 			dml2_core_calcs_get_plane_support_info(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, &in_out->mode_support_result.cfg_support_info.plane_support_info[i], i);
508 
509 			stream_index = l->svp_expanded_display_cfg.plane_descriptors[i].stream_index;
510 
511 			in_out->mode_support_result.per_stream[stream_index].dscclk_khz = (unsigned int)core->clean_me_up.mode_lib.ms.required_dscclk_freq_mhz[i] * 1000;
512 			dml2_printf("CORE_DCN4::%s: i=%d stream_index=%d, in_out->mode_support_result.per_stream[stream_index].dscclk_khz = %u\n", __func__, i, stream_index, in_out->mode_support_result.per_stream[stream_index].dscclk_khz);
513 
514 			if (!((stream_bitmask >> stream_index) & 0x1)) {
515 				in_out->mode_support_result.cfg_support_info.stream_support_info[stream_index].odms_used = odm_count;
516 				in_out->mode_support_result.cfg_support_info.stream_support_info[stream_index].num_odm_output_segments = num_odm_output_segments;
517 				in_out->mode_support_result.cfg_support_info.stream_support_info[stream_index].dsc_enable = l->mode_support_ex_params.out_evaluation_info->DSCEnabled[i];
518 				in_out->mode_support_result.cfg_support_info.stream_support_info[stream_index].num_dsc_slices = l->mode_support_ex_params.out_evaluation_info->NumberOfDSCSlices[i];
519 				dml2_core_calcs_get_stream_support_info(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, &in_out->mode_support_result.cfg_support_info.stream_support_info[stream_index], i);
520 				in_out->mode_support_result.per_stream[stream_index].dtbclk_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.RequiredDTBCLK[i] * 1000);
521 				stream_bitmask |= 0x1 << stream_index;
522 			}
523 		}
524 	}
525 
526 	return result;
527 }
528 
lookup_uclk_dpm_index_by_freq(unsigned long uclk_freq_khz,struct dml2_soc_bb * soc_bb)529 static int lookup_uclk_dpm_index_by_freq(unsigned long uclk_freq_khz, struct dml2_soc_bb *soc_bb)
530 {
531 	int i;
532 
533 	for (i = 0; i < soc_bb->clk_table.uclk.num_clk_values; i++) {
534 		if (uclk_freq_khz == soc_bb->clk_table.uclk.clk_values_khz[i])
535 			return i;
536 	}
537 	return 0;
538 }
539 
core_dcn4_mode_programming(struct dml2_core_mode_programming_in_out * in_out)540 bool core_dcn4_mode_programming(struct dml2_core_mode_programming_in_out *in_out)
541 {
542 	struct dml2_core_instance *core = (struct dml2_core_instance *)in_out->instance;
543 	struct dml2_core_mode_programming_locals *l = &core->scratch.mode_programming_locals;
544 
545 	bool result = false;
546 	unsigned int pipe_offset;
547 	int dml_internal_pipe_index;
548 	int total_pipe_regs_copied = 0;
549 	int stream_already_populated_mask = 0;
550 
551 	int main_stream_index;
552 	unsigned int plane_index;
553 
554 	expand_implict_subvp(in_out->display_cfg, &l->svp_expanded_display_cfg, &core->scratch);
555 
556 	l->mode_programming_ex_params.mode_lib = &core->clean_me_up.mode_lib;
557 	l->mode_programming_ex_params.in_display_cfg = &l->svp_expanded_display_cfg;
558 	l->mode_programming_ex_params.min_clk_table = in_out->instance->minimum_clock_table;
559 	l->mode_programming_ex_params.cfg_support_info = in_out->cfg_support_info;
560 	l->mode_programming_ex_params.programming = in_out->programming;
561 	l->mode_programming_ex_params.min_clk_index = lookup_uclk_dpm_index_by_freq(in_out->programming->min_clocks.dcn4x.active.uclk_khz,
562 		&core->clean_me_up.mode_lib.soc);
563 
564 	result = dml2_core_calcs_mode_programming_ex(&l->mode_programming_ex_params);
565 
566 	if (result) {
567 		// If the input display configuration contains implict SVP, we need to use a special packer
568 		if (in_out->display_cfg->display_config.overrides.enable_subvp_implicit_pmo) {
569 			pack_mode_programming_params_with_implicit_subvp(core, in_out->display_cfg, &l->svp_expanded_display_cfg, in_out->programming, &core->scratch);
570 		} else {
571 			memcpy(&in_out->programming->display_config, in_out->display_cfg, sizeof(struct dml2_display_cfg));
572 
573 			dml2_core_calcs_get_arb_params(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, &in_out->programming->global_regs.arb_regs);
574 			dml2_core_calcs_get_watermarks(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, &in_out->programming->global_regs.wm_regs[0]);
575 
576 			dml_internal_pipe_index = 0;
577 
578 			for (plane_index = 0; plane_index < in_out->programming->display_config.num_planes; plane_index++) {
579 				in_out->programming->plane_programming[plane_index].num_dpps_required = core->clean_me_up.mode_lib.mp.NoOfDPP[plane_index];
580 
581 				if (in_out->programming->display_config.plane_descriptors[plane_index].overrides.legacy_svp_config == dml2_svp_mode_override_main_pipe)
582 					in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_pstate_method_fw_svp;
583 				else if (in_out->programming->display_config.plane_descriptors[plane_index].overrides.legacy_svp_config == dml2_svp_mode_override_phantom_pipe)
584 					in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_pstate_method_fw_svp;
585 				else if (in_out->programming->display_config.plane_descriptors[plane_index].overrides.legacy_svp_config == dml2_svp_mode_override_phantom_pipe_no_data_return)
586 					in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_pstate_method_fw_svp;
587 				else {
588 					if (core->clean_me_up.mode_lib.mp.MaxActiveDRAMClockChangeLatencySupported[plane_index] >= core->clean_me_up.mode_lib.soc.power_management_parameters.dram_clk_change_blackout_us)
589 						in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_pstate_method_vactive;
590 					else if (core->clean_me_up.mode_lib.mp.TWait[plane_index] >= core->clean_me_up.mode_lib.soc.power_management_parameters.dram_clk_change_blackout_us)
591 						in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_pstate_method_vblank;
592 					else
593 						in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_pstate_method_na;
594 				}
595 
596 				dml2_core_calcs_get_mall_allocation(&core->clean_me_up.mode_lib, &in_out->programming->plane_programming[plane_index].surface_size_mall_bytes, dml_internal_pipe_index);
597 
598 				memcpy(&in_out->programming->plane_programming[plane_index].mcache_allocation,
599 					&in_out->display_cfg->stage2.mcache_allocations[plane_index],
600 					sizeof(struct dml2_mcache_surface_allocation));
601 
602 				for (pipe_offset = 0; pipe_offset < in_out->programming->plane_programming[plane_index].num_dpps_required; pipe_offset++) {
603 					in_out->programming->plane_programming[plane_index].plane_descriptor = &in_out->programming->display_config.plane_descriptors[plane_index];
604 
605 					// Assign storage for this pipe's register values
606 					in_out->programming->plane_programming[plane_index].pipe_regs[pipe_offset] = &in_out->programming->pipe_regs[total_pipe_regs_copied];
607 					memset(in_out->programming->plane_programming[plane_index].pipe_regs[pipe_offset], 0, sizeof(struct dml2_dchub_per_pipe_register_set));
608 					total_pipe_regs_copied++;
609 
610 					// Populate
611 					dml2_core_calcs_get_pipe_regs(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, in_out->programming->plane_programming[plane_index].pipe_regs[pipe_offset], dml_internal_pipe_index);
612 
613 					main_stream_index = in_out->programming->display_config.plane_descriptors[plane_index].stream_index;
614 
615 					// Multiple planes can refer to the same stream index, so it's only necessary to populate it once
616 					if (!(stream_already_populated_mask & (0x1 << main_stream_index))) {
617 						in_out->programming->stream_programming[main_stream_index].stream_descriptor = &in_out->programming->display_config.stream_descriptors[main_stream_index];
618 						in_out->programming->stream_programming[main_stream_index].num_odms_required = in_out->cfg_support_info->stream_support_info[main_stream_index].odms_used;
619 						dml2_core_calcs_get_stream_programming(&core->clean_me_up.mode_lib, &in_out->programming->stream_programming[main_stream_index], dml_internal_pipe_index);
620 
621 						stream_already_populated_mask |= (0x1 << main_stream_index);
622 					}
623 					dml_internal_pipe_index++;
624 				}
625 			}
626 		}
627 	}
628 
629 	return result;
630 }
631 
core_dcn4_populate_informative(struct dml2_core_populate_informative_in_out * in_out)632 bool core_dcn4_populate_informative(struct dml2_core_populate_informative_in_out *in_out)
633 {
634 	struct dml2_core_internal_display_mode_lib *mode_lib = &in_out->instance->clean_me_up.mode_lib;
635 
636 	if (in_out->mode_is_supported)
637 		in_out->programming->informative.voltage_level = in_out->instance->scratch.mode_programming_locals.mode_programming_ex_params.min_clk_index;
638 	else
639 		in_out->programming->informative.voltage_level = in_out->instance->scratch.mode_support_locals.mode_support_ex_params.min_clk_index;
640 
641 	dml2_core_calcs_get_informative(mode_lib, in_out->programming);
642 	return true;
643 }
644 
core_dcn4_calculate_mcache_allocation(struct dml2_calculate_mcache_allocation_in_out * in_out)645 bool core_dcn4_calculate_mcache_allocation(struct dml2_calculate_mcache_allocation_in_out *in_out)
646 {
647 	memset(in_out->mcache_allocation, 0, sizeof(struct dml2_mcache_surface_allocation));
648 
649 	dml2_core_calcs_get_mcache_allocation(&in_out->instance->clean_me_up.mode_lib, in_out->mcache_allocation, in_out->plane_index);
650 
651 	if (in_out->mcache_allocation->num_mcaches_plane0 > 0)
652 		in_out->mcache_allocation->mcache_x_offsets_plane0[in_out->mcache_allocation->num_mcaches_plane0 - 1] = in_out->plane_descriptor->surface.plane0.width;
653 
654 	if (in_out->mcache_allocation->num_mcaches_plane1 > 0)
655 		in_out->mcache_allocation->mcache_x_offsets_plane1[in_out->mcache_allocation->num_mcaches_plane1 - 1] = in_out->plane_descriptor->surface.plane1.width;
656 
657 	in_out->mcache_allocation->requires_dedicated_mall_mcache = false;
658 
659 	return true;
660 }
661