Linux Audio

Check our new training course

Yocto / OpenEmbedded training

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