xref: /linux/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.c (revision 2ace52718376fdb56aca863da2eebe70d7e2ddb1)
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2025 Advanced Micro Devices, Inc.
4 
5 #include "dcn401_soc_and_ip_translator.h"
6 #include "bounding_boxes/dcn4_soc_bb.h"
7 
8 /* soc_and_ip_translator component used to get up-to-date values for bounding box.
9  * Bounding box values are stored in several locations and locations can vary with DCN revision.
10  * This component provides an interface to get DCN-specific bounding box values.
11  */
12 
get_default_soc_bb(struct dml2_soc_bb * soc_bb)13 static void get_default_soc_bb(struct dml2_soc_bb *soc_bb)
14 {
15 	memcpy(soc_bb, &dml2_socbb_dcn401, sizeof(struct dml2_soc_bb));
16 	memcpy(&soc_bb->qos_parameters, &dml_dcn4_variant_a_soc_qos_params, sizeof(struct dml2_soc_qos_parameters));
17 }
18 
19 /*
20  * DC clock table is obtained from SMU during runtime.
21  * SMU stands for System Management Unit. It is a power management processor.
22  * It owns the initialization of dc's clock table and programming of clock values
23  * based on dc's requests.
24  * Our clock values in base soc bb is a dummy placeholder. The real clock values
25  * are retrieved from SMU firmware to dc clock table at runtime.
26  * This function overrides our dummy placeholder values with real values in dc
27  * clock table.
28  */
dcn401_convert_dc_clock_table_to_soc_bb_clock_table(struct dml2_soc_state_table * dml_clk_table,const struct clk_bw_params * dc_bw_params,bool use_clock_dc_limits)29 static void dcn401_convert_dc_clock_table_to_soc_bb_clock_table(
30 		struct dml2_soc_state_table *dml_clk_table,
31 		const struct clk_bw_params *dc_bw_params,
32 		bool use_clock_dc_limits)
33 {
34 	int i;
35 	const struct clk_limit_table *dc_clk_table;
36 
37 	if (dc_bw_params == NULL)
38 		/* skip if bw params could not be obtained from smu */
39 		return;
40 
41 	dc_clk_table = &dc_bw_params->clk_table;
42 
43 	/* dcfclk */
44 	if (dc_clk_table->num_entries_per_clk.num_dcfclk_levels) {
45 		dml_clk_table->dcfclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dcfclk_levels;
46 		for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
47 			if (i < dml_clk_table->dcfclk.num_clk_values) {
48 				if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.dcfclk_mhz &&
49 						dc_clk_table->entries[i].dcfclk_mhz > dc_bw_params->dc_mode_limit.dcfclk_mhz) {
50 					if (i == 0 || dc_clk_table->entries[i-1].dcfclk_mhz < dc_bw_params->dc_mode_limit.dcfclk_mhz) {
51 						dml_clk_table->dcfclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.dcfclk_mhz * 1000;
52 						dml_clk_table->dcfclk.num_clk_values = i + 1;
53 					} else {
54 						dml_clk_table->dcfclk.clk_values_khz[i] = 0;
55 						dml_clk_table->dcfclk.num_clk_values = i;
56 					}
57 				} else {
58 					dml_clk_table->dcfclk.clk_values_khz[i] = dc_clk_table->entries[i].dcfclk_mhz * 1000;
59 				}
60 			} else {
61 				dml_clk_table->dcfclk.clk_values_khz[i] = 0;
62 			}
63 		}
64 	}
65 
66 	/* fclk */
67 	if (dc_clk_table->num_entries_per_clk.num_fclk_levels) {
68 		dml_clk_table->fclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_fclk_levels;
69 		for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
70 			if (i < dml_clk_table->fclk.num_clk_values) {
71 				if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.fclk_mhz &&
72 						dc_clk_table->entries[i].fclk_mhz > dc_bw_params->dc_mode_limit.fclk_mhz) {
73 					if (i == 0 || dc_clk_table->entries[i-1].fclk_mhz < dc_bw_params->dc_mode_limit.fclk_mhz) {
74 						dml_clk_table->fclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.fclk_mhz * 1000;
75 						dml_clk_table->fclk.num_clk_values = i + 1;
76 					} else {
77 						dml_clk_table->fclk.clk_values_khz[i] = 0;
78 						dml_clk_table->fclk.num_clk_values = i;
79 					}
80 				} else {
81 					dml_clk_table->fclk.clk_values_khz[i] = dc_clk_table->entries[i].fclk_mhz * 1000;
82 				}
83 			} else {
84 				dml_clk_table->fclk.clk_values_khz[i] = 0;
85 			}
86 		}
87 	}
88 
89 	/* uclk */
90 	if (dc_clk_table->num_entries_per_clk.num_memclk_levels) {
91 		dml_clk_table->uclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_memclk_levels;
92 		for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
93 			if (i < dml_clk_table->uclk.num_clk_values) {
94 				if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.memclk_mhz &&
95 						dc_clk_table->entries[i].memclk_mhz > dc_bw_params->dc_mode_limit.memclk_mhz) {
96 					if (i == 0 || dc_clk_table->entries[i-1].memclk_mhz < dc_bw_params->dc_mode_limit.memclk_mhz) {
97 						dml_clk_table->uclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.memclk_mhz * 1000;
98 						dml_clk_table->uclk.num_clk_values = i + 1;
99 					} else {
100 						dml_clk_table->uclk.clk_values_khz[i] = 0;
101 						dml_clk_table->uclk.num_clk_values = i;
102 					}
103 				} else {
104 					dml_clk_table->uclk.clk_values_khz[i] = dc_clk_table->entries[i].memclk_mhz * 1000;
105 				}
106 			} else {
107 				dml_clk_table->uclk.clk_values_khz[i] = 0;
108 			}
109 		}
110 	}
111 
112 	/* dispclk */
113 	if (dc_clk_table->num_entries_per_clk.num_dispclk_levels) {
114 		dml_clk_table->dispclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dispclk_levels;
115 		for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
116 			if (i < dml_clk_table->dispclk.num_clk_values) {
117 				if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.dispclk_mhz &&
118 						dc_clk_table->entries[i].dispclk_mhz > dc_bw_params->dc_mode_limit.dispclk_mhz) {
119 					if (i == 0 || dc_clk_table->entries[i-1].dispclk_mhz < dc_bw_params->dc_mode_limit.dispclk_mhz) {
120 						dml_clk_table->dispclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.dispclk_mhz * 1000;
121 						dml_clk_table->dispclk.num_clk_values = i + 1;
122 					} else {
123 						dml_clk_table->dispclk.clk_values_khz[i] = 0;
124 						dml_clk_table->dispclk.num_clk_values = i;
125 					}
126 				} else {
127 					dml_clk_table->dispclk.clk_values_khz[i] = dc_clk_table->entries[i].dispclk_mhz * 1000;
128 				}
129 			} else {
130 				dml_clk_table->dispclk.clk_values_khz[i] = 0;
131 			}
132 		}
133 	}
134 
135 	/* dppclk */
136 	if (dc_clk_table->num_entries_per_clk.num_dppclk_levels) {
137 		dml_clk_table->dppclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dppclk_levels;
138 		for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
139 			if (i < dml_clk_table->dppclk.num_clk_values) {
140 				if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.dppclk_mhz &&
141 						dc_clk_table->entries[i].dppclk_mhz > dc_bw_params->dc_mode_limit.dppclk_mhz) {
142 					if (i == 0 || dc_clk_table->entries[i-1].dppclk_mhz < dc_bw_params->dc_mode_limit.dppclk_mhz) {
143 						dml_clk_table->dppclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.dppclk_mhz * 1000;
144 						dml_clk_table->dppclk.num_clk_values = i + 1;
145 					} else {
146 						dml_clk_table->dppclk.clk_values_khz[i] = 0;
147 						dml_clk_table->dppclk.num_clk_values = i;
148 					}
149 				} else {
150 					dml_clk_table->dppclk.clk_values_khz[i] = dc_clk_table->entries[i].dppclk_mhz * 1000;
151 				}
152 			} else {
153 				dml_clk_table->dppclk.clk_values_khz[i] = 0;
154 			}
155 		}
156 	}
157 
158 	/* dtbclk */
159 	if (dc_clk_table->num_entries_per_clk.num_dtbclk_levels) {
160 		dml_clk_table->dtbclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dtbclk_levels;
161 		for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
162 			if (i < dml_clk_table->dtbclk.num_clk_values) {
163 				if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.dtbclk_mhz &&
164 						dc_clk_table->entries[i].dtbclk_mhz > dc_bw_params->dc_mode_limit.dtbclk_mhz) {
165 					if (i == 0 || dc_clk_table->entries[i-1].dtbclk_mhz < dc_bw_params->dc_mode_limit.dtbclk_mhz) {
166 						dml_clk_table->dtbclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.dtbclk_mhz * 1000;
167 						dml_clk_table->dtbclk.num_clk_values = i + 1;
168 					} else {
169 						dml_clk_table->dtbclk.clk_values_khz[i] = 0;
170 						dml_clk_table->dtbclk.num_clk_values = i;
171 					}
172 				} else {
173 					dml_clk_table->dtbclk.clk_values_khz[i] = dc_clk_table->entries[i].dtbclk_mhz * 1000;
174 				}
175 			} else {
176 				dml_clk_table->dtbclk.clk_values_khz[i] = 0;
177 			}
178 		}
179 	}
180 
181 	/* socclk */
182 	if (dc_clk_table->num_entries_per_clk.num_socclk_levels) {
183 		dml_clk_table->socclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_socclk_levels;
184 		for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
185 			if (i < dml_clk_table->socclk.num_clk_values) {
186 				if (use_clock_dc_limits && dc_bw_params->dc_mode_limit.socclk_mhz &&
187 						dc_clk_table->entries[i].socclk_mhz > dc_bw_params->dc_mode_limit.socclk_mhz) {
188 					if (i == 0 || dc_clk_table->entries[i-1].socclk_mhz < dc_bw_params->dc_mode_limit.socclk_mhz) {
189 						dml_clk_table->socclk.clk_values_khz[i] = dc_bw_params->dc_mode_limit.socclk_mhz * 1000;
190 						dml_clk_table->socclk.num_clk_values = i + 1;
191 					} else {
192 						dml_clk_table->socclk.clk_values_khz[i] = 0;
193 						dml_clk_table->socclk.num_clk_values = i;
194 					}
195 				} else {
196 					dml_clk_table->socclk.clk_values_khz[i] = dc_clk_table->entries[i].socclk_mhz * 1000;
197 				}
198 			} else {
199 				dml_clk_table->socclk.clk_values_khz[i] = 0;
200 			}
201 		}
202 	}
203 
204 	/* dram config */
205 	dml_clk_table->dram_config.channel_count = dc_bw_params->num_channels;
206 	dml_clk_table->dram_config.channel_width_bytes = dc_bw_params->dram_channel_width_bytes;
207 }
208 
dcn401_update_soc_bb_with_values_from_clk_mgr(struct dml2_soc_bb * soc_bb,const struct dc * dc,const struct dml2_configuration_options * config)209 void dcn401_update_soc_bb_with_values_from_clk_mgr(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config)
210 {
211 	soc_bb->dprefclk_mhz = dc->clk_mgr->dprefclk_khz / 1000;
212 	soc_bb->dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
213 	soc_bb->mall_allocated_for_dcn_mbytes = dc->caps.mall_size_total / (1024 * 1024);
214 
215 	if (dc->clk_mgr->funcs->is_smu_present &&
216 			dc->clk_mgr->funcs->is_smu_present(dc->clk_mgr)) {
217 		dcn401_convert_dc_clock_table_to_soc_bb_clock_table(&soc_bb->clk_table,
218 			dc->clk_mgr->bw_params,
219 			config->use_clock_dc_limits);
220 	}
221 }
222 
dcn401_update_soc_bb_with_values_from_vbios(struct dml2_soc_bb * soc_bb,const struct dc * dc)223 void dcn401_update_soc_bb_with_values_from_vbios(struct dml2_soc_bb *soc_bb, const struct dc *dc)
224 {
225 	soc_bb->dchub_refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
226 	soc_bb->xtalclk_mhz = dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency / 1000;
227 
228 	/* latencies in vbios are platform specific and should be used if provided */
229 	if (dc->ctx->dc_bios->bb_info.dram_clock_change_latency_100ns)
230 		soc_bb->power_management_parameters.dram_clk_change_blackout_us =
231 				dc->ctx->dc_bios->bb_info.dram_clock_change_latency_100ns / 10.0;
232 
233 	if (dc->ctx->dc_bios->bb_info.dram_sr_enter_exit_latency_100ns)
234 		soc_bb->power_management_parameters.stutter_enter_plus_exit_latency_us =
235 				dc->ctx->dc_bios->bb_info.dram_sr_enter_exit_latency_100ns / 10.0;
236 
237 	if (dc->ctx->dc_bios->bb_info.dram_sr_exit_latency_100ns)
238 		soc_bb->power_management_parameters.stutter_exit_latency_us =
239 			dc->ctx->dc_bios->bb_info.dram_sr_exit_latency_100ns / 10.0;
240 }
241 
dcn401_update_soc_bb_with_values_from_software_policy(struct dml2_soc_bb * soc_bb,const struct dc * dc)242 void dcn401_update_soc_bb_with_values_from_software_policy(struct dml2_soc_bb *soc_bb, const struct dc *dc)
243 {
244 	/* set if the value is provided */
245 	if (dc->bb_overrides.sr_exit_time_ns)
246 		soc_bb->power_management_parameters.stutter_exit_latency_us =
247 				dc->bb_overrides.sr_exit_time_ns / 1000.0;
248 
249 	if (dc->bb_overrides.sr_enter_plus_exit_time_ns)
250 		soc_bb->power_management_parameters.stutter_enter_plus_exit_latency_us =
251 				dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0;
252 
253 	if (dc->bb_overrides.dram_clock_change_latency_ns)
254 		soc_bb->power_management_parameters.dram_clk_change_blackout_us =
255 				dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
256 
257 	if (dc->bb_overrides.fclk_clock_change_latency_ns)
258 		soc_bb->power_management_parameters.fclk_change_blackout_us =
259 				dc->bb_overrides.fclk_clock_change_latency_ns / 1000.0;
260 
261 	//Z8 values not expected nor used on DCN401 but still added for completeness
262 	if (dc->bb_overrides.sr_exit_z8_time_ns)
263 		soc_bb->power_management_parameters.z8_stutter_exit_latency_us =
264 				dc->bb_overrides.sr_exit_z8_time_ns / 1000.0;
265 
266 	if (dc->bb_overrides.sr_enter_plus_exit_z8_time_ns)
267 		soc_bb->power_management_parameters.z8_stutter_enter_plus_exit_latency_us =
268 				dc->bb_overrides.sr_enter_plus_exit_z8_time_ns / 1000.0;
269 }
270 
apply_soc_bb_updates(struct dml2_soc_bb * soc_bb,const struct dc * dc,const struct dml2_configuration_options * config)271 static void apply_soc_bb_updates(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config)
272 {
273 	/* Individual modification can be overwritten even if it was obtained by a previous function.
274 	 * Modifications are acquired in order of priority (lowest to highest).
275 	 */
276 	dc_assert_fp_enabled();
277 
278 	dcn401_update_soc_bb_with_values_from_clk_mgr(soc_bb, dc, config);
279 	dcn401_update_soc_bb_with_values_from_vbios(soc_bb, dc);
280 	dcn401_update_soc_bb_with_values_from_software_policy(soc_bb, dc);
281 }
282 
dcn401_get_soc_bb(struct dml2_soc_bb * soc_bb,const struct dc * dc,const struct dml2_configuration_options * config)283 void dcn401_get_soc_bb(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config)
284 {
285 	//get default soc_bb with static values
286 	get_default_soc_bb(soc_bb);
287 	//update soc_bb values with more accurate values
288 	apply_soc_bb_updates(soc_bb, dc, config);
289 }
290 
dcn401_get_ip_caps(struct dml2_ip_capabilities * ip_caps)291 static void dcn401_get_ip_caps(struct dml2_ip_capabilities *ip_caps)
292 {
293 	*ip_caps = dml2_dcn401_max_ip_caps;
294 }
295 
296 static struct soc_and_ip_translator_funcs dcn401_translator_funcs = {
297 	.get_soc_bb = dcn401_get_soc_bb,
298 	.get_ip_caps = dcn401_get_ip_caps,
299 };
300 
dcn401_construct_soc_and_ip_translator(struct soc_and_ip_translator * soc_and_ip_translator)301 void dcn401_construct_soc_and_ip_translator(struct soc_and_ip_translator *soc_and_ip_translator)
302 {
303 	soc_and_ip_translator->translator_funcs = &dcn401_translator_funcs;
304 }
305