File Index
Files and directories
Sign in
FILE

dml2_wrapper.c

File preview with syntax highlighting.

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