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  static const 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->max_flip_time_us = ip_params->max_flip_time_us;
94  	ip_caps->max_flip_time_lines = ip_params->max_flip_time_lines;
95  	ip_caps->hostvm_mode = ip_params->hostvm_mode;
96  
97  	// FIXME_STAGE2: cleanup after adding all dv override to ip_caps
98  	ip_caps->subvp_drr_scheduling_margin_us = 100;
99  	ip_caps->subvp_prefetch_end_to_mall_start_us = 15;
100  	ip_caps->subvp_fw_processing_delay = 16;
101  
102  }
103  
patch_ip_params_with_ip_caps(struct dml2_core_ip_params * ip_params,const struct dml2_ip_capabilities * ip_caps)104  static void patch_ip_params_with_ip_caps(struct dml2_core_ip_params *ip_params, const struct dml2_ip_capabilities *ip_caps)
105  {
106  	ip_params->max_num_dpp = ip_caps->pipe_count;
107  	ip_params->max_num_otg = ip_caps->otg_count;
108  	ip_params->num_dsc = ip_caps->num_dsc;
109  	ip_params->max_num_dp2p0_streams = ip_caps->max_num_dp2p0_streams;
110  	ip_params->max_num_dp2p0_outputs = ip_caps->max_num_dp2p0_outputs;
111  	ip_params->max_num_hdmi_frl_outputs = ip_caps->max_num_hdmi_frl_outputs;
112  	ip_params->rob_buffer_size_kbytes = ip_caps->rob_buffer_size_kbytes;
113  	ip_params->config_return_buffer_size_in_kbytes = ip_caps->config_return_buffer_size_in_kbytes;
114  	ip_params->config_return_buffer_segment_size_in_kbytes = ip_caps->config_return_buffer_segment_size_in_kbytes;
115  	ip_params->meta_fifo_size_in_kentries = ip_caps->meta_fifo_size_in_kentries;
116  	ip_params->compressed_buffer_segment_size_in_kbytes = ip_caps->compressed_buffer_segment_size_in_kbytes;
117  	ip_params->max_flip_time_us = ip_caps->max_flip_time_us;
118  	ip_params->max_flip_time_lines = ip_caps->max_flip_time_lines;
119  	ip_params->hostvm_mode = ip_caps->hostvm_mode;
120  }
121  
core_dcn4_initialize(struct dml2_core_initialize_in_out * in_out)122  bool core_dcn4_initialize(struct dml2_core_initialize_in_out *in_out)
123  {
124  	struct dml2_core_instance *core = in_out->instance;
125  
126  	if (!in_out->minimum_clock_table)
127  		return false;
128  	else
129  		core->minimum_clock_table = in_out->minimum_clock_table;
130  
131  	if (in_out->explicit_ip_bb && in_out->explicit_ip_bb_size > 0) {
132  		memcpy(&core->clean_me_up.mode_lib.ip, in_out->explicit_ip_bb, in_out->explicit_ip_bb_size);
133  
134  		// FIXME_STAGE2:
135  		// DV still uses stage1 ip_param_st for each variant, need to patch the ip_caps with ip_param info
136  		// Should move DV to use ip_caps but need move more overrides to ip_caps
137  		patch_ip_caps_with_explicit_ip_params(in_out->ip_caps, in_out->explicit_ip_bb);
138  		core->clean_me_up.mode_lib.ip.subvp_pstate_allow_width_us = core_dcn4_ip_caps_base.subvp_pstate_allow_width_us;
139  		core->clean_me_up.mode_lib.ip.subvp_fw_processing_delay_us = core_dcn4_ip_caps_base.subvp_pstate_allow_width_us;
140  		core->clean_me_up.mode_lib.ip.subvp_swath_height_margin_lines = core_dcn4_ip_caps_base.subvp_swath_height_margin_lines;
141  	} else {
142  			memcpy(&core->clean_me_up.mode_lib.ip, &core_dcn4_ip_caps_base, sizeof(struct dml2_core_ip_params));
143  		patch_ip_params_with_ip_caps(&core->clean_me_up.mode_lib.ip, in_out->ip_caps);
144  
145  		core->clean_me_up.mode_lib.ip.imall_supported = false;
146  	}
147  
148  	memcpy(&core->clean_me_up.mode_lib.soc, in_out->soc_bb, sizeof(struct dml2_soc_bb));
149  	memcpy(&core->clean_me_up.mode_lib.ip_caps, in_out->ip_caps, sizeof(struct dml2_ip_capabilities));
150  
151  	return true;
152  }
153  
create_phantom_stream_from_main_stream(struct dml2_stream_parameters * phantom,const struct dml2_stream_parameters * main,const struct dml2_implicit_svp_meta * meta)154  static void create_phantom_stream_from_main_stream(struct dml2_stream_parameters *phantom, const struct dml2_stream_parameters *main,
155  	const struct dml2_implicit_svp_meta *meta)
156  {
157  	memcpy(phantom, main, sizeof(struct dml2_stream_parameters));
158  
159  	phantom->timing.v_total = meta->v_total;
160  	phantom->timing.v_active = meta->v_active;
161  	phantom->timing.v_front_porch = meta->v_front_porch;
162  	phantom->timing.vblank_nom = phantom->timing.v_total - phantom->timing.v_active;
163  	phantom->timing.drr_config.enabled = false;
164  }
165  
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)166  static void create_phantom_plane_from_main_plane(struct dml2_plane_parameters *phantom, const struct dml2_plane_parameters *main,
167  	const struct dml2_stream_parameters *phantom_stream, int phantom_stream_index, const struct dml2_stream_parameters *main_stream)
168  {
169  	memcpy(phantom, main, sizeof(struct dml2_plane_parameters));
170  
171  	phantom->stream_index = phantom_stream_index;
172  	phantom->overrides.refresh_from_mall = dml2_refresh_from_mall_mode_override_force_disable;
173  	phantom->overrides.legacy_svp_config = dml2_svp_mode_override_phantom_pipe_no_data_return;
174  	phantom->composition.viewport.plane0.height = (long int unsigned) math_min2(math_ceil2(
175  		(double)main->composition.scaler_info.plane0.v_ratio * (double)phantom_stream->timing.v_active, 16.0),
176  		(double)main->composition.viewport.plane0.height);
177  	phantom->composition.viewport.plane1.height = (long int unsigned) math_min2(math_ceil2(
178  		(double)main->composition.scaler_info.plane1.v_ratio * (double)phantom_stream->timing.v_active, 16.0),
179  		(double)main->composition.viewport.plane1.height);
180  	phantom->immediate_flip = false;
181  	phantom->dynamic_meta_data.enable = false;
182  	phantom->cursor.num_cursors = 0;
183  	phantom->cursor.cursor_width = 0;
184  	phantom->tdlut.setup_for_tdlut = false;
185  }
186  
expand_implict_subvp(const struct display_configuation_with_meta * display_cfg,struct dml2_display_cfg * svp_expanded_display_cfg,struct dml2_core_scratch * scratch)187  static void expand_implict_subvp(const struct display_configuation_with_meta *display_cfg, struct dml2_display_cfg *svp_expanded_display_cfg,
188  	struct dml2_core_scratch *scratch)
189  {
190  	unsigned int stream_index, plane_index;
191  	const struct dml2_plane_parameters *main_plane;
192  	const struct dml2_stream_parameters *main_stream;
193  	const struct dml2_stream_parameters *phantom_stream;
194  
195  	memcpy(svp_expanded_display_cfg, &display_cfg->display_config, sizeof(struct dml2_display_cfg));
196  	memset(scratch->main_stream_index_from_svp_stream_index, 0, sizeof(int) * DML2_MAX_PLANES);
197  	memset(scratch->svp_stream_index_from_main_stream_index, 0, sizeof(int) * DML2_MAX_PLANES);
198  	memset(scratch->main_plane_index_to_phantom_plane_index, 0, sizeof(int) * DML2_MAX_PLANES);
199  
200  	if (!display_cfg->display_config.overrides.enable_subvp_implicit_pmo)
201  		return;
202  
203  	/* disable unbounded requesting for all planes until stage 3 has been performed */
204  	if (!display_cfg->stage3.performed) {
205  		svp_expanded_display_cfg->overrides.hw.force_unbounded_requesting.enable = true;
206  		svp_expanded_display_cfg->overrides.hw.force_unbounded_requesting.value = false;
207  	}
208  	// Create the phantom streams
209  	for (stream_index = 0; stream_index < display_cfg->display_config.num_streams; stream_index++) {
210  		main_stream = &display_cfg->display_config.stream_descriptors[stream_index];
211  		scratch->main_stream_index_from_svp_stream_index[stream_index] = stream_index;
212  		scratch->svp_stream_index_from_main_stream_index[stream_index] = stream_index;
213  
214  		if (display_cfg->stage3.stream_svp_meta[stream_index].valid) {
215  			// Create the phantom stream
216  			create_phantom_stream_from_main_stream(&svp_expanded_display_cfg->stream_descriptors[svp_expanded_display_cfg->num_streams],
217  				main_stream, &display_cfg->stage3.stream_svp_meta[stream_index]);
218  
219  			// Associate this phantom stream to the main stream
220  			scratch->main_stream_index_from_svp_stream_index[svp_expanded_display_cfg->num_streams] = stream_index;
221  			scratch->svp_stream_index_from_main_stream_index[stream_index] = svp_expanded_display_cfg->num_streams;
222  
223  			// Increment num streams
224  			svp_expanded_display_cfg->num_streams++;
225  		}
226  	}
227  
228  	// Create the phantom planes
229  	for (plane_index = 0; plane_index < display_cfg->display_config.num_planes; plane_index++) {
230  		main_plane = &display_cfg->display_config.plane_descriptors[plane_index];
231  
232  		if (display_cfg->stage3.stream_svp_meta[main_plane->stream_index].valid) {
233  			main_stream = &display_cfg->display_config.stream_descriptors[main_plane->stream_index];
234  			phantom_stream = &svp_expanded_display_cfg->stream_descriptors[scratch->svp_stream_index_from_main_stream_index[main_plane->stream_index]];
235  			create_phantom_plane_from_main_plane(&svp_expanded_display_cfg->plane_descriptors[svp_expanded_display_cfg->num_planes],
236  				main_plane, phantom_stream, scratch->svp_stream_index_from_main_stream_index[main_plane->stream_index], main_stream);
237  
238  			// Associate this phantom plane to the main plane
239  			scratch->phantom_plane_index_to_main_plane_index[svp_expanded_display_cfg->num_planes] = plane_index;
240  			scratch->main_plane_index_to_phantom_plane_index[plane_index] = svp_expanded_display_cfg->num_planes;
241  
242  			// Increment num planes
243  			svp_expanded_display_cfg->num_planes++;
244  
245  			// Adjust the main plane settings
246  			svp_expanded_display_cfg->plane_descriptors[plane_index].overrides.legacy_svp_config = dml2_svp_mode_override_main_pipe;
247  		}
248  	}
249  }
250  
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)251  static void pack_mode_programming_params_with_implicit_subvp(struct dml2_core_instance *core, const struct display_configuation_with_meta *display_cfg,
252  	const struct dml2_display_cfg *svp_expanded_display_cfg, struct dml2_display_cfg_programming *programming, struct dml2_core_scratch *scratch)
253  {
254  	unsigned int stream_index, plane_index, pipe_offset, stream_already_populated_mask, main_plane_index;
255  	int total_pipe_regs_copied = 0;
256  	int dml_internal_pipe_index = 0;
257  	const struct dml2_plane_parameters *main_plane;
258  	const struct dml2_plane_parameters *phantom_plane;
259  	const struct dml2_stream_parameters *main_stream;
260  	const struct dml2_stream_parameters *phantom_stream;
261  
262  	// Copy the unexpanded display config to output
263  	memcpy(&programming->display_config, &display_cfg->display_config, sizeof(struct dml2_display_cfg));
264  
265  	// Set the global register values
266  	dml2_core_calcs_get_arb_params(&display_cfg->display_config, &core->clean_me_up.mode_lib, &programming->global_regs.arb_regs);
267  	// Get watermarks uses display config for ref clock override, so it doesn't matter whether we pass the pre or post expansion
268  	// display config
269  	dml2_core_calcs_get_watermarks(&display_cfg->display_config, &core->clean_me_up.mode_lib, &programming->global_regs.wm_regs[0]);
270  
271  	// Check if FAMS2 is required
272  	if (display_cfg->stage3.performed && display_cfg->stage3.success) {
273  		programming->fams2_required = display_cfg->stage3.fams2_required;
274  
275  		dml2_core_calcs_get_global_fams2_programming(&core->clean_me_up.mode_lib, display_cfg, &programming->fams2_global_config);
276  	}
277  
278  	// Only loop over all the main streams (the implicit svp streams will be packed as part of the main stream)
279  	for (stream_index = 0; stream_index < programming->display_config.num_streams; stream_index++) {
280  		main_stream = &svp_expanded_display_cfg->stream_descriptors[stream_index];
281  		phantom_stream = &svp_expanded_display_cfg->stream_descriptors[scratch->svp_stream_index_from_main_stream_index[stream_index]];
282  
283  		// Set the descriptor
284  		programming->stream_programming[stream_index].stream_descriptor = &programming->display_config.stream_descriptors[stream_index];
285  
286  		// Set the odm combine factor
287  		programming->stream_programming[stream_index].num_odms_required = display_cfg->mode_support_result.cfg_support_info.stream_support_info[stream_index].odms_used;
288  
289  		// Check if the stream has implicit SVP enabled
290  		if (main_stream != phantom_stream) {
291  			// If so, copy the phantom stream descriptor
292  			programming->stream_programming[stream_index].phantom_stream.enabled = true;
293  			memcpy(&programming->stream_programming[stream_index].phantom_stream.descriptor, phantom_stream, sizeof(struct dml2_stream_parameters));
294  		} else {
295  			programming->stream_programming[stream_index].phantom_stream.enabled = false;
296  		}
297  
298  		// Due to the way DML indexes data internally, it's easier to populate the rest of the display
299  		// stream programming in the next stage
300  	}
301  
302  	dml_internal_pipe_index = 0;
303  	total_pipe_regs_copied = 0;
304  	stream_already_populated_mask = 0x0;
305  
306  	// Loop over all main planes
307  	for (plane_index = 0; plane_index < programming->display_config.num_planes; plane_index++) {
308  		main_plane = &svp_expanded_display_cfg->plane_descriptors[plane_index];
309  
310  		// Set the descriptor
311  		programming->plane_programming[plane_index].plane_descriptor = &programming->display_config.plane_descriptors[plane_index];
312  
313  		// Set the mpc combine factor
314  		programming->plane_programming[plane_index].num_dpps_required = core->clean_me_up.mode_lib.mp.NoOfDPP[plane_index];
315  
316  		// Setup the appropriate p-state strategy
317  		if (display_cfg->stage3.performed && display_cfg->stage3.success) {
318  			switch (display_cfg->stage3.pstate_switch_modes[plane_index]) {
319  			case dml2_uclk_pstate_support_method_vactive:
320  			case dml2_uclk_pstate_support_method_vblank:
321  			case dml2_uclk_pstate_support_method_fw_subvp_phantom:
322  			case dml2_uclk_pstate_support_method_fw_drr:
323  			case dml2_uclk_pstate_support_method_fw_vactive_drr:
324  			case dml2_uclk_pstate_support_method_fw_vblank_drr:
325  			case dml2_uclk_pstate_support_method_fw_subvp_phantom_drr:
326  				programming->plane_programming[plane_index].uclk_pstate_support_method = display_cfg->stage3.pstate_switch_modes[plane_index];
327  				break;
328  			case dml2_uclk_pstate_support_method_reserved_hw:
329  			case dml2_uclk_pstate_support_method_reserved_fw:
330  			case dml2_uclk_pstate_support_method_reserved_fw_drr_fixed:
331  			case dml2_uclk_pstate_support_method_reserved_fw_drr_var:
332  			case dml2_uclk_pstate_support_method_not_supported:
333  			case dml2_uclk_pstate_support_method_count:
334  			default:
335  				programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_not_supported;
336  				break;
337  			}
338  		} else {
339  			programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_not_supported;
340  		}
341  
342  		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);
343  
344  		for (pipe_offset = 0; pipe_offset < programming->plane_programming[plane_index].num_dpps_required; pipe_offset++) {
345  			// Assign storage for this pipe's register values
346  			programming->plane_programming[plane_index].pipe_regs[pipe_offset] = &programming->pipe_regs[total_pipe_regs_copied];
347  			memset(programming->plane_programming[plane_index].pipe_regs[pipe_offset], 0, sizeof(struct dml2_dchub_per_pipe_register_set));
348  			total_pipe_regs_copied++;
349  
350  			// Populate the main plane regs
351  			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);
352  
353  			// Multiple planes can refer to the same stream index, so it's only necessary to populate it once
354  			if (!(stream_already_populated_mask & (0x1 << main_plane->stream_index))) {
355  				dml2_core_calcs_get_stream_programming(&core->clean_me_up.mode_lib, &programming->stream_programming[main_plane->stream_index], dml_internal_pipe_index);
356  
357  				programming->stream_programming[main_plane->stream_index].uclk_pstate_method = programming->plane_programming[plane_index].uclk_pstate_support_method;
358  
359  				/* unconditionally populate fams2 params */
360  				dml2_core_calcs_get_stream_fams2_programming(&core->clean_me_up.mode_lib,
361  					display_cfg,
362  					&programming->stream_programming[main_plane->stream_index].fams2_params,
363  					programming->stream_programming[main_plane->stream_index].uclk_pstate_method,
364  					plane_index);
365  
366  				stream_already_populated_mask |= (0x1 << main_plane->stream_index);
367  			}
368  			dml_internal_pipe_index++;
369  		}
370  	}
371  
372  	for (plane_index = programming->display_config.num_planes; plane_index < svp_expanded_display_cfg->num_planes; plane_index++) {
373  		phantom_plane = &svp_expanded_display_cfg->plane_descriptors[plane_index];
374  		main_plane_index = scratch->phantom_plane_index_to_main_plane_index[plane_index];
375  		main_plane = &svp_expanded_display_cfg->plane_descriptors[main_plane_index];
376  
377  		programming->plane_programming[main_plane_index].phantom_plane.valid = true;
378  		memcpy(&programming->plane_programming[main_plane_index].phantom_plane.descriptor, phantom_plane, sizeof(struct dml2_plane_parameters));
379  
380  		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);
381  		for (pipe_offset = 0; pipe_offset < programming->plane_programming[main_plane_index].num_dpps_required; pipe_offset++) {
382  			// Assign storage for this pipe's register values
383  			programming->plane_programming[main_plane_index].phantom_plane.pipe_regs[pipe_offset] = &programming->pipe_regs[total_pipe_regs_copied];
384  			memset(programming->plane_programming[main_plane_index].phantom_plane.pipe_regs[pipe_offset], 0, sizeof(struct dml2_dchub_per_pipe_register_set));
385  			total_pipe_regs_copied++;
386  
387  			// Populate the phantom plane regs
388  			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);
389  			// Populate the phantom stream specific programming
390  			if (!(stream_already_populated_mask & (0x1 << phantom_plane->stream_index))) {
391  				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);
392  
393  				stream_already_populated_mask |= (0x1 << phantom_plane->stream_index);
394  			}
395  
396  			dml_internal_pipe_index++;
397  		}
398  	}
399  }
400  
core_dcn4_mode_support(struct dml2_core_mode_support_in_out * in_out)401  bool core_dcn4_mode_support(struct dml2_core_mode_support_in_out *in_out)
402  {
403  	struct dml2_core_instance *core = (struct dml2_core_instance *)in_out->instance;
404  	struct dml2_core_mode_support_locals *l = &core->scratch.mode_support_locals;
405  
406  	bool result;
407  	unsigned int i, stream_index, stream_bitmask;
408  	int unsigned odm_count, num_odm_output_segments, dpp_count;
409  
410  	expand_implict_subvp(in_out->display_cfg, &l->svp_expanded_display_cfg, &core->scratch);
411  
412  	l->mode_support_ex_params.mode_lib = &core->clean_me_up.mode_lib;
413  	l->mode_support_ex_params.in_display_cfg = &l->svp_expanded_display_cfg;
414  	l->mode_support_ex_params.min_clk_table = in_out->min_clk_table;
415  	l->mode_support_ex_params.min_clk_index = in_out->min_clk_index;
416  	l->mode_support_ex_params.out_evaluation_info = &in_out->mode_support_result.cfg_support_info.clean_me_up.support_info;
417  
418  	result = dml2_core_calcs_mode_support_ex(&l->mode_support_ex_params);
419  
420  	in_out->mode_support_result.cfg_support_info.is_supported = result;
421  
422  	if (result) {
423  		in_out->mode_support_result.global.dispclk_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.RequiredDISPCLK * 1000);
424  		in_out->mode_support_result.global.dcfclk_deepsleep_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.dcfclk_deepsleep * 1000);
425  		in_out->mode_support_result.global.socclk_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.SOCCLK * 1000);
426  
427  		in_out->mode_support_result.global.fclk_pstate_supported = l->mode_support_ex_params.out_evaluation_info->global_fclk_change_supported;
428  		in_out->mode_support_result.global.uclk_pstate_supported = l->mode_support_ex_params.out_evaluation_info->global_dram_clock_change_supported;
429  
430  		in_out->mode_support_result.global.active.fclk_khz = (unsigned long)(core->clean_me_up.mode_lib.ms.FabricClock * 1000);
431  		in_out->mode_support_result.global.active.dcfclk_khz = (unsigned long)(core->clean_me_up.mode_lib.ms.DCFCLK * 1000);
432  
433  
434  		in_out->mode_support_result.global.svp_prefetch.fclk_khz = (unsigned long)core->clean_me_up.mode_lib.ms.FabricClock * 1000;
435  		in_out->mode_support_result.global.svp_prefetch.dcfclk_khz = (unsigned long)core->clean_me_up.mode_lib.ms.DCFCLK * 1000;
436  
437  		in_out->mode_support_result.global.active.average_bw_sdp_kbps = 0;
438  		in_out->mode_support_result.global.active.urgent_bw_dram_kbps = 0;
439  		in_out->mode_support_result.global.svp_prefetch.average_bw_sdp_kbps = 0;
440  		in_out->mode_support_result.global.svp_prefetch.urgent_bw_dram_kbps = 0;
441  
442  		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);
443  		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);
444  		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);
445  		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);
446  
447  		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);
448  		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);
449  		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);
450  		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);
451  		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);
452  		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);
453  		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);
454  		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);
455  
456  		for (i = 0; i < l->svp_expanded_display_cfg.num_planes; i++) {
457  			in_out->mode_support_result.per_plane[i].dppclk_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.RequiredDPPCLK[i] * 1000);
458  		}
459  
460  		stream_bitmask = 0;
461  		for (i = 0; i < l->svp_expanded_display_cfg.num_planes; i++) {
462  			odm_count = 1;
463  			dpp_count = l->mode_support_ex_params.out_evaluation_info->DPPPerSurface[i];
464  			num_odm_output_segments = 1;
465  
466  			switch (l->mode_support_ex_params.out_evaluation_info->ODMMode[i]) {
467  			case dml2_odm_mode_bypass:
468  				odm_count = 1;
469  				dpp_count = l->mode_support_ex_params.out_evaluation_info->DPPPerSurface[i];
470  				break;
471  			case dml2_odm_mode_combine_2to1:
472  				odm_count = 2;
473  				dpp_count = 2;
474  				break;
475  			case dml2_odm_mode_combine_3to1:
476  				odm_count = 3;
477  				dpp_count = 3;
478  				break;
479  			case dml2_odm_mode_combine_4to1:
480  				odm_count = 4;
481  				dpp_count = 4;
482  				break;
483  			case dml2_odm_mode_split_1to2:
484  			case dml2_odm_mode_mso_1to2:
485  				num_odm_output_segments = 2;
486  				break;
487  			case dml2_odm_mode_mso_1to4:
488  				num_odm_output_segments = 4;
489  				break;
490  			case dml2_odm_mode_auto:
491  			default:
492  				odm_count = 1;
493  				dpp_count = l->mode_support_ex_params.out_evaluation_info->DPPPerSurface[i];
494  				break;
495  			}
496  
497  			in_out->mode_support_result.cfg_support_info.plane_support_info[i].dpps_used = dpp_count;
498  
499  			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);
500  
501  			stream_index = l->svp_expanded_display_cfg.plane_descriptors[i].stream_index;
502  
503  			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;
504  			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);
505  
506  			if (!((stream_bitmask >> stream_index) & 0x1)) {
507  				in_out->mode_support_result.cfg_support_info.stream_support_info[stream_index].odms_used = odm_count;
508  				in_out->mode_support_result.cfg_support_info.stream_support_info[stream_index].num_odm_output_segments = num_odm_output_segments;
509  				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];
510  				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];
511  				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);
512  				in_out->mode_support_result.per_stream[stream_index].dtbclk_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.RequiredDTBCLK[i] * 1000);
513  				stream_bitmask |= 0x1 << stream_index;
514  			}
515  		}
516  	}
517  
518  	return result;
519  }
520  
lookup_uclk_dpm_index_by_freq(unsigned long uclk_freq_khz,struct dml2_soc_bb * soc_bb)521  static int lookup_uclk_dpm_index_by_freq(unsigned long uclk_freq_khz, struct dml2_soc_bb *soc_bb)
522  {
523  	int i;
524  
525  	for (i = 0; i < soc_bb->clk_table.uclk.num_clk_values; i++) {
526  		if (uclk_freq_khz == soc_bb->clk_table.uclk.clk_values_khz[i])
527  			return i;
528  	}
529  	return 0;
530  }
531  
core_dcn4_mode_programming(struct dml2_core_mode_programming_in_out * in_out)532  bool core_dcn4_mode_programming(struct dml2_core_mode_programming_in_out *in_out)
533  {
534  	struct dml2_core_instance *core = (struct dml2_core_instance *)in_out->instance;
535  	struct dml2_core_mode_programming_locals *l = &core->scratch.mode_programming_locals;
536  
537  	bool result = false;
538  	unsigned int pipe_offset;
539  	int dml_internal_pipe_index;
540  	int total_pipe_regs_copied = 0;
541  	int stream_already_populated_mask = 0;
542  
543  	int main_stream_index;
544  	unsigned int plane_index;
545  
546  	expand_implict_subvp(in_out->display_cfg, &l->svp_expanded_display_cfg, &core->scratch);
547  
548  	l->mode_programming_ex_params.mode_lib = &core->clean_me_up.mode_lib;
549  	l->mode_programming_ex_params.in_display_cfg = &l->svp_expanded_display_cfg;
550  	l->mode_programming_ex_params.min_clk_table = in_out->instance->minimum_clock_table;
551  	l->mode_programming_ex_params.cfg_support_info = in_out->cfg_support_info;
552  	l->mode_programming_ex_params.programming = in_out->programming;
553  	l->mode_programming_ex_params.min_clk_index = lookup_uclk_dpm_index_by_freq(in_out->programming->min_clocks.dcn4x.active.uclk_khz,
554  		&core->clean_me_up.mode_lib.soc);
555  
556  	result = dml2_core_calcs_mode_programming_ex(&l->mode_programming_ex_params);
557  
558  	if (result) {
559  		// If the input display configuration contains implict SVP, we need to use a special packer
560  		if (in_out->display_cfg->display_config.overrides.enable_subvp_implicit_pmo) {
561  			pack_mode_programming_params_with_implicit_subvp(core, in_out->display_cfg, &l->svp_expanded_display_cfg, in_out->programming, &core->scratch);
562  		} else {
563  			memcpy(&in_out->programming->display_config, in_out->display_cfg, sizeof(struct dml2_display_cfg));
564  
565  			dml2_core_calcs_get_arb_params(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, &in_out->programming->global_regs.arb_regs);
566  			dml2_core_calcs_get_watermarks(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, &in_out->programming->global_regs.wm_regs[0]);
567  
568  			dml_internal_pipe_index = 0;
569  
570  			for (plane_index = 0; plane_index < in_out->programming->display_config.num_planes; plane_index++) {
571  				in_out->programming->plane_programming[plane_index].num_dpps_required = core->clean_me_up.mode_lib.mp.NoOfDPP[plane_index];
572  
573  				if (in_out->programming->display_config.plane_descriptors[plane_index].overrides.legacy_svp_config == dml2_svp_mode_override_main_pipe)
574  					in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_fw_subvp_phantom;
575  				else if (in_out->programming->display_config.plane_descriptors[plane_index].overrides.legacy_svp_config == dml2_svp_mode_override_phantom_pipe)
576  					in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_fw_subvp_phantom;
577  				else if (in_out->programming->display_config.plane_descriptors[plane_index].overrides.legacy_svp_config == dml2_svp_mode_override_phantom_pipe_no_data_return)
578  					in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_fw_subvp_phantom;
579  				else {
580  					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)
581  						in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_vactive;
582  					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)
583  						in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_vblank;
584  					else
585  						in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_not_supported;
586  				}
587  
588  				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);
589  
590  				for (pipe_offset = 0; pipe_offset < in_out->programming->plane_programming[plane_index].num_dpps_required; pipe_offset++) {
591  					in_out->programming->plane_programming[plane_index].plane_descriptor = &in_out->programming->display_config.plane_descriptors[plane_index];
592  
593  					// Assign storage for this pipe's register values
594  					in_out->programming->plane_programming[plane_index].pipe_regs[pipe_offset] = &in_out->programming->pipe_regs[total_pipe_regs_copied];
595  					memset(in_out->programming->plane_programming[plane_index].pipe_regs[pipe_offset], 0, sizeof(struct dml2_dchub_per_pipe_register_set));
596  					total_pipe_regs_copied++;
597  
598  					// Populate
599  					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);
600  
601  					main_stream_index = in_out->programming->display_config.plane_descriptors[plane_index].stream_index;
602  
603  					// Multiple planes can refer to the same stream index, so it's only necessary to populate it once
604  					if (!(stream_already_populated_mask & (0x1 << main_stream_index))) {
605  						in_out->programming->stream_programming[main_stream_index].stream_descriptor = &in_out->programming->display_config.stream_descriptors[main_stream_index];
606  						in_out->programming->stream_programming[main_stream_index].num_odms_required = in_out->cfg_support_info->stream_support_info[main_stream_index].odms_used;
607  						dml2_core_calcs_get_stream_programming(&core->clean_me_up.mode_lib, &in_out->programming->stream_programming[main_stream_index], dml_internal_pipe_index);
608  
609  						stream_already_populated_mask |= (0x1 << main_stream_index);
610  					}
611  					dml_internal_pipe_index++;
612  				}
613  			}
614  		}
615  	}
616  
617  	return result;
618  }
619  
core_dcn4_populate_informative(struct dml2_core_populate_informative_in_out * in_out)620  bool core_dcn4_populate_informative(struct dml2_core_populate_informative_in_out *in_out)
621  {
622  	struct dml2_core_internal_display_mode_lib *mode_lib = &in_out->instance->clean_me_up.mode_lib;
623  
624  	if (in_out->mode_is_supported)
625  		in_out->programming->informative.voltage_level = in_out->instance->scratch.mode_programming_locals.mode_programming_ex_params.min_clk_index;
626  	else
627  		in_out->programming->informative.voltage_level = in_out->instance->scratch.mode_support_locals.mode_support_ex_params.min_clk_index;
628  
629  	dml2_core_calcs_get_informative(mode_lib, in_out->programming);
630  	return true;
631  }
632  
core_dcn4_calculate_mcache_allocation(struct dml2_calculate_mcache_allocation_in_out * in_out)633  bool core_dcn4_calculate_mcache_allocation(struct dml2_calculate_mcache_allocation_in_out *in_out)
634  {
635  	memset(in_out->mcache_allocation, 0, sizeof(struct dml2_mcache_surface_allocation));
636  
637  	dml2_core_calcs_get_mcache_allocation(&in_out->instance->clean_me_up.mode_lib, in_out->mcache_allocation, in_out->plane_index);
638  
639  	if (in_out->mcache_allocation->num_mcaches_plane0 > 0)
640  		in_out->mcache_allocation->mcache_x_offsets_plane0[in_out->mcache_allocation->num_mcaches_plane0 - 1] = in_out->plane_descriptor->surface.plane0.width;
641  
642  	if (in_out->mcache_allocation->num_mcaches_plane1 > 0)
643  		in_out->mcache_allocation->mcache_x_offsets_plane1[in_out->mcache_allocation->num_mcaches_plane1 - 1] = in_out->plane_descriptor->surface.plane1.width;
644  
645  	in_out->mcache_allocation->requires_dedicated_mall_mcache = false;
646  
647  	return true;
648  }
649