Commit | Line | Data |
---|---|---|
6fba5906 CG |
1 | /* |
2 | * Copyright 2019 Advanced Micro Devices, Inc. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | * OTHER DEALINGS IN THE SOFTWARE. | |
21 | * | |
22 | */ | |
23 | ||
24 | #include "pp_debug.h" | |
25 | #include <linux/firmware.h> | |
26 | #include "amdgpu.h" | |
27 | #include "amdgpu_smu.h" | |
28 | #include "atomfirmware.h" | |
29 | #include "amdgpu_atomfirmware.h" | |
30 | #include "smu_v11_0.h" | |
31 | #include "smu11_driver_if_arcturus.h" | |
32 | #include "soc15_common.h" | |
33 | #include "atom.h" | |
34 | #include "power_state.h" | |
35 | #include "arcturus_ppt.h" | |
a94235af | 36 | #include "smu_v11_0_pptable.h" |
6fba5906 CG |
37 | #include "arcturus_ppsmc.h" |
38 | #include "nbio/nbio_7_4_sh_mask.h" | |
39 | ||
a94235af EQ |
40 | #define CTF_OFFSET_EDGE 5 |
41 | #define CTF_OFFSET_HOTSPOT 5 | |
42 | #define CTF_OFFSET_HBM 5 | |
43 | ||
6fba5906 | 44 | #define MSG_MAP(msg, index) \ |
7e01a2ec | 45 | [SMU_MSG_##msg] = {1, (index)} |
55bf7e62 EQ |
46 | #define ARCTURUS_FEA_MAP(smu_feature, arcturus_feature) \ |
47 | [smu_feature] = {1, (arcturus_feature)} | |
6fba5906 | 48 | |
a94235af EQ |
49 | #define SMU_FEATURES_LOW_MASK 0x00000000FFFFFFFF |
50 | #define SMU_FEATURES_LOW_SHIFT 0 | |
51 | #define SMU_FEATURES_HIGH_MASK 0xFFFFFFFF00000000 | |
52 | #define SMU_FEATURES_HIGH_SHIFT 32 | |
53 | ||
3f513bae CG |
54 | #define SMC_DPM_FEATURE ( \ |
55 | FEATURE_DPM_PREFETCHER_MASK | \ | |
56 | FEATURE_DPM_GFXCLK_MASK | \ | |
57 | FEATURE_DPM_UCLK_MASK | \ | |
58 | FEATURE_DPM_SOCCLK_MASK | \ | |
59 | FEATURE_DPM_MP0CLK_MASK | \ | |
60 | FEATURE_DPM_FCLK_MASK | \ | |
61 | FEATURE_DPM_XGMI_MASK) | |
62 | ||
1f23cadb EQ |
63 | /* possible frequency drift (1Mhz) */ |
64 | #define EPSILON 1 | |
65 | ||
7e01a2ec | 66 | static struct smu_11_0_cmn2aisc_mapping arcturus_message_map[SMU_MSG_MAX_COUNT] = { |
6fba5906 CG |
67 | MSG_MAP(TestMessage, PPSMC_MSG_TestMessage), |
68 | MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion), | |
69 | MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion), | |
70 | MSG_MAP(SetAllowedFeaturesMaskLow, PPSMC_MSG_SetAllowedFeaturesMaskLow), | |
71 | MSG_MAP(SetAllowedFeaturesMaskHigh, PPSMC_MSG_SetAllowedFeaturesMaskHigh), | |
72 | MSG_MAP(EnableAllSmuFeatures, PPSMC_MSG_EnableAllSmuFeatures), | |
73 | MSG_MAP(DisableAllSmuFeatures, PPSMC_MSG_DisableAllSmuFeatures), | |
74 | MSG_MAP(EnableSmuFeaturesLow, PPSMC_MSG_EnableSmuFeaturesLow), | |
75 | MSG_MAP(EnableSmuFeaturesHigh, PPSMC_MSG_EnableSmuFeaturesHigh), | |
76 | MSG_MAP(DisableSmuFeaturesLow, PPSMC_MSG_DisableSmuFeaturesLow), | |
77 | MSG_MAP(DisableSmuFeaturesHigh, PPSMC_MSG_DisableSmuFeaturesHigh), | |
78 | MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetEnabledSmuFeaturesLow), | |
79 | MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetEnabledSmuFeaturesHigh), | |
80 | MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh), | |
81 | MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow), | |
82 | MSG_MAP(SetToolsDramAddrHigh, PPSMC_MSG_SetToolsDramAddrHigh), | |
83 | MSG_MAP(SetToolsDramAddrLow, PPSMC_MSG_SetToolsDramAddrLow), | |
84 | MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram), | |
85 | MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu), | |
86 | MSG_MAP(UseDefaultPPTable, PPSMC_MSG_UseDefaultPPTable), | |
87 | MSG_MAP(UseBackupPPTable, PPSMC_MSG_UseBackupPPTable), | |
88 | MSG_MAP(SetSystemVirtualDramAddrHigh, PPSMC_MSG_SetSystemVirtualDramAddrHigh), | |
89 | MSG_MAP(SetSystemVirtualDramAddrLow, PPSMC_MSG_SetSystemVirtualDramAddrLow), | |
90 | MSG_MAP(EnterBaco, PPSMC_MSG_EnterBaco), | |
91 | MSG_MAP(ExitBaco, PPSMC_MSG_ExitBaco), | |
92 | MSG_MAP(ArmD3, PPSMC_MSG_ArmD3), | |
93 | MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq), | |
94 | MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq), | |
95 | MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq), | |
96 | MSG_MAP(SetHardMaxByFreq, PPSMC_MSG_SetHardMaxByFreq), | |
97 | MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq), | |
98 | MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq), | |
99 | MSG_MAP(GetDpmFreqByIndex, PPSMC_MSG_GetDpmFreqByIndex), | |
100 | MSG_MAP(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask), | |
101 | MSG_MAP(SetDfSwitchType, PPSMC_MSG_SetDfSwitchType), | |
102 | MSG_MAP(GetVoltageByDpm, PPSMC_MSG_GetVoltageByDpm), | |
103 | MSG_MAP(GetVoltageByDpmOverdrive, PPSMC_MSG_GetVoltageByDpmOverdrive), | |
104 | MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit), | |
105 | MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit), | |
106 | MSG_MAP(PowerUpVcn0, PPSMC_MSG_PowerUpVcn0), | |
a94235af | 107 | MSG_MAP(PowerDownVcn0, PPSMC_MSG_PowerDownVcn0), |
6fba5906 CG |
108 | MSG_MAP(PowerUpVcn1, PPSMC_MSG_PowerUpVcn1), |
109 | MSG_MAP(PowerDownVcn1, PPSMC_MSG_PowerDownVcn1), | |
110 | MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload), | |
111 | MSG_MAP(PrepareMp1ForReset, PPSMC_MSG_PrepareMp1ForReset), | |
112 | MSG_MAP(PrepareMp1ForShutdown, PPSMC_MSG_PrepareMp1ForShutdown), | |
113 | MSG_MAP(SoftReset, PPSMC_MSG_SoftReset), | |
114 | MSG_MAP(RunAfllBtc, PPSMC_MSG_RunAfllBtc), | |
115 | MSG_MAP(RunGfxDcBtc, PPSMC_MSG_RunGfxDcBtc), | |
116 | MSG_MAP(RunSocDcBtc, PPSMC_MSG_RunSocDcBtc), | |
117 | MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh), | |
118 | MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow), | |
119 | MSG_MAP(DramLogSetDramSize, PPSMC_MSG_DramLogSetDramSize), | |
120 | MSG_MAP(GetDebugData, PPSMC_MSG_GetDebugData), | |
121 | MSG_MAP(WaflTest, PPSMC_MSG_WaflTest), | |
122 | MSG_MAP(SetXgmiMode, PPSMC_MSG_SetXgmiMode), | |
123 | MSG_MAP(SetMemoryChannelEnable, PPSMC_MSG_SetMemoryChannelEnable), | |
124 | }; | |
125 | ||
a94235af EQ |
126 | static struct smu_11_0_cmn2aisc_mapping arcturus_clk_map[SMU_CLK_COUNT] = { |
127 | CLK_MAP(GFXCLK, PPCLK_GFXCLK), | |
128 | CLK_MAP(SCLK, PPCLK_GFXCLK), | |
129 | CLK_MAP(SOCCLK, PPCLK_SOCCLK), | |
130 | CLK_MAP(FCLK, PPCLK_FCLK), | |
131 | CLK_MAP(UCLK, PPCLK_UCLK), | |
132 | CLK_MAP(MCLK, PPCLK_UCLK), | |
133 | CLK_MAP(DCLK, PPCLK_DCLK), | |
134 | CLK_MAP(VCLK, PPCLK_VCLK), | |
135 | }; | |
136 | ||
137 | static struct smu_11_0_cmn2aisc_mapping arcturus_feature_mask_map[SMU_FEATURE_COUNT] = { | |
138 | FEA_MAP(DPM_PREFETCHER), | |
139 | FEA_MAP(DPM_GFXCLK), | |
140 | FEA_MAP(DPM_UCLK), | |
141 | FEA_MAP(DPM_SOCCLK), | |
55bf7e62 | 142 | FEA_MAP(DPM_FCLK), |
a94235af EQ |
143 | FEA_MAP(DPM_MP0CLK), |
144 | FEA_MAP(DS_GFXCLK), | |
145 | FEA_MAP(DS_SOCCLK), | |
146 | FEA_MAP(DS_LCLK), | |
55bf7e62 | 147 | FEA_MAP(DS_FCLK), |
a94235af EQ |
148 | FEA_MAP(DS_UCLK), |
149 | FEA_MAP(GFX_ULV), | |
55bf7e62 | 150 | ARCTURUS_FEA_MAP(SMU_FEATURE_VCN_PG_BIT, FEATURE_DPM_VCN_BIT), |
a94235af EQ |
151 | FEA_MAP(RSMU_SMN_CG), |
152 | FEA_MAP(PPT), | |
153 | FEA_MAP(TDC), | |
154 | FEA_MAP(APCC_PLUS), | |
155 | FEA_MAP(VR0HOT), | |
156 | FEA_MAP(VR1HOT), | |
157 | FEA_MAP(FW_CTF), | |
158 | FEA_MAP(FAN_CONTROL), | |
159 | FEA_MAP(THERMAL), | |
160 | FEA_MAP(OUT_OF_BAND_MONITOR), | |
161 | FEA_MAP(TEMP_DEPENDENT_VMIN), | |
162 | }; | |
163 | ||
164 | static struct smu_11_0_cmn2aisc_mapping arcturus_table_map[SMU_TABLE_COUNT] = { | |
165 | TAB_MAP(PPTABLE), | |
166 | TAB_MAP(AVFS), | |
167 | TAB_MAP(AVFS_PSM_DEBUG), | |
168 | TAB_MAP(AVFS_FUSE_OVERRIDE), | |
169 | TAB_MAP(PMSTATUSLOG), | |
170 | TAB_MAP(SMU_METRICS), | |
171 | TAB_MAP(DRIVER_SMU_CONFIG), | |
172 | TAB_MAP(OVERDRIVE), | |
173 | }; | |
174 | ||
175 | static struct smu_11_0_cmn2aisc_mapping arcturus_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { | |
176 | PWR_MAP(AC), | |
177 | PWR_MAP(DC), | |
178 | }; | |
179 | ||
180 | static struct smu_11_0_cmn2aisc_mapping arcturus_workload_map[PP_SMC_POWER_PROFILE_COUNT] = { | |
181 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT, WORKLOAD_PPLIB_DEFAULT_BIT), | |
182 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING, WORKLOAD_PPLIB_POWER_SAVING_BIT), | |
183 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO, WORKLOAD_PPLIB_VIDEO_BIT), | |
184 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, WORKLOAD_PPLIB_CUSTOM_BIT), | |
185 | WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, WORKLOAD_PPLIB_CUSTOM_BIT), | |
186 | }; | |
187 | ||
6fba5906 CG |
188 | static int arcturus_get_smu_msg_index(struct smu_context *smc, uint32_t index) |
189 | { | |
7e01a2ec | 190 | struct smu_11_0_cmn2aisc_mapping mapping; |
6fba5906 CG |
191 | |
192 | if (index >= SMU_MSG_MAX_COUNT) | |
193 | return -EINVAL; | |
194 | ||
7e01a2ec | 195 | mapping = arcturus_message_map[index]; |
790ef68a | 196 | if (!(mapping.valid_mapping)) |
6fba5906 CG |
197 | return -EINVAL; |
198 | ||
7e01a2ec | 199 | return mapping.map_to; |
6fba5906 CG |
200 | } |
201 | ||
a94235af EQ |
202 | static int arcturus_get_smu_clk_index(struct smu_context *smc, uint32_t index) |
203 | { | |
204 | struct smu_11_0_cmn2aisc_mapping mapping; | |
205 | ||
206 | if (index >= SMU_CLK_COUNT) | |
207 | return -EINVAL; | |
208 | ||
209 | mapping = arcturus_clk_map[index]; | |
210 | if (!(mapping.valid_mapping)) { | |
211 | pr_warn("Unsupported SMU clk: %d\n", index); | |
212 | return -EINVAL; | |
213 | } | |
214 | ||
215 | return mapping.map_to; | |
216 | } | |
217 | ||
218 | static int arcturus_get_smu_feature_index(struct smu_context *smc, uint32_t index) | |
219 | { | |
220 | struct smu_11_0_cmn2aisc_mapping mapping; | |
221 | ||
222 | if (index >= SMU_FEATURE_COUNT) | |
223 | return -EINVAL; | |
224 | ||
225 | mapping = arcturus_feature_mask_map[index]; | |
226 | if (!(mapping.valid_mapping)) { | |
a94235af EQ |
227 | return -EINVAL; |
228 | } | |
229 | ||
230 | return mapping.map_to; | |
231 | } | |
232 | ||
233 | static int arcturus_get_smu_table_index(struct smu_context *smc, uint32_t index) | |
234 | { | |
235 | struct smu_11_0_cmn2aisc_mapping mapping; | |
236 | ||
237 | if (index >= SMU_TABLE_COUNT) | |
238 | return -EINVAL; | |
239 | ||
240 | mapping = arcturus_table_map[index]; | |
241 | if (!(mapping.valid_mapping)) { | |
242 | pr_warn("Unsupported SMU table: %d\n", index); | |
243 | return -EINVAL; | |
244 | } | |
245 | ||
246 | return mapping.map_to; | |
247 | } | |
248 | ||
249 | static int arcturus_get_pwr_src_index(struct smu_context *smc, uint32_t index) | |
250 | { | |
251 | struct smu_11_0_cmn2aisc_mapping mapping; | |
252 | ||
253 | if (index >= SMU_POWER_SOURCE_COUNT) | |
254 | return -EINVAL; | |
255 | ||
256 | mapping = arcturus_pwr_src_map[index]; | |
257 | if (!(mapping.valid_mapping)) { | |
258 | pr_warn("Unsupported SMU power source: %d\n", index); | |
259 | return -EINVAL; | |
260 | } | |
261 | ||
262 | return mapping.map_to; | |
263 | } | |
264 | ||
265 | ||
266 | static int arcturus_get_workload_type(struct smu_context *smu, enum PP_SMC_POWER_PROFILE profile) | |
267 | { | |
268 | struct smu_11_0_cmn2aisc_mapping mapping; | |
269 | ||
270 | if (profile > PP_SMC_POWER_PROFILE_CUSTOM) | |
271 | return -EINVAL; | |
272 | ||
273 | mapping = arcturus_workload_map[profile]; | |
274 | if (!(mapping.valid_mapping)) { | |
275 | pr_warn("Unsupported SMU power source: %d\n", profile); | |
276 | return -EINVAL; | |
277 | } | |
278 | ||
279 | return mapping.map_to; | |
280 | } | |
281 | ||
282 | static int arcturus_tables_init(struct smu_context *smu, struct smu_table *tables) | |
283 | { | |
832a7062 EQ |
284 | struct smu_table_context *smu_table = &smu->smu_table; |
285 | ||
a94235af EQ |
286 | SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), |
287 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
288 | ||
289 | SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE, | |
290 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
291 | ||
292 | SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), | |
293 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); | |
294 | ||
832a7062 EQ |
295 | smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); |
296 | if (!smu_table->metrics_table) | |
297 | return -ENOMEM; | |
298 | smu_table->metrics_time = 0; | |
299 | ||
a94235af EQ |
300 | return 0; |
301 | } | |
302 | ||
303 | static int arcturus_allocate_dpm_context(struct smu_context *smu) | |
304 | { | |
305 | struct smu_dpm_context *smu_dpm = &smu->smu_dpm; | |
306 | ||
307 | if (smu_dpm->dpm_context) | |
308 | return -EINVAL; | |
309 | ||
310 | smu_dpm->dpm_context = kzalloc(sizeof(struct arcturus_dpm_table), | |
311 | GFP_KERNEL); | |
312 | if (!smu_dpm->dpm_context) | |
313 | return -ENOMEM; | |
314 | ||
315 | if (smu_dpm->golden_dpm_context) | |
316 | return -EINVAL; | |
317 | ||
318 | smu_dpm->golden_dpm_context = kzalloc(sizeof(struct arcturus_dpm_table), | |
319 | GFP_KERNEL); | |
320 | if (!smu_dpm->golden_dpm_context) | |
321 | return -ENOMEM; | |
322 | ||
323 | smu_dpm->dpm_context_size = sizeof(struct arcturus_dpm_table); | |
324 | ||
325 | smu_dpm->dpm_current_power_state = kzalloc(sizeof(struct smu_power_state), | |
326 | GFP_KERNEL); | |
327 | if (!smu_dpm->dpm_current_power_state) | |
328 | return -ENOMEM; | |
329 | ||
330 | smu_dpm->dpm_request_power_state = kzalloc(sizeof(struct smu_power_state), | |
331 | GFP_KERNEL); | |
332 | if (!smu_dpm->dpm_request_power_state) | |
333 | return -ENOMEM; | |
334 | ||
335 | return 0; | |
336 | } | |
337 | ||
a94235af EQ |
338 | static int |
339 | arcturus_get_allowed_feature_mask(struct smu_context *smu, | |
340 | uint32_t *feature_mask, uint32_t num) | |
341 | { | |
342 | if (num > 2) | |
343 | return -EINVAL; | |
344 | ||
59de58f8 EQ |
345 | /* pptable will handle the features to enable */ |
346 | memset(feature_mask, 0xFF, sizeof(uint32_t) * num); | |
a94235af EQ |
347 | |
348 | return 0; | |
349 | } | |
350 | ||
351 | static int | |
352 | arcturus_set_single_dpm_table(struct smu_context *smu, | |
353 | struct arcturus_single_dpm_table *single_dpm_table, | |
354 | PPCLK_e clk_id) | |
355 | { | |
356 | int ret = 0; | |
357 | uint32_t i, num_of_levels = 0, clk; | |
358 | ||
359 | ret = smu_send_smc_msg_with_param(smu, | |
360 | SMU_MSG_GetDpmFreqByIndex, | |
361 | (clk_id << 16 | 0xFF)); | |
362 | if (ret) { | |
363 | pr_err("[%s] failed to get dpm levels!\n", __func__); | |
364 | return ret; | |
365 | } | |
366 | ||
367 | smu_read_smc_arg(smu, &num_of_levels); | |
368 | if (!num_of_levels) { | |
369 | pr_err("[%s] number of clk levels is invalid!\n", __func__); | |
370 | return -EINVAL; | |
371 | } | |
372 | ||
373 | single_dpm_table->count = num_of_levels; | |
374 | for (i = 0; i < num_of_levels; i++) { | |
375 | ret = smu_send_smc_msg_with_param(smu, | |
376 | SMU_MSG_GetDpmFreqByIndex, | |
377 | (clk_id << 16 | i)); | |
378 | if (ret) { | |
379 | pr_err("[%s] failed to get dpm freq by index!\n", __func__); | |
380 | return ret; | |
381 | } | |
382 | smu_read_smc_arg(smu, &clk); | |
383 | if (!clk) { | |
384 | pr_err("[%s] clk value is invalid!\n", __func__); | |
385 | return -EINVAL; | |
386 | } | |
387 | single_dpm_table->dpm_levels[i].value = clk; | |
388 | single_dpm_table->dpm_levels[i].enabled = true; | |
389 | } | |
390 | return 0; | |
391 | } | |
392 | ||
393 | static void arcturus_init_single_dpm_state(struct arcturus_dpm_state *dpm_state) | |
394 | { | |
395 | dpm_state->soft_min_level = 0x0; | |
396 | dpm_state->soft_max_level = 0xffff; | |
397 | dpm_state->hard_min_level = 0x0; | |
398 | dpm_state->hard_max_level = 0xffff; | |
399 | } | |
400 | ||
401 | static int arcturus_set_default_dpm_table(struct smu_context *smu) | |
402 | { | |
403 | int ret; | |
404 | ||
405 | struct smu_dpm_context *smu_dpm = &smu->smu_dpm; | |
406 | struct arcturus_dpm_table *dpm_table = NULL; | |
407 | struct arcturus_single_dpm_table *single_dpm_table; | |
408 | ||
409 | dpm_table = smu_dpm->dpm_context; | |
410 | ||
411 | /* socclk */ | |
412 | single_dpm_table = &(dpm_table->soc_table); | |
8a856ced | 413 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { |
a94235af EQ |
414 | ret = arcturus_set_single_dpm_table(smu, single_dpm_table, |
415 | PPCLK_SOCCLK); | |
416 | if (ret) { | |
417 | pr_err("[%s] failed to get socclk dpm levels!\n", __func__); | |
418 | return ret; | |
419 | } | |
420 | } else { | |
421 | single_dpm_table->count = 1; | |
422 | single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100; | |
423 | } | |
424 | arcturus_init_single_dpm_state(&(single_dpm_table->dpm_state)); | |
425 | ||
426 | /* gfxclk */ | |
427 | single_dpm_table = &(dpm_table->gfx_table); | |
8a856ced | 428 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { |
a94235af EQ |
429 | ret = arcturus_set_single_dpm_table(smu, single_dpm_table, |
430 | PPCLK_GFXCLK); | |
431 | if (ret) { | |
432 | pr_err("[SetupDefaultDpmTable] failed to get gfxclk dpm levels!"); | |
433 | return ret; | |
434 | } | |
435 | } else { | |
436 | single_dpm_table->count = 1; | |
437 | single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; | |
438 | } | |
439 | arcturus_init_single_dpm_state(&(single_dpm_table->dpm_state)); | |
440 | ||
441 | /* memclk */ | |
442 | single_dpm_table = &(dpm_table->mem_table); | |
8a856ced | 443 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { |
a94235af EQ |
444 | ret = arcturus_set_single_dpm_table(smu, single_dpm_table, |
445 | PPCLK_UCLK); | |
446 | if (ret) { | |
447 | pr_err("[SetupDefaultDpmTable] failed to get memclk dpm levels!"); | |
448 | return ret; | |
449 | } | |
450 | } else { | |
451 | single_dpm_table->count = 1; | |
452 | single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100; | |
453 | } | |
454 | arcturus_init_single_dpm_state(&(single_dpm_table->dpm_state)); | |
455 | ||
456 | /* fclk */ | |
457 | single_dpm_table = &(dpm_table->fclk_table); | |
8a856ced | 458 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) { |
a94235af EQ |
459 | ret = arcturus_set_single_dpm_table(smu, single_dpm_table, |
460 | PPCLK_FCLK); | |
461 | if (ret) { | |
462 | pr_err("[SetupDefaultDpmTable] failed to get fclk dpm levels!"); | |
463 | return ret; | |
464 | } | |
465 | } else { | |
69174eeb EQ |
466 | single_dpm_table->count = 1; |
467 | single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.fclk / 100; | |
a94235af EQ |
468 | } |
469 | arcturus_init_single_dpm_state(&(single_dpm_table->dpm_state)); | |
470 | ||
471 | memcpy(smu_dpm->golden_dpm_context, dpm_table, | |
472 | sizeof(struct arcturus_dpm_table)); | |
473 | ||
474 | return 0; | |
475 | } | |
476 | ||
477 | static int arcturus_check_powerplay_table(struct smu_context *smu) | |
478 | { | |
479 | return 0; | |
480 | } | |
481 | ||
482 | static int arcturus_store_powerplay_table(struct smu_context *smu) | |
483 | { | |
484 | struct smu_11_0_powerplay_table *powerplay_table = NULL; | |
485 | struct smu_table_context *table_context = &smu->smu_table; | |
486 | int ret = 0; | |
487 | ||
488 | if (!table_context->power_play_table) | |
489 | return -EINVAL; | |
490 | ||
491 | powerplay_table = table_context->power_play_table; | |
492 | ||
493 | memcpy(table_context->driver_pptable, &powerplay_table->smc_pptable, | |
494 | sizeof(PPTable_t)); | |
495 | ||
496 | table_context->thermal_controller_type = powerplay_table->thermal_controller_type; | |
497 | ||
498 | return ret; | |
499 | } | |
500 | ||
501 | static int arcturus_append_powerplay_table(struct smu_context *smu) | |
502 | { | |
503 | struct smu_table_context *table_context = &smu->smu_table; | |
504 | PPTable_t *smc_pptable = table_context->driver_pptable; | |
505 | struct atom_smc_dpm_info_v4_6 *smc_dpm_table; | |
506 | int index, ret; | |
507 | ||
508 | index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, | |
509 | smc_dpm_info); | |
510 | ||
511 | ret = smu_get_atom_data_table(smu, index, NULL, NULL, NULL, | |
512 | (uint8_t **)&smc_dpm_table); | |
513 | if (ret) | |
514 | return ret; | |
515 | ||
516 | pr_info("smc_dpm_info table revision(format.content): %d.%d\n", | |
517 | smc_dpm_table->table_header.format_revision, | |
518 | smc_dpm_table->table_header.content_revision); | |
519 | ||
520 | if ((smc_dpm_table->table_header.format_revision == 4) && | |
521 | (smc_dpm_table->table_header.content_revision == 6)) | |
522 | memcpy(&smc_pptable->MaxVoltageStepGfx, | |
523 | &smc_dpm_table->maxvoltagestepgfx, | |
524 | sizeof(*smc_dpm_table) - offsetof(struct atom_smc_dpm_info_v4_6, maxvoltagestepgfx)); | |
525 | ||
526 | return 0; | |
527 | } | |
528 | ||
529 | static int arcturus_run_btc_afll(struct smu_context *smu) | |
530 | { | |
531 | return smu_send_smc_msg(smu, SMU_MSG_RunAfllBtc); | |
532 | } | |
533 | ||
534 | static int arcturus_populate_umd_state_clk(struct smu_context *smu) | |
535 | { | |
536 | struct smu_dpm_context *smu_dpm = &smu->smu_dpm; | |
537 | struct arcturus_dpm_table *dpm_table = NULL; | |
538 | struct arcturus_single_dpm_table *gfx_table = NULL; | |
539 | struct arcturus_single_dpm_table *mem_table = NULL; | |
540 | ||
541 | dpm_table = smu_dpm->dpm_context; | |
542 | gfx_table = &(dpm_table->gfx_table); | |
543 | mem_table = &(dpm_table->mem_table); | |
544 | ||
545 | smu->pstate_sclk = gfx_table->dpm_levels[0].value; | |
546 | smu->pstate_mclk = mem_table->dpm_levels[0].value; | |
547 | ||
548 | if (gfx_table->count > ARCTURUS_UMD_PSTATE_GFXCLK_LEVEL && | |
549 | mem_table->count > ARCTURUS_UMD_PSTATE_MCLK_LEVEL) { | |
550 | smu->pstate_sclk = gfx_table->dpm_levels[ARCTURUS_UMD_PSTATE_GFXCLK_LEVEL].value; | |
551 | smu->pstate_mclk = mem_table->dpm_levels[ARCTURUS_UMD_PSTATE_MCLK_LEVEL].value; | |
552 | } | |
553 | ||
554 | smu->pstate_sclk = smu->pstate_sclk * 100; | |
555 | smu->pstate_mclk = smu->pstate_mclk * 100; | |
556 | ||
557 | return 0; | |
558 | } | |
559 | ||
560 | static int arcturus_get_clk_table(struct smu_context *smu, | |
561 | struct pp_clock_levels_with_latency *clocks, | |
562 | struct arcturus_single_dpm_table *dpm_table) | |
563 | { | |
564 | int i, count; | |
565 | ||
566 | count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count; | |
567 | clocks->num_levels = count; | |
568 | ||
569 | for (i = 0; i < count; i++) { | |
570 | clocks->data[i].clocks_in_khz = | |
571 | dpm_table->dpm_levels[i].value * 1000; | |
572 | clocks->data[i].latency_in_us = 0; | |
573 | } | |
574 | ||
575 | return 0; | |
576 | } | |
577 | ||
1f23cadb EQ |
578 | static int arcturus_freqs_in_same_level(int32_t frequency1, |
579 | int32_t frequency2) | |
580 | { | |
581 | return (abs(frequency1 - frequency2) <= EPSILON); | |
582 | } | |
583 | ||
a94235af EQ |
584 | static int arcturus_print_clk_levels(struct smu_context *smu, |
585 | enum smu_clk_type type, char *buf) | |
586 | { | |
587 | int i, now, size = 0; | |
588 | int ret = 0; | |
589 | struct pp_clock_levels_with_latency clocks; | |
590 | struct arcturus_single_dpm_table *single_dpm_table; | |
591 | struct smu_dpm_context *smu_dpm = &smu->smu_dpm; | |
592 | struct arcturus_dpm_table *dpm_table = NULL; | |
593 | ||
594 | dpm_table = smu_dpm->dpm_context; | |
595 | ||
596 | switch (type) { | |
597 | case SMU_SCLK: | |
598 | ret = smu_get_current_clk_freq(smu, SMU_GFXCLK, &now); | |
599 | if (ret) { | |
600 | pr_err("Attempt to get current gfx clk Failed!"); | |
601 | return ret; | |
602 | } | |
603 | ||
604 | single_dpm_table = &(dpm_table->gfx_table); | |
605 | ret = arcturus_get_clk_table(smu, &clocks, single_dpm_table); | |
606 | if (ret) { | |
607 | pr_err("Attempt to get gfx clk levels Failed!"); | |
608 | return ret; | |
609 | } | |
610 | ||
611 | for (i = 0; i < clocks.num_levels; i++) | |
612 | size += sprintf(buf + size, "%d: %uMhz %s\n", i, | |
613 | clocks.data[i].clocks_in_khz / 1000, | |
1f23cadb EQ |
614 | arcturus_freqs_in_same_level( |
615 | clocks.data[i].clocks_in_khz / 1000, | |
616 | now / 100) ? "*" : ""); | |
a94235af EQ |
617 | break; |
618 | ||
619 | case SMU_MCLK: | |
620 | ret = smu_get_current_clk_freq(smu, SMU_UCLK, &now); | |
621 | if (ret) { | |
622 | pr_err("Attempt to get current mclk Failed!"); | |
623 | return ret; | |
624 | } | |
625 | ||
626 | single_dpm_table = &(dpm_table->mem_table); | |
627 | ret = arcturus_get_clk_table(smu, &clocks, single_dpm_table); | |
628 | if (ret) { | |
629 | pr_err("Attempt to get memory clk levels Failed!"); | |
630 | return ret; | |
631 | } | |
632 | ||
633 | for (i = 0; i < clocks.num_levels; i++) | |
634 | size += sprintf(buf + size, "%d: %uMhz %s\n", | |
635 | i, clocks.data[i].clocks_in_khz / 1000, | |
1f23cadb EQ |
636 | arcturus_freqs_in_same_level( |
637 | clocks.data[i].clocks_in_khz / 1000, | |
638 | now / 100) ? "*" : ""); | |
a94235af EQ |
639 | break; |
640 | ||
641 | case SMU_SOCCLK: | |
642 | ret = smu_get_current_clk_freq(smu, SMU_SOCCLK, &now); | |
643 | if (ret) { | |
644 | pr_err("Attempt to get current socclk Failed!"); | |
645 | return ret; | |
646 | } | |
647 | ||
648 | single_dpm_table = &(dpm_table->soc_table); | |
649 | ret = arcturus_get_clk_table(smu, &clocks, single_dpm_table); | |
650 | if (ret) { | |
651 | pr_err("Attempt to get socclk levels Failed!"); | |
652 | return ret; | |
653 | } | |
654 | ||
655 | for (i = 0; i < clocks.num_levels; i++) | |
656 | size += sprintf(buf + size, "%d: %uMhz %s\n", | |
657 | i, clocks.data[i].clocks_in_khz / 1000, | |
1f23cadb EQ |
658 | arcturus_freqs_in_same_level( |
659 | clocks.data[i].clocks_in_khz / 1000, | |
660 | now / 100) ? "*" : ""); | |
a94235af EQ |
661 | break; |
662 | ||
663 | case SMU_FCLK: | |
664 | ret = smu_get_current_clk_freq(smu, SMU_FCLK, &now); | |
665 | if (ret) { | |
666 | pr_err("Attempt to get current fclk Failed!"); | |
667 | return ret; | |
668 | } | |
669 | ||
670 | single_dpm_table = &(dpm_table->fclk_table); | |
1f23cadb EQ |
671 | ret = arcturus_get_clk_table(smu, &clocks, single_dpm_table); |
672 | if (ret) { | |
673 | pr_err("Attempt to get fclk levels Failed!"); | |
674 | return ret; | |
675 | } | |
676 | ||
a94235af EQ |
677 | for (i = 0; i < single_dpm_table->count; i++) |
678 | size += sprintf(buf + size, "%d: %uMhz %s\n", | |
679 | i, single_dpm_table->dpm_levels[i].value, | |
1f23cadb EQ |
680 | arcturus_freqs_in_same_level( |
681 | clocks.data[i].clocks_in_khz / 1000, | |
682 | now / 100) ? "*" : ""); | |
a94235af EQ |
683 | break; |
684 | ||
685 | default: | |
686 | break; | |
687 | } | |
688 | ||
689 | return size; | |
690 | } | |
691 | ||
692 | static int arcturus_upload_dpm_level(struct smu_context *smu, bool max, | |
60d435b7 | 693 | uint32_t feature_mask) |
a94235af | 694 | { |
a94235af | 695 | struct arcturus_single_dpm_table *single_dpm_table; |
60d435b7 EQ |
696 | struct arcturus_dpm_table *dpm_table = |
697 | smu->smu_dpm.dpm_context; | |
a94235af EQ |
698 | uint32_t freq; |
699 | int ret = 0; | |
700 | ||
60d435b7 | 701 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT) && |
a94235af EQ |
702 | (feature_mask & FEATURE_DPM_GFXCLK_MASK)) { |
703 | single_dpm_table = &(dpm_table->gfx_table); | |
704 | freq = max ? single_dpm_table->dpm_state.soft_max_level : | |
705 | single_dpm_table->dpm_state.soft_min_level; | |
706 | ret = smu_send_smc_msg_with_param(smu, | |
707 | (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq), | |
708 | (PPCLK_GFXCLK << 16) | (freq & 0xffff)); | |
709 | if (ret) { | |
710 | pr_err("Failed to set soft %s gfxclk !\n", | |
711 | max ? "max" : "min"); | |
712 | return ret; | |
713 | } | |
714 | } | |
715 | ||
60d435b7 EQ |
716 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT) && |
717 | (feature_mask & FEATURE_DPM_UCLK_MASK)) { | |
718 | single_dpm_table = &(dpm_table->mem_table); | |
719 | freq = max ? single_dpm_table->dpm_state.soft_max_level : | |
720 | single_dpm_table->dpm_state.soft_min_level; | |
721 | ret = smu_send_smc_msg_with_param(smu, | |
722 | (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq), | |
723 | (PPCLK_UCLK << 16) | (freq & 0xffff)); | |
724 | if (ret) { | |
725 | pr_err("Failed to set soft %s memclk !\n", | |
726 | max ? "max" : "min"); | |
727 | return ret; | |
728 | } | |
729 | } | |
730 | ||
731 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT) && | |
732 | (feature_mask & FEATURE_DPM_SOCCLK_MASK)) { | |
733 | single_dpm_table = &(dpm_table->soc_table); | |
734 | freq = max ? single_dpm_table->dpm_state.soft_max_level : | |
735 | single_dpm_table->dpm_state.soft_min_level; | |
736 | ret = smu_send_smc_msg_with_param(smu, | |
737 | (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq), | |
738 | (PPCLK_SOCCLK << 16) | (freq & 0xffff)); | |
739 | if (ret) { | |
740 | pr_err("Failed to set soft %s socclk !\n", | |
741 | max ? "max" : "min"); | |
742 | return ret; | |
743 | } | |
744 | } | |
745 | ||
a94235af EQ |
746 | return ret; |
747 | } | |
748 | ||
749 | static int arcturus_force_clk_levels(struct smu_context *smu, | |
750 | enum smu_clk_type type, uint32_t mask) | |
751 | { | |
752 | struct arcturus_dpm_table *dpm_table; | |
753 | struct arcturus_single_dpm_table *single_dpm_table; | |
754 | uint32_t soft_min_level, soft_max_level; | |
755 | int ret = 0; | |
756 | ||
757 | mutex_lock(&(smu->mutex)); | |
758 | ||
759 | soft_min_level = mask ? (ffs(mask) - 1) : 0; | |
760 | soft_max_level = mask ? (fls(mask) - 1) : 0; | |
761 | ||
762 | dpm_table = smu->smu_dpm.dpm_context; | |
763 | ||
764 | switch (type) { | |
765 | case SMU_SCLK: | |
766 | single_dpm_table = &(dpm_table->gfx_table); | |
767 | ||
768 | if (soft_max_level >= single_dpm_table->count) { | |
769 | pr_err("Clock level specified %d is over max allowed %d\n", | |
770 | soft_max_level, single_dpm_table->count - 1); | |
771 | ret = -EINVAL; | |
772 | break; | |
773 | } | |
774 | ||
775 | single_dpm_table->dpm_state.soft_min_level = | |
776 | single_dpm_table->dpm_levels[soft_min_level].value; | |
777 | single_dpm_table->dpm_state.soft_max_level = | |
778 | single_dpm_table->dpm_levels[soft_max_level].value; | |
779 | ||
780 | ret = arcturus_upload_dpm_level(smu, false, FEATURE_DPM_GFXCLK_MASK); | |
781 | if (ret) { | |
782 | pr_err("Failed to upload boot level to lowest!\n"); | |
783 | break; | |
784 | } | |
785 | ||
786 | ret = arcturus_upload_dpm_level(smu, true, FEATURE_DPM_GFXCLK_MASK); | |
787 | if (ret) | |
788 | pr_err("Failed to upload dpm max level to highest!\n"); | |
789 | ||
790 | break; | |
791 | ||
792 | case SMU_MCLK: | |
793 | single_dpm_table = &(dpm_table->mem_table); | |
794 | ||
795 | if (soft_max_level >= single_dpm_table->count) { | |
796 | pr_err("Clock level specified %d is over max allowed %d\n", | |
797 | soft_max_level, single_dpm_table->count - 1); | |
798 | ret = -EINVAL; | |
799 | break; | |
800 | } | |
801 | ||
802 | single_dpm_table->dpm_state.soft_min_level = | |
803 | single_dpm_table->dpm_levels[soft_min_level].value; | |
804 | single_dpm_table->dpm_state.soft_max_level = | |
805 | single_dpm_table->dpm_levels[soft_max_level].value; | |
806 | ||
807 | ret = arcturus_upload_dpm_level(smu, false, FEATURE_DPM_UCLK_MASK); | |
808 | if (ret) { | |
809 | pr_err("Failed to upload boot level to lowest!\n"); | |
810 | break; | |
811 | } | |
812 | ||
813 | ret = arcturus_upload_dpm_level(smu, true, FEATURE_DPM_UCLK_MASK); | |
814 | if (ret) | |
815 | pr_err("Failed to upload dpm max level to highest!\n"); | |
816 | ||
817 | break; | |
818 | ||
819 | case SMU_SOCCLK: | |
820 | single_dpm_table = &(dpm_table->soc_table); | |
821 | ||
822 | if (soft_max_level >= single_dpm_table->count) { | |
823 | pr_err("Clock level specified %d is over max allowed %d\n", | |
824 | soft_max_level, single_dpm_table->count - 1); | |
825 | ret = -EINVAL; | |
826 | break; | |
827 | } | |
828 | ||
829 | single_dpm_table->dpm_state.soft_min_level = | |
830 | single_dpm_table->dpm_levels[soft_min_level].value; | |
831 | single_dpm_table->dpm_state.soft_max_level = | |
832 | single_dpm_table->dpm_levels[soft_max_level].value; | |
833 | ||
834 | ret = arcturus_upload_dpm_level(smu, false, FEATURE_DPM_SOCCLK_MASK); | |
835 | if (ret) { | |
836 | pr_err("Failed to upload boot level to lowest!\n"); | |
837 | break; | |
838 | } | |
839 | ||
840 | ret = arcturus_upload_dpm_level(smu, true, FEATURE_DPM_SOCCLK_MASK); | |
841 | if (ret) | |
842 | pr_err("Failed to upload dpm max level to highest!\n"); | |
843 | ||
844 | break; | |
845 | ||
846 | case SMU_FCLK: | |
847 | single_dpm_table = &(dpm_table->fclk_table); | |
848 | ||
849 | if (soft_max_level >= single_dpm_table->count) { | |
850 | pr_err("Clock level specified %d is over max allowed %d\n", | |
851 | soft_max_level, single_dpm_table->count - 1); | |
852 | ret = -EINVAL; | |
853 | break; | |
854 | } | |
855 | ||
856 | single_dpm_table->dpm_state.soft_min_level = | |
857 | single_dpm_table->dpm_levels[soft_min_level].value; | |
858 | single_dpm_table->dpm_state.soft_max_level = | |
859 | single_dpm_table->dpm_levels[soft_max_level].value; | |
860 | ||
861 | ret = arcturus_upload_dpm_level(smu, false, FEATURE_DPM_FCLK_MASK); | |
862 | if (ret) { | |
863 | pr_err("Failed to upload boot level to lowest!\n"); | |
864 | break; | |
865 | } | |
866 | ||
867 | ret = arcturus_upload_dpm_level(smu, true, FEATURE_DPM_FCLK_MASK); | |
868 | if (ret) | |
869 | pr_err("Failed to upload dpm max level to highest!\n"); | |
870 | ||
871 | break; | |
872 | ||
873 | default: | |
874 | break; | |
875 | } | |
876 | ||
877 | mutex_unlock(&(smu->mutex)); | |
878 | return ret; | |
879 | } | |
880 | ||
881 | static const struct smu_temperature_range arcturus_thermal_policy[] = | |
882 | { | |
883 | {-273150, 99000, 99000, -273150, 99000, 99000, -273150, 99000, 99000}, | |
884 | { 120000, 120000, 120000, 120000, 120000, 120000, 120000, 120000, 120000}, | |
885 | }; | |
886 | ||
887 | static int arcturus_get_thermal_temperature_range(struct smu_context *smu, | |
888 | struct smu_temperature_range *range) | |
889 | { | |
890 | ||
891 | PPTable_t *pptable = smu->smu_table.driver_pptable; | |
892 | ||
893 | if (!range) | |
894 | return -EINVAL; | |
895 | ||
896 | memcpy(range, &arcturus_thermal_policy[0], sizeof(struct smu_temperature_range)); | |
897 | ||
898 | range->max = pptable->TedgeLimit * | |
899 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
900 | range->edge_emergency_max = (pptable->TedgeLimit + CTF_OFFSET_EDGE) * | |
901 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
902 | range->hotspot_crit_max = pptable->ThotspotLimit * | |
903 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
904 | range->hotspot_emergency_max = (pptable->ThotspotLimit + CTF_OFFSET_HOTSPOT) * | |
905 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
906 | range->mem_crit_max = pptable->TmemLimit * | |
907 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
908 | range->mem_emergency_max = (pptable->TmemLimit + CTF_OFFSET_HBM)* | |
909 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
910 | ||
911 | ||
912 | return 0; | |
913 | } | |
914 | ||
ba74c8bf EQ |
915 | static int arcturus_get_metrics_table(struct smu_context *smu, |
916 | SmuMetrics_t *metrics_table) | |
917 | { | |
918 | struct smu_table_context *smu_table= &smu->smu_table; | |
919 | int ret = 0; | |
920 | ||
921 | if (!smu_table->metrics_time || | |
922 | time_after(jiffies, smu_table->metrics_time + HZ / 1000)) { | |
923 | ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, | |
924 | (void *)smu_table->metrics_table, false); | |
925 | if (ret) { | |
926 | pr_info("Failed to export SMU metrics table!\n"); | |
927 | return ret; | |
928 | } | |
929 | smu_table->metrics_time = jiffies; | |
930 | } | |
931 | ||
932 | memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t)); | |
933 | ||
934 | return ret; | |
935 | } | |
936 | ||
937 | static int arcturus_get_current_activity_percent(struct smu_context *smu, | |
938 | enum amd_pp_sensors sensor, | |
939 | uint32_t *value) | |
940 | { | |
941 | SmuMetrics_t metrics; | |
942 | int ret = 0; | |
943 | ||
944 | if (!value) | |
945 | return -EINVAL; | |
946 | ||
947 | ret = arcturus_get_metrics_table(smu, &metrics); | |
948 | if (ret) | |
949 | return ret; | |
950 | ||
951 | switch (sensor) { | |
952 | case AMDGPU_PP_SENSOR_GPU_LOAD: | |
953 | *value = metrics.AverageGfxActivity; | |
954 | break; | |
955 | case AMDGPU_PP_SENSOR_MEM_LOAD: | |
956 | *value = metrics.AverageUclkActivity; | |
957 | break; | |
958 | default: | |
959 | pr_err("Invalid sensor for retrieving clock activity\n"); | |
960 | return -EINVAL; | |
961 | } | |
962 | ||
963 | return 0; | |
964 | } | |
965 | ||
966 | static int arcturus_get_gpu_power(struct smu_context *smu, uint32_t *value) | |
967 | { | |
968 | SmuMetrics_t metrics; | |
969 | int ret = 0; | |
970 | ||
971 | if (!value) | |
972 | return -EINVAL; | |
973 | ||
974 | ret = arcturus_get_metrics_table(smu, &metrics); | |
975 | if (ret) | |
976 | return ret; | |
977 | ||
978 | *value = metrics.AverageSocketPower << 8; | |
979 | ||
980 | return 0; | |
981 | } | |
982 | ||
983 | static int arcturus_thermal_get_temperature(struct smu_context *smu, | |
984 | enum amd_pp_sensors sensor, | |
985 | uint32_t *value) | |
986 | { | |
987 | SmuMetrics_t metrics; | |
988 | int ret = 0; | |
989 | ||
990 | if (!value) | |
991 | return -EINVAL; | |
992 | ||
993 | ret = arcturus_get_metrics_table(smu, &metrics); | |
994 | if (ret) | |
995 | return ret; | |
996 | ||
997 | switch (sensor) { | |
998 | case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: | |
999 | *value = metrics.TemperatureHotspot * | |
1000 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
1001 | break; | |
1002 | case AMDGPU_PP_SENSOR_EDGE_TEMP: | |
1003 | *value = metrics.TemperatureEdge * | |
1004 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
1005 | break; | |
1006 | case AMDGPU_PP_SENSOR_MEM_TEMP: | |
1007 | *value = metrics.TemperatureHBM * | |
1008 | SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
1009 | break; | |
1010 | default: | |
1011 | pr_err("Invalid sensor for retrieving temp\n"); | |
1012 | return -EINVAL; | |
1013 | } | |
1014 | ||
1015 | return 0; | |
1016 | } | |
1017 | ||
1018 | static int arcturus_read_sensor(struct smu_context *smu, | |
1019 | enum amd_pp_sensors sensor, | |
1020 | void *data, uint32_t *size) | |
1021 | { | |
1022 | struct smu_table_context *table_context = &smu->smu_table; | |
1023 | PPTable_t *pptable = table_context->driver_pptable; | |
1024 | int ret = 0; | |
1025 | ||
97442140 KW |
1026 | if (!data || !size) |
1027 | return -EINVAL; | |
1028 | ||
ba74c8bf EQ |
1029 | switch (sensor) { |
1030 | case AMDGPU_PP_SENSOR_MAX_FAN_RPM: | |
1031 | *(uint32_t *)data = pptable->FanMaximumRpm; | |
1032 | *size = 4; | |
1033 | break; | |
1034 | case AMDGPU_PP_SENSOR_MEM_LOAD: | |
1035 | case AMDGPU_PP_SENSOR_GPU_LOAD: | |
1036 | ret = arcturus_get_current_activity_percent(smu, | |
1037 | sensor, | |
1038 | (uint32_t *)data); | |
1039 | *size = 4; | |
1040 | break; | |
1041 | case AMDGPU_PP_SENSOR_GPU_POWER: | |
1042 | ret = arcturus_get_gpu_power(smu, (uint32_t *)data); | |
1043 | *size = 4; | |
1044 | break; | |
1045 | case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: | |
1046 | case AMDGPU_PP_SENSOR_EDGE_TEMP: | |
1047 | case AMDGPU_PP_SENSOR_MEM_TEMP: | |
1048 | ret = arcturus_thermal_get_temperature(smu, sensor, | |
1049 | (uint32_t *)data); | |
1050 | *size = 4; | |
1051 | break; | |
1052 | default: | |
97442140 | 1053 | ret = smu_smc_read_sensor(smu, sensor, data, size); |
ba74c8bf EQ |
1054 | } |
1055 | ||
1056 | return ret; | |
1057 | } | |
1058 | ||
d427cf8f EQ |
1059 | static int arcturus_get_fan_speed_rpm(struct smu_context *smu, |
1060 | uint32_t *speed) | |
1061 | { | |
1062 | SmuMetrics_t metrics; | |
1063 | int ret = 0; | |
1064 | ||
1065 | if (!speed) | |
1066 | return -EINVAL; | |
1067 | ||
1068 | ret = arcturus_get_metrics_table(smu, &metrics); | |
1069 | if (ret) | |
1070 | return ret; | |
1071 | ||
1072 | *speed = metrics.CurrFanSpeed; | |
1073 | ||
1074 | return ret; | |
1075 | } | |
1076 | ||
1077 | static int arcturus_get_fan_speed_percent(struct smu_context *smu, | |
1078 | uint32_t *speed) | |
1079 | { | |
1080 | PPTable_t *pptable = smu->smu_table.driver_pptable; | |
1081 | uint32_t percent, current_rpm; | |
1082 | int ret = 0; | |
1083 | ||
1084 | if (!speed) | |
1085 | return -EINVAL; | |
1086 | ||
1087 | ret = arcturus_get_fan_speed_rpm(smu, ¤t_rpm); | |
1088 | if (ret) | |
1089 | return ret; | |
1090 | ||
1091 | percent = current_rpm * 100 / pptable->FanMaximumRpm; | |
1092 | *speed = percent > 100 ? 100 : percent; | |
1093 | ||
1094 | return ret; | |
1095 | } | |
1096 | ||
631807f0 EQ |
1097 | static int arcturus_get_current_clk_freq_by_table(struct smu_context *smu, |
1098 | enum smu_clk_type clk_type, | |
1099 | uint32_t *value) | |
1100 | { | |
1101 | static SmuMetrics_t metrics; | |
1102 | int ret = 0, clk_id = 0; | |
1103 | ||
1104 | if (!value) | |
1105 | return -EINVAL; | |
1106 | ||
1107 | clk_id = smu_clk_get_index(smu, clk_type); | |
1108 | if (clk_id < 0) | |
1109 | return -EINVAL; | |
1110 | ||
1111 | ret = arcturus_get_metrics_table(smu, &metrics); | |
1112 | if (ret) | |
1113 | return ret; | |
1114 | ||
4bf76e60 EQ |
1115 | switch (clk_id) { |
1116 | case PPCLK_GFXCLK: | |
1117 | /* | |
1118 | * CurrClock[clk_id] can provide accurate | |
1119 | * output only when the dpm feature is enabled. | |
1120 | * We can use Average_* for dpm disabled case. | |
1121 | * But this is available for gfxclk/uclk/socclk. | |
1122 | */ | |
1123 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) | |
1124 | *value = metrics.CurrClock[PPCLK_GFXCLK]; | |
1125 | else | |
1126 | *value = metrics.AverageGfxclkFrequency; | |
1127 | break; | |
1128 | case PPCLK_UCLK: | |
1129 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) | |
1130 | *value = metrics.CurrClock[PPCLK_UCLK]; | |
1131 | else | |
1132 | *value = metrics.AverageUclkFrequency; | |
1133 | break; | |
1134 | case PPCLK_SOCCLK: | |
1135 | if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) | |
1136 | *value = metrics.CurrClock[PPCLK_SOCCLK]; | |
1137 | else | |
1138 | *value = metrics.AverageSocclkFrequency; | |
1139 | break; | |
1140 | default: | |
1141 | *value = metrics.CurrClock[clk_id]; | |
1142 | break; | |
1143 | } | |
631807f0 EQ |
1144 | |
1145 | return ret; | |
1146 | } | |
1147 | ||
60d435b7 EQ |
1148 | static uint32_t arcturus_find_lowest_dpm_level(struct arcturus_single_dpm_table *table) |
1149 | { | |
1150 | uint32_t i; | |
1151 | ||
1152 | for (i = 0; i < table->count; i++) { | |
1153 | if (table->dpm_levels[i].enabled) | |
1154 | break; | |
1155 | } | |
1156 | if (i >= table->count) { | |
1157 | i = 0; | |
1158 | table->dpm_levels[i].enabled = true; | |
1159 | } | |
1160 | ||
1161 | return i; | |
1162 | } | |
1163 | ||
1164 | static uint32_t arcturus_find_highest_dpm_level(struct arcturus_single_dpm_table *table) | |
1165 | { | |
1166 | int i = 0; | |
1167 | ||
1168 | if (table->count <= 0) { | |
1169 | pr_err("[%s] DPM Table has no entry!", __func__); | |
1170 | return 0; | |
1171 | } | |
1172 | if (table->count > MAX_DPM_NUMBER) { | |
1173 | pr_err("[%s] DPM Table has too many entries!", __func__); | |
1174 | return MAX_DPM_NUMBER - 1; | |
1175 | } | |
1176 | ||
1177 | for (i = table->count - 1; i >= 0; i--) { | |
1178 | if (table->dpm_levels[i].enabled) | |
1179 | break; | |
1180 | } | |
1181 | if (i < 0) { | |
1182 | i = 0; | |
1183 | table->dpm_levels[i].enabled = true; | |
1184 | } | |
1185 | ||
1186 | return i; | |
1187 | } | |
1188 | ||
1189 | ||
1190 | ||
1191 | static int arcturus_force_dpm_limit_value(struct smu_context *smu, bool highest) | |
1192 | { | |
1193 | struct arcturus_dpm_table *dpm_table = | |
1194 | (struct arcturus_dpm_table *)smu->smu_dpm.dpm_context; | |
1195 | uint32_t soft_level; | |
1196 | int ret = 0; | |
1197 | ||
1198 | /* gfxclk */ | |
1199 | if (highest) | |
1200 | soft_level = arcturus_find_highest_dpm_level(&(dpm_table->gfx_table)); | |
1201 | else | |
1202 | soft_level = arcturus_find_lowest_dpm_level(&(dpm_table->gfx_table)); | |
1203 | ||
1204 | dpm_table->gfx_table.dpm_state.soft_min_level = | |
1205 | dpm_table->gfx_table.dpm_state.soft_max_level = | |
1206 | dpm_table->gfx_table.dpm_levels[soft_level].value; | |
1207 | ||
1208 | /* uclk */ | |
1209 | if (highest) | |
1210 | soft_level = arcturus_find_highest_dpm_level(&(dpm_table->mem_table)); | |
1211 | else | |
1212 | soft_level = arcturus_find_lowest_dpm_level(&(dpm_table->mem_table)); | |
1213 | ||
1214 | dpm_table->mem_table.dpm_state.soft_min_level = | |
1215 | dpm_table->mem_table.dpm_state.soft_max_level = | |
1216 | dpm_table->mem_table.dpm_levels[soft_level].value; | |
1217 | ||
1218 | /* socclk */ | |
1219 | if (highest) | |
1220 | soft_level = arcturus_find_highest_dpm_level(&(dpm_table->soc_table)); | |
1221 | else | |
1222 | soft_level = arcturus_find_lowest_dpm_level(&(dpm_table->soc_table)); | |
1223 | ||
1224 | dpm_table->soc_table.dpm_state.soft_min_level = | |
1225 | dpm_table->soc_table.dpm_state.soft_max_level = | |
1226 | dpm_table->soc_table.dpm_levels[soft_level].value; | |
1227 | ||
1228 | ret = arcturus_upload_dpm_level(smu, false, 0xFFFFFFFF); | |
1229 | if (ret) { | |
1230 | pr_err("Failed to upload boot level to %s!\n", | |
1231 | highest ? "highest" : "lowest"); | |
1232 | return ret; | |
1233 | } | |
1234 | ||
1235 | ret = arcturus_upload_dpm_level(smu, true, 0xFFFFFFFF); | |
1236 | if (ret) { | |
1237 | pr_err("Failed to upload dpm max level to %s!\n!", | |
1238 | highest ? "highest" : "lowest"); | |
1239 | return ret; | |
1240 | } | |
1241 | ||
1242 | return ret; | |
1243 | } | |
1244 | ||
1245 | static int arcturus_unforce_dpm_levels(struct smu_context *smu) | |
1246 | { | |
1247 | struct arcturus_dpm_table *dpm_table = | |
1248 | (struct arcturus_dpm_table *)smu->smu_dpm.dpm_context; | |
1249 | uint32_t soft_min_level, soft_max_level; | |
1250 | int ret = 0; | |
1251 | ||
1252 | /* gfxclk */ | |
1253 | soft_min_level = arcturus_find_lowest_dpm_level(&(dpm_table->gfx_table)); | |
1254 | soft_max_level = arcturus_find_highest_dpm_level(&(dpm_table->gfx_table)); | |
1255 | dpm_table->gfx_table.dpm_state.soft_min_level = | |
1256 | dpm_table->gfx_table.dpm_levels[soft_min_level].value; | |
1257 | dpm_table->gfx_table.dpm_state.soft_max_level = | |
1258 | dpm_table->gfx_table.dpm_levels[soft_max_level].value; | |
1259 | ||
1260 | /* uclk */ | |
1261 | soft_min_level = arcturus_find_lowest_dpm_level(&(dpm_table->mem_table)); | |
1262 | soft_max_level = arcturus_find_highest_dpm_level(&(dpm_table->mem_table)); | |
1263 | dpm_table->mem_table.dpm_state.soft_min_level = | |
1264 | dpm_table->gfx_table.dpm_levels[soft_min_level].value; | |
1265 | dpm_table->mem_table.dpm_state.soft_max_level = | |
1266 | dpm_table->gfx_table.dpm_levels[soft_max_level].value; | |
1267 | ||
1268 | /* socclk */ | |
1269 | soft_min_level = arcturus_find_lowest_dpm_level(&(dpm_table->soc_table)); | |
1270 | soft_max_level = arcturus_find_highest_dpm_level(&(dpm_table->soc_table)); | |
1271 | dpm_table->soc_table.dpm_state.soft_min_level = | |
1272 | dpm_table->soc_table.dpm_levels[soft_min_level].value; | |
1273 | dpm_table->soc_table.dpm_state.soft_max_level = | |
1274 | dpm_table->soc_table.dpm_levels[soft_max_level].value; | |
1275 | ||
1276 | ret = arcturus_upload_dpm_level(smu, false, 0xFFFFFFFF); | |
1277 | if (ret) { | |
1278 | pr_err("Failed to upload DPM Bootup Levels!"); | |
1279 | return ret; | |
1280 | } | |
1281 | ||
1282 | ret = arcturus_upload_dpm_level(smu, true, 0xFFFFFFFF); | |
1283 | if (ret) { | |
1284 | pr_err("Failed to upload DPM Max Levels!"); | |
1285 | return ret; | |
1286 | } | |
1287 | ||
1288 | return ret; | |
1289 | } | |
1290 | ||
1291 | static int | |
1292 | arcturus_get_profiling_clk_mask(struct smu_context *smu, | |
1293 | enum amd_dpm_forced_level level, | |
1294 | uint32_t *sclk_mask, | |
1295 | uint32_t *mclk_mask, | |
1296 | uint32_t *soc_mask) | |
1297 | { | |
1298 | struct arcturus_dpm_table *dpm_table = | |
1299 | (struct arcturus_dpm_table *)smu->smu_dpm.dpm_context; | |
1300 | struct arcturus_single_dpm_table *gfx_dpm_table; | |
1301 | struct arcturus_single_dpm_table *mem_dpm_table; | |
1302 | struct arcturus_single_dpm_table *soc_dpm_table; | |
1303 | ||
1304 | if (!smu->smu_dpm.dpm_context) | |
1305 | return -EINVAL; | |
1306 | ||
1307 | gfx_dpm_table = &dpm_table->gfx_table; | |
1308 | mem_dpm_table = &dpm_table->mem_table; | |
1309 | soc_dpm_table = &dpm_table->soc_table; | |
1310 | ||
1311 | *sclk_mask = 0; | |
1312 | *mclk_mask = 0; | |
1313 | *soc_mask = 0; | |
1314 | ||
1315 | if (gfx_dpm_table->count > ARCTURUS_UMD_PSTATE_GFXCLK_LEVEL && | |
1316 | mem_dpm_table->count > ARCTURUS_UMD_PSTATE_MCLK_LEVEL && | |
1317 | soc_dpm_table->count > ARCTURUS_UMD_PSTATE_SOCCLK_LEVEL) { | |
1318 | *sclk_mask = ARCTURUS_UMD_PSTATE_GFXCLK_LEVEL; | |
1319 | *mclk_mask = ARCTURUS_UMD_PSTATE_MCLK_LEVEL; | |
1320 | *soc_mask = ARCTURUS_UMD_PSTATE_SOCCLK_LEVEL; | |
1321 | } | |
1322 | ||
1323 | if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { | |
1324 | *sclk_mask = 0; | |
1325 | } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { | |
1326 | *mclk_mask = 0; | |
1327 | } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { | |
1328 | *sclk_mask = gfx_dpm_table->count - 1; | |
1329 | *mclk_mask = mem_dpm_table->count - 1; | |
1330 | *soc_mask = soc_dpm_table->count - 1; | |
1331 | } | |
1332 | ||
1333 | return 0; | |
1334 | } | |
1335 | ||
b4af964e EQ |
1336 | static int arcturus_get_power_limit(struct smu_context *smu, |
1337 | uint32_t *limit, | |
1338 | bool asic_default) | |
1339 | { | |
1340 | PPTable_t *pptable = smu->smu_table.driver_pptable; | |
b56a53db | 1341 | uint32_t asic_default_power_limit = 0; |
b4af964e EQ |
1342 | int ret = 0; |
1343 | int power_src; | |
1344 | ||
1345 | if (!smu->default_power_limit || | |
1346 | !smu->power_limit) { | |
1347 | if (smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) { | |
1348 | power_src = smu_power_get_index(smu, SMU_POWER_SOURCE_AC); | |
1349 | if (power_src < 0) | |
1350 | return -EINVAL; | |
1351 | ||
1352 | ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit, | |
1353 | power_src << 16); | |
1354 | if (ret) { | |
1355 | pr_err("[%s] get PPT limit failed!", __func__); | |
1356 | return ret; | |
1357 | } | |
1358 | smu_read_smc_arg(smu, &asic_default_power_limit); | |
1359 | } else { | |
1360 | /* the last hope to figure out the ppt limit */ | |
1361 | if (!pptable) { | |
1362 | pr_err("Cannot get PPT limit due to pptable missing!"); | |
1363 | return -EINVAL; | |
1364 | } | |
1365 | asic_default_power_limit = | |
1366 | pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0]; | |
1367 | } | |
1368 | ||
1369 | if (smu->od_enabled) { | |
1370 | asic_default_power_limit *= (100 + smu->smu_table.TDPODLimit); | |
1371 | asic_default_power_limit /= 100; | |
1372 | } | |
1373 | ||
1374 | smu->default_power_limit = asic_default_power_limit; | |
1375 | smu->power_limit = asic_default_power_limit; | |
1376 | } | |
1377 | ||
1378 | if (asic_default) | |
1379 | *limit = smu->default_power_limit; | |
1380 | else | |
1381 | *limit = smu->power_limit; | |
1382 | ||
1383 | return 0; | |
1384 | } | |
1385 | ||
7aa3f675 EQ |
1386 | static int arcturus_get_power_profile_mode(struct smu_context *smu, |
1387 | char *buf) | |
1388 | { | |
1389 | static const char *profile_name[] = { | |
1390 | "BOOTUP_DEFAULT", | |
1391 | "3D_FULL_SCREEN", | |
1392 | "POWER_SAVING", | |
1393 | "VIDEO", | |
1394 | "VR", | |
1395 | "COMPUTE", | |
1396 | "CUSTOM"}; | |
1397 | uint32_t i, size = 0; | |
1398 | int16_t workload_type = 0; | |
1399 | ||
1400 | if (!smu->pm_enabled || !buf) | |
1401 | return -EINVAL; | |
1402 | ||
1403 | for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { | |
1404 | /* | |
1405 | * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT | |
1406 | * Not all profile modes are supported on arcturus. | |
1407 | */ | |
1408 | workload_type = smu_workload_get_type(smu, i); | |
1409 | if (workload_type < 0) | |
1410 | continue; | |
1411 | ||
1412 | size += sprintf(buf + size, "%2d %14s%s\n", | |
1413 | i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " "); | |
1414 | } | |
1415 | ||
1416 | return size; | |
1417 | } | |
1418 | ||
1419 | static int arcturus_set_power_profile_mode(struct smu_context *smu, | |
1420 | long *input, | |
1421 | uint32_t size) | |
1422 | { | |
1423 | int workload_type = 0; | |
1424 | uint32_t profile_mode = input[size]; | |
1425 | int ret = 0; | |
1426 | ||
1427 | if (!smu->pm_enabled) | |
1428 | return -EINVAL; | |
1429 | ||
1430 | if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { | |
1431 | pr_err("Invalid power profile mode %d\n", profile_mode); | |
1432 | return -EINVAL; | |
1433 | } | |
1434 | ||
1435 | /* | |
1436 | * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT | |
1437 | * Not all profile modes are supported on arcturus. | |
1438 | */ | |
1439 | workload_type = smu_workload_get_type(smu, profile_mode); | |
1440 | if (workload_type < 0) { | |
1441 | pr_err("Unsupported power profile mode %d on arcturus\n", profile_mode); | |
1442 | return -EINVAL; | |
1443 | } | |
1444 | ||
1445 | ret = smu_send_smc_msg_with_param(smu, | |
1446 | SMU_MSG_SetWorkloadMask, | |
1447 | 1 << workload_type); | |
1448 | if (ret) { | |
1449 | pr_err("Fail to set workload type %d\n", workload_type); | |
1450 | return ret; | |
1451 | } | |
1452 | ||
1453 | smu->power_profile_mode = profile_mode; | |
1454 | ||
1455 | return 0; | |
1456 | } | |
1457 | ||
a94235af EQ |
1458 | static void arcturus_dump_pptable(struct smu_context *smu) |
1459 | { | |
1460 | struct smu_table_context *table_context = &smu->smu_table; | |
1461 | PPTable_t *pptable = table_context->driver_pptable; | |
1462 | int i; | |
1463 | ||
1464 | pr_info("Dumped PPTable:\n"); | |
1465 | ||
1466 | pr_info("Version = 0x%08x\n", pptable->Version); | |
1467 | ||
1468 | pr_info("FeaturesToRun[0] = 0x%08x\n", pptable->FeaturesToRun[0]); | |
1469 | pr_info("FeaturesToRun[1] = 0x%08x\n", pptable->FeaturesToRun[1]); | |
1470 | ||
1471 | for (i = 0; i < PPT_THROTTLER_COUNT; i++) { | |
1472 | pr_info("SocketPowerLimitAc[%d] = %d\n", i, pptable->SocketPowerLimitAc[i]); | |
1473 | pr_info("SocketPowerLimitAcTau[%d] = %d\n", i, pptable->SocketPowerLimitAcTau[i]); | |
1474 | } | |
1475 | ||
1476 | pr_info("TdcLimitSoc = %d\n", pptable->TdcLimitSoc); | |
1477 | pr_info("TdcLimitSocTau = %d\n", pptable->TdcLimitSocTau); | |
1478 | pr_info("TdcLimitGfx = %d\n", pptable->TdcLimitGfx); | |
1479 | pr_info("TdcLimitGfxTau = %d\n", pptable->TdcLimitGfxTau); | |
1480 | ||
1481 | pr_info("TedgeLimit = %d\n", pptable->TedgeLimit); | |
1482 | pr_info("ThotspotLimit = %d\n", pptable->ThotspotLimit); | |
1483 | pr_info("TmemLimit = %d\n", pptable->TmemLimit); | |
1484 | pr_info("Tvr_gfxLimit = %d\n", pptable->Tvr_gfxLimit); | |
1485 | pr_info("Tvr_memLimit = %d\n", pptable->Tvr_memLimit); | |
1486 | pr_info("Tvr_socLimit = %d\n", pptable->Tvr_socLimit); | |
1487 | pr_info("FitLimit = %d\n", pptable->FitLimit); | |
1488 | ||
1489 | pr_info("PpmPowerLimit = %d\n", pptable->PpmPowerLimit); | |
1490 | pr_info("PpmTemperatureThreshold = %d\n", pptable->PpmTemperatureThreshold); | |
1491 | ||
1492 | pr_info("ThrottlerControlMask = %d\n", pptable->ThrottlerControlMask); | |
1493 | ||
1494 | pr_info("UlvVoltageOffsetGfx = %d\n", pptable->UlvVoltageOffsetGfx); | |
1495 | pr_info("UlvPadding = 0x%08x\n", pptable->UlvPadding); | |
1496 | ||
1497 | pr_info("UlvGfxclkBypass = %d\n", pptable->UlvGfxclkBypass); | |
1498 | pr_info("Padding234[0] = 0x%02x\n", pptable->Padding234[0]); | |
1499 | pr_info("Padding234[1] = 0x%02x\n", pptable->Padding234[1]); | |
1500 | pr_info("Padding234[2] = 0x%02x\n", pptable->Padding234[2]); | |
1501 | ||
1502 | pr_info("MinVoltageGfx = %d\n", pptable->MinVoltageGfx); | |
1503 | pr_info("MinVoltageSoc = %d\n", pptable->MinVoltageSoc); | |
1504 | pr_info("MaxVoltageGfx = %d\n", pptable->MaxVoltageGfx); | |
1505 | pr_info("MaxVoltageSoc = %d\n", pptable->MaxVoltageSoc); | |
1506 | ||
1507 | pr_info("LoadLineResistanceGfx = %d\n", pptable->LoadLineResistanceGfx); | |
1508 | pr_info("LoadLineResistanceSoc = %d\n", pptable->LoadLineResistanceSoc); | |
1509 | ||
1510 | pr_info("[PPCLK_GFXCLK]\n" | |
1511 | " .VoltageMode = 0x%02x\n" | |
1512 | " .SnapToDiscrete = 0x%02x\n" | |
1513 | " .NumDiscreteLevels = 0x%02x\n" | |
1514 | " .padding = 0x%02x\n" | |
1515 | " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" | |
1516 | " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" | |
1517 | " .SsFmin = 0x%04x\n" | |
1518 | " .Padding_16 = 0x%04x\n", | |
1519 | pptable->DpmDescriptor[PPCLK_GFXCLK].VoltageMode, | |
1520 | pptable->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete, | |
1521 | pptable->DpmDescriptor[PPCLK_GFXCLK].NumDiscreteLevels, | |
1522 | pptable->DpmDescriptor[PPCLK_GFXCLK].padding, | |
1523 | pptable->DpmDescriptor[PPCLK_GFXCLK].ConversionToAvfsClk.m, | |
1524 | pptable->DpmDescriptor[PPCLK_GFXCLK].ConversionToAvfsClk.b, | |
1525 | pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.a, | |
1526 | pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.b, | |
1527 | pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.c, | |
1528 | pptable->DpmDescriptor[PPCLK_GFXCLK].SsFmin, | |
1529 | pptable->DpmDescriptor[PPCLK_GFXCLK].Padding16); | |
1530 | ||
1531 | pr_info("[PPCLK_VCLK]\n" | |
1532 | " .VoltageMode = 0x%02x\n" | |
1533 | " .SnapToDiscrete = 0x%02x\n" | |
1534 | " .NumDiscreteLevels = 0x%02x\n" | |
1535 | " .padding = 0x%02x\n" | |
1536 | " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" | |
1537 | " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" | |
1538 | " .SsFmin = 0x%04x\n" | |
1539 | " .Padding_16 = 0x%04x\n", | |
1540 | pptable->DpmDescriptor[PPCLK_VCLK].VoltageMode, | |
1541 | pptable->DpmDescriptor[PPCLK_VCLK].SnapToDiscrete, | |
1542 | pptable->DpmDescriptor[PPCLK_VCLK].NumDiscreteLevels, | |
1543 | pptable->DpmDescriptor[PPCLK_VCLK].padding, | |
1544 | pptable->DpmDescriptor[PPCLK_VCLK].ConversionToAvfsClk.m, | |
1545 | pptable->DpmDescriptor[PPCLK_VCLK].ConversionToAvfsClk.b, | |
1546 | pptable->DpmDescriptor[PPCLK_VCLK].SsCurve.a, | |
1547 | pptable->DpmDescriptor[PPCLK_VCLK].SsCurve.b, | |
1548 | pptable->DpmDescriptor[PPCLK_VCLK].SsCurve.c, | |
1549 | pptable->DpmDescriptor[PPCLK_VCLK].SsFmin, | |
1550 | pptable->DpmDescriptor[PPCLK_VCLK].Padding16); | |
1551 | ||
1552 | pr_info("[PPCLK_DCLK]\n" | |
1553 | " .VoltageMode = 0x%02x\n" | |
1554 | " .SnapToDiscrete = 0x%02x\n" | |
1555 | " .NumDiscreteLevels = 0x%02x\n" | |
1556 | " .padding = 0x%02x\n" | |
1557 | " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" | |
1558 | " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" | |
1559 | " .SsFmin = 0x%04x\n" | |
1560 | " .Padding_16 = 0x%04x\n", | |
1561 | pptable->DpmDescriptor[PPCLK_DCLK].VoltageMode, | |
1562 | pptable->DpmDescriptor[PPCLK_DCLK].SnapToDiscrete, | |
1563 | pptable->DpmDescriptor[PPCLK_DCLK].NumDiscreteLevels, | |
1564 | pptable->DpmDescriptor[PPCLK_DCLK].padding, | |
1565 | pptable->DpmDescriptor[PPCLK_DCLK].ConversionToAvfsClk.m, | |
1566 | pptable->DpmDescriptor[PPCLK_DCLK].ConversionToAvfsClk.b, | |
1567 | pptable->DpmDescriptor[PPCLK_DCLK].SsCurve.a, | |
1568 | pptable->DpmDescriptor[PPCLK_DCLK].SsCurve.b, | |
1569 | pptable->DpmDescriptor[PPCLK_DCLK].SsCurve.c, | |
1570 | pptable->DpmDescriptor[PPCLK_DCLK].SsFmin, | |
1571 | pptable->DpmDescriptor[PPCLK_DCLK].Padding16); | |
1572 | ||
1573 | pr_info("[PPCLK_SOCCLK]\n" | |
1574 | " .VoltageMode = 0x%02x\n" | |
1575 | " .SnapToDiscrete = 0x%02x\n" | |
1576 | " .NumDiscreteLevels = 0x%02x\n" | |
1577 | " .padding = 0x%02x\n" | |
1578 | " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" | |
1579 | " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" | |
1580 | " .SsFmin = 0x%04x\n" | |
1581 | " .Padding_16 = 0x%04x\n", | |
1582 | pptable->DpmDescriptor[PPCLK_SOCCLK].VoltageMode, | |
1583 | pptable->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete, | |
1584 | pptable->DpmDescriptor[PPCLK_SOCCLK].NumDiscreteLevels, | |
1585 | pptable->DpmDescriptor[PPCLK_SOCCLK].padding, | |
1586 | pptable->DpmDescriptor[PPCLK_SOCCLK].ConversionToAvfsClk.m, | |
1587 | pptable->DpmDescriptor[PPCLK_SOCCLK].ConversionToAvfsClk.b, | |
1588 | pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.a, | |
1589 | pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.b, | |
1590 | pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.c, | |
1591 | pptable->DpmDescriptor[PPCLK_SOCCLK].SsFmin, | |
1592 | pptable->DpmDescriptor[PPCLK_SOCCLK].Padding16); | |
1593 | ||
1594 | pr_info("[PPCLK_UCLK]\n" | |
1595 | " .VoltageMode = 0x%02x\n" | |
1596 | " .SnapToDiscrete = 0x%02x\n" | |
1597 | " .NumDiscreteLevels = 0x%02x\n" | |
1598 | " .padding = 0x%02x\n" | |
1599 | " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" | |
1600 | " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" | |
1601 | " .SsFmin = 0x%04x\n" | |
1602 | " .Padding_16 = 0x%04x\n", | |
1603 | pptable->DpmDescriptor[PPCLK_UCLK].VoltageMode, | |
1604 | pptable->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete, | |
1605 | pptable->DpmDescriptor[PPCLK_UCLK].NumDiscreteLevels, | |
1606 | pptable->DpmDescriptor[PPCLK_UCLK].padding, | |
1607 | pptable->DpmDescriptor[PPCLK_UCLK].ConversionToAvfsClk.m, | |
1608 | pptable->DpmDescriptor[PPCLK_UCLK].ConversionToAvfsClk.b, | |
1609 | pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.a, | |
1610 | pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.b, | |
1611 | pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.c, | |
1612 | pptable->DpmDescriptor[PPCLK_UCLK].SsFmin, | |
1613 | pptable->DpmDescriptor[PPCLK_UCLK].Padding16); | |
1614 | ||
1615 | pr_info("[PPCLK_FCLK]\n" | |
1616 | " .VoltageMode = 0x%02x\n" | |
1617 | " .SnapToDiscrete = 0x%02x\n" | |
1618 | " .NumDiscreteLevels = 0x%02x\n" | |
1619 | " .padding = 0x%02x\n" | |
1620 | " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" | |
1621 | " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" | |
1622 | " .SsFmin = 0x%04x\n" | |
1623 | " .Padding_16 = 0x%04x\n", | |
1624 | pptable->DpmDescriptor[PPCLK_FCLK].VoltageMode, | |
1625 | pptable->DpmDescriptor[PPCLK_FCLK].SnapToDiscrete, | |
1626 | pptable->DpmDescriptor[PPCLK_FCLK].NumDiscreteLevels, | |
1627 | pptable->DpmDescriptor[PPCLK_FCLK].padding, | |
1628 | pptable->DpmDescriptor[PPCLK_FCLK].ConversionToAvfsClk.m, | |
1629 | pptable->DpmDescriptor[PPCLK_FCLK].ConversionToAvfsClk.b, | |
1630 | pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.a, | |
1631 | pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.b, | |
1632 | pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.c, | |
1633 | pptable->DpmDescriptor[PPCLK_FCLK].SsFmin, | |
1634 | pptable->DpmDescriptor[PPCLK_FCLK].Padding16); | |
1635 | ||
1636 | ||
1637 | pr_info("FreqTableGfx\n"); | |
1638 | for (i = 0; i < NUM_GFXCLK_DPM_LEVELS; i++) | |
1639 | pr_info(" .[%02d] = %d\n", i, pptable->FreqTableGfx[i]); | |
1640 | ||
1641 | pr_info("FreqTableVclk\n"); | |
1642 | for (i = 0; i < NUM_VCLK_DPM_LEVELS; i++) | |
1643 | pr_info(" .[%02d] = %d\n", i, pptable->FreqTableVclk[i]); | |
1644 | ||
1645 | pr_info("FreqTableDclk\n"); | |
1646 | for (i = 0; i < NUM_DCLK_DPM_LEVELS; i++) | |
1647 | pr_info(" .[%02d] = %d\n", i, pptable->FreqTableDclk[i]); | |
1648 | ||
1649 | pr_info("FreqTableSocclk\n"); | |
1650 | for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) | |
1651 | pr_info(" .[%02d] = %d\n", i, pptable->FreqTableSocclk[i]); | |
1652 | ||
1653 | pr_info("FreqTableUclk\n"); | |
1654 | for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) | |
1655 | pr_info(" .[%02d] = %d\n", i, pptable->FreqTableUclk[i]); | |
1656 | ||
1657 | pr_info("FreqTableFclk\n"); | |
1658 | for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) | |
1659 | pr_info(" .[%02d] = %d\n", i, pptable->FreqTableFclk[i]); | |
1660 | ||
1661 | pr_info("Mp0clkFreq\n"); | |
1662 | for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) | |
1663 | pr_info(" .[%d] = %d\n", i, pptable->Mp0clkFreq[i]); | |
1664 | ||
1665 | pr_info("Mp0DpmVoltage\n"); | |
1666 | for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) | |
1667 | pr_info(" .[%d] = %d\n", i, pptable->Mp0DpmVoltage[i]); | |
1668 | ||
1669 | pr_info("GfxclkFidle = 0x%x\n", pptable->GfxclkFidle); | |
1670 | pr_info("GfxclkSlewRate = 0x%x\n", pptable->GfxclkSlewRate); | |
1671 | pr_info("Padding567[0] = 0x%x\n", pptable->Padding567[0]); | |
1672 | pr_info("Padding567[1] = 0x%x\n", pptable->Padding567[1]); | |
1673 | pr_info("Padding567[2] = 0x%x\n", pptable->Padding567[2]); | |
1674 | pr_info("Padding567[3] = 0x%x\n", pptable->Padding567[3]); | |
1675 | pr_info("GfxclkDsMaxFreq = %d\n", pptable->GfxclkDsMaxFreq); | |
1676 | pr_info("GfxclkSource = 0x%x\n", pptable->GfxclkSource); | |
1677 | pr_info("Padding456 = 0x%x\n", pptable->Padding456); | |
1678 | ||
1679 | pr_info("EnableTdpm = %d\n", pptable->EnableTdpm); | |
1680 | pr_info("TdpmHighHystTemperature = %d\n", pptable->TdpmHighHystTemperature); | |
1681 | pr_info("TdpmLowHystTemperature = %d\n", pptable->TdpmLowHystTemperature); | |
1682 | pr_info("GfxclkFreqHighTempLimit = %d\n", pptable->GfxclkFreqHighTempLimit); | |
1683 | ||
1684 | pr_info("FanStopTemp = %d\n", pptable->FanStopTemp); | |
1685 | pr_info("FanStartTemp = %d\n", pptable->FanStartTemp); | |
1686 | ||
1687 | pr_info("FanGainEdge = %d\n", pptable->FanGainEdge); | |
1688 | pr_info("FanGainHotspot = %d\n", pptable->FanGainHotspot); | |
1689 | pr_info("FanGainVrGfx = %d\n", pptable->FanGainVrGfx); | |
1690 | pr_info("FanGainVrSoc = %d\n", pptable->FanGainVrSoc); | |
1691 | pr_info("FanGainVrMem = %d\n", pptable->FanGainVrMem); | |
1692 | pr_info("FanGainHbm = %d\n", pptable->FanGainHbm); | |
1693 | ||
1694 | pr_info("FanPwmMin = %d\n", pptable->FanPwmMin); | |
1695 | pr_info("FanAcousticLimitRpm = %d\n", pptable->FanAcousticLimitRpm); | |
1696 | pr_info("FanThrottlingRpm = %d\n", pptable->FanThrottlingRpm); | |
1697 | pr_info("FanMaximumRpm = %d\n", pptable->FanMaximumRpm); | |
1698 | pr_info("FanTargetTemperature = %d\n", pptable->FanTargetTemperature); | |
1699 | pr_info("FanTargetGfxclk = %d\n", pptable->FanTargetGfxclk); | |
1700 | pr_info("FanZeroRpmEnable = %d\n", pptable->FanZeroRpmEnable); | |
1701 | pr_info("FanTachEdgePerRev = %d\n", pptable->FanTachEdgePerRev); | |
1702 | pr_info("FanTempInputSelect = %d\n", pptable->FanTempInputSelect); | |
1703 | ||
1704 | pr_info("FuzzyFan_ErrorSetDelta = %d\n", pptable->FuzzyFan_ErrorSetDelta); | |
1705 | pr_info("FuzzyFan_ErrorRateSetDelta = %d\n", pptable->FuzzyFan_ErrorRateSetDelta); | |
1706 | pr_info("FuzzyFan_PwmSetDelta = %d\n", pptable->FuzzyFan_PwmSetDelta); | |
1707 | pr_info("FuzzyFan_Reserved = %d\n", pptable->FuzzyFan_Reserved); | |
1708 | ||
1709 | pr_info("OverrideAvfsGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_GFX]); | |
1710 | pr_info("OverrideAvfsGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_SOC]); | |
1711 | pr_info("Padding8_Avfs[0] = %d\n", pptable->Padding8_Avfs[0]); | |
1712 | pr_info("Padding8_Avfs[1] = %d\n", pptable->Padding8_Avfs[1]); | |
1713 | ||
1714 | pr_info("dBtcGbGfxPll{a = 0x%x b = 0x%x c = 0x%x}\n", | |
1715 | pptable->dBtcGbGfxPll.a, | |
1716 | pptable->dBtcGbGfxPll.b, | |
1717 | pptable->dBtcGbGfxPll.c); | |
1718 | pr_info("dBtcGbGfxAfll{a = 0x%x b = 0x%x c = 0x%x}\n", | |
1719 | pptable->dBtcGbGfxAfll.a, | |
1720 | pptable->dBtcGbGfxAfll.b, | |
1721 | pptable->dBtcGbGfxAfll.c); | |
1722 | pr_info("dBtcGbSoc{a = 0x%x b = 0x%x c = 0x%x}\n", | |
1723 | pptable->dBtcGbSoc.a, | |
1724 | pptable->dBtcGbSoc.b, | |
1725 | pptable->dBtcGbSoc.c); | |
1726 | ||
1727 | pr_info("qAgingGb[AVFS_VOLTAGE_GFX]{m = 0x%x b = 0x%x}\n", | |
1728 | pptable->qAgingGb[AVFS_VOLTAGE_GFX].m, | |
1729 | pptable->qAgingGb[AVFS_VOLTAGE_GFX].b); | |
1730 | pr_info("qAgingGb[AVFS_VOLTAGE_SOC]{m = 0x%x b = 0x%x}\n", | |
1731 | pptable->qAgingGb[AVFS_VOLTAGE_SOC].m, | |
1732 | pptable->qAgingGb[AVFS_VOLTAGE_SOC].b); | |
1733 | ||
1734 | pr_info("qStaticVoltageOffset[AVFS_VOLTAGE_GFX]{a = 0x%x b = 0x%x c = 0x%x}\n", | |
1735 | pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].a, | |
1736 | pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].b, | |
1737 | pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].c); | |
1738 | pr_info("qStaticVoltageOffset[AVFS_VOLTAGE_SOC]{a = 0x%x b = 0x%x c = 0x%x}\n", | |
1739 | pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].a, | |
1740 | pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].b, | |
1741 | pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].c); | |
1742 | ||
1743 | pr_info("DcTol[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_GFX]); | |
1744 | pr_info("DcTol[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_SOC]); | |
1745 | ||
1746 | pr_info("DcBtcEnabled[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_GFX]); | |
1747 | pr_info("DcBtcEnabled[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_SOC]); | |
1748 | pr_info("Padding8_GfxBtc[0] = 0x%x\n", pptable->Padding8_GfxBtc[0]); | |
1749 | pr_info("Padding8_GfxBtc[1] = 0x%x\n", pptable->Padding8_GfxBtc[1]); | |
1750 | ||
1751 | pr_info("DcBtcMin[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_GFX]); | |
1752 | pr_info("DcBtcMin[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_SOC]); | |
1753 | pr_info("DcBtcMax[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_GFX]); | |
1754 | pr_info("DcBtcMax[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_SOC]); | |
1755 | ||
1756 | pr_info("DcBtcGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_GFX]); | |
1757 | pr_info("DcBtcGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_SOC]); | |
1758 | ||
1759 | pr_info("XgmiDpmPstates\n"); | |
1760 | for (i = 0; i < NUM_XGMI_LEVELS; i++) | |
1761 | pr_info(" .[%d] = %d\n", i, pptable->XgmiDpmPstates[i]); | |
1762 | pr_info("XgmiDpmSpare[0] = 0x%02x\n", pptable->XgmiDpmSpare[0]); | |
1763 | pr_info("XgmiDpmSpare[1] = 0x%02x\n", pptable->XgmiDpmSpare[1]); | |
1764 | ||
1765 | pr_info("VDDGFX_TVmin = %d\n", pptable->VDDGFX_TVmin); | |
1766 | pr_info("VDDSOC_TVmin = %d\n", pptable->VDDSOC_TVmin); | |
1767 | pr_info("VDDGFX_Vmin_HiTemp = %d\n", pptable->VDDGFX_Vmin_HiTemp); | |
1768 | pr_info("VDDGFX_Vmin_LoTemp = %d\n", pptable->VDDGFX_Vmin_LoTemp); | |
1769 | pr_info("VDDSOC_Vmin_HiTemp = %d\n", pptable->VDDSOC_Vmin_HiTemp); | |
1770 | pr_info("VDDSOC_Vmin_LoTemp = %d\n", pptable->VDDSOC_Vmin_LoTemp); | |
1771 | pr_info("VDDGFX_TVminHystersis = %d\n", pptable->VDDGFX_TVminHystersis); | |
1772 | pr_info("VDDSOC_TVminHystersis = %d\n", pptable->VDDSOC_TVminHystersis); | |
1773 | ||
1774 | pr_info("DebugOverrides = 0x%x\n", pptable->DebugOverrides); | |
1775 | pr_info("ReservedEquation0{a = 0x%x b = 0x%x c = 0x%x}\n", | |
1776 | pptable->ReservedEquation0.a, | |
1777 | pptable->ReservedEquation0.b, | |
1778 | pptable->ReservedEquation0.c); | |
1779 | pr_info("ReservedEquation1{a = 0x%x b = 0x%x c = 0x%x}\n", | |
1780 | pptable->ReservedEquation1.a, | |
1781 | pptable->ReservedEquation1.b, | |
1782 | pptable->ReservedEquation1.c); | |
1783 | pr_info("ReservedEquation2{a = 0x%x b = 0x%x c = 0x%x}\n", | |
1784 | pptable->ReservedEquation2.a, | |
1785 | pptable->ReservedEquation2.b, | |
1786 | pptable->ReservedEquation2.c); | |
1787 | pr_info("ReservedEquation3{a = 0x%x b = 0x%x c = 0x%x}\n", | |
1788 | pptable->ReservedEquation3.a, | |
1789 | pptable->ReservedEquation3.b, | |
1790 | pptable->ReservedEquation3.c); | |
1791 | ||
1792 | pr_info("MinVoltageUlvGfx = %d\n", pptable->MinVoltageUlvGfx); | |
1793 | pr_info("PaddingUlv = %d\n", pptable->PaddingUlv); | |
1794 | ||
1795 | pr_info("TotalPowerConfig = %d\n", pptable->TotalPowerConfig); | |
1796 | pr_info("TotalPowerSpare1 = %d\n", pptable->TotalPowerSpare1); | |
1797 | pr_info("TotalPowerSpare2 = %d\n", pptable->TotalPowerSpare2); | |
1798 | ||
1799 | pr_info("PccThresholdLow = %d\n", pptable->PccThresholdLow); | |
1800 | pr_info("PccThresholdHigh = %d\n", pptable->PccThresholdHigh); | |
1801 | ||
1802 | pr_info("Board Parameters:\n"); | |
1803 | pr_info("MaxVoltageStepGfx = 0x%x\n", pptable->MaxVoltageStepGfx); | |
1804 | pr_info("MaxVoltageStepSoc = 0x%x\n", pptable->MaxVoltageStepSoc); | |
1805 | ||
1806 | pr_info("VddGfxVrMapping = 0x%x\n", pptable->VddGfxVrMapping); | |
1807 | pr_info("VddSocVrMapping = 0x%x\n", pptable->VddSocVrMapping); | |
1808 | pr_info("VddMemVrMapping = 0x%x\n", pptable->VddMemVrMapping); | |
1809 | pr_info("BoardVrMapping = 0x%x\n", pptable->BoardVrMapping); | |
1810 | ||
1811 | pr_info("GfxUlvPhaseSheddingMask = 0x%x\n", pptable->GfxUlvPhaseSheddingMask); | |
1812 | pr_info("ExternalSensorPresent = 0x%x\n", pptable->ExternalSensorPresent); | |
1813 | ||
1814 | pr_info("GfxMaxCurrent = 0x%x\n", pptable->GfxMaxCurrent); | |
1815 | pr_info("GfxOffset = 0x%x\n", pptable->GfxOffset); | |
1816 | pr_info("Padding_TelemetryGfx = 0x%x\n", pptable->Padding_TelemetryGfx); | |
1817 | ||
1818 | pr_info("SocMaxCurrent = 0x%x\n", pptable->SocMaxCurrent); | |
1819 | pr_info("SocOffset = 0x%x\n", pptable->SocOffset); | |
1820 | pr_info("Padding_TelemetrySoc = 0x%x\n", pptable->Padding_TelemetrySoc); | |
1821 | ||
1822 | pr_info("MemMaxCurrent = 0x%x\n", pptable->MemMaxCurrent); | |
1823 | pr_info("MemOffset = 0x%x\n", pptable->MemOffset); | |
1824 | pr_info("Padding_TelemetryMem = 0x%x\n", pptable->Padding_TelemetryMem); | |
1825 | ||
1826 | pr_info("BoardMaxCurrent = 0x%x\n", pptable->BoardMaxCurrent); | |
1827 | pr_info("BoardOffset = 0x%x\n", pptable->BoardOffset); | |
1828 | pr_info("Padding_TelemetryBoardInput = 0x%x\n", pptable->Padding_TelemetryBoardInput); | |
1829 | ||
1830 | pr_info("VR0HotGpio = %d\n", pptable->VR0HotGpio); | |
1831 | pr_info("VR0HotPolarity = %d\n", pptable->VR0HotPolarity); | |
1832 | pr_info("VR1HotGpio = %d\n", pptable->VR1HotGpio); | |
1833 | pr_info("VR1HotPolarity = %d\n", pptable->VR1HotPolarity); | |
1834 | ||
1835 | pr_info("PllGfxclkSpreadEnabled = %d\n", pptable->PllGfxclkSpreadEnabled); | |
1836 | pr_info("PllGfxclkSpreadPercent = %d\n", pptable->PllGfxclkSpreadPercent); | |
1837 | pr_info("PllGfxclkSpreadFreq = %d\n", pptable->PllGfxclkSpreadFreq); | |
1838 | ||
1839 | pr_info("UclkSpreadEnabled = %d\n", pptable->UclkSpreadEnabled); | |
1840 | pr_info("UclkSpreadPercent = %d\n", pptable->UclkSpreadPercent); | |
1841 | pr_info("UclkSpreadFreq = %d\n", pptable->UclkSpreadFreq); | |
1842 | ||
1843 | pr_info("FclkSpreadEnabled = %d\n", pptable->FclkSpreadEnabled); | |
1844 | pr_info("FclkSpreadPercent = %d\n", pptable->FclkSpreadPercent); | |
1845 | pr_info("FclkSpreadFreq = %d\n", pptable->FclkSpreadFreq); | |
1846 | ||
1847 | pr_info("FllGfxclkSpreadEnabled = %d\n", pptable->FllGfxclkSpreadEnabled); | |
1848 | pr_info("FllGfxclkSpreadPercent = %d\n", pptable->FllGfxclkSpreadPercent); | |
1849 | pr_info("FllGfxclkSpreadFreq = %d\n", pptable->FllGfxclkSpreadFreq); | |
1850 | ||
1851 | for (i = 0; i < NUM_I2C_CONTROLLERS; i++) { | |
1852 | pr_info("I2cControllers[%d]:\n", i); | |
1853 | pr_info(" .Enabled = %d\n", | |
1854 | pptable->I2cControllers[i].Enabled); | |
1855 | pr_info(" .SlaveAddress = 0x%x\n", | |
1856 | pptable->I2cControllers[i].SlaveAddress); | |
1857 | pr_info(" .ControllerPort = %d\n", | |
1858 | pptable->I2cControllers[i].ControllerPort); | |
1859 | pr_info(" .ControllerName = %d\n", | |
1860 | pptable->I2cControllers[i].ControllerName); | |
1861 | pr_info(" .ThermalThrottler = %d\n", | |
1862 | pptable->I2cControllers[i].ThermalThrotter); | |
1863 | pr_info(" .I2cProtocol = %d\n", | |
1864 | pptable->I2cControllers[i].I2cProtocol); | |
1865 | pr_info(" .Speed = %d\n", | |
1866 | pptable->I2cControllers[i].Speed); | |
1867 | } | |
1868 | ||
1869 | pr_info("MemoryChannelEnabled = %d\n", pptable->MemoryChannelEnabled); | |
1870 | pr_info("DramBitWidth = %d\n", pptable->DramBitWidth); | |
1871 | ||
1872 | pr_info("TotalBoardPower = %d\n", pptable->TotalBoardPower); | |
1873 | ||
1874 | pr_info("XgmiLinkSpeed\n"); | |
1875 | for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) | |
1876 | pr_info(" .[%d] = %d\n", i, pptable->XgmiLinkSpeed[i]); | |
1877 | pr_info("XgmiLinkWidth\n"); | |
1878 | for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) | |
1879 | pr_info(" .[%d] = %d\n", i, pptable->XgmiLinkWidth[i]); | |
1880 | pr_info("XgmiFclkFreq\n"); | |
1881 | for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) | |
1882 | pr_info(" .[%d] = %d\n", i, pptable->XgmiFclkFreq[i]); | |
1883 | pr_info("XgmiSocVoltage\n"); | |
1884 | for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) | |
1885 | pr_info(" .[%d] = %d\n", i, pptable->XgmiSocVoltage[i]); | |
1886 | ||
1887 | } | |
1888 | ||
3f513bae CG |
1889 | static bool arcturus_is_dpm_running(struct smu_context *smu) |
1890 | { | |
1891 | int ret = 0; | |
1892 | uint32_t feature_mask[2]; | |
1893 | unsigned long feature_enabled; | |
1894 | ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); | |
1895 | feature_enabled = (unsigned long)((uint64_t)feature_mask[0] | | |
1896 | ((uint64_t)feature_mask[1] << 32)); | |
1897 | return !!(feature_enabled & SMC_DPM_FEATURE); | |
1898 | } | |
1899 | ||
6fba5906 | 1900 | static const struct pptable_funcs arcturus_ppt_funcs = { |
a94235af | 1901 | /* translate smu index into arcturus specific index */ |
6fba5906 | 1902 | .get_smu_msg_index = arcturus_get_smu_msg_index, |
a94235af EQ |
1903 | .get_smu_clk_index = arcturus_get_smu_clk_index, |
1904 | .get_smu_feature_index = arcturus_get_smu_feature_index, | |
1905 | .get_smu_table_index = arcturus_get_smu_table_index, | |
1906 | .get_smu_power_index= arcturus_get_pwr_src_index, | |
1907 | .get_workload_type = arcturus_get_workload_type, | |
1908 | /* internal structurs allocations */ | |
1909 | .tables_init = arcturus_tables_init, | |
1910 | .alloc_dpm_context = arcturus_allocate_dpm_context, | |
1911 | /* pptable related */ | |
1912 | .check_powerplay_table = arcturus_check_powerplay_table, | |
1913 | .store_powerplay_table = arcturus_store_powerplay_table, | |
1914 | .append_powerplay_table = arcturus_append_powerplay_table, | |
1915 | /* init dpm */ | |
1916 | .get_allowed_feature_mask = arcturus_get_allowed_feature_mask, | |
1917 | /* btc */ | |
1918 | .run_afll_btc = arcturus_run_btc_afll, | |
1919 | /* dpm/clk tables */ | |
1920 | .set_default_dpm_table = arcturus_set_default_dpm_table, | |
1921 | .populate_umd_state_clk = arcturus_populate_umd_state_clk, | |
1922 | .get_thermal_temperature_range = arcturus_get_thermal_temperature_range, | |
631807f0 | 1923 | .get_current_clk_freq_by_table = arcturus_get_current_clk_freq_by_table, |
a94235af EQ |
1924 | .print_clk_levels = arcturus_print_clk_levels, |
1925 | .force_clk_levels = arcturus_force_clk_levels, | |
ba74c8bf | 1926 | .read_sensor = arcturus_read_sensor, |
d427cf8f EQ |
1927 | .get_fan_speed_percent = arcturus_get_fan_speed_percent, |
1928 | .get_fan_speed_rpm = arcturus_get_fan_speed_rpm, | |
60d435b7 EQ |
1929 | .force_dpm_limit_value = arcturus_force_dpm_limit_value, |
1930 | .unforce_dpm_levels = arcturus_unforce_dpm_levels, | |
1931 | .get_profiling_clk_mask = arcturus_get_profiling_clk_mask, | |
7aa3f675 EQ |
1932 | .get_power_profile_mode = arcturus_get_power_profile_mode, |
1933 | .set_power_profile_mode = arcturus_set_power_profile_mode, | |
a94235af EQ |
1934 | /* debug (internal used) */ |
1935 | .dump_pptable = arcturus_dump_pptable, | |
b4af964e | 1936 | .get_power_limit = arcturus_get_power_limit, |
3f513bae | 1937 | .is_dpm_running = arcturus_is_dpm_running, |
6fba5906 CG |
1938 | }; |
1939 | ||
1940 | void arcturus_set_ppt_funcs(struct smu_context *smu) | |
1941 | { | |
a94235af EQ |
1942 | struct smu_table_context *smu_table = &smu->smu_table; |
1943 | ||
6fba5906 | 1944 | smu->ppt_funcs = &arcturus_ppt_funcs; |
a94235af | 1945 | smu_table->table_count = TABLE_COUNT; |
6fba5906 | 1946 | } |