Commit | Line | Data |
---|---|---|
f83a9991 EH |
1 | /* |
2 | * Copyright 2016 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 | #include <linux/module.h> | |
24 | #include <linux/slab.h> | |
25 | #include <linux/fb.h> | |
26 | ||
27 | #include "vega10_processpptables.h" | |
28 | #include "ppatomfwctrl.h" | |
29 | #include "atomfirmware.h" | |
30 | #include "pp_debug.h" | |
31 | #include "cgs_common.h" | |
32 | #include "vega10_pptable.h" | |
33 | ||
34 | static void set_hw_cap(struct pp_hwmgr *hwmgr, bool enable, | |
35 | enum phm_platform_caps cap) | |
36 | { | |
37 | if (enable) | |
38 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap); | |
39 | else | |
40 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap); | |
41 | } | |
42 | ||
43 | static const void *get_powerplay_table(struct pp_hwmgr *hwmgr) | |
44 | { | |
45 | int index = GetIndexIntoMasterDataTable(powerplayinfo); | |
46 | ||
47 | u16 size; | |
48 | u8 frev, crev; | |
49 | const void *table_address = hwmgr->soft_pp_table; | |
50 | ||
51 | if (!table_address) { | |
52 | table_address = (ATOM_Vega10_POWERPLAYTABLE *) | |
53 | cgs_atom_get_data_table(hwmgr->device, index, | |
54 | &size, &frev, &crev); | |
55 | ||
56 | hwmgr->soft_pp_table = table_address; /*Cache the result in RAM.*/ | |
57 | } | |
58 | ||
59 | return table_address; | |
60 | } | |
61 | ||
62 | static int check_powerplay_tables( | |
63 | struct pp_hwmgr *hwmgr, | |
64 | const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) | |
65 | { | |
66 | const ATOM_Vega10_State_Array *state_arrays; | |
67 | ||
68 | state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)powerplay_table) + | |
69 | le16_to_cpu(powerplay_table->usStateArrayOffset)); | |
70 | ||
71 | PP_ASSERT_WITH_CODE((powerplay_table->sHeader.format_revision >= | |
72 | ATOM_Vega10_TABLE_REVISION_VEGA10), | |
73 | "Unsupported PPTable format!", return -1); | |
74 | PP_ASSERT_WITH_CODE(powerplay_table->usStateArrayOffset, | |
75 | "State table is not set!", return -1); | |
76 | PP_ASSERT_WITH_CODE(powerplay_table->sHeader.structuresize > 0, | |
77 | "Invalid PowerPlay Table!", return -1); | |
78 | PP_ASSERT_WITH_CODE(state_arrays->ucNumEntries > 0, | |
79 | "Invalid PowerPlay Table!", return -1); | |
80 | ||
81 | return 0; | |
82 | } | |
83 | ||
84 | static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps) | |
85 | { | |
86 | set_hw_cap( | |
87 | hwmgr, | |
88 | 0 != (powerplay_caps & ATOM_VEGA10_PP_PLATFORM_CAP_POWERPLAY), | |
89 | PHM_PlatformCaps_PowerPlaySupport); | |
90 | ||
91 | set_hw_cap( | |
92 | hwmgr, | |
93 | 0 != (powerplay_caps & ATOM_VEGA10_PP_PLATFORM_CAP_SBIOSPOWERSOURCE), | |
94 | PHM_PlatformCaps_BiosPowerSourceControl); | |
95 | ||
96 | set_hw_cap( | |
97 | hwmgr, | |
98 | 0 != (powerplay_caps & ATOM_VEGA10_PP_PLATFORM_CAP_HARDWAREDC), | |
99 | PHM_PlatformCaps_AutomaticDCTransition); | |
100 | ||
101 | set_hw_cap( | |
102 | hwmgr, | |
103 | 0 != (powerplay_caps & ATOM_VEGA10_PP_PLATFORM_CAP_BACO), | |
104 | PHM_PlatformCaps_BACO); | |
105 | ||
106 | set_hw_cap( | |
107 | hwmgr, | |
108 | 0 != (powerplay_caps & ATOM_VEGA10_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL), | |
109 | PHM_PlatformCaps_CombinePCCWithThermalSignal); | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
114 | static int init_thermal_controller( | |
115 | struct pp_hwmgr *hwmgr, | |
116 | const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) | |
117 | { | |
118 | const ATOM_Vega10_Thermal_Controller *thermal_controller; | |
8250880e RZ |
119 | const Vega10_PPTable_Generic_SubTable_Header *header; |
120 | const ATOM_Vega10_Fan_Table *fan_table_v1; | |
121 | const ATOM_Vega10_Fan_Table_V2 *fan_table_v2; | |
f83a9991 EH |
122 | |
123 | thermal_controller = (ATOM_Vega10_Thermal_Controller *) | |
124 | (((unsigned long)powerplay_table) + | |
125 | le16_to_cpu(powerplay_table->usThermalControllerOffset)); | |
126 | ||
127 | PP_ASSERT_WITH_CODE((powerplay_table->usThermalControllerOffset != 0), | |
8250880e | 128 | "Thermal controller table not set!", return -EINVAL); |
f83a9991 EH |
129 | |
130 | hwmgr->thermal_controller.ucType = thermal_controller->ucType; | |
131 | hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine; | |
132 | hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress; | |
133 | ||
134 | hwmgr->thermal_controller.fanInfo.bNoFan = | |
135 | (0 != (thermal_controller->ucFanParameters & | |
136 | ATOM_VEGA10_PP_FANPARAMETERS_NOFAN)); | |
137 | ||
138 | hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution = | |
139 | thermal_controller->ucFanParameters & | |
140 | ATOM_VEGA10_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK; | |
141 | ||
142 | hwmgr->thermal_controller.fanInfo.ulMinRPM = | |
143 | thermal_controller->ucFanMinRPM * 100UL; | |
144 | hwmgr->thermal_controller.fanInfo.ulMaxRPM = | |
145 | thermal_controller->ucFanMaxRPM * 100UL; | |
146 | ||
8250880e RZ |
147 | hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay |
148 | = 100000; | |
149 | ||
f83a9991 EH |
150 | set_hw_cap( |
151 | hwmgr, | |
152 | ATOM_VEGA10_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType, | |
153 | PHM_PlatformCaps_ThermalController); | |
154 | ||
155 | if (!powerplay_table->usFanTableOffset) | |
156 | return 0; | |
157 | ||
8250880e | 158 | header = (const Vega10_PPTable_Generic_SubTable_Header *) |
f83a9991 EH |
159 | (((unsigned long)powerplay_table) + |
160 | le16_to_cpu(powerplay_table->usFanTableOffset)); | |
161 | ||
8250880e RZ |
162 | if (header->ucRevId == 10) { |
163 | fan_table_v1 = (ATOM_Vega10_Fan_Table *)header; | |
164 | ||
165 | PP_ASSERT_WITH_CODE((fan_table_v1->ucRevId >= 8), | |
166 | "Invalid Input Fan Table!", return -EINVAL); | |
167 | ||
168 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | |
169 | PHM_PlatformCaps_MicrocodeFanControl); | |
170 | ||
171 | hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity = | |
172 | le16_to_cpu(fan_table_v1->usFanOutputSensitivity); | |
173 | hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM = | |
174 | le16_to_cpu(fan_table_v1->usFanRPMMax); | |
175 | hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMMaxLimit = | |
176 | le16_to_cpu(fan_table_v1->usThrottlingRPM); | |
177 | hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit = | |
178 | le16_to_cpu(fan_table_v1->usFanAcousticLimit); | |
179 | hwmgr->thermal_controller.advanceFanControlParameters.usTMax = | |
180 | le16_to_cpu(fan_table_v1->usTargetTemperature); | |
181 | hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin = | |
182 | le16_to_cpu(fan_table_v1->usMinimumPWMLimit); | |
183 | hwmgr->thermal_controller.advanceFanControlParameters.ulTargetGfxClk = | |
184 | le16_to_cpu(fan_table_v1->usTargetGfxClk); | |
185 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainEdge = | |
186 | le16_to_cpu(fan_table_v1->usFanGainEdge); | |
187 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHotspot = | |
188 | le16_to_cpu(fan_table_v1->usFanGainHotspot); | |
189 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainLiquid = | |
190 | le16_to_cpu(fan_table_v1->usFanGainLiquid); | |
191 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrVddc = | |
192 | le16_to_cpu(fan_table_v1->usFanGainVrVddc); | |
193 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrMvdd = | |
194 | le16_to_cpu(fan_table_v1->usFanGainVrMvdd); | |
195 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainPlx = | |
196 | le16_to_cpu(fan_table_v1->usFanGainPlx); | |
197 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHbm = | |
198 | le16_to_cpu(fan_table_v1->usFanGainHbm); | |
199 | ||
200 | hwmgr->thermal_controller.advanceFanControlParameters.ucEnableZeroRPM = | |
201 | fan_table_v1->ucEnableZeroRPM; | |
202 | hwmgr->thermal_controller.advanceFanControlParameters.usZeroRPMStopTemperature = | |
203 | le16_to_cpu(fan_table_v1->usFanStopTemperature); | |
204 | hwmgr->thermal_controller.advanceFanControlParameters.usZeroRPMStartTemperature = | |
205 | le16_to_cpu(fan_table_v1->usFanStartTemperature); | |
206 | } else if (header->ucRevId > 10) { | |
207 | fan_table_v2 = (ATOM_Vega10_Fan_Table_V2 *)header; | |
208 | ||
209 | hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution = | |
210 | fan_table_v2->ucFanParameters & ATOM_VEGA10_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK; | |
211 | hwmgr->thermal_controller.fanInfo.ulMinRPM = fan_table_v2->ucFanMinRPM * 100UL; | |
212 | hwmgr->thermal_controller.fanInfo.ulMaxRPM = fan_table_v2->ucFanMaxRPM * 100UL; | |
213 | ||
214 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | |
215 | PHM_PlatformCaps_MicrocodeFanControl); | |
216 | ||
217 | hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity = | |
218 | le16_to_cpu(fan_table_v2->usFanOutputSensitivity); | |
219 | hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM = | |
220 | fan_table_v2->ucFanMaxRPM * 100UL; | |
221 | hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMMaxLimit = | |
222 | le16_to_cpu(fan_table_v2->usThrottlingRPM); | |
223 | hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit = | |
224 | le16_to_cpu(fan_table_v2->usFanAcousticLimitRpm); | |
225 | hwmgr->thermal_controller.advanceFanControlParameters.usTMax = | |
226 | le16_to_cpu(fan_table_v2->usTargetTemperature); | |
227 | hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin = | |
228 | le16_to_cpu(fan_table_v2->usMinimumPWMLimit); | |
229 | hwmgr->thermal_controller.advanceFanControlParameters.ulTargetGfxClk = | |
230 | le16_to_cpu(fan_table_v2->usTargetGfxClk); | |
231 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainEdge = | |
232 | le16_to_cpu(fan_table_v2->usFanGainEdge); | |
233 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHotspot = | |
234 | le16_to_cpu(fan_table_v2->usFanGainHotspot); | |
235 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainLiquid = | |
236 | le16_to_cpu(fan_table_v2->usFanGainLiquid); | |
237 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrVddc = | |
238 | le16_to_cpu(fan_table_v2->usFanGainVrVddc); | |
239 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrMvdd = | |
240 | le16_to_cpu(fan_table_v2->usFanGainVrMvdd); | |
241 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainPlx = | |
242 | le16_to_cpu(fan_table_v2->usFanGainPlx); | |
243 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHbm = | |
244 | le16_to_cpu(fan_table_v2->usFanGainHbm); | |
245 | ||
246 | hwmgr->thermal_controller.advanceFanControlParameters.ucEnableZeroRPM = | |
247 | fan_table_v2->ucEnableZeroRPM; | |
248 | hwmgr->thermal_controller.advanceFanControlParameters.usZeroRPMStopTemperature = | |
249 | le16_to_cpu(fan_table_v2->usFanStopTemperature); | |
250 | hwmgr->thermal_controller.advanceFanControlParameters.usZeroRPMStartTemperature = | |
251 | le16_to_cpu(fan_table_v2->usFanStartTemperature); | |
252 | } | |
f83a9991 EH |
253 | return 0; |
254 | } | |
255 | ||
256 | static int init_over_drive_limits( | |
257 | struct pp_hwmgr *hwmgr, | |
258 | const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) | |
259 | { | |
260 | hwmgr->platform_descriptor.overdriveLimit.engineClock = | |
261 | le32_to_cpu(powerplay_table->ulMaxODEngineClock); | |
262 | hwmgr->platform_descriptor.overdriveLimit.memoryClock = | |
263 | le32_to_cpu(powerplay_table->ulMaxODMemoryClock); | |
264 | ||
265 | hwmgr->platform_descriptor.minOverdriveVDDC = 0; | |
266 | hwmgr->platform_descriptor.maxOverdriveVDDC = 0; | |
267 | hwmgr->platform_descriptor.overdriveVDDCStep = 0; | |
268 | ||
269 | if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0 && | |
270 | hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0) { | |
271 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | |
272 | PHM_PlatformCaps_ACOverdriveSupport); | |
273 | } | |
274 | ||
275 | return 0; | |
276 | } | |
277 | ||
278 | static int get_mm_clock_voltage_table( | |
279 | struct pp_hwmgr *hwmgr, | |
280 | phm_ppt_v1_mm_clock_voltage_dependency_table **vega10_mm_table, | |
281 | const ATOM_Vega10_MM_Dependency_Table *mm_dependency_table) | |
282 | { | |
283 | uint32_t table_size, i; | |
284 | const ATOM_Vega10_MM_Dependency_Record *mm_dependency_record; | |
285 | phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table; | |
286 | ||
287 | PP_ASSERT_WITH_CODE((mm_dependency_table->ucNumEntries != 0), | |
288 | "Invalid PowerPlay Table!", return -1); | |
289 | ||
290 | table_size = sizeof(uint32_t) + | |
291 | sizeof(phm_ppt_v1_mm_clock_voltage_dependency_record) * | |
292 | mm_dependency_table->ucNumEntries; | |
293 | mm_table = (phm_ppt_v1_mm_clock_voltage_dependency_table *) | |
294 | kzalloc(table_size, GFP_KERNEL); | |
295 | ||
296 | if (!mm_table) | |
297 | return -ENOMEM; | |
298 | ||
299 | mm_table->count = mm_dependency_table->ucNumEntries; | |
300 | ||
301 | for (i = 0; i < mm_dependency_table->ucNumEntries; i++) { | |
302 | mm_dependency_record = &mm_dependency_table->entries[i]; | |
303 | mm_table->entries[i].vddcInd = mm_dependency_record->ucVddcInd; | |
304 | mm_table->entries[i].samclock = | |
305 | le32_to_cpu(mm_dependency_record->ulPSPClk); | |
306 | mm_table->entries[i].eclk = le32_to_cpu(mm_dependency_record->ulEClk); | |
307 | mm_table->entries[i].vclk = le32_to_cpu(mm_dependency_record->ulVClk); | |
308 | mm_table->entries[i].dclk = le32_to_cpu(mm_dependency_record->ulDClk); | |
309 | } | |
310 | ||
311 | *vega10_mm_table = mm_table; | |
312 | ||
313 | return 0; | |
314 | } | |
315 | ||
1e1eb6a8 RZ |
316 | static void get_scl_sda_value(uint8_t line, uint8_t *scl, uint8_t* sda) |
317 | { | |
318 | switch(line){ | |
319 | case Vega10_I2CLineID_DDC1: | |
320 | *scl = Vega10_I2C_DDC1CLK; | |
321 | *sda = Vega10_I2C_DDC1DATA; | |
322 | break; | |
323 | case Vega10_I2CLineID_DDC2: | |
324 | *scl = Vega10_I2C_DDC2CLK; | |
325 | *sda = Vega10_I2C_DDC2DATA; | |
326 | break; | |
327 | case Vega10_I2CLineID_DDC3: | |
328 | *scl = Vega10_I2C_DDC3CLK; | |
329 | *sda = Vega10_I2C_DDC3DATA; | |
330 | break; | |
331 | case Vega10_I2CLineID_DDC4: | |
332 | *scl = Vega10_I2C_DDC4CLK; | |
333 | *sda = Vega10_I2C_DDC4DATA; | |
334 | break; | |
335 | case Vega10_I2CLineID_DDC5: | |
336 | *scl = Vega10_I2C_DDC5CLK; | |
337 | *sda = Vega10_I2C_DDC5DATA; | |
338 | break; | |
339 | case Vega10_I2CLineID_DDC6: | |
340 | *scl = Vega10_I2C_DDC6CLK; | |
341 | *sda = Vega10_I2C_DDC6DATA; | |
342 | break; | |
343 | case Vega10_I2CLineID_SCLSDA: | |
344 | *scl = Vega10_I2C_SCL; | |
345 | *sda = Vega10_I2C_SDA; | |
346 | break; | |
347 | case Vega10_I2CLineID_DDCVGA: | |
348 | *scl = Vega10_I2C_DDCVGACLK; | |
349 | *sda = Vega10_I2C_DDCVGADATA; | |
350 | break; | |
351 | default: | |
352 | *scl = 0; | |
353 | *sda = 0; | |
354 | break; | |
355 | } | |
356 | } | |
357 | ||
f83a9991 EH |
358 | static int get_tdp_table( |
359 | struct pp_hwmgr *hwmgr, | |
360 | struct phm_tdp_table **info_tdp_table, | |
361 | const Vega10_PPTable_Generic_SubTable_Header *table) | |
362 | { | |
363 | uint32_t table_size; | |
364 | struct phm_tdp_table *tdp_table; | |
1e1eb6a8 RZ |
365 | uint8_t scl; |
366 | uint8_t sda; | |
367 | const ATOM_Vega10_PowerTune_Table *power_tune_table; | |
368 | const ATOM_Vega10_PowerTune_Table_V2 *power_tune_table_v2; | |
f83a9991 EH |
369 | |
370 | table_size = sizeof(uint32_t) + sizeof(struct phm_tdp_table); | |
1e1eb6a8 | 371 | |
f83a9991 EH |
372 | tdp_table = kzalloc(table_size, GFP_KERNEL); |
373 | ||
1e1eb6a8 | 374 | if (!tdp_table) |
f83a9991 | 375 | return -ENOMEM; |
f83a9991 | 376 | |
1e1eb6a8 RZ |
377 | if (table->ucRevId == 5) { |
378 | power_tune_table = (ATOM_Vega10_PowerTune_Table *)table; | |
379 | tdp_table->usMaximumPowerDeliveryLimit = le16_to_cpu(power_tune_table->usSocketPowerLimit); | |
380 | tdp_table->usTDC = le16_to_cpu(power_tune_table->usTdcLimit); | |
381 | tdp_table->usEDCLimit = le16_to_cpu(power_tune_table->usEdcLimit); | |
382 | tdp_table->usSoftwareShutdownTemp = | |
383 | le16_to_cpu(power_tune_table->usSoftwareShutdownTemp); | |
384 | tdp_table->usTemperatureLimitTedge = | |
385 | le16_to_cpu(power_tune_table->usTemperatureLimitTedge); | |
386 | tdp_table->usTemperatureLimitHotspot = | |
387 | le16_to_cpu(power_tune_table->usTemperatureLimitHotSpot); | |
388 | tdp_table->usTemperatureLimitLiquid1 = | |
389 | le16_to_cpu(power_tune_table->usTemperatureLimitLiquid1); | |
390 | tdp_table->usTemperatureLimitLiquid2 = | |
391 | le16_to_cpu(power_tune_table->usTemperatureLimitLiquid2); | |
392 | tdp_table->usTemperatureLimitHBM = | |
393 | le16_to_cpu(power_tune_table->usTemperatureLimitHBM); | |
394 | tdp_table->usTemperatureLimitVrVddc = | |
395 | le16_to_cpu(power_tune_table->usTemperatureLimitVrSoc); | |
396 | tdp_table->usTemperatureLimitVrMvdd = | |
397 | le16_to_cpu(power_tune_table->usTemperatureLimitVrMem); | |
398 | tdp_table->usTemperatureLimitPlx = | |
399 | le16_to_cpu(power_tune_table->usTemperatureLimitPlx); | |
400 | tdp_table->ucLiquid1_I2C_address = power_tune_table->ucLiquid1_I2C_address; | |
401 | tdp_table->ucLiquid2_I2C_address = power_tune_table->ucLiquid2_I2C_address; | |
402 | tdp_table->ucLiquid_I2C_Line = power_tune_table->ucLiquid_I2C_LineSCL; | |
403 | tdp_table->ucLiquid_I2C_LineSDA = power_tune_table->ucLiquid_I2C_LineSDA; | |
404 | tdp_table->ucVr_I2C_address = power_tune_table->ucVr_I2C_address; | |
405 | tdp_table->ucVr_I2C_Line = power_tune_table->ucVr_I2C_LineSCL; | |
406 | tdp_table->ucVr_I2C_LineSDA = power_tune_table->ucVr_I2C_LineSDA; | |
407 | tdp_table->ucPlx_I2C_address = power_tune_table->ucPlx_I2C_address; | |
408 | tdp_table->ucPlx_I2C_Line = power_tune_table->ucPlx_I2C_LineSCL; | |
409 | tdp_table->ucPlx_I2C_LineSDA = power_tune_table->ucPlx_I2C_LineSDA; | |
410 | hwmgr->platform_descriptor.LoadLineSlope = power_tune_table->usLoadLineResistance; | |
411 | } else { | |
412 | power_tune_table_v2 = (ATOM_Vega10_PowerTune_Table_V2 *)table; | |
413 | tdp_table->usMaximumPowerDeliveryLimit = le16_to_cpu(power_tune_table_v2->usSocketPowerLimit); | |
414 | tdp_table->usTDC = le16_to_cpu(power_tune_table_v2->usTdcLimit); | |
415 | tdp_table->usEDCLimit = le16_to_cpu(power_tune_table_v2->usEdcLimit); | |
416 | tdp_table->usSoftwareShutdownTemp = | |
417 | le16_to_cpu(power_tune_table_v2->usSoftwareShutdownTemp); | |
418 | tdp_table->usTemperatureLimitTedge = | |
419 | le16_to_cpu(power_tune_table_v2->usTemperatureLimitTedge); | |
420 | tdp_table->usTemperatureLimitHotspot = | |
421 | le16_to_cpu(power_tune_table_v2->usTemperatureLimitHotSpot); | |
422 | tdp_table->usTemperatureLimitLiquid1 = | |
423 | le16_to_cpu(power_tune_table_v2->usTemperatureLimitLiquid1); | |
424 | tdp_table->usTemperatureLimitLiquid2 = | |
425 | le16_to_cpu(power_tune_table_v2->usTemperatureLimitLiquid2); | |
426 | tdp_table->usTemperatureLimitHBM = | |
427 | le16_to_cpu(power_tune_table_v2->usTemperatureLimitHBM); | |
428 | tdp_table->usTemperatureLimitVrVddc = | |
429 | le16_to_cpu(power_tune_table_v2->usTemperatureLimitVrSoc); | |
430 | tdp_table->usTemperatureLimitVrMvdd = | |
431 | le16_to_cpu(power_tune_table_v2->usTemperatureLimitVrMem); | |
432 | tdp_table->usTemperatureLimitPlx = | |
433 | le16_to_cpu(power_tune_table_v2->usTemperatureLimitPlx); | |
434 | tdp_table->ucLiquid1_I2C_address = power_tune_table_v2->ucLiquid1_I2C_address; | |
435 | tdp_table->ucLiquid2_I2C_address = power_tune_table_v2->ucLiquid2_I2C_address; | |
436 | ||
437 | get_scl_sda_value(power_tune_table_v2->ucLiquid_I2C_Line, &scl, &sda); | |
438 | ||
439 | tdp_table->ucLiquid_I2C_Line = scl; | |
440 | tdp_table->ucLiquid_I2C_LineSDA = sda; | |
441 | ||
442 | tdp_table->ucVr_I2C_address = power_tune_table_v2->ucVr_I2C_address; | |
443 | ||
444 | get_scl_sda_value(power_tune_table_v2->ucVr_I2C_Line, &scl, &sda); | |
445 | ||
446 | tdp_table->ucVr_I2C_Line = scl; | |
447 | tdp_table->ucVr_I2C_LineSDA = sda; | |
448 | tdp_table->ucPlx_I2C_address = power_tune_table_v2->ucPlx_I2C_address; | |
449 | ||
450 | get_scl_sda_value(power_tune_table_v2->ucPlx_I2C_Line, &scl, &sda); | |
451 | ||
452 | tdp_table->ucPlx_I2C_Line = scl; | |
453 | tdp_table->ucPlx_I2C_LineSDA = sda; | |
454 | ||
455 | hwmgr->platform_descriptor.LoadLineSlope = | |
456 | power_tune_table_v2->usLoadLineResistance; | |
457 | } | |
f83a9991 EH |
458 | |
459 | *info_tdp_table = tdp_table; | |
460 | ||
461 | return 0; | |
462 | } | |
463 | ||
464 | static int get_socclk_voltage_dependency_table( | |
465 | struct pp_hwmgr *hwmgr, | |
466 | phm_ppt_v1_clock_voltage_dependency_table **pp_vega10_clk_dep_table, | |
467 | const ATOM_Vega10_SOCCLK_Dependency_Table *clk_dep_table) | |
468 | { | |
469 | uint32_t table_size, i; | |
470 | phm_ppt_v1_clock_voltage_dependency_table *clk_table; | |
471 | ||
472 | PP_ASSERT_WITH_CODE(clk_dep_table->ucNumEntries, | |
473 | "Invalid PowerPlay Table!", return -1); | |
474 | ||
475 | table_size = sizeof(uint32_t) + | |
476 | sizeof(phm_ppt_v1_clock_voltage_dependency_record) * | |
477 | clk_dep_table->ucNumEntries; | |
478 | ||
479 | clk_table = (phm_ppt_v1_clock_voltage_dependency_table *) | |
480 | kzalloc(table_size, GFP_KERNEL); | |
481 | ||
482 | if (!clk_table) | |
483 | return -ENOMEM; | |
484 | ||
485 | clk_table->count = (uint32_t)clk_dep_table->ucNumEntries; | |
486 | ||
487 | for (i = 0; i < clk_dep_table->ucNumEntries; i++) { | |
488 | clk_table->entries[i].vddInd = | |
489 | clk_dep_table->entries[i].ucVddInd; | |
490 | clk_table->entries[i].clk = | |
491 | le32_to_cpu(clk_dep_table->entries[i].ulClk); | |
492 | } | |
493 | ||
494 | *pp_vega10_clk_dep_table = clk_table; | |
495 | ||
496 | return 0; | |
497 | } | |
498 | ||
499 | static int get_mclk_voltage_dependency_table( | |
500 | struct pp_hwmgr *hwmgr, | |
501 | phm_ppt_v1_clock_voltage_dependency_table **pp_vega10_mclk_dep_table, | |
502 | const ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table) | |
503 | { | |
504 | uint32_t table_size, i; | |
505 | phm_ppt_v1_clock_voltage_dependency_table *mclk_table; | |
506 | ||
507 | PP_ASSERT_WITH_CODE(mclk_dep_table->ucNumEntries, | |
508 | "Invalid PowerPlay Table!", return -1); | |
509 | ||
510 | table_size = sizeof(uint32_t) + | |
511 | sizeof(phm_ppt_v1_clock_voltage_dependency_record) * | |
512 | mclk_dep_table->ucNumEntries; | |
513 | ||
514 | mclk_table = (phm_ppt_v1_clock_voltage_dependency_table *) | |
515 | kzalloc(table_size, GFP_KERNEL); | |
516 | ||
517 | if (!mclk_table) | |
518 | return -ENOMEM; | |
519 | ||
520 | mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries; | |
521 | ||
522 | for (i = 0; i < mclk_dep_table->ucNumEntries; i++) { | |
523 | mclk_table->entries[i].vddInd = | |
524 | mclk_dep_table->entries[i].ucVddInd; | |
525 | mclk_table->entries[i].vddciInd = | |
526 | mclk_dep_table->entries[i].ucVddciInd; | |
527 | mclk_table->entries[i].mvddInd = | |
528 | mclk_dep_table->entries[i].ucVddMemInd; | |
529 | mclk_table->entries[i].clk = | |
530 | le32_to_cpu(mclk_dep_table->entries[i].ulMemClk); | |
531 | } | |
532 | ||
533 | *pp_vega10_mclk_dep_table = mclk_table; | |
534 | ||
535 | return 0; | |
536 | } | |
537 | ||
538 | static int get_gfxclk_voltage_dependency_table( | |
539 | struct pp_hwmgr *hwmgr, | |
540 | struct phm_ppt_v1_clock_voltage_dependency_table | |
541 | **pp_vega10_clk_dep_table, | |
542 | const ATOM_Vega10_GFXCLK_Dependency_Table *clk_dep_table) | |
543 | { | |
544 | uint32_t table_size, i; | |
545 | struct phm_ppt_v1_clock_voltage_dependency_table | |
546 | *clk_table; | |
547 | ||
548 | PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0), | |
549 | "Invalid PowerPlay Table!", return -1); | |
550 | ||
551 | table_size = sizeof(uint32_t) + | |
552 | sizeof(phm_ppt_v1_clock_voltage_dependency_record) * | |
553 | clk_dep_table->ucNumEntries; | |
554 | ||
555 | clk_table = (struct phm_ppt_v1_clock_voltage_dependency_table *) | |
556 | kzalloc(table_size, GFP_KERNEL); | |
557 | ||
558 | if (!clk_table) | |
559 | return -ENOMEM; | |
560 | ||
561 | clk_table->count = clk_dep_table->ucNumEntries; | |
562 | ||
563 | for (i = 0; i < clk_table->count; i++) { | |
564 | clk_table->entries[i].vddInd = | |
565 | clk_dep_table->entries[i].ucVddInd; | |
566 | clk_table->entries[i].clk = | |
567 | le32_to_cpu(clk_dep_table->entries[i].ulClk); | |
568 | clk_table->entries[i].cks_enable = | |
569 | (((clk_dep_table->entries[i].usCKSVOffsetandDisable & 0x80) | |
570 | >> 15) == 0) ? 1 : 0; | |
571 | clk_table->entries[i].cks_voffset = | |
572 | (clk_dep_table->entries[i].usCKSVOffsetandDisable & 0x7F); | |
573 | clk_table->entries[i].sclk_offset = | |
574 | clk_dep_table->entries[i].usAVFSOffset; | |
575 | } | |
576 | ||
577 | *pp_vega10_clk_dep_table = clk_table; | |
578 | ||
579 | return 0; | |
580 | } | |
581 | ||
582 | static int get_dcefclk_voltage_dependency_table( | |
583 | struct pp_hwmgr *hwmgr, | |
584 | struct phm_ppt_v1_clock_voltage_dependency_table | |
585 | **pp_vega10_clk_dep_table, | |
586 | const ATOM_Vega10_DCEFCLK_Dependency_Table *clk_dep_table) | |
587 | { | |
588 | uint32_t table_size, i; | |
589 | struct phm_ppt_v1_clock_voltage_dependency_table | |
590 | *clk_table; | |
591 | ||
592 | PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0), | |
593 | "Invalid PowerPlay Table!", return -1); | |
594 | ||
595 | table_size = sizeof(uint32_t) + | |
596 | sizeof(phm_ppt_v1_clock_voltage_dependency_record) * | |
597 | clk_dep_table->ucNumEntries; | |
598 | ||
599 | clk_table = (struct phm_ppt_v1_clock_voltage_dependency_table *) | |
600 | kzalloc(table_size, GFP_KERNEL); | |
601 | ||
602 | if (!clk_table) | |
603 | return -ENOMEM; | |
604 | ||
605 | clk_table->count = clk_dep_table->ucNumEntries; | |
606 | ||
607 | for (i = 0; i < clk_table->count; i++) { | |
608 | clk_table->entries[i].vddInd = | |
609 | clk_dep_table->entries[i].ucVddInd; | |
610 | clk_table->entries[i].clk = | |
611 | le32_to_cpu(clk_dep_table->entries[i].ulClk); | |
612 | } | |
613 | ||
614 | *pp_vega10_clk_dep_table = clk_table; | |
615 | ||
616 | return 0; | |
617 | } | |
618 | ||
619 | static int get_pcie_table(struct pp_hwmgr *hwmgr, | |
620 | struct phm_ppt_v1_pcie_table **vega10_pcie_table, | |
621 | const Vega10_PPTable_Generic_SubTable_Header *table) | |
622 | { | |
623 | uint32_t table_size, i, pcie_count; | |
624 | struct phm_ppt_v1_pcie_table *pcie_table; | |
625 | struct phm_ppt_v2_information *table_info = | |
626 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | |
627 | const ATOM_Vega10_PCIE_Table *atom_pcie_table = | |
628 | (ATOM_Vega10_PCIE_Table *)table; | |
629 | ||
630 | PP_ASSERT_WITH_CODE(atom_pcie_table->ucNumEntries, | |
631 | "Invalid PowerPlay Table!", | |
632 | return 0); | |
633 | ||
634 | table_size = sizeof(uint32_t) + | |
635 | sizeof(struct phm_ppt_v1_pcie_record) * | |
636 | atom_pcie_table->ucNumEntries; | |
637 | ||
638 | pcie_table = (struct phm_ppt_v1_pcie_table *) | |
639 | kzalloc(table_size, GFP_KERNEL); | |
640 | ||
641 | if (!pcie_table) | |
642 | return -ENOMEM; | |
643 | ||
644 | pcie_count = table_info->vdd_dep_on_sclk->count; | |
645 | if (atom_pcie_table->ucNumEntries <= pcie_count) | |
646 | pcie_count = atom_pcie_table->ucNumEntries; | |
647 | else | |
648 | pr_info("Number of Pcie Entries exceed the number of" | |
649 | " GFXCLK Dpm Levels!" | |
650 | " Disregarding the excess entries...\n"); | |
651 | ||
652 | pcie_table->count = pcie_count; | |
653 | ||
654 | for (i = 0; i < pcie_count; i++) { | |
655 | pcie_table->entries[i].gen_speed = | |
656 | atom_pcie_table->entries[i].ucPCIEGenSpeed; | |
657 | pcie_table->entries[i].lane_width = | |
658 | atom_pcie_table->entries[i].ucPCIELaneWidth; | |
659 | pcie_table->entries[i].pcie_sclk = | |
660 | atom_pcie_table->entries[i].ulLCLK; | |
661 | } | |
662 | ||
663 | *vega10_pcie_table = pcie_table; | |
664 | ||
665 | return 0; | |
666 | } | |
667 | ||
668 | static int get_hard_limits( | |
669 | struct pp_hwmgr *hwmgr, | |
670 | struct phm_clock_and_voltage_limits *limits, | |
671 | const ATOM_Vega10_Hard_Limit_Table *limit_table) | |
672 | { | |
673 | PP_ASSERT_WITH_CODE(limit_table->ucNumEntries, | |
674 | "Invalid PowerPlay Table!", return -1); | |
675 | ||
676 | /* currently we always take entries[0] parameters */ | |
677 | limits->sclk = le32_to_cpu(limit_table->entries[0].ulSOCCLKLimit); | |
678 | limits->mclk = le32_to_cpu(limit_table->entries[0].ulMCLKLimit); | |
679 | limits->gfxclk = le32_to_cpu(limit_table->entries[0].ulGFXCLKLimit); | |
680 | limits->vddc = le16_to_cpu(limit_table->entries[0].usVddcLimit); | |
681 | limits->vddci = le16_to_cpu(limit_table->entries[0].usVddciLimit); | |
682 | limits->vddmem = le16_to_cpu(limit_table->entries[0].usVddMemLimit); | |
683 | ||
684 | return 0; | |
685 | } | |
686 | ||
687 | static int get_valid_clk( | |
688 | struct pp_hwmgr *hwmgr, | |
689 | struct phm_clock_array **clk_table, | |
690 | const phm_ppt_v1_clock_voltage_dependency_table *clk_volt_pp_table) | |
691 | { | |
692 | uint32_t table_size, i; | |
693 | struct phm_clock_array *table; | |
694 | ||
695 | PP_ASSERT_WITH_CODE(clk_volt_pp_table->count, | |
696 | "Invalid PowerPlay Table!", return -1); | |
697 | ||
698 | table_size = sizeof(uint32_t) + | |
699 | sizeof(uint32_t) * clk_volt_pp_table->count; | |
700 | ||
701 | table = kzalloc(table_size, GFP_KERNEL); | |
702 | ||
703 | if (!table) | |
704 | return -ENOMEM; | |
705 | ||
706 | table->count = (uint32_t)clk_volt_pp_table->count; | |
707 | ||
708 | for (i = 0; i < table->count; i++) | |
709 | table->values[i] = (uint32_t)clk_volt_pp_table->entries[i].clk; | |
710 | ||
711 | *clk_table = table; | |
712 | ||
713 | return 0; | |
714 | } | |
715 | ||
716 | static int init_powerplay_extended_tables( | |
717 | struct pp_hwmgr *hwmgr, | |
718 | const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) | |
719 | { | |
720 | int result = 0; | |
721 | struct phm_ppt_v2_information *pp_table_info = | |
722 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | |
723 | ||
724 | const ATOM_Vega10_MM_Dependency_Table *mm_dependency_table = | |
725 | (const ATOM_Vega10_MM_Dependency_Table *) | |
726 | (((unsigned long) powerplay_table) + | |
727 | le16_to_cpu(powerplay_table->usMMDependencyTableOffset)); | |
728 | const Vega10_PPTable_Generic_SubTable_Header *power_tune_table = | |
729 | (const Vega10_PPTable_Generic_SubTable_Header *) | |
730 | (((unsigned long) powerplay_table) + | |
731 | le16_to_cpu(powerplay_table->usPowerTuneTableOffset)); | |
732 | const ATOM_Vega10_SOCCLK_Dependency_Table *socclk_dep_table = | |
733 | (const ATOM_Vega10_SOCCLK_Dependency_Table *) | |
734 | (((unsigned long) powerplay_table) + | |
735 | le16_to_cpu(powerplay_table->usSocclkDependencyTableOffset)); | |
736 | const ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table = | |
737 | (const ATOM_Vega10_GFXCLK_Dependency_Table *) | |
738 | (((unsigned long) powerplay_table) + | |
739 | le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset)); | |
740 | const ATOM_Vega10_DCEFCLK_Dependency_Table *dcefclk_dep_table = | |
741 | (const ATOM_Vega10_DCEFCLK_Dependency_Table *) | |
742 | (((unsigned long) powerplay_table) + | |
743 | le16_to_cpu(powerplay_table->usDcefclkDependencyTableOffset)); | |
744 | const ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table = | |
745 | (const ATOM_Vega10_MCLK_Dependency_Table *) | |
746 | (((unsigned long) powerplay_table) + | |
747 | le16_to_cpu(powerplay_table->usMclkDependencyTableOffset)); | |
748 | const ATOM_Vega10_Hard_Limit_Table *hard_limits = | |
749 | (const ATOM_Vega10_Hard_Limit_Table *) | |
750 | (((unsigned long) powerplay_table) + | |
751 | le16_to_cpu(powerplay_table->usHardLimitTableOffset)); | |
752 | const Vega10_PPTable_Generic_SubTable_Header *pcie_table = | |
753 | (const Vega10_PPTable_Generic_SubTable_Header *) | |
754 | (((unsigned long) powerplay_table) + | |
755 | le16_to_cpu(powerplay_table->usPCIETableOffset)); | |
756 | const ATOM_Vega10_PIXCLK_Dependency_Table *pixclk_dep_table = | |
757 | (const ATOM_Vega10_PIXCLK_Dependency_Table *) | |
758 | (((unsigned long) powerplay_table) + | |
759 | le16_to_cpu(powerplay_table->usPixclkDependencyTableOffset)); | |
760 | const ATOM_Vega10_PHYCLK_Dependency_Table *phyclk_dep_table = | |
761 | (const ATOM_Vega10_PHYCLK_Dependency_Table *) | |
762 | (((unsigned long) powerplay_table) + | |
763 | le16_to_cpu(powerplay_table->usPhyClkDependencyTableOffset)); | |
764 | const ATOM_Vega10_DISPCLK_Dependency_Table *dispclk_dep_table = | |
765 | (const ATOM_Vega10_DISPCLK_Dependency_Table *) | |
766 | (((unsigned long) powerplay_table) + | |
767 | le16_to_cpu(powerplay_table->usDispClkDependencyTableOffset)); | |
768 | ||
769 | pp_table_info->vdd_dep_on_socclk = NULL; | |
770 | pp_table_info->vdd_dep_on_sclk = NULL; | |
771 | pp_table_info->vdd_dep_on_mclk = NULL; | |
772 | pp_table_info->vdd_dep_on_dcefclk = NULL; | |
773 | pp_table_info->mm_dep_table = NULL; | |
774 | pp_table_info->tdp_table = NULL; | |
775 | pp_table_info->vdd_dep_on_pixclk = NULL; | |
776 | pp_table_info->vdd_dep_on_phyclk = NULL; | |
777 | pp_table_info->vdd_dep_on_dispclk = NULL; | |
778 | ||
779 | if (powerplay_table->usMMDependencyTableOffset) | |
780 | result = get_mm_clock_voltage_table(hwmgr, | |
781 | &pp_table_info->mm_dep_table, | |
782 | mm_dependency_table); | |
783 | ||
784 | if (!result && powerplay_table->usPowerTuneTableOffset) | |
785 | result = get_tdp_table(hwmgr, | |
786 | &pp_table_info->tdp_table, | |
787 | power_tune_table); | |
788 | ||
789 | if (!result && powerplay_table->usSocclkDependencyTableOffset) | |
790 | result = get_socclk_voltage_dependency_table(hwmgr, | |
791 | &pp_table_info->vdd_dep_on_socclk, | |
792 | socclk_dep_table); | |
793 | ||
794 | if (!result && powerplay_table->usGfxclkDependencyTableOffset) | |
795 | result = get_gfxclk_voltage_dependency_table(hwmgr, | |
796 | &pp_table_info->vdd_dep_on_sclk, | |
797 | gfxclk_dep_table); | |
798 | ||
799 | if (!result && powerplay_table->usPixclkDependencyTableOffset) | |
800 | result = get_dcefclk_voltage_dependency_table(hwmgr, | |
801 | &pp_table_info->vdd_dep_on_pixclk, | |
802 | (const ATOM_Vega10_DCEFCLK_Dependency_Table*) | |
803 | pixclk_dep_table); | |
804 | ||
805 | if (!result && powerplay_table->usPhyClkDependencyTableOffset) | |
806 | result = get_dcefclk_voltage_dependency_table(hwmgr, | |
807 | &pp_table_info->vdd_dep_on_phyclk, | |
808 | (const ATOM_Vega10_DCEFCLK_Dependency_Table *) | |
809 | phyclk_dep_table); | |
810 | ||
811 | if (!result && powerplay_table->usDispClkDependencyTableOffset) | |
812 | result = get_dcefclk_voltage_dependency_table(hwmgr, | |
813 | &pp_table_info->vdd_dep_on_dispclk, | |
814 | (const ATOM_Vega10_DCEFCLK_Dependency_Table *) | |
815 | dispclk_dep_table); | |
816 | ||
817 | if (!result && powerplay_table->usDcefclkDependencyTableOffset) | |
818 | result = get_dcefclk_voltage_dependency_table(hwmgr, | |
819 | &pp_table_info->vdd_dep_on_dcefclk, | |
820 | dcefclk_dep_table); | |
821 | ||
822 | if (!result && powerplay_table->usMclkDependencyTableOffset) | |
823 | result = get_mclk_voltage_dependency_table(hwmgr, | |
824 | &pp_table_info->vdd_dep_on_mclk, | |
825 | mclk_dep_table); | |
826 | ||
827 | if (!result && powerplay_table->usPCIETableOffset) | |
828 | result = get_pcie_table(hwmgr, | |
829 | &pp_table_info->pcie_table, | |
830 | pcie_table); | |
831 | ||
832 | if (!result && powerplay_table->usHardLimitTableOffset) | |
833 | result = get_hard_limits(hwmgr, | |
834 | &pp_table_info->max_clock_voltage_on_dc, | |
835 | hard_limits); | |
836 | ||
837 | hwmgr->dyn_state.max_clock_voltage_on_dc.sclk = | |
838 | pp_table_info->max_clock_voltage_on_dc.sclk; | |
839 | hwmgr->dyn_state.max_clock_voltage_on_dc.mclk = | |
840 | pp_table_info->max_clock_voltage_on_dc.mclk; | |
841 | hwmgr->dyn_state.max_clock_voltage_on_dc.vddc = | |
842 | pp_table_info->max_clock_voltage_on_dc.vddc; | |
843 | hwmgr->dyn_state.max_clock_voltage_on_dc.vddci = | |
844 | pp_table_info->max_clock_voltage_on_dc.vddci; | |
845 | ||
846 | if (!result && | |
847 | pp_table_info->vdd_dep_on_socclk && | |
848 | pp_table_info->vdd_dep_on_socclk->count) | |
849 | result = get_valid_clk(hwmgr, | |
850 | &pp_table_info->valid_socclk_values, | |
851 | pp_table_info->vdd_dep_on_socclk); | |
852 | ||
853 | if (!result && | |
854 | pp_table_info->vdd_dep_on_sclk && | |
855 | pp_table_info->vdd_dep_on_sclk->count) | |
856 | result = get_valid_clk(hwmgr, | |
857 | &pp_table_info->valid_sclk_values, | |
858 | pp_table_info->vdd_dep_on_sclk); | |
859 | ||
860 | if (!result && | |
861 | pp_table_info->vdd_dep_on_dcefclk && | |
862 | pp_table_info->vdd_dep_on_dcefclk->count) | |
863 | result = get_valid_clk(hwmgr, | |
864 | &pp_table_info->valid_dcefclk_values, | |
865 | pp_table_info->vdd_dep_on_dcefclk); | |
866 | ||
867 | if (!result && | |
868 | pp_table_info->vdd_dep_on_mclk && | |
869 | pp_table_info->vdd_dep_on_mclk->count) | |
870 | result = get_valid_clk(hwmgr, | |
871 | &pp_table_info->valid_mclk_values, | |
872 | pp_table_info->vdd_dep_on_mclk); | |
873 | ||
874 | return result; | |
875 | } | |
876 | ||
877 | static int get_vddc_lookup_table( | |
878 | struct pp_hwmgr *hwmgr, | |
879 | phm_ppt_v1_voltage_lookup_table **lookup_table, | |
880 | const ATOM_Vega10_Voltage_Lookup_Table *vddc_lookup_pp_tables, | |
881 | uint32_t max_levels) | |
882 | { | |
883 | uint32_t table_size, i; | |
884 | phm_ppt_v1_voltage_lookup_table *table; | |
885 | ||
886 | PP_ASSERT_WITH_CODE((vddc_lookup_pp_tables->ucNumEntries != 0), | |
887 | "Invalid SOC_VDDD Lookup Table!", return 1); | |
888 | ||
889 | table_size = sizeof(uint32_t) + | |
890 | sizeof(phm_ppt_v1_voltage_lookup_record) * max_levels; | |
891 | ||
892 | table = (phm_ppt_v1_voltage_lookup_table *) | |
893 | kzalloc(table_size, GFP_KERNEL); | |
894 | ||
895 | if (NULL == table) | |
896 | return -ENOMEM; | |
897 | ||
898 | table->count = vddc_lookup_pp_tables->ucNumEntries; | |
899 | ||
900 | for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) | |
901 | table->entries[i].us_vdd = | |
902 | le16_to_cpu(vddc_lookup_pp_tables->entries[i].usVdd); | |
903 | ||
904 | *lookup_table = table; | |
905 | ||
906 | return 0; | |
907 | } | |
908 | ||
909 | static int init_dpm_2_parameters( | |
910 | struct pp_hwmgr *hwmgr, | |
911 | const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) | |
912 | { | |
913 | int result = 0; | |
914 | struct phm_ppt_v2_information *pp_table_info = | |
915 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | |
916 | uint32_t disable_power_control = 0; | |
917 | ||
918 | pp_table_info->us_ulv_voltage_offset = | |
919 | le16_to_cpu(powerplay_table->usUlvVoltageOffset); | |
920 | ||
921 | pp_table_info->us_ulv_smnclk_did = | |
922 | le16_to_cpu(powerplay_table->usUlvSmnclkDid); | |
923 | pp_table_info->us_ulv_mp1clk_did = | |
924 | le16_to_cpu(powerplay_table->usUlvMp1clkDid); | |
925 | pp_table_info->us_ulv_gfxclk_bypass = | |
926 | le16_to_cpu(powerplay_table->usUlvGfxclkBypass); | |
927 | pp_table_info->us_gfxclk_slew_rate = | |
928 | le16_to_cpu(powerplay_table->usGfxclkSlewRate); | |
929 | pp_table_info->uc_gfx_dpm_voltage_mode = | |
930 | le16_to_cpu(powerplay_table->ucGfxVoltageMode); | |
931 | pp_table_info->uc_soc_dpm_voltage_mode = | |
932 | le16_to_cpu(powerplay_table->ucSocVoltageMode); | |
933 | pp_table_info->uc_uclk_dpm_voltage_mode = | |
934 | le16_to_cpu(powerplay_table->ucUclkVoltageMode); | |
935 | pp_table_info->uc_uvd_dpm_voltage_mode = | |
936 | le16_to_cpu(powerplay_table->ucUvdVoltageMode); | |
937 | pp_table_info->uc_vce_dpm_voltage_mode = | |
938 | le16_to_cpu(powerplay_table->ucVceVoltageMode); | |
939 | pp_table_info->uc_mp0_dpm_voltage_mode = | |
940 | le16_to_cpu(powerplay_table->ucMp0VoltageMode); | |
941 | pp_table_info->uc_dcef_dpm_voltage_mode = | |
942 | le16_to_cpu(powerplay_table->ucDcefVoltageMode); | |
943 | ||
944 | pp_table_info->ppm_parameter_table = NULL; | |
945 | pp_table_info->vddc_lookup_table = NULL; | |
946 | pp_table_info->vddmem_lookup_table = NULL; | |
947 | pp_table_info->vddci_lookup_table = NULL; | |
948 | ||
949 | /* TDP limits */ | |
950 | hwmgr->platform_descriptor.TDPODLimit = | |
951 | le16_to_cpu(powerplay_table->usPowerControlLimit); | |
952 | hwmgr->platform_descriptor.TDPAdjustment = 0; | |
953 | hwmgr->platform_descriptor.VidAdjustment = 0; | |
954 | hwmgr->platform_descriptor.VidAdjustmentPolarity = 0; | |
955 | hwmgr->platform_descriptor.VidMinLimit = 0; | |
956 | hwmgr->platform_descriptor.VidMaxLimit = 1500000; | |
957 | hwmgr->platform_descriptor.VidStep = 6250; | |
958 | ||
959 | disable_power_control = 0; | |
960 | if (!disable_power_control) { | |
961 | /* enable TDP overdrive (PowerControl) feature as well if supported */ | |
962 | if (hwmgr->platform_descriptor.TDPODLimit) | |
963 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | |
964 | PHM_PlatformCaps_PowerControl); | |
965 | } | |
966 | ||
967 | if (powerplay_table->usVddcLookupTableOffset) { | |
968 | const ATOM_Vega10_Voltage_Lookup_Table *vddc_table = | |
969 | (ATOM_Vega10_Voltage_Lookup_Table *) | |
970 | (((unsigned long)powerplay_table) + | |
971 | le16_to_cpu(powerplay_table->usVddcLookupTableOffset)); | |
972 | result = get_vddc_lookup_table(hwmgr, | |
1e1eb6a8 | 973 | &pp_table_info->vddc_lookup_table, vddc_table, 8); |
f83a9991 EH |
974 | } |
975 | ||
976 | if (powerplay_table->usVddmemLookupTableOffset) { | |
977 | const ATOM_Vega10_Voltage_Lookup_Table *vdd_mem_table = | |
978 | (ATOM_Vega10_Voltage_Lookup_Table *) | |
979 | (((unsigned long)powerplay_table) + | |
980 | le16_to_cpu(powerplay_table->usVddmemLookupTableOffset)); | |
981 | result = get_vddc_lookup_table(hwmgr, | |
1e1eb6a8 | 982 | &pp_table_info->vddmem_lookup_table, vdd_mem_table, 4); |
f83a9991 EH |
983 | } |
984 | ||
985 | if (powerplay_table->usVddciLookupTableOffset) { | |
986 | const ATOM_Vega10_Voltage_Lookup_Table *vddci_table = | |
987 | (ATOM_Vega10_Voltage_Lookup_Table *) | |
988 | (((unsigned long)powerplay_table) + | |
989 | le16_to_cpu(powerplay_table->usVddciLookupTableOffset)); | |
990 | result = get_vddc_lookup_table(hwmgr, | |
1e1eb6a8 | 991 | &pp_table_info->vddci_lookup_table, vddci_table, 4); |
f83a9991 EH |
992 | } |
993 | ||
994 | return result; | |
995 | } | |
996 | ||
997 | int vega10_pp_tables_initialize(struct pp_hwmgr *hwmgr) | |
998 | { | |
999 | int result = 0; | |
1000 | const ATOM_Vega10_POWERPLAYTABLE *powerplay_table; | |
1001 | ||
1002 | hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v2_information), GFP_KERNEL); | |
1003 | ||
1004 | PP_ASSERT_WITH_CODE((NULL != hwmgr->pptable), | |
1005 | "Failed to allocate hwmgr->pptable!", return -ENOMEM); | |
1006 | ||
1007 | powerplay_table = get_powerplay_table(hwmgr); | |
1008 | ||
1009 | PP_ASSERT_WITH_CODE((NULL != powerplay_table), | |
1010 | "Missing PowerPlay Table!", return -1); | |
1011 | ||
1012 | result = check_powerplay_tables(hwmgr, powerplay_table); | |
1013 | ||
1014 | PP_ASSERT_WITH_CODE((result == 0), | |
1015 | "check_powerplay_tables failed", return result); | |
1016 | ||
1017 | result = set_platform_caps(hwmgr, | |
1018 | le32_to_cpu(powerplay_table->ulPlatformCaps)); | |
1019 | ||
1020 | PP_ASSERT_WITH_CODE((result == 0), | |
1021 | "set_platform_caps failed", return result); | |
1022 | ||
1023 | result = init_thermal_controller(hwmgr, powerplay_table); | |
1024 | ||
1025 | PP_ASSERT_WITH_CODE((result == 0), | |
1026 | "init_thermal_controller failed", return result); | |
1027 | ||
1028 | result = init_over_drive_limits(hwmgr, powerplay_table); | |
1029 | ||
1030 | PP_ASSERT_WITH_CODE((result == 0), | |
1031 | "init_over_drive_limits failed", return result); | |
1032 | ||
1033 | result = init_powerplay_extended_tables(hwmgr, powerplay_table); | |
1034 | ||
1035 | PP_ASSERT_WITH_CODE((result == 0), | |
1036 | "init_powerplay_extended_tables failed", return result); | |
1037 | ||
1038 | result = init_dpm_2_parameters(hwmgr, powerplay_table); | |
1039 | ||
1040 | PP_ASSERT_WITH_CODE((result == 0), | |
1041 | "init_dpm_2_parameters failed", return result); | |
1042 | ||
1043 | return result; | |
1044 | } | |
1045 | ||
1046 | static int vega10_pp_tables_uninitialize(struct pp_hwmgr *hwmgr) | |
1047 | { | |
1048 | int result = 0; | |
1049 | struct phm_ppt_v2_information *pp_table_info = | |
1050 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | |
1051 | ||
1052 | kfree(pp_table_info->vdd_dep_on_sclk); | |
1053 | pp_table_info->vdd_dep_on_sclk = NULL; | |
1054 | ||
1055 | kfree(pp_table_info->vdd_dep_on_mclk); | |
1056 | pp_table_info->vdd_dep_on_mclk = NULL; | |
1057 | ||
1058 | kfree(pp_table_info->valid_mclk_values); | |
1059 | pp_table_info->valid_mclk_values = NULL; | |
1060 | ||
1061 | kfree(pp_table_info->valid_sclk_values); | |
1062 | pp_table_info->valid_sclk_values = NULL; | |
1063 | ||
1064 | kfree(pp_table_info->vddc_lookup_table); | |
1065 | pp_table_info->vddc_lookup_table = NULL; | |
1066 | ||
1067 | kfree(pp_table_info->vddmem_lookup_table); | |
1068 | pp_table_info->vddmem_lookup_table = NULL; | |
1069 | ||
1070 | kfree(pp_table_info->vddci_lookup_table); | |
1071 | pp_table_info->vddci_lookup_table = NULL; | |
1072 | ||
1073 | kfree(pp_table_info->ppm_parameter_table); | |
1074 | pp_table_info->ppm_parameter_table = NULL; | |
1075 | ||
1076 | kfree(pp_table_info->mm_dep_table); | |
1077 | pp_table_info->mm_dep_table = NULL; | |
1078 | ||
1079 | kfree(pp_table_info->cac_dtp_table); | |
1080 | pp_table_info->cac_dtp_table = NULL; | |
1081 | ||
1082 | kfree(hwmgr->dyn_state.cac_dtp_table); | |
1083 | hwmgr->dyn_state.cac_dtp_table = NULL; | |
1084 | ||
1085 | kfree(pp_table_info->tdp_table); | |
1086 | pp_table_info->tdp_table = NULL; | |
1087 | ||
1088 | kfree(hwmgr->pptable); | |
1089 | hwmgr->pptable = NULL; | |
1090 | ||
1091 | return result; | |
1092 | } | |
1093 | ||
1094 | const struct pp_table_func vega10_pptable_funcs = { | |
1095 | .pptable_init = vega10_pp_tables_initialize, | |
1096 | .pptable_fini = vega10_pp_tables_uninitialize, | |
1097 | }; | |
1098 | ||
1099 | int vega10_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr) | |
1100 | { | |
1101 | const ATOM_Vega10_State_Array *state_arrays; | |
1102 | const ATOM_Vega10_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr); | |
1103 | ||
1104 | PP_ASSERT_WITH_CODE((NULL != pp_table), | |
1105 | "Missing PowerPlay Table!", return -1); | |
1106 | PP_ASSERT_WITH_CODE((pp_table->sHeader.format_revision >= | |
1107 | ATOM_Vega10_TABLE_REVISION_VEGA10), | |
1108 | "Incorrect PowerPlay table revision!", return -1); | |
1109 | ||
1110 | state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)pp_table) + | |
1111 | le16_to_cpu(pp_table->usStateArrayOffset)); | |
1112 | ||
1113 | return (uint32_t)(state_arrays->ucNumEntries); | |
1114 | } | |
1115 | ||
1116 | static uint32_t make_classification_flags(struct pp_hwmgr *hwmgr, | |
1117 | uint16_t classification, uint16_t classification2) | |
1118 | { | |
1119 | uint32_t result = 0; | |
1120 | ||
1121 | if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT) | |
1122 | result |= PP_StateClassificationFlag_Boot; | |
1123 | ||
1124 | if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL) | |
1125 | result |= PP_StateClassificationFlag_Thermal; | |
1126 | ||
1127 | if (classification & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE) | |
1128 | result |= PP_StateClassificationFlag_LimitedPowerSource; | |
1129 | ||
1130 | if (classification & ATOM_PPLIB_CLASSIFICATION_REST) | |
1131 | result |= PP_StateClassificationFlag_Rest; | |
1132 | ||
1133 | if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED) | |
1134 | result |= PP_StateClassificationFlag_Forced; | |
1135 | ||
1136 | if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI) | |
1137 | result |= PP_StateClassificationFlag_ACPI; | |
1138 | ||
1139 | if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2) | |
1140 | result |= PP_StateClassificationFlag_LimitedPowerSource_2; | |
1141 | ||
1142 | return result; | |
1143 | } | |
1144 | ||
1145 | int vega10_get_powerplay_table_entry(struct pp_hwmgr *hwmgr, | |
1146 | uint32_t entry_index, struct pp_power_state *power_state, | |
1147 | int (*call_back_func)(struct pp_hwmgr *, void *, | |
1148 | struct pp_power_state *, void *, uint32_t)) | |
1149 | { | |
1150 | int result = 0; | |
1151 | const ATOM_Vega10_State_Array *state_arrays; | |
1152 | const ATOM_Vega10_State *state_entry; | |
1153 | const ATOM_Vega10_POWERPLAYTABLE *pp_table = | |
1154 | get_powerplay_table(hwmgr); | |
1155 | ||
1156 | PP_ASSERT_WITH_CODE(pp_table, "Missing PowerPlay Table!", | |
1157 | return -1;); | |
1158 | power_state->classification.bios_index = entry_index; | |
1159 | ||
1160 | if (pp_table->sHeader.format_revision >= | |
1161 | ATOM_Vega10_TABLE_REVISION_VEGA10) { | |
1162 | state_arrays = (ATOM_Vega10_State_Array *) | |
1163 | (((unsigned long)pp_table) + | |
1164 | le16_to_cpu(pp_table->usStateArrayOffset)); | |
1165 | ||
1166 | PP_ASSERT_WITH_CODE(pp_table->usStateArrayOffset > 0, | |
1167 | "Invalid PowerPlay Table State Array Offset.", | |
1168 | return -1); | |
1169 | PP_ASSERT_WITH_CODE(state_arrays->ucNumEntries > 0, | |
1170 | "Invalid PowerPlay Table State Array.", | |
1171 | return -1); | |
1172 | PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries), | |
1173 | "Invalid PowerPlay Table State Array Entry.", | |
1174 | return -1); | |
1175 | ||
1176 | state_entry = &(state_arrays->states[entry_index]); | |
1177 | ||
1178 | result = call_back_func(hwmgr, (void *)state_entry, power_state, | |
1179 | (void *)pp_table, | |
1180 | make_classification_flags(hwmgr, | |
1181 | le16_to_cpu(state_entry->usClassification), | |
1182 | le16_to_cpu(state_entry->usClassification2))); | |
1183 | } | |
1184 | ||
1185 | if (!result && (power_state->classification.flags & | |
1186 | PP_StateClassificationFlag_Boot)) | |
1187 | result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(power_state->hardware)); | |
1188 | ||
1189 | return result; | |
1190 | } |