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