1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Copyright 2023 Advanced Micro Devices, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors: AMD
24 *
25 */
26
27 #include <linux/vmalloc.h>
28
29 #include "display_mode_core.h"
30 #include "dml2_internal_types.h"
31 #include "dml2_utils.h"
32 #include "dml2_policy.h"
33 #include "dml2_translation_helper.h"
34 #include "dml2_mall_phantom.h"
35 #include "dml2_dc_resource_mgmt.h"
36 #include "dml21_wrapper.h"
37
38
initialize_dml2_ip_params(struct dml2_context * dml2,const struct dc * in_dc,struct ip_params_st * out)39 static void initialize_dml2_ip_params(struct dml2_context *dml2, const struct dc *in_dc, struct ip_params_st *out)
40 {
41 if (dml2->config.use_native_soc_bb_construction)
42 dml2_init_ip_params(dml2, in_dc, out);
43 else
44 dml2_translate_ip_params(in_dc, out);
45 }
46
initialize_dml2_soc_bbox(struct dml2_context * dml2,const struct dc * in_dc,struct soc_bounding_box_st * out)47 static void initialize_dml2_soc_bbox(struct dml2_context *dml2, const struct dc *in_dc, struct soc_bounding_box_st *out)
48 {
49 if (dml2->config.use_native_soc_bb_construction)
50 dml2_init_socbb_params(dml2, in_dc, out);
51 else
52 dml2_translate_socbb_params(in_dc, out);
53 }
54
initialize_dml2_soc_states(struct dml2_context * dml2,const struct dc * in_dc,const struct soc_bounding_box_st * in_bbox,struct soc_states_st * out)55 static void initialize_dml2_soc_states(struct dml2_context *dml2,
56 const struct dc *in_dc, const struct soc_bounding_box_st *in_bbox, struct soc_states_st *out)
57 {
58 if (dml2->config.use_native_soc_bb_construction)
59 dml2_init_soc_states(dml2, in_dc, in_bbox, out);
60 else
61 dml2_translate_soc_states(in_dc, out, in_dc->dml.soc.num_states);
62 }
63
map_hw_resources(struct dml2_context * dml2,struct dml_display_cfg_st * in_out_display_cfg,struct dml_mode_support_info_st * mode_support_info)64 static void map_hw_resources(struct dml2_context *dml2,
65 struct dml_display_cfg_st *in_out_display_cfg, struct dml_mode_support_info_st *mode_support_info)
66 {
67 unsigned int num_pipes = 0;
68 int i, j;
69
70 for (i = 0; i < __DML_NUM_PLANES__; i++) {
71 in_out_display_cfg->hw.ODMMode[i] = mode_support_info->ODMMode[i];
72 in_out_display_cfg->hw.DPPPerSurface[i] = mode_support_info->DPPPerSurface[i];
73 in_out_display_cfg->hw.DSCEnabled[i] = mode_support_info->DSCEnabled[i];
74 in_out_display_cfg->hw.NumberOfDSCSlices[i] = mode_support_info->NumberOfDSCSlices[i];
75 in_out_display_cfg->hw.DLGRefClkFreqMHz = 24;
76 if (dml2->v20.dml_core_ctx.project != dml_project_dcn35 &&
77 dml2->v20.dml_core_ctx.project != dml_project_dcn351) {
78 /*dGPU default as 50Mhz*/
79 in_out_display_cfg->hw.DLGRefClkFreqMHz = 50;
80 }
81 for (j = 0; j < mode_support_info->DPPPerSurface[i]; j++) {
82 if (i >= __DML2_WRAPPER_MAX_STREAMS_PLANES__) {
83 dml_print("DML::%s: Index out of bounds: i=%d, __DML2_WRAPPER_MAX_STREAMS_PLANES__=%d\n",
84 __func__, i, __DML2_WRAPPER_MAX_STREAMS_PLANES__);
85 break;
86 }
87 dml2->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id[num_pipes] = dml2->v20.scratch.dml_to_dc_pipe_mapping.disp_cfg_to_stream_id[i];
88 dml2->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id_valid[num_pipes] = true;
89 dml2->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id[num_pipes] = dml2->v20.scratch.dml_to_dc_pipe_mapping.disp_cfg_to_plane_id[i];
90 dml2->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id_valid[num_pipes] = true;
91 num_pipes++;
92 }
93 }
94 }
95
pack_and_call_dml_mode_support_ex(struct dml2_context * dml2,const struct dml_display_cfg_st * display_cfg,struct dml_mode_support_info_st * evaluation_info)96 static unsigned int pack_and_call_dml_mode_support_ex(struct dml2_context *dml2,
97 const struct dml_display_cfg_st *display_cfg,
98 struct dml_mode_support_info_st *evaluation_info)
99 {
100 struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
101
102 s->mode_support_params.mode_lib = &dml2->v20.dml_core_ctx;
103 s->mode_support_params.in_display_cfg = display_cfg;
104 s->mode_support_params.out_evaluation_info = evaluation_info;
105
106 memset(evaluation_info, 0, sizeof(struct dml_mode_support_info_st));
107 s->mode_support_params.out_lowest_state_idx = 0;
108
109 return dml_mode_support_ex(&s->mode_support_params);
110 }
111
optimize_configuration(struct dml2_context * dml2,struct dml2_wrapper_optimize_configuration_params * p)112 static bool optimize_configuration(struct dml2_context *dml2, struct dml2_wrapper_optimize_configuration_params *p)
113 {
114 int unused_dpps = p->ip_params->max_num_dpp;
115 int i, j;
116 int odms_needed, refresh_rate_hz, dpps_needed, subvp_height, pstate_width_fw_delay_lines, surface_count;
117 int subvp_timing_to_add, new_timing_index, subvp_surface_to_add, new_surface_index;
118 float frame_time_sec, max_frame_time_sec;
119 int largest_blend_and_timing = 0;
120 bool optimization_done = false;
121
122 for (i = 0; i < (int) p->cur_display_config->num_timings; i++) {
123 if (p->cur_display_config->plane.BlendingAndTiming[i] > largest_blend_and_timing)
124 largest_blend_and_timing = p->cur_display_config->plane.BlendingAndTiming[i];
125 }
126
127 if (p->new_policy != p->cur_policy)
128 *p->new_policy = *p->cur_policy;
129
130 if (p->new_display_config != p->cur_display_config)
131 *p->new_display_config = *p->cur_display_config;
132
133 // Optimize P-State Support
134 if (dml2->config.use_native_pstate_optimization) {
135 if (p->cur_mode_support_info->DRAMClockChangeSupport[0] == dml_dram_clock_change_unsupported) {
136 // Find a display with < 120Hz refresh rate with maximal refresh rate that's not already subvp
137 subvp_timing_to_add = -1;
138 subvp_surface_to_add = -1;
139 max_frame_time_sec = 0;
140 surface_count = 0;
141 for (i = 0; i < (int) p->cur_display_config->num_timings; i++) {
142 refresh_rate_hz = (int)div_u64((unsigned long long) p->cur_display_config->timing.PixelClock[i] * 1000 * 1000,
143 (p->cur_display_config->timing.HTotal[i] * p->cur_display_config->timing.VTotal[i]));
144 if (refresh_rate_hz < 120) {
145 // Check its upstream surfaces to see if this one could be converted to subvp.
146 dpps_needed = 0;
147 for (j = 0; j < (int) p->cur_display_config->num_surfaces; j++) {
148 if (p->cur_display_config->plane.BlendingAndTiming[j] == i &&
149 p->cur_display_config->plane.UseMALLForPStateChange[j] == dml_use_mall_pstate_change_disable) {
150 dpps_needed += p->cur_mode_support_info->DPPPerSurface[j];
151 subvp_surface_to_add = j;
152 surface_count++;
153 }
154 }
155
156 if (surface_count == 1 && dpps_needed > 0 && dpps_needed <= unused_dpps) {
157 frame_time_sec = (float)1 / refresh_rate_hz;
158 if (frame_time_sec > max_frame_time_sec) {
159 max_frame_time_sec = frame_time_sec;
160 subvp_timing_to_add = i;
161 }
162 }
163 }
164 }
165 if (subvp_timing_to_add >= 0) {
166 new_timing_index = p->new_display_config->num_timings++;
167 new_surface_index = p->new_display_config->num_surfaces++;
168 // Add a phantom pipe reflecting the main pipe's timing
169 dml2_util_copy_dml_timing(&p->new_display_config->timing, new_timing_index, subvp_timing_to_add);
170
171 pstate_width_fw_delay_lines = (int)(((double)(p->config->svp_pstate.subvp_fw_processing_delay_us +
172 p->config->svp_pstate.subvp_pstate_allow_width_us) / 1000000) *
173 (p->new_display_config->timing.PixelClock[subvp_timing_to_add] * 1000 * 1000) /
174 (double)p->new_display_config->timing.HTotal[subvp_timing_to_add]);
175
176 subvp_height = p->cur_mode_support_info->SubViewportLinesNeededInMALL[subvp_timing_to_add] + pstate_width_fw_delay_lines;
177
178 p->new_display_config->timing.VActive[new_timing_index] = subvp_height;
179 p->new_display_config->timing.VTotal[new_timing_index] = subvp_height +
180 p->new_display_config->timing.VTotal[subvp_timing_to_add] - p->new_display_config->timing.VActive[subvp_timing_to_add];
181
182 p->new_display_config->output.OutputDisabled[new_timing_index] = true;
183
184 p->new_display_config->plane.UseMALLForPStateChange[subvp_surface_to_add] = dml_use_mall_pstate_change_sub_viewport;
185
186 dml2_util_copy_dml_plane(&p->new_display_config->plane, new_surface_index, subvp_surface_to_add);
187 dml2_util_copy_dml_surface(&p->new_display_config->surface, new_surface_index, subvp_surface_to_add);
188
189 p->new_display_config->plane.ViewportHeight[new_surface_index] = subvp_height;
190 p->new_display_config->plane.ViewportHeightChroma[new_surface_index] = subvp_height;
191 p->new_display_config->plane.ViewportStationary[new_surface_index] = false;
192
193 p->new_display_config->plane.UseMALLForStaticScreen[new_surface_index] = dml_use_mall_static_screen_disable;
194 p->new_display_config->plane.UseMALLForPStateChange[new_surface_index] = dml_use_mall_pstate_change_phantom_pipe;
195
196 p->new_display_config->plane.NumberOfCursors[new_surface_index] = 0;
197
198 p->new_policy->ImmediateFlipRequirement[new_surface_index] = dml_immediate_flip_not_required;
199
200 p->new_display_config->plane.BlendingAndTiming[new_surface_index] = new_timing_index;
201
202 optimization_done = true;
203 }
204 }
205 }
206
207 // Optimize Clocks
208 if (!optimization_done) {
209 if (largest_blend_and_timing == 0 && p->cur_policy->ODMUse[0] == dml_odm_use_policy_combine_as_needed && dml2->config.minimize_dispclk_using_odm) {
210 odms_needed = dml2_util_get_maximum_odm_combine_for_output(dml2->config.optimize_odm_4to1,
211 p->cur_display_config->output.OutputEncoder[0], p->cur_mode_support_info->DSCEnabled[0]) - 1;
212
213 if (odms_needed <= unused_dpps) {
214 unused_dpps -= odms_needed;
215
216 if (odms_needed == 1) {
217 p->new_policy->ODMUse[0] = dml_odm_use_policy_combine_2to1;
218 optimization_done = true;
219 } else if (odms_needed == 3) {
220 p->new_policy->ODMUse[0] = dml_odm_use_policy_combine_4to1;
221 optimization_done = true;
222 } else
223 optimization_done = false;
224 }
225 }
226 }
227
228 return optimization_done;
229 }
230
calculate_lowest_supported_state_for_temp_read(struct dml2_context * dml2,struct dc_state * display_state)231 static int calculate_lowest_supported_state_for_temp_read(struct dml2_context *dml2, struct dc_state *display_state)
232 {
233 struct dml2_calculate_lowest_supported_state_for_temp_read_scratch *s = &dml2->v20.scratch.dml2_calculate_lowest_supported_state_for_temp_read_scratch;
234 struct dml2_wrapper_scratch *s_global = &dml2->v20.scratch;
235
236 unsigned int dml_result = 0;
237 int result = -1, i, j;
238
239 build_unoptimized_policy_settings(dml2->v20.dml_core_ctx.project, &dml2->v20.dml_core_ctx.policy);
240
241 /* Zero out before each call before proceeding */
242 memset(s, 0, sizeof(struct dml2_calculate_lowest_supported_state_for_temp_read_scratch));
243 memset(&s_global->mode_support_params, 0, sizeof(struct dml_mode_support_ex_params_st));
244 memset(&s_global->dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping));
245
246 for (i = 0; i < dml2->config.dcn_pipe_count; i++) {
247 /* Calling resource_build_scaling_params will populate the pipe params
248 * with the necessary information needed for correct DML calculations
249 * This is also done in DML1 driver code path and hence display_state
250 * cannot be const.
251 */
252 struct pipe_ctx *pipe = &display_state->res_ctx.pipe_ctx[i];
253
254 if (pipe->plane_state) {
255 if (!dml2->config.callbacks.build_scaling_params(pipe)) {
256 ASSERT(false);
257 return false;
258 }
259 }
260 }
261
262 map_dc_state_into_dml_display_cfg(dml2, display_state, &s->cur_display_config);
263
264 for (i = 0; i < dml2->v20.dml_core_ctx.states.num_states; i++) {
265 s->uclk_change_latencies[i] = dml2->v20.dml_core_ctx.states.state_array[i].dram_clock_change_latency_us;
266 }
267
268 for (i = 0; i < 4; i++) {
269 for (j = 0; j < dml2->v20.dml_core_ctx.states.num_states; j++) {
270 dml2->v20.dml_core_ctx.states.state_array[j].dram_clock_change_latency_us = s_global->dummy_pstate_table[i].dummy_pstate_latency_us;
271 }
272
273 dml_result = pack_and_call_dml_mode_support_ex(dml2, &s->cur_display_config, &s->evaluation_info);
274
275 if (dml_result && s->evaluation_info.DRAMClockChangeSupport[0] == dml_dram_clock_change_vactive) {
276 map_hw_resources(dml2, &s->cur_display_config, &s->evaluation_info);
277 dml_result = dml_mode_programming(&dml2->v20.dml_core_ctx, s_global->mode_support_params.out_lowest_state_idx, &s->cur_display_config, true);
278
279 ASSERT(dml_result);
280
281 dml2_extract_watermark_set(&dml2->v20.g6_temp_read_watermark_set, &dml2->v20.dml_core_ctx);
282 dml2->v20.g6_temp_read_watermark_set.cstate_pstate.fclk_pstate_change_ns = dml2->v20.g6_temp_read_watermark_set.cstate_pstate.pstate_change_ns;
283
284 result = s_global->mode_support_params.out_lowest_state_idx;
285
286 while (dml2->v20.dml_core_ctx.states.state_array[result].dram_speed_mts < s_global->dummy_pstate_table[i].dram_speed_mts)
287 result++;
288
289 break;
290 }
291 }
292
293 for (i = 0; i < dml2->v20.dml_core_ctx.states.num_states; i++) {
294 dml2->v20.dml_core_ctx.states.state_array[i].dram_clock_change_latency_us = s->uclk_change_latencies[i];
295 }
296
297 return result;
298 }
299
copy_dummy_pstate_table(struct dummy_pstate_entry * dest,struct dummy_pstate_entry * src,unsigned int num_entries)300 static void copy_dummy_pstate_table(struct dummy_pstate_entry *dest, struct dummy_pstate_entry *src, unsigned int num_entries)
301 {
302 for (int i = 0; i < num_entries; i++) {
303 dest[i] = src[i];
304 }
305 }
306
are_timings_requiring_odm_doing_blending(const struct dml_display_cfg_st * display_cfg,const struct dml_mode_support_info_st * evaluation_info)307 static bool are_timings_requiring_odm_doing_blending(const struct dml_display_cfg_st *display_cfg,
308 const struct dml_mode_support_info_st *evaluation_info)
309 {
310 unsigned int planes_per_timing[__DML_NUM_PLANES__] = {0};
311 int i;
312
313 for (i = 0; i < display_cfg->num_surfaces; i++)
314 planes_per_timing[display_cfg->plane.BlendingAndTiming[i]]++;
315
316 for (i = 0; i < __DML_NUM_PLANES__; i++) {
317 if (planes_per_timing[i] > 1 && evaluation_info->ODMMode[i] != dml_odm_mode_bypass)
318 return true;
319 }
320
321 return false;
322 }
323
does_configuration_meet_sw_policies(struct dml2_context * ctx,const struct dml_display_cfg_st * display_cfg,const struct dml_mode_support_info_st * evaluation_info)324 static bool does_configuration_meet_sw_policies(struct dml2_context *ctx, const struct dml_display_cfg_st *display_cfg,
325 const struct dml_mode_support_info_st *evaluation_info)
326 {
327 bool pass = true;
328
329 if (!ctx->config.enable_windowed_mpo_odm) {
330 if (are_timings_requiring_odm_doing_blending(display_cfg, evaluation_info))
331 pass = false;
332 }
333
334 return pass;
335 }
336
dml_mode_support_wrapper(struct dml2_context * dml2,struct dc_state * display_state)337 static bool dml_mode_support_wrapper(struct dml2_context *dml2,
338 struct dc_state *display_state)
339 {
340 struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
341 unsigned int result = 0, i;
342 unsigned int optimized_result = true;
343
344 build_unoptimized_policy_settings(dml2->v20.dml_core_ctx.project, &dml2->v20.dml_core_ctx.policy);
345
346 /* Zero out before each call before proceeding */
347 memset(&s->cur_display_config, 0, sizeof(struct dml_display_cfg_st));
348 memset(&s->mode_support_params, 0, sizeof(struct dml_mode_support_ex_params_st));
349 memset(&s->dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping));
350 memset(&s->optimize_configuration_params, 0, sizeof(struct dml2_wrapper_optimize_configuration_params));
351
352 for (i = 0; i < dml2->config.dcn_pipe_count; i++) {
353 /* Calling resource_build_scaling_params will populate the pipe params
354 * with the necessary information needed for correct DML calculations
355 * This is also done in DML1 driver code path and hence display_state
356 * cannot be const.
357 */
358 struct pipe_ctx *pipe = &display_state->res_ctx.pipe_ctx[i];
359
360 if (pipe->plane_state) {
361 if (!dml2->config.callbacks.build_scaling_params(pipe)) {
362 ASSERT(false);
363 return false;
364 }
365 }
366 }
367
368 map_dc_state_into_dml_display_cfg(dml2, display_state, &s->cur_display_config);
369 if (!dml2->config.skip_hw_state_mapping)
370 dml2_apply_det_buffer_allocation_policy(dml2, &s->cur_display_config);
371
372 result = pack_and_call_dml_mode_support_ex(dml2,
373 &s->cur_display_config,
374 &s->mode_support_info);
375
376 if (result)
377 result = does_configuration_meet_sw_policies(dml2, &s->cur_display_config, &s->mode_support_info);
378
379 // Try to optimize
380 if (result) {
381 s->cur_policy = dml2->v20.dml_core_ctx.policy;
382 s->optimize_configuration_params.dml_core_ctx = &dml2->v20.dml_core_ctx;
383 s->optimize_configuration_params.config = &dml2->config;
384 s->optimize_configuration_params.ip_params = &dml2->v20.dml_core_ctx.ip;
385 s->optimize_configuration_params.cur_display_config = &s->cur_display_config;
386 s->optimize_configuration_params.cur_mode_support_info = &s->mode_support_info;
387 s->optimize_configuration_params.cur_policy = &s->cur_policy;
388 s->optimize_configuration_params.new_display_config = &s->new_display_config;
389 s->optimize_configuration_params.new_policy = &s->new_policy;
390
391 while (optimized_result && optimize_configuration(dml2, &s->optimize_configuration_params)) {
392 dml2->v20.dml_core_ctx.policy = s->new_policy;
393 optimized_result = pack_and_call_dml_mode_support_ex(dml2,
394 &s->new_display_config,
395 &s->mode_support_info);
396
397 if (optimized_result)
398 optimized_result = does_configuration_meet_sw_policies(dml2, &s->new_display_config, &s->mode_support_info);
399
400 // If the new optimized state is supposed, then set current = new
401 if (optimized_result) {
402 s->cur_display_config = s->new_display_config;
403 s->cur_policy = s->new_policy;
404 } else {
405 // Else, restore policy to current
406 dml2->v20.dml_core_ctx.policy = s->cur_policy;
407 }
408 }
409
410 // Optimize ended with a failed config, so we need to restore DML state to last passing
411 if (!optimized_result) {
412 result = pack_and_call_dml_mode_support_ex(dml2,
413 &s->cur_display_config,
414 &s->mode_support_info);
415 }
416 }
417
418 if (result)
419 map_hw_resources(dml2, &s->cur_display_config, &s->mode_support_info);
420
421 return result;
422 }
423
find_drr_eligible_stream(struct dc_state * display_state)424 static int find_drr_eligible_stream(struct dc_state *display_state)
425 {
426 int i;
427
428 for (i = 0; i < display_state->stream_count; i++) {
429 if (dc_state_get_stream_subvp_type(display_state, display_state->streams[i]) == SUBVP_NONE
430 && display_state->streams[i]->ignore_msa_timing_param) {
431 // Use ignore_msa_timing_param flag to identify as DRR
432 return i;
433 }
434 }
435
436 return -1;
437 }
438
optimize_pstate_with_svp_and_drr(struct dml2_context * dml2,struct dc_state * display_state)439 static bool optimize_pstate_with_svp_and_drr(struct dml2_context *dml2, struct dc_state *display_state)
440 {
441 struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
442 bool pstate_optimization_done = false;
443 bool pstate_optimization_success = false;
444 bool result = false;
445 int drr_display_index = 0, non_svp_streams = 0;
446 bool force_svp = dml2->config.svp_pstate.force_enable_subvp;
447
448 display_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false;
449 display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index_valid = false;
450
451 result = dml_mode_support_wrapper(dml2, display_state);
452
453 if (!result) {
454 pstate_optimization_done = true;
455 } else if (s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported && !force_svp) {
456 pstate_optimization_success = true;
457 pstate_optimization_done = true;
458 }
459
460 if (display_state->stream_count == 1 && dml2->config.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch(dml2->config.callbacks.dc, display_state)) {
461 display_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = true;
462
463 result = dml_mode_support_wrapper(dml2, display_state);
464 } else {
465 non_svp_streams = display_state->stream_count;
466
467 while (!pstate_optimization_done) {
468 result = dml_mode_programming(&dml2->v20.dml_core_ctx, s->mode_support_params.out_lowest_state_idx, &s->cur_display_config, true);
469
470 // Always try adding SVP first
471 if (result)
472 result = dml2_svp_add_phantom_pipe_to_dc_state(dml2, display_state, &s->mode_support_info);
473 else
474 pstate_optimization_done = true;
475
476
477 if (result) {
478 result = dml_mode_support_wrapper(dml2, display_state);
479 } else {
480 pstate_optimization_done = true;
481 }
482
483 if (result) {
484 non_svp_streams--;
485
486 if (s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported) {
487 if (dml2_svp_validate_static_schedulability(dml2, display_state, s->mode_support_info.DRAMClockChangeSupport[0])) {
488 pstate_optimization_success = true;
489 pstate_optimization_done = true;
490 } else {
491 pstate_optimization_success = false;
492 pstate_optimization_done = false;
493 }
494 } else {
495 drr_display_index = find_drr_eligible_stream(display_state);
496
497 // If there is only 1 remaining non SubVP pipe that is DRR, check static
498 // schedulability for SubVP + DRR.
499 if (non_svp_streams == 1 && drr_display_index >= 0) {
500 if (dml2_svp_drr_schedulable(dml2, display_state, &display_state->streams[drr_display_index]->timing)) {
501 display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index_valid = true;
502 display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index = drr_display_index;
503 result = dml_mode_support_wrapper(dml2, display_state);
504 }
505
506 if (result && s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported) {
507 pstate_optimization_success = true;
508 pstate_optimization_done = true;
509 } else {
510 pstate_optimization_success = false;
511 pstate_optimization_done = false;
512 }
513 }
514
515 if (pstate_optimization_success) {
516 pstate_optimization_done = true;
517 } else {
518 pstate_optimization_done = false;
519 }
520 }
521 }
522 }
523 }
524
525 if (!pstate_optimization_success) {
526 dml2_svp_remove_all_phantom_pipes(dml2, display_state);
527 display_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false;
528 display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index_valid = false;
529 result = dml_mode_support_wrapper(dml2, display_state);
530 }
531
532 return result;
533 }
534
call_dml_mode_support_and_programming(struct dc_state * context)535 static bool call_dml_mode_support_and_programming(struct dc_state *context)
536 {
537 unsigned int result = 0;
538 unsigned int min_state = 0;
539 int min_state_for_g6_temp_read = 0;
540
541
542 if (!context)
543 return false;
544
545 struct dml2_context *dml2 = context->bw_ctx.dml2;
546 struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
547
548 if (!context->streams[0]->sink->link->dc->caps.is_apu) {
549 min_state_for_g6_temp_read = calculate_lowest_supported_state_for_temp_read(dml2, context);
550
551 ASSERT(min_state_for_g6_temp_read >= 0);
552 }
553
554 if (!dml2->config.use_native_pstate_optimization) {
555 result = optimize_pstate_with_svp_and_drr(dml2, context);
556 } else {
557 result = dml_mode_support_wrapper(dml2, context);
558 }
559
560 /* Upon trying to sett certain frequencies in FRL, min_state_for_g6_temp_read is reported as -1. This leads to an invalid value of min_state causing crashes later on.
561 * Use the default logic for min_state only when min_state_for_g6_temp_read is a valid value. In other cases, use the value calculated by the DML directly.
562 */
563 if (!context->streams[0]->sink->link->dc->caps.is_apu) {
564 if (min_state_for_g6_temp_read >= 0)
565 min_state = min_state_for_g6_temp_read > s->mode_support_params.out_lowest_state_idx ? min_state_for_g6_temp_read : s->mode_support_params.out_lowest_state_idx;
566 else
567 min_state = s->mode_support_params.out_lowest_state_idx;
568 }
569
570 if (result) {
571 if (!context->streams[0]->sink->link->dc->caps.is_apu) {
572 result = dml_mode_programming(&dml2->v20.dml_core_ctx, min_state, &s->cur_display_config, true);
573 } else {
574 result = dml_mode_programming(&dml2->v20.dml_core_ctx, s->mode_support_params.out_lowest_state_idx, &s->cur_display_config, true);
575 }
576 }
577 return result;
578 }
579
dml2_validate_and_build_resource(const struct dc * in_dc,struct dc_state * context)580 static bool dml2_validate_and_build_resource(const struct dc *in_dc, struct dc_state *context)
581 {
582 struct dml2_context *dml2 = context->bw_ctx.dml2;
583 struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
584 struct dml2_dcn_clocks out_clks;
585 unsigned int result = 0;
586 bool need_recalculation = false;
587 uint32_t cstate_enter_plus_exit_z8_ns;
588
589 if (context->stream_count == 0) {
590 unsigned int lowest_state_idx = 0;
591
592 out_clks.p_state_supported = true;
593 out_clks.dispclk_khz = 0; /* No requirement, and lowest index will generally be maximum dispclk. */
594 out_clks.dcfclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dcfclk_mhz * 1000;
595 out_clks.fclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].fabricclk_mhz * 1000;
596 out_clks.uclk_mts = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dram_speed_mts;
597 out_clks.phyclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].phyclk_mhz * 1000;
598 out_clks.socclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].socclk_mhz * 1000;
599 out_clks.ref_dtbclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dtbclk_mhz * 1000;
600 context->bw_ctx.bw.dcn.clk.dtbclk_en = false;
601 dml2_copy_clocks_to_dc_state(&out_clks, context);
602 return true;
603 }
604
605 /* Zero out before each call before proceeding */
606 memset(&dml2->v20.scratch, 0, sizeof(struct dml2_wrapper_scratch));
607 memset(&dml2->v20.dml_core_ctx.policy, 0, sizeof(struct dml_mode_eval_policy_st));
608 memset(&dml2->v20.dml_core_ctx.ms, 0, sizeof(struct mode_support_st));
609 memset(&dml2->v20.dml_core_ctx.mp, 0, sizeof(struct mode_program_st));
610
611 /* Initialize DET scratch */
612 dml2_initialize_det_scratch(dml2);
613
614 copy_dummy_pstate_table(s->dummy_pstate_table, in_dc->clk_mgr->bw_params->dummy_pstate_table, 4);
615
616 result = call_dml_mode_support_and_programming(context);
617 /* Call map dc pipes to map the pipes based on the DML output. For correctly determining if recalculation
618 * is required or not, the resource context needs to correctly reflect the number of active pipes. We would
619 * only know the correct number if active pipes after dml2_map_dc_pipes is called.
620 */
621 if (result && !dml2->config.skip_hw_state_mapping)
622 dml2_map_dc_pipes(dml2, context, &s->cur_display_config, &s->dml_to_dc_pipe_mapping, in_dc->current_state);
623
624 /* Verify and update DET Buffer configuration if needed. dml2_verify_det_buffer_configuration will check if DET Buffer
625 * size needs to be updated. If yes it will update the DETOverride variable and set need_recalculation flag to true.
626 * Based on that flag, run mode support again. Verification needs to be run after dml_mode_programming because the getters
627 * return correct det buffer values only after dml_mode_programming is called.
628 */
629 if (result && !dml2->config.skip_hw_state_mapping) {
630 need_recalculation = dml2_verify_det_buffer_configuration(dml2, context, &dml2->det_helper_scratch);
631 if (need_recalculation) {
632 /* Engage the DML again if recalculation is required. */
633 call_dml_mode_support_and_programming(context);
634 if (!dml2->config.skip_hw_state_mapping) {
635 dml2_map_dc_pipes(dml2, context, &s->cur_display_config, &s->dml_to_dc_pipe_mapping, in_dc->current_state);
636 }
637 need_recalculation = dml2_verify_det_buffer_configuration(dml2, context, &dml2->det_helper_scratch);
638 ASSERT(need_recalculation == false);
639 }
640 }
641
642 if (result) {
643 unsigned int lowest_state_idx = s->mode_support_params.out_lowest_state_idx;
644 out_clks.dispclk_khz = (unsigned int)dml2->v20.dml_core_ctx.mp.Dispclk_calculated * 1000;
645 out_clks.p_state_supported = s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported;
646 if (in_dc->config.use_default_clock_table &&
647 (lowest_state_idx < dml2->v20.dml_core_ctx.states.num_states - 1)) {
648 lowest_state_idx = dml2->v20.dml_core_ctx.states.num_states - 1;
649 out_clks.dispclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dispclk_mhz * 1000;
650 }
651
652 out_clks.dcfclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dcfclk_mhz * 1000;
653 out_clks.fclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].fabricclk_mhz * 1000;
654 out_clks.uclk_mts = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dram_speed_mts;
655 out_clks.phyclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].phyclk_mhz * 1000;
656 out_clks.socclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].socclk_mhz * 1000;
657 out_clks.ref_dtbclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dtbclk_mhz * 1000;
658 context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(in_dc, context);
659
660 if (!dml2->config.skip_hw_state_mapping) {
661 /* Call dml2_calculate_rq_and_dlg_params */
662 dml2_calculate_rq_and_dlg_params(in_dc, context, &context->res_ctx, dml2, in_dc->res_pool->pipe_count);
663 }
664
665 dml2_copy_clocks_to_dc_state(&out_clks, context);
666 dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.a, &dml2->v20.dml_core_ctx);
667 dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.b, &dml2->v20.dml_core_ctx);
668 memcpy(&context->bw_ctx.bw.dcn.watermarks.c, &dml2->v20.g6_temp_read_watermark_set, sizeof(context->bw_ctx.bw.dcn.watermarks.c));
669 dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.d, &dml2->v20.dml_core_ctx);
670 dml2_extract_writeback_wm(context, &dml2->v20.dml_core_ctx);
671 //copy for deciding zstate use
672 context->bw_ctx.dml.vba.StutterPeriod = context->bw_ctx.dml2->v20.dml_core_ctx.mp.StutterPeriod;
673
674 cstate_enter_plus_exit_z8_ns = context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns;
675
676 if (context->bw_ctx.dml.vba.StutterPeriod < in_dc->debug.minimum_z8_residency_time &&
677 cstate_enter_plus_exit_z8_ns < in_dc->debug.minimum_z8_residency_time * 1000)
678 cstate_enter_plus_exit_z8_ns = in_dc->debug.minimum_z8_residency_time * 1000;
679
680 context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns = cstate_enter_plus_exit_z8_ns;
681 }
682
683 return result;
684 }
685
dml2_validate_only(struct dc_state * context)686 static bool dml2_validate_only(struct dc_state *context)
687 {
688 struct dml2_context *dml2;
689 unsigned int result = 0;
690
691 if (!context || context->stream_count == 0)
692 return true;
693
694 dml2 = context->bw_ctx.dml2;
695
696 /* Zero out before each call before proceeding */
697 memset(&dml2->v20.scratch, 0, sizeof(struct dml2_wrapper_scratch));
698 memset(&dml2->v20.dml_core_ctx.policy, 0, sizeof(struct dml_mode_eval_policy_st));
699 memset(&dml2->v20.dml_core_ctx.ms, 0, sizeof(struct mode_support_st));
700 memset(&dml2->v20.dml_core_ctx.mp, 0, sizeof(struct mode_program_st));
701
702 build_unoptimized_policy_settings(dml2->v20.dml_core_ctx.project, &dml2->v20.dml_core_ctx.policy);
703
704 map_dc_state_into_dml_display_cfg(dml2, context, &dml2->v20.scratch.cur_display_config);
705 if (!dml2->config.skip_hw_state_mapping)
706 dml2_apply_det_buffer_allocation_policy(dml2, &dml2->v20.scratch.cur_display_config);
707
708 result = pack_and_call_dml_mode_support_ex(dml2,
709 &dml2->v20.scratch.cur_display_config,
710 &dml2->v20.scratch.mode_support_info);
711
712 if (result)
713 result = does_configuration_meet_sw_policies(dml2, &dml2->v20.scratch.cur_display_config, &dml2->v20.scratch.mode_support_info);
714
715 return (result == 1) ? true : false;
716 }
717
dml2_apply_debug_options(const struct dc * dc,struct dml2_context * dml2)718 static void dml2_apply_debug_options(const struct dc *dc, struct dml2_context *dml2)
719 {
720 if (dc->debug.override_odm_optimization) {
721 dml2->config.minimize_dispclk_using_odm = dc->debug.minimize_dispclk_using_odm;
722 }
723 }
724
dml2_validate(const struct dc * in_dc,struct dc_state * context,struct dml2_context * dml2,bool fast_validate)725 bool dml2_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml2, bool fast_validate)
726 {
727 bool out = false;
728
729 if (!dml2)
730 return false;
731 dml2_apply_debug_options(in_dc, dml2);
732
733 /* DML2.1 validation path */
734 if (dml2->architecture == dml2_architecture_21) {
735 out = dml21_validate(in_dc, context, dml2, fast_validate);
736 return out;
737 }
738
739 DC_FP_START();
740
741 /* Use dml_validate_only for fast_validate path */
742 if (fast_validate)
743 out = dml2_validate_only(context);
744 else
745 out = dml2_validate_and_build_resource(in_dc, context);
746
747 DC_FP_END();
748
749 return out;
750 }
751
dml2_allocate_memory(void)752 static inline struct dml2_context *dml2_allocate_memory(void)
753 {
754 return (struct dml2_context *) vzalloc(sizeof(struct dml2_context));
755 }
756
dml2_init(const struct dc * in_dc,const struct dml2_configuration_options * config,struct dml2_context ** dml2)757 static void dml2_init(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2)
758 {
759 // TODO : Temporarily add DCN_VERSION_3_2 for N-1 validation. Remove DCN_VERSION_3_2 after N-1 validation phase is complete.
760 if ((in_dc->debug.using_dml21) && (in_dc->ctx->dce_version == DCN_VERSION_4_01 || in_dc->ctx->dce_version == DCN_VERSION_3_2)) {
761 dml21_reinit(in_dc, dml2, config);
762 return;
763 }
764
765 // Store config options
766 (*dml2)->config = *config;
767
768 switch (in_dc->ctx->dce_version) {
769 case DCN_VERSION_3_5:
770 (*dml2)->v20.dml_core_ctx.project = dml_project_dcn35;
771 break;
772 case DCN_VERSION_3_51:
773 (*dml2)->v20.dml_core_ctx.project = dml_project_dcn351;
774 break;
775 case DCN_VERSION_3_2:
776 (*dml2)->v20.dml_core_ctx.project = dml_project_dcn32;
777 break;
778 case DCN_VERSION_3_21:
779 (*dml2)->v20.dml_core_ctx.project = dml_project_dcn321;
780 break;
781 case DCN_VERSION_4_01:
782 (*dml2)->v20.dml_core_ctx.project = dml_project_dcn401;
783 break;
784 default:
785 (*dml2)->v20.dml_core_ctx.project = dml_project_default;
786 break;
787 }
788
789 DC_FP_START();
790
791 initialize_dml2_ip_params(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.ip);
792
793 initialize_dml2_soc_bbox(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc);
794
795 initialize_dml2_soc_states(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc, &(*dml2)->v20.dml_core_ctx.states);
796
797 DC_FP_END();
798 }
799
dml2_create(const struct dc * in_dc,const struct dml2_configuration_options * config,struct dml2_context ** dml2)800 bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2)
801 {
802 // TODO : Temporarily add DCN_VERSION_3_2 for N-1 validation. Remove DCN_VERSION_3_2 after N-1 validation phase is complete.
803 if ((in_dc->debug.using_dml21) && (in_dc->ctx->dce_version == DCN_VERSION_4_01 || in_dc->ctx->dce_version == DCN_VERSION_3_2)) {
804 return dml21_create(in_dc, dml2, config);
805 }
806
807 // Allocate Mode Lib Ctx
808 *dml2 = dml2_allocate_memory();
809
810 if (!(*dml2))
811 return false;
812
813 dml2_init(in_dc, config, dml2);
814
815 return true;
816 }
817
dml2_destroy(struct dml2_context * dml2)818 void dml2_destroy(struct dml2_context *dml2)
819 {
820 if (!dml2)
821 return;
822
823 if (dml2->architecture == dml2_architecture_21)
824 dml21_destroy(dml2);
825 vfree(dml2);
826 }
827
dml2_extract_dram_and_fclk_change_support(struct dml2_context * dml2,unsigned int * fclk_change_support,unsigned int * dram_clk_change_support)828 void dml2_extract_dram_and_fclk_change_support(struct dml2_context *dml2,
829 unsigned int *fclk_change_support, unsigned int *dram_clk_change_support)
830 {
831 *fclk_change_support = (unsigned int) dml2->v20.dml_core_ctx.ms.support.FCLKChangeSupport[0];
832 *dram_clk_change_support = (unsigned int) dml2->v20.dml_core_ctx.ms.support.DRAMClockChangeSupport[0];
833 }
834
dml2_prepare_mcache_programming(struct dc * in_dc,struct dc_state * context,struct dml2_context * dml2)835 void dml2_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context, struct dml2_context *dml2)
836 {
837 if (dml2->architecture == dml2_architecture_21)
838 dml21_prepare_mcache_programming(in_dc, context, dml2);
839 }
840
dml2_copy(struct dml2_context * dst_dml2,struct dml2_context * src_dml2)841 void dml2_copy(struct dml2_context *dst_dml2,
842 struct dml2_context *src_dml2)
843 {
844 if (src_dml2->architecture == dml2_architecture_21) {
845 dml21_copy(dst_dml2, src_dml2);
846 return;
847 }
848 /* copy Mode Lib Ctx */
849 memcpy(dst_dml2, src_dml2, sizeof(struct dml2_context));
850 }
851
dml2_create_copy(struct dml2_context ** dst_dml2,struct dml2_context * src_dml2)852 bool dml2_create_copy(struct dml2_context **dst_dml2,
853 struct dml2_context *src_dml2)
854 {
855 if (src_dml2->architecture == dml2_architecture_21)
856 return dml21_create_copy(dst_dml2, src_dml2);
857 /* Allocate Mode Lib Ctx */
858 *dst_dml2 = dml2_allocate_memory();
859
860 if (!(*dst_dml2))
861 return false;
862
863 /* copy Mode Lib Ctx */
864 dml2_copy(*dst_dml2, src_dml2);
865
866 return true;
867 }
868
dml2_reinit(const struct dc * in_dc,const struct dml2_configuration_options * config,struct dml2_context ** dml2)869 void dml2_reinit(const struct dc *in_dc,
870 const struct dml2_configuration_options *config,
871 struct dml2_context **dml2)
872 {
873 // TODO : Temporarily add DCN_VERSION_3_2 for N-1 validation. Remove DCN_VERSION_3_2 after N-1 validation phase is complete.
874 if ((in_dc->debug.using_dml21) && (in_dc->ctx->dce_version == DCN_VERSION_4_01 || in_dc->ctx->dce_version == DCN_VERSION_3_2)) {
875 dml21_reinit(in_dc, dml2, config);
876 return;
877 }
878
879 dml2_init(in_dc, config, dml2);
880 }
881