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