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