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 "display_mode_core.h"
28 #include "dml2_internal_types.h"
29 #include "dml2_utils.h"
30 #include "dml2_policy.h"
31 #include "dml2_translation_helper.h"
32 #include "dml2_mall_phantom.h"
33 #include "dml2_dc_resource_mgmt.h"
34 #include "dml2_wrapper.h"
35 #include "dml2_wrapper_fpu.h"
36 #include "dml21_wrapper.h"
37 #include "dml21_wrapper_fpu.h"
38
initialize_dml2_ip_params(struct dml2_context * dml2,const struct dc * in_dc,struct ip_params_st * out)39 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 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 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_dcn36 &&
78 dml2->v20.dml_core_ctx.project != dml_project_dcn351) {
79 /*dGPU default as 50Mhz*/
80 in_out_display_cfg->hw.DLGRefClkFreqMHz = 50;
81 }
82 for (j = 0; j < mode_support_info->DPPPerSurface[i]; j++) {
83 if (i >= __DML2_WRAPPER_MAX_STREAMS_PLANES__) {
84 dml_print("DML::%s: Index out of bounds: i=%d, __DML2_WRAPPER_MAX_STREAMS_PLANES__=%d\n",
85 __func__, i, __DML2_WRAPPER_MAX_STREAMS_PLANES__);
86 break;
87 }
88 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];
89 dml2->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id_valid[num_pipes] = true;
90 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];
91 dml2->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id_valid[num_pipes] = true;
92 num_pipes++;
93 }
94 }
95 }
96
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,enum dc_validate_mode validate_mode)97 static unsigned int pack_and_call_dml_mode_support_ex(struct dml2_context *dml2,
98 const struct dml_display_cfg_st *display_cfg,
99 struct dml_mode_support_info_st *evaluation_info,
100 enum dc_validate_mode validate_mode)
101 {
102 struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
103
104 s->mode_support_params.mode_lib = &dml2->v20.dml_core_ctx;
105 s->mode_support_params.in_display_cfg = display_cfg;
106 if (validate_mode == DC_VALIDATE_MODE_ONLY)
107 s->mode_support_params.in_start_state_idx = dml2->v20.dml_core_ctx.states.num_states - 1;
108 else
109 s->mode_support_params.in_start_state_idx = 0;
110 s->mode_support_params.out_evaluation_info = evaluation_info;
111
112 memset(evaluation_info, 0, sizeof(struct dml_mode_support_info_st));
113 s->mode_support_params.out_lowest_state_idx = 0;
114
115 return dml_mode_support_ex(&s->mode_support_params);
116 }
117
optimize_configuration(struct dml2_context * dml2,struct dml2_wrapper_optimize_configuration_params * p)118 static bool optimize_configuration(struct dml2_context *dml2, struct dml2_wrapper_optimize_configuration_params *p)
119 {
120 int unused_dpps = p->ip_params->max_num_dpp;
121 int i;
122 int odms_needed;
123 int largest_blend_and_timing = 0;
124 bool optimization_done = false;
125
126 for (i = 0; i < (int) p->cur_display_config->num_timings; i++) {
127 if (p->cur_display_config->plane.BlendingAndTiming[i] > largest_blend_and_timing)
128 largest_blend_and_timing = p->cur_display_config->plane.BlendingAndTiming[i];
129 }
130
131 if (p->new_policy != p->cur_policy)
132 *p->new_policy = *p->cur_policy;
133
134 if (p->new_display_config != p->cur_display_config)
135 *p->new_display_config = *p->cur_display_config;
136
137
138 // Optimize Clocks
139 if (!optimization_done) {
140 if (largest_blend_and_timing == 0 && p->cur_policy->ODMUse[0] == dml_odm_use_policy_combine_as_needed && dml2->config.minimize_dispclk_using_odm) {
141 odms_needed = dml2_util_get_maximum_odm_combine_for_output(dml2->config.optimize_odm_4to1,
142 p->cur_display_config->output.OutputEncoder[0], p->cur_mode_support_info->DSCEnabled[0]) - 1;
143
144 if (odms_needed <= unused_dpps) {
145 if (odms_needed == 1) {
146 p->new_policy->ODMUse[0] = dml_odm_use_policy_combine_2to1;
147 optimization_done = true;
148 } else if (odms_needed == 3) {
149 p->new_policy->ODMUse[0] = dml_odm_use_policy_combine_4to1;
150 optimization_done = true;
151 } else
152 optimization_done = false;
153 }
154 }
155 }
156
157 return optimization_done;
158 }
159
calculate_lowest_supported_state_for_temp_read(struct dml2_context * dml2,struct dc_state * display_state,enum dc_validate_mode validate_mode)160 static int calculate_lowest_supported_state_for_temp_read(struct dml2_context *dml2, struct dc_state *display_state,
161 enum dc_validate_mode validate_mode)
162 {
163 struct dml2_calculate_lowest_supported_state_for_temp_read_scratch *s = &dml2->v20.scratch.dml2_calculate_lowest_supported_state_for_temp_read_scratch;
164 struct dml2_wrapper_scratch *s_global = &dml2->v20.scratch;
165
166 unsigned int dml_result = 0;
167 int result = -1, i, j;
168
169 build_unoptimized_policy_settings(dml2->v20.dml_core_ctx.project, &dml2->v20.dml_core_ctx.policy);
170
171 /* Zero out before each call before proceeding */
172 memset(s, 0, sizeof(struct dml2_calculate_lowest_supported_state_for_temp_read_scratch));
173 memset(&s_global->mode_support_params, 0, sizeof(struct dml_mode_support_ex_params_st));
174 memset(&s_global->dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping));
175
176 for (i = 0; i < dml2->config.dcn_pipe_count; i++) {
177 /* Calling resource_build_scaling_params will populate the pipe params
178 * with the necessary information needed for correct DML calculations
179 * This is also done in DML1 driver code path and hence display_state
180 * cannot be const.
181 */
182 struct pipe_ctx *pipe = &display_state->res_ctx.pipe_ctx[i];
183
184 if (pipe->plane_state) {
185 if (!dml2->config.callbacks.build_scaling_params(pipe)) {
186 ASSERT(false);
187 return false;
188 }
189 }
190 }
191
192 map_dc_state_into_dml_display_cfg(dml2, display_state, &s->cur_display_config);
193
194 for (i = 0; i < dml2->v20.dml_core_ctx.states.num_states; i++) {
195 s->uclk_change_latencies[i] = dml2->v20.dml_core_ctx.states.state_array[i].dram_clock_change_latency_us;
196 }
197
198 for (i = 0; i < 4; i++) {
199 for (j = 0; j < dml2->v20.dml_core_ctx.states.num_states; j++) {
200 dml2->v20.dml_core_ctx.states.state_array[j].dram_clock_change_latency_us = s_global->dummy_pstate_table[i].dummy_pstate_latency_us;
201 }
202
203 dml_result = pack_and_call_dml_mode_support_ex(dml2, &s->cur_display_config, &s->evaluation_info,
204 validate_mode);
205
206 if (dml_result && s->evaluation_info.DRAMClockChangeSupport[0] == dml_dram_clock_change_vactive) {
207 map_hw_resources(dml2, &s->cur_display_config, &s->evaluation_info);
208 dml_result = dml_mode_programming(&dml2->v20.dml_core_ctx, s_global->mode_support_params.out_lowest_state_idx, &s->cur_display_config, true);
209
210 ASSERT(dml_result);
211
212 dml2_extract_watermark_set(&dml2->v20.g6_temp_read_watermark_set, &dml2->v20.dml_core_ctx);
213 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;
214
215 result = s_global->mode_support_params.out_lowest_state_idx;
216
217 while (dml2->v20.dml_core_ctx.states.state_array[result].dram_speed_mts < s_global->dummy_pstate_table[i].dram_speed_mts)
218 result++;
219
220 break;
221 }
222 }
223
224 for (i = 0; i < dml2->v20.dml_core_ctx.states.num_states; i++) {
225 dml2->v20.dml_core_ctx.states.state_array[i].dram_clock_change_latency_us = s->uclk_change_latencies[i];
226 }
227
228 return result;
229 }
230
copy_dummy_pstate_table(struct dummy_pstate_entry * dest,struct dummy_pstate_entry * src,unsigned int num_entries)231 static void copy_dummy_pstate_table(struct dummy_pstate_entry *dest, struct dummy_pstate_entry *src, unsigned int num_entries)
232 {
233 for (int i = 0; i < num_entries; i++) {
234 dest[i] = src[i];
235 }
236 }
237
are_timings_requiring_odm_doing_blending(const struct dml_display_cfg_st * display_cfg,const struct dml_mode_support_info_st * evaluation_info)238 static bool are_timings_requiring_odm_doing_blending(const struct dml_display_cfg_st *display_cfg,
239 const struct dml_mode_support_info_st *evaluation_info)
240 {
241 unsigned int planes_per_timing[__DML_NUM_PLANES__] = {0};
242 int i;
243
244 for (i = 0; i < display_cfg->num_surfaces; i++)
245 planes_per_timing[display_cfg->plane.BlendingAndTiming[i]]++;
246
247 for (i = 0; i < __DML_NUM_PLANES__; i++) {
248 if (planes_per_timing[i] > 1 && evaluation_info->ODMMode[i] != dml_odm_mode_bypass)
249 return true;
250 }
251
252 return false;
253 }
254
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)255 static bool does_configuration_meet_sw_policies(struct dml2_context *ctx, const struct dml_display_cfg_st *display_cfg,
256 const struct dml_mode_support_info_st *evaluation_info)
257 {
258 bool pass = true;
259
260 if (!ctx->config.enable_windowed_mpo_odm) {
261 if (are_timings_requiring_odm_doing_blending(display_cfg, evaluation_info))
262 pass = false;
263 }
264
265 return pass;
266 }
267
dml_mode_support_wrapper(struct dml2_context * dml2,struct dc_state * display_state,enum dc_validate_mode validate_mode)268 static bool dml_mode_support_wrapper(struct dml2_context *dml2,
269 struct dc_state *display_state,
270 enum dc_validate_mode validate_mode)
271 {
272 struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
273 unsigned int result = 0, i;
274 unsigned int optimized_result = true;
275
276 build_unoptimized_policy_settings(dml2->v20.dml_core_ctx.project, &dml2->v20.dml_core_ctx.policy);
277
278 /* Zero out before each call before proceeding */
279 memset(&s->cur_display_config, 0, sizeof(struct dml_display_cfg_st));
280 memset(&s->mode_support_params, 0, sizeof(struct dml_mode_support_ex_params_st));
281 memset(&s->dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping));
282 memset(&s->optimize_configuration_params, 0, sizeof(struct dml2_wrapper_optimize_configuration_params));
283
284 for (i = 0; i < dml2->config.dcn_pipe_count; i++) {
285 /* Calling resource_build_scaling_params will populate the pipe params
286 * with the necessary information needed for correct DML calculations
287 * This is also done in DML1 driver code path and hence display_state
288 * cannot be const.
289 */
290 struct pipe_ctx *pipe = &display_state->res_ctx.pipe_ctx[i];
291
292 if (pipe->plane_state) {
293 if (!dml2->config.callbacks.build_scaling_params(pipe)) {
294 ASSERT(false);
295 return false;
296 }
297 }
298 }
299
300 map_dc_state_into_dml_display_cfg(dml2, display_state, &s->cur_display_config);
301 if (!dml2->config.skip_hw_state_mapping)
302 dml2_apply_det_buffer_allocation_policy(dml2, &s->cur_display_config);
303
304 result = pack_and_call_dml_mode_support_ex(dml2,
305 &s->cur_display_config,
306 &s->mode_support_info,
307 validate_mode);
308
309 if (result)
310 result = does_configuration_meet_sw_policies(dml2, &s->cur_display_config, &s->mode_support_info);
311
312 // Try to optimize
313 if (result) {
314 s->cur_policy = dml2->v20.dml_core_ctx.policy;
315 s->optimize_configuration_params.dml_core_ctx = &dml2->v20.dml_core_ctx;
316 s->optimize_configuration_params.config = &dml2->config;
317 s->optimize_configuration_params.ip_params = &dml2->v20.dml_core_ctx.ip;
318 s->optimize_configuration_params.cur_display_config = &s->cur_display_config;
319 s->optimize_configuration_params.cur_mode_support_info = &s->mode_support_info;
320 s->optimize_configuration_params.cur_policy = &s->cur_policy;
321 s->optimize_configuration_params.new_display_config = &s->new_display_config;
322 s->optimize_configuration_params.new_policy = &s->new_policy;
323
324 while (optimized_result && optimize_configuration(dml2, &s->optimize_configuration_params)) {
325 dml2->v20.dml_core_ctx.policy = s->new_policy;
326 optimized_result = pack_and_call_dml_mode_support_ex(dml2,
327 &s->new_display_config,
328 &s->mode_support_info,
329 validate_mode);
330
331 if (optimized_result)
332 optimized_result = does_configuration_meet_sw_policies(dml2, &s->new_display_config, &s->mode_support_info);
333
334 // If the new optimized state is supposed, then set current = new
335 if (optimized_result) {
336 s->cur_display_config = s->new_display_config;
337 s->cur_policy = s->new_policy;
338 } else {
339 // Else, restore policy to current
340 dml2->v20.dml_core_ctx.policy = s->cur_policy;
341 }
342 }
343
344 // Optimize ended with a failed config, so we need to restore DML state to last passing
345 if (!optimized_result) {
346 result = pack_and_call_dml_mode_support_ex(dml2,
347 &s->cur_display_config,
348 &s->mode_support_info,
349 validate_mode);
350 }
351 }
352
353 if (result)
354 map_hw_resources(dml2, &s->cur_display_config, &s->mode_support_info);
355
356 return result;
357 }
358
call_dml_mode_support_and_programming(struct dc_state * context,enum dc_validate_mode validate_mode)359 static bool call_dml_mode_support_and_programming(struct dc_state *context, enum dc_validate_mode validate_mode)
360 {
361 unsigned int result = 0;
362 unsigned int min_state = 0;
363 int min_state_for_g6_temp_read = 0;
364
365
366 if (!context)
367 return false;
368
369 struct dml2_context *dml2 = context->bw_ctx.dml2;
370 struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
371
372 if (!context->streams[0]->sink->link->dc->caps.is_apu) {
373 min_state_for_g6_temp_read = calculate_lowest_supported_state_for_temp_read(dml2, context,
374 validate_mode);
375
376 ASSERT(min_state_for_g6_temp_read >= 0);
377 }
378
379 result = dml_mode_support_wrapper(dml2, context, validate_mode);
380
381 /* 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.
382 * 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.
383 */
384 if (!context->streams[0]->sink->link->dc->caps.is_apu) {
385 if (min_state_for_g6_temp_read >= 0)
386 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;
387 else
388 min_state = s->mode_support_params.out_lowest_state_idx;
389 }
390
391 if (result) {
392 if (!context->streams[0]->sink->link->dc->caps.is_apu) {
393 result = dml_mode_programming(&dml2->v20.dml_core_ctx, min_state, &s->cur_display_config, true);
394 } else {
395 result = dml_mode_programming(&dml2->v20.dml_core_ctx, s->mode_support_params.out_lowest_state_idx, &s->cur_display_config, true);
396 }
397 }
398 return result;
399 }
400
dml2_validate_and_build_resource(const struct dc * in_dc,struct dc_state * context,enum dc_validate_mode validate_mode)401 bool dml2_validate_and_build_resource(const struct dc *in_dc, struct dc_state *context,
402 enum dc_validate_mode validate_mode)
403 {
404 struct dml2_context *dml2 = context->bw_ctx.dml2;
405 struct dml2_wrapper_scratch *s = &dml2->v20.scratch;
406 struct dml2_dcn_clocks out_clks;
407 unsigned int result = 0;
408 bool need_recalculation = false;
409 uint32_t cstate_enter_plus_exit_z8_ns;
410
411 if (context->stream_count == 0) {
412 unsigned int lowest_state_idx = 0;
413
414 out_clks.p_state_supported = true;
415 out_clks.dispclk_khz = 0; /* No requirement, and lowest index will generally be maximum dispclk. */
416 out_clks.dcfclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dcfclk_mhz * 1000;
417 out_clks.fclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].fabricclk_mhz * 1000;
418 out_clks.uclk_mts = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dram_speed_mts;
419 out_clks.phyclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].phyclk_mhz * 1000;
420 out_clks.socclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].socclk_mhz * 1000;
421 out_clks.ref_dtbclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dtbclk_mhz * 1000;
422 context->bw_ctx.bw.dcn.clk.dtbclk_en = false;
423 dml2_copy_clocks_to_dc_state(&out_clks, context);
424 return true;
425 }
426
427 /* Zero out before each call before proceeding */
428 memset(&dml2->v20.scratch, 0, sizeof(struct dml2_wrapper_scratch));
429 memset(&dml2->v20.dml_core_ctx.policy, 0, sizeof(struct dml_mode_eval_policy_st));
430 memset(&dml2->v20.dml_core_ctx.ms, 0, sizeof(struct mode_support_st));
431 memset(&dml2->v20.dml_core_ctx.mp, 0, sizeof(struct mode_program_st));
432
433 /* Initialize DET scratch */
434 dml2_initialize_det_scratch(dml2);
435
436 copy_dummy_pstate_table(s->dummy_pstate_table, in_dc->clk_mgr->bw_params->dummy_pstate_table, 4);
437
438 result = call_dml_mode_support_and_programming(context, validate_mode);
439 /* Call map dc pipes to map the pipes based on the DML output. For correctly determining if recalculation
440 * is required or not, the resource context needs to correctly reflect the number of active pipes. We would
441 * only know the correct number if active pipes after dml2_map_dc_pipes is called.
442 */
443 if (result && !dml2->config.skip_hw_state_mapping)
444 dml2_map_dc_pipes(dml2, context, &s->cur_display_config, &s->dml_to_dc_pipe_mapping, in_dc->current_state);
445
446 /* Verify and update DET Buffer configuration if needed. dml2_verify_det_buffer_configuration will check if DET Buffer
447 * size needs to be updated. If yes it will update the DETOverride variable and set need_recalculation flag to true.
448 * Based on that flag, run mode support again. Verification needs to be run after dml_mode_programming because the getters
449 * return correct det buffer values only after dml_mode_programming is called.
450 */
451 if (result && !dml2->config.skip_hw_state_mapping) {
452 need_recalculation = dml2_verify_det_buffer_configuration(dml2, context, &dml2->det_helper_scratch);
453 if (need_recalculation) {
454 /* Engage the DML again if recalculation is required. */
455 call_dml_mode_support_and_programming(context, validate_mode);
456 if (!dml2->config.skip_hw_state_mapping) {
457 dml2_map_dc_pipes(dml2, context, &s->cur_display_config, &s->dml_to_dc_pipe_mapping, in_dc->current_state);
458 }
459 need_recalculation = dml2_verify_det_buffer_configuration(dml2, context, &dml2->det_helper_scratch);
460 ASSERT(need_recalculation == false);
461 }
462 }
463
464 if (result) {
465 unsigned int lowest_state_idx = s->mode_support_params.out_lowest_state_idx;
466 out_clks.dispclk_khz = (unsigned int)dml2->v20.dml_core_ctx.mp.Dispclk_calculated * 1000;
467 out_clks.p_state_supported = s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported;
468 if (in_dc->config.use_default_clock_table &&
469 (lowest_state_idx < dml2->v20.dml_core_ctx.states.num_states - 1)) {
470 lowest_state_idx = dml2->v20.dml_core_ctx.states.num_states - 1;
471 out_clks.dispclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dispclk_mhz * 1000;
472 }
473
474 out_clks.dcfclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dcfclk_mhz * 1000;
475 out_clks.fclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].fabricclk_mhz * 1000;
476 out_clks.uclk_mts = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dram_speed_mts;
477 out_clks.phyclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].phyclk_mhz * 1000;
478 out_clks.socclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].socclk_mhz * 1000;
479 out_clks.ref_dtbclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dtbclk_mhz * 1000;
480 context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(in_dc, context);
481
482 if (!dml2->config.skip_hw_state_mapping) {
483 /* Call dml2_calculate_rq_and_dlg_params */
484 dml2_calculate_rq_and_dlg_params(in_dc, context, &context->res_ctx, dml2, in_dc->res_pool->pipe_count);
485 }
486
487 dml2_copy_clocks_to_dc_state(&out_clks, context);
488 dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.a, &dml2->v20.dml_core_ctx);
489 dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.b, &dml2->v20.dml_core_ctx);
490 if (context->streams[0]->sink->link->dc->caps.is_apu)
491 dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.c, &dml2->v20.dml_core_ctx);
492 else
493 memcpy(&context->bw_ctx.bw.dcn.watermarks.c, &dml2->v20.g6_temp_read_watermark_set, sizeof(context->bw_ctx.bw.dcn.watermarks.c));
494 dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.d, &dml2->v20.dml_core_ctx);
495 dml2_extract_writeback_wm(context, &dml2->v20.dml_core_ctx);
496 //copy for deciding zstate use
497 context->bw_ctx.dml.vba.StutterPeriod = context->bw_ctx.dml2->v20.dml_core_ctx.mp.StutterPeriod;
498
499 cstate_enter_plus_exit_z8_ns = context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns;
500
501 if (context->bw_ctx.dml.vba.StutterPeriod < in_dc->debug.minimum_z8_residency_time &&
502 cstate_enter_plus_exit_z8_ns < in_dc->debug.minimum_z8_residency_time * 1000)
503 cstate_enter_plus_exit_z8_ns = in_dc->debug.minimum_z8_residency_time * 1000;
504
505 context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns = cstate_enter_plus_exit_z8_ns;
506 }
507
508 return result;
509 }
510
dml2_validate_only(struct dc_state * context,enum dc_validate_mode validate_mode)511 bool dml2_validate_only(struct dc_state *context, enum dc_validate_mode validate_mode)
512 {
513 struct dml2_context *dml2;
514 unsigned int result = 0;
515
516 if (!context || context->stream_count == 0)
517 return true;
518
519 dml2 = context->bw_ctx.dml2;
520
521 /* Zero out before each call before proceeding */
522 memset(&dml2->v20.scratch, 0, sizeof(struct dml2_wrapper_scratch));
523 memset(&dml2->v20.dml_core_ctx.policy, 0, sizeof(struct dml_mode_eval_policy_st));
524 memset(&dml2->v20.dml_core_ctx.ms, 0, sizeof(struct mode_support_st));
525 memset(&dml2->v20.dml_core_ctx.mp, 0, sizeof(struct mode_program_st));
526
527 build_unoptimized_policy_settings(dml2->v20.dml_core_ctx.project, &dml2->v20.dml_core_ctx.policy);
528
529 map_dc_state_into_dml_display_cfg(dml2, context, &dml2->v20.scratch.cur_display_config);
530 if (!dml2->config.skip_hw_state_mapping)
531 dml2_apply_det_buffer_allocation_policy(dml2, &dml2->v20.scratch.cur_display_config);
532
533 result = pack_and_call_dml_mode_support_ex(dml2,
534 &dml2->v20.scratch.cur_display_config,
535 &dml2->v20.scratch.mode_support_info,
536 validate_mode);
537
538 if (result)
539 result = does_configuration_meet_sw_policies(dml2, &dml2->v20.scratch.cur_display_config, &dml2->v20.scratch.mode_support_info);
540
541 return result == 1;
542 }
543
dml2_apply_debug_options(const struct dc * dc,struct dml2_context * dml2)544 void dml2_apply_debug_options(const struct dc *dc, struct dml2_context *dml2)
545 {
546 if (dc->debug.override_odm_optimization) {
547 dml2->config.minimize_dispclk_using_odm = dc->debug.minimize_dispclk_using_odm;
548 }
549 }
550
dml2_extract_dram_and_fclk_change_support(struct dml2_context * dml2,unsigned int * fclk_change_support,unsigned int * dram_clk_change_support)551 void dml2_extract_dram_and_fclk_change_support(struct dml2_context *dml2,
552 unsigned int *fclk_change_support, unsigned int *dram_clk_change_support)
553 {
554 *fclk_change_support = (unsigned int) dml2->v20.dml_core_ctx.ms.support.FCLKChangeSupport[0];
555 *dram_clk_change_support = (unsigned int) dml2->v20.dml_core_ctx.ms.support.DRAMClockChangeSupport[0];
556 }
557
dml2_prepare_mcache_programming(struct dc * in_dc,struct dc_state * context,struct dml2_context * dml2)558 void dml2_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context, struct dml2_context *dml2)
559 {
560 if (dml2->architecture == dml2_architecture_21)
561 dml21_prepare_mcache_programming(in_dc, context, dml2);
562 }
563
dml2_copy(struct dml2_context * dst_dml2,struct dml2_context * src_dml2)564 void dml2_copy(struct dml2_context *dst_dml2,
565 struct dml2_context *src_dml2)
566 {
567 if (src_dml2->architecture == dml2_architecture_21) {
568 dml21_copy(dst_dml2, src_dml2);
569 return;
570 }
571 /* copy Mode Lib Ctx */
572 memcpy(dst_dml2, src_dml2, sizeof(struct dml2_context));
573 }
574
dml2_create_copy(struct dml2_context ** dst_dml2,struct dml2_context * src_dml2)575 bool dml2_create_copy(struct dml2_context **dst_dml2,
576 struct dml2_context *src_dml2)
577 {
578 if (src_dml2->architecture == dml2_architecture_21)
579 return dml21_create_copy(dst_dml2, src_dml2);
580 /* Allocate Mode Lib Ctx */
581 *dst_dml2 = dml2_allocate_memory();
582
583 if (!(*dst_dml2))
584 return false;
585
586 /* copy Mode Lib Ctx */
587 dml2_copy(*dst_dml2, src_dml2);
588
589 return true;
590 }
591
592