brintos

brintos / linux-shallow public Read only

0
0
Text · 33.6 KiB · 866b0ab Raw
855 lines · 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 a6 * copy of this software and associated documentation files (the "Software"),7 * to deal in the Software without restriction, including without limitation8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,9 * and/or sell copies of the Software, and to permit persons to whom the10 * Software is furnished to do so, subject to the following conditions:11 *12 * The above copyright notice and this permission notice shall be included in13 * all copies or substantial portions of the Software.14 *15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR19 * 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 OR21 * OTHER DEALINGS IN THE SOFTWARE.22 *23 * Authors: AMD24 *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	else42		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	else50		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	else59		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 Support132	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 subvp135			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 timing167				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 Clocks206	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				unused_dpps -= odms_needed;213 214				if (odms_needed == 1) {215					p->new_policy->ODMUse[0] = dml_odm_use_policy_combine_2to1;216					optimization_done = true;217				} else if (odms_needed == 3) {218					p->new_policy->ODMUse[0] = dml_odm_use_policy_combine_4to1;219					optimization_done = true;220				} else221					optimization_done = false;222			}223		}224	}225 226	return optimization_done;227}228 229static int calculate_lowest_supported_state_for_temp_read(struct dml2_context *dml2, struct dc_state *display_state)230{231	struct dml2_calculate_lowest_supported_state_for_temp_read_scratch *s = &dml2->v20.scratch.dml2_calculate_lowest_supported_state_for_temp_read_scratch;232	struct dml2_wrapper_scratch *s_global = &dml2->v20.scratch;233 234	unsigned int dml_result = 0;235	int result = -1, i, j;236 237	build_unoptimized_policy_settings(dml2->v20.dml_core_ctx.project, &dml2->v20.dml_core_ctx.policy);238 239	/* Zero out before each call before proceeding */240	memset(s, 0, sizeof(struct dml2_calculate_lowest_supported_state_for_temp_read_scratch));241	memset(&s_global->mode_support_params, 0, sizeof(struct dml_mode_support_ex_params_st));242	memset(&s_global->dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping));243 244	for (i = 0; i < dml2->config.dcn_pipe_count; i++) {245		/* Calling resource_build_scaling_params will populate the pipe params246		 * with the necessary information needed for correct DML calculations247		 * This is also done in DML1 driver code path and hence display_state248		 * cannot be const.249		 */250		struct pipe_ctx *pipe = &display_state->res_ctx.pipe_ctx[i];251 252		if (pipe->plane_state) {253			if (!dml2->config.callbacks.build_scaling_params(pipe)) {254				ASSERT(false);255				return false;256			}257		}258	}259 260	map_dc_state_into_dml_display_cfg(dml2, display_state, &s->cur_display_config);261 262	for (i = 0; i < dml2->v20.dml_core_ctx.states.num_states; i++) {263		s->uclk_change_latencies[i] = dml2->v20.dml_core_ctx.states.state_array[i].dram_clock_change_latency_us;264	}265 266	for (i = 0; i < 4; i++) {267		for (j = 0; j < dml2->v20.dml_core_ctx.states.num_states; j++) {268			dml2->v20.dml_core_ctx.states.state_array[j].dram_clock_change_latency_us = s_global->dummy_pstate_table[i].dummy_pstate_latency_us;269		}270 271		dml_result = pack_and_call_dml_mode_support_ex(dml2, &s->cur_display_config, &s->evaluation_info);272 273		if (dml_result && s->evaluation_info.DRAMClockChangeSupport[0] == dml_dram_clock_change_vactive) {274			map_hw_resources(dml2, &s->cur_display_config, &s->evaluation_info);275			dml_result = dml_mode_programming(&dml2->v20.dml_core_ctx, s_global->mode_support_params.out_lowest_state_idx, &s->cur_display_config, true);276 277			ASSERT(dml_result);278 279			dml2_extract_watermark_set(&dml2->v20.g6_temp_read_watermark_set, &dml2->v20.dml_core_ctx);280			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;281 282			result = s_global->mode_support_params.out_lowest_state_idx;283 284			while (dml2->v20.dml_core_ctx.states.state_array[result].dram_speed_mts < s_global->dummy_pstate_table[i].dram_speed_mts)285				result++;286 287			break;288		}289	}290 291	for (i = 0; i < dml2->v20.dml_core_ctx.states.num_states; i++) {292		dml2->v20.dml_core_ctx.states.state_array[i].dram_clock_change_latency_us = s->uclk_change_latencies[i];293	}294 295	return result;296}297 298static void copy_dummy_pstate_table(struct dummy_pstate_entry *dest, struct dummy_pstate_entry *src, unsigned int num_entries)299{300	for (int i = 0; i < num_entries; i++) {301		dest[i] = src[i];302	}303}304 305static bool are_timings_requiring_odm_doing_blending(const struct dml_display_cfg_st *display_cfg,306		const struct dml_mode_support_info_st *evaluation_info)307{308	unsigned int planes_per_timing[__DML_NUM_PLANES__] = {0};309	int i;310 311	for (i = 0; i < display_cfg->num_surfaces; i++)312		planes_per_timing[display_cfg->plane.BlendingAndTiming[i]]++;313 314	for (i = 0; i < __DML_NUM_PLANES__; i++) {315		if (planes_per_timing[i] > 1 && evaluation_info->ODMMode[i] != dml_odm_mode_bypass)316			return true;317	}318 319	return false;320}321 322static bool does_configuration_meet_sw_policies(struct dml2_context *ctx, const struct dml_display_cfg_st *display_cfg,323	const struct dml_mode_support_info_st *evaluation_info)324{325	bool pass = true;326 327	if (!ctx->config.enable_windowed_mpo_odm) {328		if (are_timings_requiring_odm_doing_blending(display_cfg, evaluation_info))329			pass = false;330	}331 332	return pass;333}334 335static bool dml_mode_support_wrapper(struct dml2_context *dml2,336		struct dc_state *display_state)337{338	struct dml2_wrapper_scratch *s = &dml2->v20.scratch;339	unsigned int result = 0, i;340	unsigned int optimized_result = true;341 342	build_unoptimized_policy_settings(dml2->v20.dml_core_ctx.project, &dml2->v20.dml_core_ctx.policy);343 344	/* Zero out before each call before proceeding */345	memset(&s->cur_display_config, 0, sizeof(struct dml_display_cfg_st));346	memset(&s->mode_support_params, 0, sizeof(struct dml_mode_support_ex_params_st));347	memset(&s->dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping));348	memset(&s->optimize_configuration_params, 0, sizeof(struct dml2_wrapper_optimize_configuration_params));349 350	for (i = 0; i < dml2->config.dcn_pipe_count; i++) {351		/* Calling resource_build_scaling_params will populate the pipe params352		 * with the necessary information needed for correct DML calculations353		 * This is also done in DML1 driver code path and hence display_state354		 * cannot be const.355		 */356		struct pipe_ctx *pipe = &display_state->res_ctx.pipe_ctx[i];357 358		if (pipe->plane_state) {359			if (!dml2->config.callbacks.build_scaling_params(pipe)) {360				ASSERT(false);361				return false;362			}363		}364	}365 366	map_dc_state_into_dml_display_cfg(dml2, display_state, &s->cur_display_config);367	if (!dml2->config.skip_hw_state_mapping)368		dml2_apply_det_buffer_allocation_policy(dml2, &s->cur_display_config);369 370	result = pack_and_call_dml_mode_support_ex(dml2,371		&s->cur_display_config,372		&s->mode_support_info);373 374	if (result)375		result = does_configuration_meet_sw_policies(dml2, &s->cur_display_config, &s->mode_support_info);376 377	// Try to optimize378	if (result) {379		s->cur_policy = dml2->v20.dml_core_ctx.policy;380		s->optimize_configuration_params.dml_core_ctx = &dml2->v20.dml_core_ctx;381		s->optimize_configuration_params.config = &dml2->config;382		s->optimize_configuration_params.ip_params = &dml2->v20.dml_core_ctx.ip;383		s->optimize_configuration_params.cur_display_config = &s->cur_display_config;384		s->optimize_configuration_params.cur_mode_support_info = &s->mode_support_info;385		s->optimize_configuration_params.cur_policy = &s->cur_policy;386		s->optimize_configuration_params.new_display_config = &s->new_display_config;387		s->optimize_configuration_params.new_policy = &s->new_policy;388 389		while (optimized_result && optimize_configuration(dml2, &s->optimize_configuration_params)) {390			dml2->v20.dml_core_ctx.policy = s->new_policy;391			optimized_result = pack_and_call_dml_mode_support_ex(dml2,392				&s->new_display_config,393				&s->mode_support_info);394 395			if (optimized_result)396				optimized_result = does_configuration_meet_sw_policies(dml2, &s->new_display_config, &s->mode_support_info);397 398			// If the new optimized state is supposed, then set current = new399			if (optimized_result) {400				s->cur_display_config = s->new_display_config;401				s->cur_policy = s->new_policy;402			} else {403				// Else, restore policy to current404				dml2->v20.dml_core_ctx.policy = s->cur_policy;405			}406		}407 408		// Optimize ended with a failed config, so we need to restore DML state to last passing409		if (!optimized_result) {410			result = pack_and_call_dml_mode_support_ex(dml2,411				&s->cur_display_config,412				&s->mode_support_info);413		}414	}415 416	if (result)417		map_hw_resources(dml2, &s->cur_display_config, &s->mode_support_info);418 419	return result;420}421 422static int find_drr_eligible_stream(struct dc_state *display_state)423{424	int i;425 426	for (i = 0; i < display_state->stream_count; i++) {427		if (dc_state_get_stream_subvp_type(display_state, display_state->streams[i]) == SUBVP_NONE428			&& display_state->streams[i]->ignore_msa_timing_param) {429			// Use ignore_msa_timing_param flag to identify as DRR430			return i;431		}432	}433 434	return -1;435}436 437static bool optimize_pstate_with_svp_and_drr(struct dml2_context *dml2, struct dc_state *display_state)438{439	struct dml2_wrapper_scratch *s = &dml2->v20.scratch;440	bool pstate_optimization_done = false;441	bool pstate_optimization_success = false;442	bool result = false;443	int drr_display_index = 0, non_svp_streams = 0;444	bool force_svp = dml2->config.svp_pstate.force_enable_subvp;445 446	display_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false;447	display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index_valid = false;448 449	result = dml_mode_support_wrapper(dml2, display_state);450 451	if (!result) {452		pstate_optimization_done = true;453	} else if (s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported && !force_svp) {454		pstate_optimization_success = true;455		pstate_optimization_done = true;456	}457 458	if (display_state->stream_count == 1 && dml2->config.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch(dml2->config.callbacks.dc, display_state)) {459			display_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = true;460 461			result = dml_mode_support_wrapper(dml2, display_state);462	} else {463		non_svp_streams = display_state->stream_count;464 465		while (!pstate_optimization_done) {466			result = dml_mode_programming(&dml2->v20.dml_core_ctx, s->mode_support_params.out_lowest_state_idx, &s->cur_display_config, true);467 468			// Always try adding SVP first469			if (result)470				result = dml2_svp_add_phantom_pipe_to_dc_state(dml2, display_state, &s->mode_support_info);471			else472				pstate_optimization_done = true;473 474 475			if (result) {476				result = dml_mode_support_wrapper(dml2, display_state);477			} else {478				pstate_optimization_done = true;479			}480 481			if (result) {482				non_svp_streams--;483 484				if (s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported) {485					if (dml2_svp_validate_static_schedulability(dml2, display_state, s->mode_support_info.DRAMClockChangeSupport[0])) {486						pstate_optimization_success = true;487						pstate_optimization_done = true;488					} else {489						pstate_optimization_success = false;490						pstate_optimization_done = false;491					}492				} else {493					drr_display_index = find_drr_eligible_stream(display_state);494 495					// If there is only 1 remaining non SubVP pipe that is DRR, check static496					// schedulability for SubVP + DRR.497					if (non_svp_streams == 1 && drr_display_index >= 0) {498						if (dml2_svp_drr_schedulable(dml2, display_state, &display_state->streams[drr_display_index]->timing)) {499							display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index_valid = true;500							display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index = drr_display_index;501							result = dml_mode_support_wrapper(dml2, display_state);502						}503 504						if (result && s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported) {505							pstate_optimization_success = true;506							pstate_optimization_done = true;507						} else {508							pstate_optimization_success = false;509							pstate_optimization_done = false;510						}511					}512 513					if (pstate_optimization_success) {514						pstate_optimization_done = true;515					} else {516						pstate_optimization_done = false;517					}518				}519			}520		}521	}522 523	if (!pstate_optimization_success) {524		dml2_svp_remove_all_phantom_pipes(dml2, display_state);525		display_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false;526		display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index_valid = false;527		result = dml_mode_support_wrapper(dml2, display_state);528	}529 530	return result;531}532 533static bool call_dml_mode_support_and_programming(struct dc_state *context)534{535	unsigned int result = 0;536	unsigned int min_state;537	int min_state_for_g6_temp_read = 0;538	struct dml2_context *dml2 = context->bw_ctx.dml2;539	struct dml2_wrapper_scratch *s = &dml2->v20.scratch;540 541	min_state_for_g6_temp_read = calculate_lowest_supported_state_for_temp_read(dml2, context);542 543	ASSERT(min_state_for_g6_temp_read >= 0);544 545	if (!dml2->config.use_native_pstate_optimization) {546		result = optimize_pstate_with_svp_and_drr(dml2, context);547	} else {548		result = dml_mode_support_wrapper(dml2, context);549	}550 551	/* 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.552	 * 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.553	 */554	if (min_state_for_g6_temp_read >= 0)555		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;556	else557		min_state = s->mode_support_params.out_lowest_state_idx;558 559	if (result)560		result = dml_mode_programming(&dml2->v20.dml_core_ctx, min_state, &s->cur_display_config, true);561 562	return result;563}564 565static bool dml2_validate_and_build_resource(const struct dc *in_dc, struct dc_state *context)566{567	struct dml2_context *dml2 = context->bw_ctx.dml2;568	struct dml2_wrapper_scratch *s = &dml2->v20.scratch;569	struct dml2_dcn_clocks out_clks;570	unsigned int result = 0;571	bool need_recalculation = false;572	uint32_t cstate_enter_plus_exit_z8_ns;573 574	if (context->stream_count == 0) {575		unsigned int lowest_state_idx = 0;576 577		out_clks.p_state_supported = true;578		out_clks.dispclk_khz = 0; /* No requirement, and lowest index will generally be maximum dispclk. */579		out_clks.dcfclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dcfclk_mhz * 1000;580		out_clks.fclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].fabricclk_mhz * 1000;581		out_clks.uclk_mts = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dram_speed_mts;582		out_clks.phyclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].phyclk_mhz * 1000;583		out_clks.socclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].socclk_mhz * 1000;584		out_clks.ref_dtbclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dtbclk_mhz * 1000;585		context->bw_ctx.bw.dcn.clk.dtbclk_en = false;586		dml2_copy_clocks_to_dc_state(&out_clks, context);587		return true;588	}589 590	/* Zero out before each call before proceeding */591	memset(&dml2->v20.scratch, 0, sizeof(struct dml2_wrapper_scratch));592	memset(&dml2->v20.dml_core_ctx.policy, 0, sizeof(struct dml_mode_eval_policy_st));593	memset(&dml2->v20.dml_core_ctx.ms, 0, sizeof(struct mode_support_st));594	memset(&dml2->v20.dml_core_ctx.mp, 0, sizeof(struct mode_program_st));595 596	/* Initialize DET scratch */597	dml2_initialize_det_scratch(dml2);598 599	copy_dummy_pstate_table(s->dummy_pstate_table, in_dc->clk_mgr->bw_params->dummy_pstate_table, 4);600 601	result = call_dml_mode_support_and_programming(context);602	/* Call map dc pipes to map the pipes based on the DML output. For correctly determining if recalculation603	 * is required or not, the resource context needs to correctly reflect the number of active pipes. We would604	 * only know the correct number if active pipes after dml2_map_dc_pipes is called.605	 */606	if (result && !dml2->config.skip_hw_state_mapping)607		dml2_map_dc_pipes(dml2, context, &s->cur_display_config, &s->dml_to_dc_pipe_mapping, in_dc->current_state);608 609	/* Verify and update DET Buffer configuration if needed. dml2_verify_det_buffer_configuration will check if DET Buffer610	 * size needs to be updated. If yes it will update the DETOverride variable and set need_recalculation flag to true.611	 * Based on that flag, run mode support again. Verification needs to be run after dml_mode_programming because the getters612	 * return correct det buffer values only after dml_mode_programming is called.613	 */614	if (result && !dml2->config.skip_hw_state_mapping) {615		need_recalculation = dml2_verify_det_buffer_configuration(dml2, context, &dml2->det_helper_scratch);616		if (need_recalculation) {617			/* Engage the DML again if recalculation is required. */618			call_dml_mode_support_and_programming(context);619			if (!dml2->config.skip_hw_state_mapping) {620				dml2_map_dc_pipes(dml2, context, &s->cur_display_config, &s->dml_to_dc_pipe_mapping, in_dc->current_state);621			}622			need_recalculation = dml2_verify_det_buffer_configuration(dml2, context, &dml2->det_helper_scratch);623			ASSERT(need_recalculation == false);624		}625	}626 627	if (result) {628		unsigned int lowest_state_idx = s->mode_support_params.out_lowest_state_idx;629		out_clks.dispclk_khz = (unsigned int)dml2->v20.dml_core_ctx.mp.Dispclk_calculated * 1000;630		out_clks.p_state_supported = s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported;631		if (in_dc->config.use_default_clock_table &&632			(lowest_state_idx < dml2->v20.dml_core_ctx.states.num_states - 1)) {633			lowest_state_idx = dml2->v20.dml_core_ctx.states.num_states - 1;634			out_clks.dispclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dispclk_mhz * 1000;635		}636 637		out_clks.dcfclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dcfclk_mhz * 1000;638		out_clks.fclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].fabricclk_mhz * 1000;639		out_clks.uclk_mts = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dram_speed_mts;640		out_clks.phyclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].phyclk_mhz * 1000;641		out_clks.socclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].socclk_mhz * 1000;642		out_clks.ref_dtbclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dtbclk_mhz * 1000;643		context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(in_dc, context);644 645		if (!dml2->config.skip_hw_state_mapping) {646			/* Call dml2_calculate_rq_and_dlg_params */647			dml2_calculate_rq_and_dlg_params(in_dc, context, &context->res_ctx, dml2, in_dc->res_pool->pipe_count);648		}649 650		dml2_copy_clocks_to_dc_state(&out_clks, context);651		dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.a, &dml2->v20.dml_core_ctx);652		dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.b, &dml2->v20.dml_core_ctx);653		memcpy(&context->bw_ctx.bw.dcn.watermarks.c, &dml2->v20.g6_temp_read_watermark_set, sizeof(context->bw_ctx.bw.dcn.watermarks.c));654		dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.d, &dml2->v20.dml_core_ctx);655		dml2_extract_writeback_wm(context, &dml2->v20.dml_core_ctx);656		//copy for deciding zstate use657		context->bw_ctx.dml.vba.StutterPeriod = context->bw_ctx.dml2->v20.dml_core_ctx.mp.StutterPeriod;658 659		cstate_enter_plus_exit_z8_ns = context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns;660 661		if (context->bw_ctx.dml.vba.StutterPeriod < in_dc->debug.minimum_z8_residency_time &&662				cstate_enter_plus_exit_z8_ns < in_dc->debug.minimum_z8_residency_time * 1000)663			cstate_enter_plus_exit_z8_ns = in_dc->debug.minimum_z8_residency_time * 1000;664 665		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns = cstate_enter_plus_exit_z8_ns;666	}667 668	return result;669}670 671static bool dml2_validate_only(struct dc_state *context)672{673	struct dml2_context *dml2;674	unsigned int result = 0;675 676	if (!context || context->stream_count == 0)677		return true;678 679	dml2 = context->bw_ctx.dml2;680 681	/* Zero out before each call before proceeding */682	memset(&dml2->v20.scratch, 0, sizeof(struct dml2_wrapper_scratch));683	memset(&dml2->v20.dml_core_ctx.policy, 0, sizeof(struct dml_mode_eval_policy_st));684	memset(&dml2->v20.dml_core_ctx.ms, 0, sizeof(struct mode_support_st));685	memset(&dml2->v20.dml_core_ctx.mp, 0, sizeof(struct mode_program_st));686 687	build_unoptimized_policy_settings(dml2->v20.dml_core_ctx.project, &dml2->v20.dml_core_ctx.policy);688 689	map_dc_state_into_dml_display_cfg(dml2, context, &dml2->v20.scratch.cur_display_config);690 691	result = pack_and_call_dml_mode_support_ex(dml2,692		&dml2->v20.scratch.cur_display_config,693		&dml2->v20.scratch.mode_support_info);694 695	if (result)696		result = does_configuration_meet_sw_policies(dml2, &dml2->v20.scratch.cur_display_config, &dml2->v20.scratch.mode_support_info);697 698	return (result == 1) ? true : false;699}700 701static void dml2_apply_debug_options(const struct dc *dc, struct dml2_context *dml2)702{703	if (dc->debug.override_odm_optimization) {704		dml2->config.minimize_dispclk_using_odm = dc->debug.minimize_dispclk_using_odm;705	}706}707 708bool dml2_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml2, bool fast_validate)709{710	bool out = false;711 712	if (!dml2)713		return false;714	dml2_apply_debug_options(in_dc, dml2);715 716	/* DML2.1 validation path */717	if (dml2->architecture == dml2_architecture_21) {718		out = dml21_validate(in_dc, context, dml2, fast_validate);719		return out;720	}721 722	/* Use dml_validate_only for fast_validate path */723	if (fast_validate)724		out = dml2_validate_only(context);725	else726		out = dml2_validate_and_build_resource(in_dc, context);727	return out;728}729 730static inline struct dml2_context *dml2_allocate_memory(void)731{732	return (struct dml2_context *) kzalloc(sizeof(struct dml2_context), GFP_KERNEL);733}734 735static void dml2_init(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2)736{737	// TODO : Temporarily add DCN_VERSION_3_2 for N-1 validation. Remove DCN_VERSION_3_2 after N-1 validation phase is complete.738        if ((in_dc->debug.using_dml21) && (in_dc->ctx->dce_version == DCN_VERSION_4_01 || in_dc->ctx->dce_version == DCN_VERSION_3_2)) {739                dml21_reinit(in_dc, dml2, config);740		return;741        }742 743	// Store config options744	(*dml2)->config = *config;745 746	switch (in_dc->ctx->dce_version) {747	case DCN_VERSION_3_5:748		(*dml2)->v20.dml_core_ctx.project = dml_project_dcn35;749		break;750	case DCN_VERSION_3_51:751		(*dml2)->v20.dml_core_ctx.project = dml_project_dcn351;752		break;753	case DCN_VERSION_3_2:754		(*dml2)->v20.dml_core_ctx.project = dml_project_dcn32;755		break;756	case DCN_VERSION_3_21:757		(*dml2)->v20.dml_core_ctx.project = dml_project_dcn321;758		break;759	case DCN_VERSION_4_01:760		(*dml2)->v20.dml_core_ctx.project = dml_project_dcn401;761		break;762	default:763		(*dml2)->v20.dml_core_ctx.project = dml_project_default;764		break;765	}766 767	initialize_dml2_ip_params(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.ip);768 769	initialize_dml2_soc_bbox(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc);770 771	initialize_dml2_soc_states(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc, &(*dml2)->v20.dml_core_ctx.states);772}773 774bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2)775{776	// TODO : Temporarily add DCN_VERSION_3_2 for N-1 validation. Remove DCN_VERSION_3_2 after N-1 validation phase is complete.777	if ((in_dc->debug.using_dml21) && (in_dc->ctx->dce_version == DCN_VERSION_4_01 || in_dc->ctx->dce_version == DCN_VERSION_3_2)) {778		return dml21_create(in_dc, dml2, config);779	}780 781	// Allocate Mode Lib Ctx782	*dml2 = dml2_allocate_memory();783 784	if (!(*dml2))785		return false;786 787	dml2_init(in_dc, config, dml2);788 789	return true;790}791 792void dml2_destroy(struct dml2_context *dml2)793{794	if (!dml2)795		return;796 797	if (dml2->architecture == dml2_architecture_21)798		dml21_destroy(dml2);799	kfree(dml2);800}801 802void dml2_extract_dram_and_fclk_change_support(struct dml2_context *dml2,803	unsigned int *fclk_change_support, unsigned int *dram_clk_change_support)804{805	*fclk_change_support = (unsigned int) dml2->v20.dml_core_ctx.ms.support.FCLKChangeSupport[0];806	*dram_clk_change_support = (unsigned int) dml2->v20.dml_core_ctx.ms.support.DRAMClockChangeSupport[0];807}808 809void dml2_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context, struct dml2_context *dml2)810{811	if (dml2->architecture == dml2_architecture_21)812		dml21_prepare_mcache_programming(in_dc, context, dml2);813}814 815void dml2_copy(struct dml2_context *dst_dml2,816	struct dml2_context *src_dml2)817{818	if (src_dml2->architecture == dml2_architecture_21) {819		dml21_copy(dst_dml2, src_dml2);820		return;821	}822	/* copy Mode Lib Ctx */823	memcpy(dst_dml2, src_dml2, sizeof(struct dml2_context));824}825 826bool dml2_create_copy(struct dml2_context **dst_dml2,827	struct dml2_context *src_dml2)828{829	if (src_dml2->architecture == dml2_architecture_21)830		return dml21_create_copy(dst_dml2, src_dml2);831	/* Allocate Mode Lib Ctx */832	*dst_dml2 = dml2_allocate_memory();833 834	if (!(*dst_dml2))835		return false;836 837	/* copy Mode Lib Ctx */838	dml2_copy(*dst_dml2, src_dml2);839 840	return true;841}842 843void dml2_reinit(const struct dc *in_dc,844				 const struct dml2_configuration_options *config,845				 struct dml2_context **dml2)846{847	// TODO : Temporarily add DCN_VERSION_3_2 for N-1 validation. Remove DCN_VERSION_3_2 after N-1 validation phase is complete.848	if ((in_dc->debug.using_dml21) && (in_dc->ctx->dce_version == DCN_VERSION_4_01 || in_dc->ctx->dce_version == DCN_VERSION_3_2)) {849		dml21_reinit(in_dc, dml2, config);850		return;851	}852 853	dml2_init(in_dc, config, dml2);854}855