]>
Commit | Line | Data |
---|---|---|
c82baa28 | 1 | /* |
2 | * Copyright 2015 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 | */ | |
7bd55429 | 23 | #include "pp_debug.h" |
c82baa28 | 24 | #include <linux/module.h> |
25 | #include <linux/slab.h> | |
c82baa28 | 26 | |
e1aa5715 | 27 | #include "process_pptables_v1_0.h" |
c82baa28 | 28 | #include "ppatomctrl.h" |
29 | #include "atombios.h" | |
c82baa28 | 30 | #include "hwmgr.h" |
31 | #include "cgs_common.h" | |
e1aa5715 | 32 | #include "pptable_v1_0.h" |
c82baa28 | 33 | |
34 | /** | |
35 | * Private Function used during initialization. | |
36 | * @param hwmgr Pointer to the hardware manager. | |
37 | * @param setIt A flag indication if the capability should be set (TRUE) or reset (FALSE). | |
38 | * @param cap Which capability to set/reset. | |
39 | */ | |
40 | static void set_hw_cap(struct pp_hwmgr *hwmgr, bool setIt, enum phm_platform_caps cap) | |
41 | { | |
42 | if (setIt) | |
43 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap); | |
44 | else | |
45 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap); | |
46 | } | |
47 | ||
48 | ||
49 | /** | |
50 | * Private Function used during initialization. | |
51 | * @param hwmgr Pointer to the hardware manager. | |
52 | * @param powerplay_caps the bit array (from BIOS) of capability bits. | |
53 | * @exception the current implementation always returns 1. | |
54 | */ | |
55 | static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps) | |
56 | { | |
57 | PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE16____), | |
58 | "ATOM_PP_PLATFORM_CAP_ASPM_L1 is not supported!", continue); | |
59 | PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE64____), | |
60 | "ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY is not supported!", continue); | |
61 | PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE512____), | |
62 | "ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL is not supported!", continue); | |
63 | PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE1024____), | |
64 | "ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1 is not supported!", continue); | |
65 | PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE2048____), | |
66 | "ATOM_PP_PLATFORM_CAP_HTLINKCONTROL is not supported!", continue); | |
67 | ||
68 | set_hw_cap( | |
69 | hwmgr, | |
70 | 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_POWERPLAY), | |
71 | PHM_PlatformCaps_PowerPlaySupport | |
72 | ); | |
73 | ||
74 | set_hw_cap( | |
75 | hwmgr, | |
76 | 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_SBIOSPOWERSOURCE), | |
77 | PHM_PlatformCaps_BiosPowerSourceControl | |
78 | ); | |
79 | ||
80 | set_hw_cap( | |
81 | hwmgr, | |
82 | 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_HARDWAREDC), | |
83 | PHM_PlatformCaps_AutomaticDCTransition | |
84 | ); | |
85 | ||
86 | set_hw_cap( | |
87 | hwmgr, | |
88 | 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_MVDD_CONTROL), | |
89 | PHM_PlatformCaps_EnableMVDDControl | |
90 | ); | |
91 | ||
92 | set_hw_cap( | |
93 | hwmgr, | |
94 | 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDCI_CONTROL), | |
95 | PHM_PlatformCaps_ControlVDDCI | |
96 | ); | |
97 | ||
98 | set_hw_cap( | |
99 | hwmgr, | |
100 | 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDGFX_CONTROL), | |
101 | PHM_PlatformCaps_ControlVDDGFX | |
102 | ); | |
103 | ||
104 | set_hw_cap( | |
105 | hwmgr, | |
106 | 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_BACO), | |
107 | PHM_PlatformCaps_BACO | |
108 | ); | |
109 | ||
110 | set_hw_cap( | |
111 | hwmgr, | |
112 | 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_DISABLE_VOLTAGE_ISLAND), | |
113 | PHM_PlatformCaps_DisableVoltageIsland | |
114 | ); | |
115 | ||
116 | set_hw_cap( | |
117 | hwmgr, | |
118 | 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL), | |
119 | PHM_PlatformCaps_CombinePCCWithThermalSignal | |
120 | ); | |
121 | ||
122 | set_hw_cap( | |
123 | hwmgr, | |
124 | 0 != (powerplay_caps & ATOM_TONGA_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE), | |
125 | PHM_PlatformCaps_LoadPostProductionFirmware | |
126 | ); | |
127 | ||
128 | return 0; | |
129 | } | |
130 | ||
131 | /** | |
132 | * Private Function to get the PowerPlay Table Address. | |
133 | */ | |
f8a4c11b | 134 | static const void *get_powerplay_table(struct pp_hwmgr *hwmgr) |
c82baa28 | 135 | { |
136 | int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); | |
137 | ||
138 | u16 size; | |
139 | u8 frev, crev; | |
15510195 EH |
140 | void *table_address = (void *)hwmgr->soft_pp_table; |
141 | ||
142 | if (!table_address) { | |
143 | table_address = (ATOM_Tonga_POWERPLAYTABLE *) | |
144 | cgs_atom_get_data_table(hwmgr->device, | |
145 | index, &size, &frev, &crev); | |
146 | hwmgr->soft_pp_table = table_address; /*Cache the result in RAM.*/ | |
147 | hwmgr->soft_pp_table_size = size; | |
148 | } | |
c82baa28 | 149 | |
150 | return table_address; | |
151 | } | |
152 | ||
153 | static int get_vddc_lookup_table( | |
154 | struct pp_hwmgr *hwmgr, | |
155 | phm_ppt_v1_voltage_lookup_table **lookup_table, | |
519df8a6 RZ |
156 | const ATOM_Tonga_Voltage_Lookup_Table *vddc_lookup_pp_tables, |
157 | uint32_t max_levels | |
c82baa28 | 158 | ) |
159 | { | |
160 | uint32_t table_size, i; | |
161 | phm_ppt_v1_voltage_lookup_table *table; | |
519df8a6 RZ |
162 | phm_ppt_v1_voltage_lookup_record *record; |
163 | ATOM_Tonga_Voltage_Lookup_Record *atom_record; | |
c82baa28 | 164 | |
165 | PP_ASSERT_WITH_CODE((0 != vddc_lookup_pp_tables->ucNumEntries), | |
166 | "Invalid CAC Leakage PowerPlay Table!", return 1); | |
167 | ||
168 | table_size = sizeof(uint32_t) + | |
169 | sizeof(phm_ppt_v1_voltage_lookup_record) * max_levels; | |
170 | ||
5969a8c7 | 171 | table = kzalloc(table_size, GFP_KERNEL); |
c82baa28 | 172 | |
173 | if (NULL == table) | |
c15c8d70 | 174 | return -ENOMEM; |
c82baa28 | 175 | |
c82baa28 | 176 | table->count = vddc_lookup_pp_tables->ucNumEntries; |
177 | ||
178 | for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) { | |
519df8a6 RZ |
179 | record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( |
180 | phm_ppt_v1_voltage_lookup_record, | |
181 | entries, table, i); | |
182 | atom_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( | |
183 | ATOM_Tonga_Voltage_Lookup_Record, | |
184 | entries, vddc_lookup_pp_tables, i); | |
185 | record->us_calculated = 0; | |
186 | record->us_vdd = atom_record->usVdd; | |
187 | record->us_cac_low = atom_record->usCACLow; | |
188 | record->us_cac_mid = atom_record->usCACMid; | |
189 | record->us_cac_high = atom_record->usCACHigh; | |
c82baa28 | 190 | } |
191 | ||
192 | *lookup_table = table; | |
193 | ||
194 | return 0; | |
195 | } | |
196 | ||
197 | /** | |
198 | * Private Function used during initialization. | |
199 | * Initialize Platform Power Management Parameter table | |
200 | * @param hwmgr Pointer to the hardware manager. | |
201 | * @param atom_ppm_table Pointer to PPM table in VBIOS | |
202 | */ | |
203 | static int get_platform_power_management_table( | |
204 | struct pp_hwmgr *hwmgr, | |
205 | ATOM_Tonga_PPM_Table *atom_ppm_table) | |
206 | { | |
207 | struct phm_ppm_table *ptr = kzalloc(sizeof(ATOM_Tonga_PPM_Table), GFP_KERNEL); | |
208 | struct phm_ppt_v1_information *pp_table_information = | |
209 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | |
210 | ||
211 | if (NULL == ptr) | |
c15c8d70 | 212 | return -ENOMEM; |
c82baa28 | 213 | |
214 | ptr->ppm_design | |
215 | = atom_ppm_table->ucPpmDesign; | |
216 | ptr->cpu_core_number | |
217 | = atom_ppm_table->usCpuCoreNumber; | |
218 | ptr->platform_tdp | |
219 | = atom_ppm_table->ulPlatformTDP; | |
220 | ptr->small_ac_platform_tdp | |
221 | = atom_ppm_table->ulSmallACPlatformTDP; | |
222 | ptr->platform_tdc | |
223 | = atom_ppm_table->ulPlatformTDC; | |
224 | ptr->small_ac_platform_tdc | |
225 | = atom_ppm_table->ulSmallACPlatformTDC; | |
226 | ptr->apu_tdp | |
227 | = atom_ppm_table->ulApuTDP; | |
228 | ptr->dgpu_tdp | |
229 | = atom_ppm_table->ulDGpuTDP; | |
230 | ptr->dgpu_ulv_power | |
231 | = atom_ppm_table->ulDGpuUlvPower; | |
232 | ptr->tj_max | |
233 | = atom_ppm_table->ulTjmax; | |
234 | ||
235 | pp_table_information->ppm_parameter_table = ptr; | |
236 | ||
237 | return 0; | |
238 | } | |
239 | ||
240 | /** | |
241 | * Private Function used during initialization. | |
242 | * Initialize TDP limits for DPM2 | |
243 | * @param hwmgr Pointer to the hardware manager. | |
244 | * @param powerplay_table Pointer to the PowerPlay Table. | |
245 | */ | |
246 | static int init_dpm_2_parameters( | |
247 | struct pp_hwmgr *hwmgr, | |
248 | const ATOM_Tonga_POWERPLAYTABLE *powerplay_table | |
249 | ) | |
250 | { | |
251 | int result = 0; | |
252 | struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable); | |
253 | ATOM_Tonga_PPM_Table *atom_ppm_table; | |
254 | uint32_t disable_ppm = 0; | |
255 | uint32_t disable_power_control = 0; | |
256 | ||
257 | pp_table_information->us_ulv_voltage_offset = | |
258 | le16_to_cpu(powerplay_table->usUlvVoltageOffset); | |
259 | ||
260 | pp_table_information->ppm_parameter_table = NULL; | |
261 | pp_table_information->vddc_lookup_table = NULL; | |
262 | pp_table_information->vddgfx_lookup_table = NULL; | |
263 | /* TDP limits */ | |
264 | hwmgr->platform_descriptor.TDPODLimit = | |
265 | le16_to_cpu(powerplay_table->usPowerControlLimit); | |
266 | hwmgr->platform_descriptor.TDPAdjustment = 0; | |
267 | hwmgr->platform_descriptor.VidAdjustment = 0; | |
268 | hwmgr->platform_descriptor.VidAdjustmentPolarity = 0; | |
269 | hwmgr->platform_descriptor.VidMinLimit = 0; | |
270 | hwmgr->platform_descriptor.VidMaxLimit = 1500000; | |
271 | hwmgr->platform_descriptor.VidStep = 6250; | |
272 | ||
273 | disable_power_control = 0; | |
274 | if (0 == disable_power_control) { | |
275 | /* enable TDP overdrive (PowerControl) feature as well if supported */ | |
276 | if (hwmgr->platform_descriptor.TDPODLimit != 0) | |
277 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | |
278 | PHM_PlatformCaps_PowerControl); | |
279 | } | |
280 | ||
281 | if (0 != powerplay_table->usVddcLookupTableOffset) { | |
282 | const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable = | |
283 | (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) + | |
284 | le16_to_cpu(powerplay_table->usVddcLookupTableOffset)); | |
285 | ||
286 | result = get_vddc_lookup_table(hwmgr, | |
287 | &pp_table_information->vddc_lookup_table, pVddcCACTable, 16); | |
288 | } | |
289 | ||
290 | if (0 != powerplay_table->usVddgfxLookupTableOffset) { | |
291 | const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable = | |
292 | (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) + | |
293 | le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset)); | |
294 | ||
295 | result = get_vddc_lookup_table(hwmgr, | |
296 | &pp_table_information->vddgfx_lookup_table, pVddgfxCACTable, 16); | |
297 | } | |
298 | ||
299 | disable_ppm = 0; | |
300 | if (0 == disable_ppm) { | |
301 | atom_ppm_table = (ATOM_Tonga_PPM_Table *) | |
302 | (((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usPPMTableOffset)); | |
303 | ||
304 | if (0 != powerplay_table->usPPMTableOffset) { | |
4b242760 | 305 | if (get_platform_power_management_table(hwmgr, atom_ppm_table) == 0) { |
c82baa28 | 306 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, |
307 | PHM_PlatformCaps_EnablePlatformPowerManagement); | |
308 | } | |
309 | } | |
310 | } | |
311 | ||
312 | return result; | |
313 | } | |
314 | ||
315 | static int get_valid_clk( | |
316 | struct pp_hwmgr *hwmgr, | |
317 | struct phm_clock_array **clk_table, | |
519df8a6 | 318 | phm_ppt_v1_clock_voltage_dependency_table const *clk_volt_pp_table |
c82baa28 | 319 | ) |
320 | { | |
321 | uint32_t table_size, i; | |
322 | struct phm_clock_array *table; | |
519df8a6 | 323 | phm_ppt_v1_clock_voltage_dependency_record *dep_record; |
c82baa28 | 324 | |
325 | PP_ASSERT_WITH_CODE((0 != clk_volt_pp_table->count), | |
326 | "Invalid PowerPlay Table!", return -1); | |
327 | ||
328 | table_size = sizeof(uint32_t) + | |
329 | sizeof(uint32_t) * clk_volt_pp_table->count; | |
330 | ||
5969a8c7 | 331 | table = kzalloc(table_size, GFP_KERNEL); |
c82baa28 | 332 | |
333 | if (NULL == table) | |
c15c8d70 | 334 | return -ENOMEM; |
c82baa28 | 335 | |
c82baa28 | 336 | table->count = (uint32_t)clk_volt_pp_table->count; |
337 | ||
519df8a6 RZ |
338 | for (i = 0; i < table->count; i++) { |
339 | dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( | |
340 | phm_ppt_v1_clock_voltage_dependency_record, | |
341 | entries, clk_volt_pp_table, i); | |
342 | table->values[i] = (uint32_t)dep_record->clk; | |
343 | } | |
c82baa28 | 344 | *clk_table = table; |
345 | ||
346 | return 0; | |
347 | } | |
348 | ||
349 | static int get_hard_limits( | |
350 | struct pp_hwmgr *hwmgr, | |
351 | struct phm_clock_and_voltage_limits *limits, | |
519df8a6 | 352 | ATOM_Tonga_Hard_Limit_Table const *limitable |
c82baa28 | 353 | ) |
354 | { | |
355 | PP_ASSERT_WITH_CODE((0 != limitable->ucNumEntries), "Invalid PowerPlay Table!", return -1); | |
356 | ||
357 | /* currently we always take entries[0] parameters */ | |
358 | limits->sclk = (uint32_t)limitable->entries[0].ulSCLKLimit; | |
359 | limits->mclk = (uint32_t)limitable->entries[0].ulMCLKLimit; | |
360 | limits->vddc = (uint16_t)limitable->entries[0].usVddcLimit; | |
361 | limits->vddci = (uint16_t)limitable->entries[0].usVddciLimit; | |
362 | limits->vddgfx = (uint16_t)limitable->entries[0].usVddgfxLimit; | |
363 | ||
364 | return 0; | |
365 | } | |
366 | ||
367 | static int get_mclk_voltage_dependency_table( | |
368 | struct pp_hwmgr *hwmgr, | |
369 | phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_mclk_dep_table, | |
519df8a6 | 370 | ATOM_Tonga_MCLK_Dependency_Table const *mclk_dep_table |
c82baa28 | 371 | ) |
372 | { | |
373 | uint32_t table_size, i; | |
374 | phm_ppt_v1_clock_voltage_dependency_table *mclk_table; | |
519df8a6 RZ |
375 | phm_ppt_v1_clock_voltage_dependency_record *mclk_table_record; |
376 | ATOM_Tonga_MCLK_Dependency_Record *mclk_dep_record; | |
c82baa28 | 377 | |
378 | PP_ASSERT_WITH_CODE((0 != mclk_dep_table->ucNumEntries), | |
379 | "Invalid PowerPlay Table!", return -1); | |
380 | ||
381 | table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record) | |
382 | * mclk_dep_table->ucNumEntries; | |
383 | ||
5969a8c7 | 384 | mclk_table = kzalloc(table_size, GFP_KERNEL); |
c82baa28 | 385 | |
386 | if (NULL == mclk_table) | |
c15c8d70 | 387 | return -ENOMEM; |
c82baa28 | 388 | |
c82baa28 | 389 | mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries; |
390 | ||
391 | for (i = 0; i < mclk_dep_table->ucNumEntries; i++) { | |
519df8a6 RZ |
392 | mclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( |
393 | phm_ppt_v1_clock_voltage_dependency_record, | |
394 | entries, mclk_table, i); | |
395 | mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( | |
396 | ATOM_Tonga_MCLK_Dependency_Record, | |
397 | entries, mclk_dep_table, i); | |
398 | mclk_table_record->vddInd = mclk_dep_record->ucVddcInd; | |
399 | mclk_table_record->vdd_offset = mclk_dep_record->usVddgfxOffset; | |
400 | mclk_table_record->vddci = mclk_dep_record->usVddci; | |
401 | mclk_table_record->mvdd = mclk_dep_record->usMvdd; | |
402 | mclk_table_record->clk = mclk_dep_record->ulMclk; | |
c82baa28 | 403 | } |
404 | ||
405 | *pp_tonga_mclk_dep_table = mclk_table; | |
406 | ||
407 | return 0; | |
408 | } | |
409 | ||
410 | static int get_sclk_voltage_dependency_table( | |
411 | struct pp_hwmgr *hwmgr, | |
412 | phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_sclk_dep_table, | |
e1aa5715 | 413 | PPTable_Generic_SubTable_Header const *sclk_dep_table |
c82baa28 | 414 | ) |
415 | { | |
416 | uint32_t table_size, i; | |
417 | phm_ppt_v1_clock_voltage_dependency_table *sclk_table; | |
519df8a6 | 418 | phm_ppt_v1_clock_voltage_dependency_record *sclk_table_record; |
c82baa28 | 419 | |
3ff21127 RZ |
420 | if (sclk_dep_table->ucRevId < 1) { |
421 | const ATOM_Tonga_SCLK_Dependency_Table *tonga_table = | |
422 | (ATOM_Tonga_SCLK_Dependency_Table *)sclk_dep_table; | |
519df8a6 | 423 | ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record; |
c82baa28 | 424 | |
3ff21127 RZ |
425 | PP_ASSERT_WITH_CODE((0 != tonga_table->ucNumEntries), |
426 | "Invalid PowerPlay Table!", return -1); | |
c82baa28 | 427 | |
3ff21127 RZ |
428 | table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record) |
429 | * tonga_table->ucNumEntries; | |
c82baa28 | 430 | |
5969a8c7 | 431 | sclk_table = kzalloc(table_size, GFP_KERNEL); |
c82baa28 | 432 | |
3ff21127 RZ |
433 | if (NULL == sclk_table) |
434 | return -ENOMEM; | |
435 | ||
3ff21127 RZ |
436 | sclk_table->count = (uint32_t)tonga_table->ucNumEntries; |
437 | ||
438 | for (i = 0; i < tonga_table->ucNumEntries; i++) { | |
519df8a6 RZ |
439 | sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( |
440 | ATOM_Tonga_SCLK_Dependency_Record, | |
441 | entries, tonga_table, i); | |
442 | sclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( | |
443 | phm_ppt_v1_clock_voltage_dependency_record, | |
444 | entries, sclk_table, i); | |
445 | sclk_table_record->vddInd = sclk_dep_record->ucVddInd; | |
446 | sclk_table_record->vdd_offset = sclk_dep_record->usVddcOffset; | |
447 | sclk_table_record->clk = sclk_dep_record->ulSclk; | |
448 | sclk_table_record->cks_enable = | |
449 | (((sclk_dep_record->ucCKSVOffsetandDisable & 0x80) >> 7) == 0) ? 1 : 0; | |
450 | sclk_table_record->cks_voffset = (sclk_dep_record->ucCKSVOffsetandDisable & 0x7F); | |
3ff21127 RZ |
451 | } |
452 | } else { | |
453 | const ATOM_Polaris_SCLK_Dependency_Table *polaris_table = | |
454 | (ATOM_Polaris_SCLK_Dependency_Table *)sclk_dep_table; | |
519df8a6 | 455 | ATOM_Polaris_SCLK_Dependency_Record *sclk_dep_record; |
c82baa28 | 456 | |
3ff21127 RZ |
457 | PP_ASSERT_WITH_CODE((0 != polaris_table->ucNumEntries), |
458 | "Invalid PowerPlay Table!", return -1); | |
459 | ||
460 | table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record) | |
461 | * polaris_table->ucNumEntries; | |
462 | ||
5969a8c7 | 463 | sclk_table = kzalloc(table_size, GFP_KERNEL); |
3ff21127 RZ |
464 | |
465 | if (NULL == sclk_table) | |
466 | return -ENOMEM; | |
467 | ||
3ff21127 RZ |
468 | sclk_table->count = (uint32_t)polaris_table->ucNumEntries; |
469 | ||
470 | for (i = 0; i < polaris_table->ucNumEntries; i++) { | |
519df8a6 RZ |
471 | sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( |
472 | ATOM_Polaris_SCLK_Dependency_Record, | |
473 | entries, polaris_table, i); | |
474 | sclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( | |
475 | phm_ppt_v1_clock_voltage_dependency_record, | |
476 | entries, sclk_table, i); | |
477 | sclk_table_record->vddInd = sclk_dep_record->ucVddInd; | |
478 | sclk_table_record->vdd_offset = sclk_dep_record->usVddcOffset; | |
479 | sclk_table_record->clk = sclk_dep_record->ulSclk; | |
480 | sclk_table_record->cks_enable = | |
481 | (((sclk_dep_record->ucCKSVOffsetandDisable & 0x80) >> 7) == 0) ? 1 : 0; | |
482 | sclk_table_record->cks_voffset = (sclk_dep_record->ucCKSVOffsetandDisable & 0x7F); | |
483 | sclk_table_record->sclk_offset = sclk_dep_record->ulSclkOffset; | |
3ff21127 RZ |
484 | } |
485 | } | |
c82baa28 | 486 | *pp_tonga_sclk_dep_table = sclk_table; |
487 | ||
488 | return 0; | |
489 | } | |
490 | ||
491 | static int get_pcie_table( | |
492 | struct pp_hwmgr *hwmgr, | |
493 | phm_ppt_v1_pcie_table **pp_tonga_pcie_table, | |
519df8a6 | 494 | PPTable_Generic_SubTable_Header const *ptable |
c82baa28 | 495 | ) |
496 | { | |
497 | uint32_t table_size, i, pcie_count; | |
498 | phm_ppt_v1_pcie_table *pcie_table; | |
499 | struct phm_ppt_v1_information *pp_table_information = | |
500 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | |
519df8a6 RZ |
501 | phm_ppt_v1_pcie_record *pcie_record; |
502 | ||
503 | if (ptable->ucRevId < 1) { | |
504 | const ATOM_Tonga_PCIE_Table *atom_pcie_table = (ATOM_Tonga_PCIE_Table *)ptable; | |
505 | ATOM_Tonga_PCIE_Record *atom_pcie_record; | |
c82baa28 | 506 | |
e85c7d66 | 507 | PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0), |
508 | "Invalid PowerPlay Table!", return -1); | |
c82baa28 | 509 | |
e85c7d66 | 510 | table_size = sizeof(uint32_t) + |
511 | sizeof(phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries; | |
c82baa28 | 512 | |
5969a8c7 | 513 | pcie_table = kzalloc(table_size, GFP_KERNEL); |
c82baa28 | 514 | |
e85c7d66 | 515 | if (pcie_table == NULL) |
516 | return -ENOMEM; | |
c82baa28 | 517 | |
e85c7d66 | 518 | /* |
519 | * Make sure the number of pcie entries are less than or equal to sclk dpm levels. | |
520 | * Since first PCIE entry is for ULV, #pcie has to be <= SclkLevel + 1. | |
521 | */ | |
522 | pcie_count = (pp_table_information->vdd_dep_on_sclk->count) + 1; | |
523 | if ((uint32_t)atom_pcie_table->ucNumEntries <= pcie_count) | |
524 | pcie_count = (uint32_t)atom_pcie_table->ucNumEntries; | |
525 | else | |
b5c11b8e | 526 | pr_err("Number of Pcie Entries exceed the number of SCLK Dpm Levels! \ |
e85c7d66 | 527 | Disregarding the excess entries... \n"); |
c82baa28 | 528 | |
e85c7d66 | 529 | pcie_table->count = pcie_count; |
e85c7d66 | 530 | for (i = 0; i < pcie_count; i++) { |
519df8a6 RZ |
531 | pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( |
532 | phm_ppt_v1_pcie_record, | |
533 | entries, pcie_table, i); | |
534 | atom_pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( | |
535 | ATOM_Tonga_PCIE_Record, | |
536 | entries, atom_pcie_table, i); | |
537 | pcie_record->gen_speed = atom_pcie_record->ucPCIEGenSpeed; | |
538 | pcie_record->lane_width = atom_pcie_record->usPCIELaneWidth; | |
e85c7d66 | 539 | } |
540 | ||
541 | *pp_tonga_pcie_table = pcie_table; | |
542 | } else { | |
2cc0c0b5 | 543 | /* Polaris10/Polaris11 and newer. */ |
519df8a6 RZ |
544 | const ATOM_Polaris10_PCIE_Table *atom_pcie_table = (ATOM_Polaris10_PCIE_Table *)ptable; |
545 | ATOM_Polaris10_PCIE_Record *atom_pcie_record; | |
546 | ||
e85c7d66 | 547 | PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0), |
548 | "Invalid PowerPlay Table!", return -1); | |
549 | ||
550 | table_size = sizeof(uint32_t) + | |
551 | sizeof(phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries; | |
552 | ||
5969a8c7 | 553 | pcie_table = kzalloc(table_size, GFP_KERNEL); |
e85c7d66 | 554 | |
555 | if (pcie_table == NULL) | |
556 | return -ENOMEM; | |
557 | ||
e85c7d66 | 558 | /* |
559 | * Make sure the number of pcie entries are less than or equal to sclk dpm levels. | |
560 | * Since first PCIE entry is for ULV, #pcie has to be <= SclkLevel + 1. | |
561 | */ | |
562 | pcie_count = (pp_table_information->vdd_dep_on_sclk->count) + 1; | |
563 | if ((uint32_t)atom_pcie_table->ucNumEntries <= pcie_count) | |
564 | pcie_count = (uint32_t)atom_pcie_table->ucNumEntries; | |
565 | else | |
b5c11b8e | 566 | pr_err("Number of Pcie Entries exceed the number of SCLK Dpm Levels! \ |
e85c7d66 | 567 | Disregarding the excess entries... \n"); |
568 | ||
569 | pcie_table->count = pcie_count; | |
570 | ||
571 | for (i = 0; i < pcie_count; i++) { | |
519df8a6 RZ |
572 | pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( |
573 | phm_ppt_v1_pcie_record, | |
574 | entries, pcie_table, i); | |
575 | atom_pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( | |
576 | ATOM_Polaris10_PCIE_Record, | |
577 | entries, atom_pcie_table, i); | |
578 | pcie_record->gen_speed = atom_pcie_record->ucPCIEGenSpeed; | |
579 | pcie_record->lane_width = atom_pcie_record->usPCIELaneWidth; | |
580 | pcie_record->pcie_sclk = atom_pcie_record->ulPCIE_Sclk; | |
e85c7d66 | 581 | } |
582 | ||
583 | *pp_tonga_pcie_table = pcie_table; | |
584 | } | |
c82baa28 | 585 | |
586 | return 0; | |
587 | } | |
588 | ||
589 | static int get_cac_tdp_table( | |
590 | struct pp_hwmgr *hwmgr, | |
591 | struct phm_cac_tdp_table **cac_tdp_table, | |
592 | const PPTable_Generic_SubTable_Header * table | |
593 | ) | |
594 | { | |
595 | uint32_t table_size; | |
596 | struct phm_cac_tdp_table *tdp_table; | |
597 | ||
598 | table_size = sizeof(uint32_t) + sizeof(struct phm_cac_tdp_table); | |
599 | tdp_table = kzalloc(table_size, GFP_KERNEL); | |
600 | ||
601 | if (NULL == tdp_table) | |
c15c8d70 | 602 | return -ENOMEM; |
c82baa28 | 603 | |
c82baa28 | 604 | hwmgr->dyn_state.cac_dtp_table = kzalloc(table_size, GFP_KERNEL); |
605 | ||
a82d397b CIK |
606 | if (NULL == hwmgr->dyn_state.cac_dtp_table) { |
607 | kfree(tdp_table); | |
c15c8d70 | 608 | return -ENOMEM; |
a82d397b | 609 | } |
c82baa28 | 610 | |
c82baa28 | 611 | if (table->ucRevId < 3) { |
612 | const ATOM_Tonga_PowerTune_Table *tonga_table = | |
613 | (ATOM_Tonga_PowerTune_Table *)table; | |
614 | tdp_table->usTDP = tonga_table->usTDP; | |
615 | tdp_table->usConfigurableTDP = | |
616 | tonga_table->usConfigurableTDP; | |
617 | tdp_table->usTDC = tonga_table->usTDC; | |
618 | tdp_table->usBatteryPowerLimit = | |
619 | tonga_table->usBatteryPowerLimit; | |
620 | tdp_table->usSmallPowerLimit = | |
621 | tonga_table->usSmallPowerLimit; | |
622 | tdp_table->usLowCACLeakage = | |
623 | tonga_table->usLowCACLeakage; | |
624 | tdp_table->usHighCACLeakage = | |
625 | tonga_table->usHighCACLeakage; | |
626 | tdp_table->usMaximumPowerDeliveryLimit = | |
627 | tonga_table->usMaximumPowerDeliveryLimit; | |
628 | tdp_table->usDefaultTargetOperatingTemp = | |
629 | tonga_table->usTjMax; | |
630 | tdp_table->usTargetOperatingTemp = | |
631 | tonga_table->usTjMax; /*Set the initial temp to the same as default */ | |
632 | tdp_table->usPowerTuneDataSetID = | |
633 | tonga_table->usPowerTuneDataSetID; | |
634 | tdp_table->usSoftwareShutdownTemp = | |
635 | tonga_table->usSoftwareShutdownTemp; | |
636 | tdp_table->usClockStretchAmount = | |
637 | tonga_table->usClockStretchAmount; | |
638 | } else { /* Fiji and newer */ | |
639 | const ATOM_Fiji_PowerTune_Table *fijitable = | |
640 | (ATOM_Fiji_PowerTune_Table *)table; | |
641 | tdp_table->usTDP = fijitable->usTDP; | |
642 | tdp_table->usConfigurableTDP = fijitable->usConfigurableTDP; | |
643 | tdp_table->usTDC = fijitable->usTDC; | |
644 | tdp_table->usBatteryPowerLimit = fijitable->usBatteryPowerLimit; | |
645 | tdp_table->usSmallPowerLimit = fijitable->usSmallPowerLimit; | |
646 | tdp_table->usLowCACLeakage = fijitable->usLowCACLeakage; | |
647 | tdp_table->usHighCACLeakage = fijitable->usHighCACLeakage; | |
648 | tdp_table->usMaximumPowerDeliveryLimit = | |
649 | fijitable->usMaximumPowerDeliveryLimit; | |
650 | tdp_table->usDefaultTargetOperatingTemp = | |
651 | fijitable->usTjMax; | |
652 | tdp_table->usTargetOperatingTemp = | |
653 | fijitable->usTjMax; /*Set the initial temp to the same as default */ | |
654 | tdp_table->usPowerTuneDataSetID = | |
655 | fijitable->usPowerTuneDataSetID; | |
656 | tdp_table->usSoftwareShutdownTemp = | |
657 | fijitable->usSoftwareShutdownTemp; | |
658 | tdp_table->usClockStretchAmount = | |
659 | fijitable->usClockStretchAmount; | |
660 | tdp_table->usTemperatureLimitHotspot = | |
661 | fijitable->usTemperatureLimitHotspot; | |
662 | tdp_table->usTemperatureLimitLiquid1 = | |
663 | fijitable->usTemperatureLimitLiquid1; | |
664 | tdp_table->usTemperatureLimitLiquid2 = | |
665 | fijitable->usTemperatureLimitLiquid2; | |
666 | tdp_table->usTemperatureLimitVrVddc = | |
667 | fijitable->usTemperatureLimitVrVddc; | |
668 | tdp_table->usTemperatureLimitVrMvdd = | |
669 | fijitable->usTemperatureLimitVrMvdd; | |
670 | tdp_table->usTemperatureLimitPlx = | |
671 | fijitable->usTemperatureLimitPlx; | |
672 | tdp_table->ucLiquid1_I2C_address = | |
673 | fijitable->ucLiquid1_I2C_address; | |
674 | tdp_table->ucLiquid2_I2C_address = | |
675 | fijitable->ucLiquid2_I2C_address; | |
676 | tdp_table->ucLiquid_I2C_Line = | |
677 | fijitable->ucLiquid_I2C_Line; | |
678 | tdp_table->ucVr_I2C_address = fijitable->ucVr_I2C_address; | |
679 | tdp_table->ucVr_I2C_Line = fijitable->ucVr_I2C_Line; | |
680 | tdp_table->ucPlx_I2C_address = fijitable->ucPlx_I2C_address; | |
681 | tdp_table->ucPlx_I2C_Line = fijitable->ucPlx_I2C_Line; | |
682 | } | |
683 | ||
684 | *cac_tdp_table = tdp_table; | |
685 | ||
686 | return 0; | |
687 | } | |
688 | ||
689 | static int get_mm_clock_voltage_table( | |
690 | struct pp_hwmgr *hwmgr, | |
691 | phm_ppt_v1_mm_clock_voltage_dependency_table **tonga_mm_table, | |
692 | const ATOM_Tonga_MM_Dependency_Table * mm_dependency_table | |
693 | ) | |
694 | { | |
695 | uint32_t table_size, i; | |
696 | const ATOM_Tonga_MM_Dependency_Record *mm_dependency_record; | |
697 | phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table; | |
519df8a6 | 698 | phm_ppt_v1_mm_clock_voltage_dependency_record *mm_table_record; |
c82baa28 | 699 | |
700 | PP_ASSERT_WITH_CODE((0 != mm_dependency_table->ucNumEntries), | |
701 | "Invalid PowerPlay Table!", return -1); | |
702 | table_size = sizeof(uint32_t) + | |
703 | sizeof(phm_ppt_v1_mm_clock_voltage_dependency_record) | |
704 | * mm_dependency_table->ucNumEntries; | |
5969a8c7 | 705 | mm_table = kzalloc(table_size, GFP_KERNEL); |
c82baa28 | 706 | |
707 | if (NULL == mm_table) | |
c15c8d70 | 708 | return -ENOMEM; |
c82baa28 | 709 | |
c82baa28 | 710 | mm_table->count = mm_dependency_table->ucNumEntries; |
711 | ||
712 | for (i = 0; i < mm_dependency_table->ucNumEntries; i++) { | |
519df8a6 RZ |
713 | mm_dependency_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( |
714 | ATOM_Tonga_MM_Dependency_Record, | |
715 | entries, mm_dependency_table, i); | |
716 | mm_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( | |
717 | phm_ppt_v1_mm_clock_voltage_dependency_record, | |
718 | entries, mm_table, i); | |
719 | mm_table_record->vddcInd = mm_dependency_record->ucVddcInd; | |
720 | mm_table_record->vddgfx_offset = mm_dependency_record->usVddgfxOffset; | |
721 | mm_table_record->aclk = mm_dependency_record->ulAClk; | |
722 | mm_table_record->samclock = mm_dependency_record->ulSAMUClk; | |
723 | mm_table_record->eclk = mm_dependency_record->ulEClk; | |
724 | mm_table_record->vclk = mm_dependency_record->ulVClk; | |
725 | mm_table_record->dclk = mm_dependency_record->ulDClk; | |
c82baa28 | 726 | } |
727 | ||
728 | *tonga_mm_table = mm_table; | |
729 | ||
730 | return 0; | |
731 | } | |
732 | ||
733 | /** | |
734 | * Private Function used during initialization. | |
735 | * Initialize clock voltage dependency | |
736 | * @param hwmgr Pointer to the hardware manager. | |
737 | * @param powerplay_table Pointer to the PowerPlay Table. | |
738 | */ | |
739 | static int init_clock_voltage_dependency( | |
740 | struct pp_hwmgr *hwmgr, | |
741 | const ATOM_Tonga_POWERPLAYTABLE *powerplay_table | |
742 | ) | |
743 | { | |
744 | int result = 0; | |
745 | struct phm_ppt_v1_information *pp_table_information = | |
746 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | |
747 | ||
748 | const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table = | |
749 | (const ATOM_Tonga_MM_Dependency_Table *)(((unsigned long) powerplay_table) + | |
750 | le16_to_cpu(powerplay_table->usMMDependencyTableOffset)); | |
751 | const PPTable_Generic_SubTable_Header *pPowerTuneTable = | |
752 | (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) + | |
753 | le16_to_cpu(powerplay_table->usPowerTuneTableOffset)); | |
754 | const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table = | |
755 | (const ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long) powerplay_table) + | |
756 | le16_to_cpu(powerplay_table->usMclkDependencyTableOffset)); | |
3ff21127 RZ |
757 | const PPTable_Generic_SubTable_Header *sclk_dep_table = |
758 | (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) + | |
c82baa28 | 759 | le16_to_cpu(powerplay_table->usSclkDependencyTableOffset)); |
760 | const ATOM_Tonga_Hard_Limit_Table *pHardLimits = | |
761 | (const ATOM_Tonga_Hard_Limit_Table *)(((unsigned long) powerplay_table) + | |
762 | le16_to_cpu(powerplay_table->usHardLimitTableOffset)); | |
e85c7d66 | 763 | const PPTable_Generic_SubTable_Header *pcie_table = |
764 | (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) + | |
c82baa28 | 765 | le16_to_cpu(powerplay_table->usPCIETableOffset)); |
766 | ||
767 | pp_table_information->vdd_dep_on_sclk = NULL; | |
768 | pp_table_information->vdd_dep_on_mclk = NULL; | |
769 | pp_table_information->mm_dep_table = NULL; | |
770 | pp_table_information->pcie_table = NULL; | |
771 | ||
772 | if (powerplay_table->usMMDependencyTableOffset != 0) | |
773 | result = get_mm_clock_voltage_table(hwmgr, | |
774 | &pp_table_information->mm_dep_table, mm_dependency_table); | |
775 | ||
776 | if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0) | |
777 | result = get_cac_tdp_table(hwmgr, | |
778 | &pp_table_information->cac_dtp_table, pPowerTuneTable); | |
779 | ||
780 | if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0) | |
781 | result = get_sclk_voltage_dependency_table(hwmgr, | |
782 | &pp_table_information->vdd_dep_on_sclk, sclk_dep_table); | |
783 | ||
784 | if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0) | |
785 | result = get_mclk_voltage_dependency_table(hwmgr, | |
786 | &pp_table_information->vdd_dep_on_mclk, mclk_dep_table); | |
787 | ||
788 | if (result == 0 && powerplay_table->usPCIETableOffset != 0) | |
789 | result = get_pcie_table(hwmgr, | |
790 | &pp_table_information->pcie_table, pcie_table); | |
791 | ||
792 | if (result == 0 && powerplay_table->usHardLimitTableOffset != 0) | |
793 | result = get_hard_limits(hwmgr, | |
794 | &pp_table_information->max_clock_voltage_on_dc, pHardLimits); | |
795 | ||
796 | hwmgr->dyn_state.max_clock_voltage_on_dc.sclk = | |
797 | pp_table_information->max_clock_voltage_on_dc.sclk; | |
798 | hwmgr->dyn_state.max_clock_voltage_on_dc.mclk = | |
799 | pp_table_information->max_clock_voltage_on_dc.mclk; | |
800 | hwmgr->dyn_state.max_clock_voltage_on_dc.vddc = | |
801 | pp_table_information->max_clock_voltage_on_dc.vddc; | |
802 | hwmgr->dyn_state.max_clock_voltage_on_dc.vddci = | |
803 | pp_table_information->max_clock_voltage_on_dc.vddci; | |
804 | ||
805 | if (result == 0 && (NULL != pp_table_information->vdd_dep_on_mclk) | |
806 | && (0 != pp_table_information->vdd_dep_on_mclk->count)) | |
807 | result = get_valid_clk(hwmgr, &pp_table_information->valid_mclk_values, | |
808 | pp_table_information->vdd_dep_on_mclk); | |
809 | ||
810 | if (result == 0 && (NULL != pp_table_information->vdd_dep_on_sclk) | |
811 | && (0 != pp_table_information->vdd_dep_on_sclk->count)) | |
812 | result = get_valid_clk(hwmgr, &pp_table_information->valid_sclk_values, | |
813 | pp_table_information->vdd_dep_on_sclk); | |
814 | ||
815 | return result; | |
816 | } | |
817 | ||
818 | /** Retrieves the (signed) Overdrive limits from VBIOS. | |
819 | * The max engine clock, memory clock and max temperature come from the firmware info table. | |
820 | * | |
821 | * The information is placed into the platform descriptor. | |
822 | * | |
823 | * @param hwmgr source of the VBIOS table and owner of the platform descriptor to be updated. | |
824 | * @param powerplay_table the address of the PowerPlay table. | |
825 | * | |
826 | * @return 1 as long as the firmware info table was present and of a supported version. | |
827 | */ | |
828 | static int init_over_drive_limits( | |
829 | struct pp_hwmgr *hwmgr, | |
830 | const ATOM_Tonga_POWERPLAYTABLE *powerplay_table) | |
831 | { | |
832 | hwmgr->platform_descriptor.overdriveLimit.engineClock = | |
8d8258bd | 833 | le32_to_cpu(powerplay_table->ulMaxODEngineClock); |
c82baa28 | 834 | hwmgr->platform_descriptor.overdriveLimit.memoryClock = |
8d8258bd | 835 | le32_to_cpu(powerplay_table->ulMaxODMemoryClock); |
c82baa28 | 836 | |
837 | hwmgr->platform_descriptor.minOverdriveVDDC = 0; | |
838 | hwmgr->platform_descriptor.maxOverdriveVDDC = 0; | |
839 | hwmgr->platform_descriptor.overdriveVDDCStep = 0; | |
840 | ||
841 | if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0 \ | |
842 | && hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0) { | |
843 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | |
844 | PHM_PlatformCaps_ACOverdriveSupport); | |
845 | } | |
846 | ||
847 | return 0; | |
848 | } | |
849 | ||
850 | /** | |
851 | * Private Function used during initialization. | |
852 | * Inspect the PowerPlay table for obvious signs of corruption. | |
853 | * @param hwmgr Pointer to the hardware manager. | |
854 | * @param powerplay_table Pointer to the PowerPlay Table. | |
855 | * @exception This implementation always returns 1. | |
856 | */ | |
857 | static int init_thermal_controller( | |
858 | struct pp_hwmgr *hwmgr, | |
859 | const ATOM_Tonga_POWERPLAYTABLE *powerplay_table | |
860 | ) | |
861 | { | |
862 | const PPTable_Generic_SubTable_Header *fan_table; | |
863 | ATOM_Tonga_Thermal_Controller *thermal_controller; | |
864 | ||
865 | thermal_controller = (ATOM_Tonga_Thermal_Controller *) | |
866 | (((unsigned long)powerplay_table) + | |
867 | le16_to_cpu(powerplay_table->usThermalControllerOffset)); | |
868 | PP_ASSERT_WITH_CODE((0 != powerplay_table->usThermalControllerOffset), | |
869 | "Thermal controller table not set!", return -1); | |
870 | ||
871 | hwmgr->thermal_controller.ucType = thermal_controller->ucType; | |
872 | hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine; | |
873 | hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress; | |
874 | ||
875 | hwmgr->thermal_controller.fanInfo.bNoFan = | |
876 | (0 != (thermal_controller->ucFanParameters & ATOM_TONGA_PP_FANPARAMETERS_NOFAN)); | |
877 | ||
878 | hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution = | |
879 | thermal_controller->ucFanParameters & | |
880 | ATOM_TONGA_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK; | |
881 | ||
882 | hwmgr->thermal_controller.fanInfo.ulMinRPM | |
883 | = thermal_controller->ucFanMinRPM * 100UL; | |
884 | hwmgr->thermal_controller.fanInfo.ulMaxRPM | |
885 | = thermal_controller->ucFanMaxRPM * 100UL; | |
886 | ||
887 | set_hw_cap( | |
888 | hwmgr, | |
889 | ATOM_TONGA_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType, | |
890 | PHM_PlatformCaps_ThermalController | |
891 | ); | |
892 | ||
893 | if (0 == powerplay_table->usFanTableOffset) | |
283b1a8b | 894 | return 0; |
c82baa28 | 895 | |
896 | fan_table = (const PPTable_Generic_SubTable_Header *) | |
897 | (((unsigned long)powerplay_table) + | |
898 | le16_to_cpu(powerplay_table->usFanTableOffset)); | |
899 | ||
900 | PP_ASSERT_WITH_CODE((0 != powerplay_table->usFanTableOffset), | |
901 | "Fan table not set!", return -1); | |
902 | PP_ASSERT_WITH_CODE((0 < fan_table->ucRevId), | |
903 | "Unsupported fan table format!", return -1); | |
904 | ||
905 | hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay | |
906 | = 100000; | |
907 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | |
908 | PHM_PlatformCaps_MicrocodeFanControl); | |
909 | ||
910 | if (fan_table->ucRevId < 8) { | |
911 | const ATOM_Tonga_Fan_Table *tonga_fan_table = | |
912 | (ATOM_Tonga_Fan_Table *)fan_table; | |
913 | hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst | |
914 | = tonga_fan_table->ucTHyst; | |
915 | hwmgr->thermal_controller.advanceFanControlParameters.usTMin | |
916 | = tonga_fan_table->usTMin; | |
917 | hwmgr->thermal_controller.advanceFanControlParameters.usTMed | |
918 | = tonga_fan_table->usTMed; | |
919 | hwmgr->thermal_controller.advanceFanControlParameters.usTHigh | |
920 | = tonga_fan_table->usTHigh; | |
921 | hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin | |
922 | = tonga_fan_table->usPWMMin; | |
923 | hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed | |
924 | = tonga_fan_table->usPWMMed; | |
925 | hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh | |
926 | = tonga_fan_table->usPWMHigh; | |
927 | hwmgr->thermal_controller.advanceFanControlParameters.usTMax | |
928 | = 10900; /* hard coded */ | |
929 | hwmgr->thermal_controller.advanceFanControlParameters.usTMax | |
930 | = tonga_fan_table->usTMax; | |
931 | hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode | |
932 | = tonga_fan_table->ucFanControlMode; | |
933 | hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM | |
934 | = tonga_fan_table->usFanPWMMax; | |
935 | hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity | |
936 | = 4836; | |
937 | hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity | |
938 | = tonga_fan_table->usFanOutputSensitivity; | |
939 | hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM | |
940 | = tonga_fan_table->usFanRPMMax; | |
941 | hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit | |
942 | = (tonga_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places. SMC wants MHz. */ | |
943 | hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature | |
944 | = tonga_fan_table->ucTargetTemperature; | |
945 | hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit | |
946 | = tonga_fan_table->ucMinimumPWMLimit; | |
947 | } else { | |
948 | const ATOM_Fiji_Fan_Table *fiji_fan_table = | |
949 | (ATOM_Fiji_Fan_Table *)fan_table; | |
950 | hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst | |
951 | = fiji_fan_table->ucTHyst; | |
952 | hwmgr->thermal_controller.advanceFanControlParameters.usTMin | |
953 | = fiji_fan_table->usTMin; | |
954 | hwmgr->thermal_controller.advanceFanControlParameters.usTMed | |
955 | = fiji_fan_table->usTMed; | |
956 | hwmgr->thermal_controller.advanceFanControlParameters.usTHigh | |
957 | = fiji_fan_table->usTHigh; | |
958 | hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin | |
959 | = fiji_fan_table->usPWMMin; | |
960 | hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed | |
961 | = fiji_fan_table->usPWMMed; | |
962 | hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh | |
963 | = fiji_fan_table->usPWMHigh; | |
964 | hwmgr->thermal_controller.advanceFanControlParameters.usTMax | |
965 | = fiji_fan_table->usTMax; | |
966 | hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode | |
967 | = fiji_fan_table->ucFanControlMode; | |
968 | hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM | |
969 | = fiji_fan_table->usFanPWMMax; | |
970 | hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity | |
971 | = 4836; | |
972 | hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity | |
973 | = fiji_fan_table->usFanOutputSensitivity; | |
974 | hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM | |
975 | = fiji_fan_table->usFanRPMMax; | |
976 | hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit | |
977 | = (fiji_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places. SMC wants MHz. */ | |
978 | hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature | |
979 | = fiji_fan_table->ucTargetTemperature; | |
980 | hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit | |
981 | = fiji_fan_table->ucMinimumPWMLimit; | |
982 | ||
983 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainEdge | |
984 | = fiji_fan_table->usFanGainEdge; | |
985 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHotspot | |
986 | = fiji_fan_table->usFanGainHotspot; | |
987 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainLiquid | |
988 | = fiji_fan_table->usFanGainLiquid; | |
989 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrVddc | |
990 | = fiji_fan_table->usFanGainVrVddc; | |
991 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrMvdd | |
992 | = fiji_fan_table->usFanGainVrMvdd; | |
993 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainPlx | |
994 | = fiji_fan_table->usFanGainPlx; | |
995 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHbm | |
996 | = fiji_fan_table->usFanGainHbm; | |
997 | } | |
998 | ||
999 | return 0; | |
1000 | } | |
1001 | ||
1002 | /** | |
1003 | * Private Function used during initialization. | |
1004 | * Inspect the PowerPlay table for obvious signs of corruption. | |
1005 | * @param hwmgr Pointer to the hardware manager. | |
1006 | * @param powerplay_table Pointer to the PowerPlay Table. | |
1007 | * @exception 2 if the powerplay table is incorrect. | |
1008 | */ | |
1009 | static int check_powerplay_tables( | |
1010 | struct pp_hwmgr *hwmgr, | |
1011 | const ATOM_Tonga_POWERPLAYTABLE *powerplay_table | |
1012 | ) | |
1013 | { | |
1014 | const ATOM_Tonga_State_Array *state_arrays; | |
1015 | ||
1016 | state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)powerplay_table) + | |
1017 | le16_to_cpu(powerplay_table->usStateArrayOffset)); | |
1018 | ||
1019 | PP_ASSERT_WITH_CODE((ATOM_Tonga_TABLE_REVISION_TONGA <= | |
1020 | powerplay_table->sHeader.ucTableFormatRevision), | |
1021 | "Unsupported PPTable format!", return -1); | |
1022 | PP_ASSERT_WITH_CODE((0 != powerplay_table->usStateArrayOffset), | |
1023 | "State table is not set!", return -1); | |
1024 | PP_ASSERT_WITH_CODE((0 < powerplay_table->sHeader.usStructureSize), | |
1025 | "Invalid PowerPlay Table!", return -1); | |
1026 | PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries), | |
1027 | "Invalid PowerPlay Table!", return -1); | |
1028 | ||
1029 | return 0; | |
1030 | } | |
1031 | ||
f8a4c11b | 1032 | static int pp_tables_v1_0_initialize(struct pp_hwmgr *hwmgr) |
c82baa28 | 1033 | { |
1034 | int result = 0; | |
1035 | const ATOM_Tonga_POWERPLAYTABLE *powerplay_table; | |
1036 | ||
1037 | hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v1_information), GFP_KERNEL); | |
1038 | ||
1d5498c2 | 1039 | PP_ASSERT_WITH_CODE((NULL != hwmgr->pptable), |
c15c8d70 | 1040 | "Failed to allocate hwmgr->pptable!", return -ENOMEM); |
c82baa28 | 1041 | |
1042 | memset(hwmgr->pptable, 0x00, sizeof(struct phm_ppt_v1_information)); | |
1043 | ||
1044 | powerplay_table = get_powerplay_table(hwmgr); | |
1045 | ||
1046 | PP_ASSERT_WITH_CODE((NULL != powerplay_table), | |
1047 | "Missing PowerPlay Table!", return -1); | |
1048 | ||
1049 | result = check_powerplay_tables(hwmgr, powerplay_table); | |
1050 | ||
1d5498c2 AD |
1051 | PP_ASSERT_WITH_CODE((result == 0), |
1052 | "check_powerplay_tables failed", return result); | |
1053 | ||
1054 | result = set_platform_caps(hwmgr, | |
1055 | le32_to_cpu(powerplay_table->ulPlatformCaps)); | |
1056 | ||
1057 | PP_ASSERT_WITH_CODE((result == 0), | |
1058 | "set_platform_caps failed", return result); | |
1059 | ||
1060 | result = init_thermal_controller(hwmgr, powerplay_table); | |
1061 | ||
1062 | PP_ASSERT_WITH_CODE((result == 0), | |
1063 | "init_thermal_controller failed", return result); | |
1064 | ||
1065 | result = init_over_drive_limits(hwmgr, powerplay_table); | |
1066 | ||
1067 | PP_ASSERT_WITH_CODE((result == 0), | |
1068 | "init_over_drive_limits failed", return result); | |
c82baa28 | 1069 | |
1d5498c2 | 1070 | result = init_clock_voltage_dependency(hwmgr, powerplay_table); |
c82baa28 | 1071 | |
1d5498c2 AD |
1072 | PP_ASSERT_WITH_CODE((result == 0), |
1073 | "init_clock_voltage_dependency failed", return result); | |
c82baa28 | 1074 | |
1d5498c2 | 1075 | result = init_dpm_2_parameters(hwmgr, powerplay_table); |
c82baa28 | 1076 | |
1d5498c2 AD |
1077 | PP_ASSERT_WITH_CODE((result == 0), |
1078 | "init_dpm_2_parameters failed", return result); | |
c82baa28 | 1079 | |
1080 | return result; | |
1081 | } | |
1082 | ||
f8a4c11b | 1083 | static int pp_tables_v1_0_uninitialize(struct pp_hwmgr *hwmgr) |
c82baa28 | 1084 | { |
c82baa28 | 1085 | struct phm_ppt_v1_information *pp_table_information = |
1086 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | |
1087 | ||
9d8f086c ML |
1088 | kfree(pp_table_information->vdd_dep_on_sclk); |
1089 | pp_table_information->vdd_dep_on_sclk = NULL; | |
c82baa28 | 1090 | |
9d8f086c ML |
1091 | kfree(pp_table_information->vdd_dep_on_mclk); |
1092 | pp_table_information->vdd_dep_on_mclk = NULL; | |
c82baa28 | 1093 | |
9d8f086c ML |
1094 | kfree(pp_table_information->valid_mclk_values); |
1095 | pp_table_information->valid_mclk_values = NULL; | |
c82baa28 | 1096 | |
9d8f086c ML |
1097 | kfree(pp_table_information->valid_sclk_values); |
1098 | pp_table_information->valid_sclk_values = NULL; | |
c82baa28 | 1099 | |
9d8f086c ML |
1100 | kfree(pp_table_information->vddc_lookup_table); |
1101 | pp_table_information->vddc_lookup_table = NULL; | |
c82baa28 | 1102 | |
9d8f086c ML |
1103 | kfree(pp_table_information->vddgfx_lookup_table); |
1104 | pp_table_information->vddgfx_lookup_table = NULL; | |
c82baa28 | 1105 | |
9d8f086c ML |
1106 | kfree(pp_table_information->mm_dep_table); |
1107 | pp_table_information->mm_dep_table = NULL; | |
c82baa28 | 1108 | |
9d8f086c ML |
1109 | kfree(pp_table_information->cac_dtp_table); |
1110 | pp_table_information->cac_dtp_table = NULL; | |
c82baa28 | 1111 | |
9d8f086c ML |
1112 | kfree(hwmgr->dyn_state.cac_dtp_table); |
1113 | hwmgr->dyn_state.cac_dtp_table = NULL; | |
c82baa28 | 1114 | |
9d8f086c ML |
1115 | kfree(pp_table_information->ppm_parameter_table); |
1116 | pp_table_information->ppm_parameter_table = NULL; | |
c82baa28 | 1117 | |
9d8f086c ML |
1118 | kfree(pp_table_information->pcie_table); |
1119 | pp_table_information->pcie_table = NULL; | |
c82baa28 | 1120 | |
9d8f086c ML |
1121 | kfree(hwmgr->pptable); |
1122 | hwmgr->pptable = NULL; | |
c82baa28 | 1123 | |
538f1ef3 | 1124 | return 0; |
c82baa28 | 1125 | } |
1126 | ||
e1aa5715 RZ |
1127 | const struct pp_table_func pptable_v1_0_funcs = { |
1128 | .pptable_init = pp_tables_v1_0_initialize, | |
1129 | .pptable_fini = pp_tables_v1_0_uninitialize, | |
c82baa28 | 1130 | }; |
1131 | ||
e1aa5715 | 1132 | int get_number_of_powerplay_table_entries_v1_0(struct pp_hwmgr *hwmgr) |
c82baa28 | 1133 | { |
e1aa5715 | 1134 | ATOM_Tonga_State_Array const *state_arrays; |
c82baa28 | 1135 | const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr); |
1136 | ||
1137 | PP_ASSERT_WITH_CODE((NULL != pp_table), | |
1138 | "Missing PowerPlay Table!", return -1); | |
1139 | PP_ASSERT_WITH_CODE((pp_table->sHeader.ucTableFormatRevision >= | |
1140 | ATOM_Tonga_TABLE_REVISION_TONGA), | |
1141 | "Incorrect PowerPlay table revision!", return -1); | |
1142 | ||
1143 | state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) + | |
1144 | le16_to_cpu(pp_table->usStateArrayOffset)); | |
1145 | ||
1146 | return (uint32_t)(state_arrays->ucNumEntries); | |
1147 | } | |
1148 | ||
1149 | /** | |
1150 | * Private function to convert flags stored in the BIOS to software flags in PowerPlay. | |
1151 | */ | |
1152 | static uint32_t make_classification_flags(struct pp_hwmgr *hwmgr, | |
1153 | uint16_t classification, uint16_t classification2) | |
1154 | { | |
1155 | uint32_t result = 0; | |
1156 | ||
1157 | if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT) | |
1158 | result |= PP_StateClassificationFlag_Boot; | |
1159 | ||
1160 | if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL) | |
1161 | result |= PP_StateClassificationFlag_Thermal; | |
1162 | ||
1163 | if (classification & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE) | |
1164 | result |= PP_StateClassificationFlag_LimitedPowerSource; | |
1165 | ||
1166 | if (classification & ATOM_PPLIB_CLASSIFICATION_REST) | |
1167 | result |= PP_StateClassificationFlag_Rest; | |
1168 | ||
1169 | if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED) | |
1170 | result |= PP_StateClassificationFlag_Forced; | |
1171 | ||
1172 | if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI) | |
1173 | result |= PP_StateClassificationFlag_ACPI; | |
1174 | ||
1175 | if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2) | |
1176 | result |= PP_StateClassificationFlag_LimitedPowerSource_2; | |
1177 | ||
1178 | return result; | |
1179 | } | |
1180 | ||
48d7b759 RZ |
1181 | static int ppt_get_num_of_vce_state_table_entries_v1_0(struct pp_hwmgr *hwmgr) |
1182 | { | |
1183 | const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr); | |
51585e03 | 1184 | const ATOM_Tonga_VCE_State_Table *vce_state_table; |
48d7b759 | 1185 | |
51585e03 RZ |
1186 | |
1187 | if (pp_table == NULL) | |
48d7b759 RZ |
1188 | return 0; |
1189 | ||
51585e03 RZ |
1190 | vce_state_table = (void *)pp_table + |
1191 | le16_to_cpu(pp_table->usVCEStateTableOffset); | |
1192 | ||
48d7b759 RZ |
1193 | return vce_state_table->ucNumEntries; |
1194 | } | |
1195 | ||
48d7b759 | 1196 | static int ppt_get_vce_state_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t i, |
0d8de7ca | 1197 | struct amd_vce_state *vce_state, void **clock_info, uint32_t *flag) |
48d7b759 RZ |
1198 | { |
1199 | const ATOM_Tonga_VCE_State_Record *vce_state_record; | |
519df8a6 RZ |
1200 | ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record; |
1201 | ATOM_Tonga_MCLK_Dependency_Record *mclk_dep_record; | |
1202 | ATOM_Tonga_MM_Dependency_Record *mm_dep_record; | |
48d7b759 RZ |
1203 | const ATOM_Tonga_POWERPLAYTABLE *pptable = get_powerplay_table(hwmgr); |
1204 | const ATOM_Tonga_VCE_State_Table *vce_state_table = (ATOM_Tonga_VCE_State_Table *)(((unsigned long)pptable) | |
1205 | + le16_to_cpu(pptable->usVCEStateTableOffset)); | |
1206 | const ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table = (ATOM_Tonga_SCLK_Dependency_Table *)(((unsigned long)pptable) | |
1207 | + le16_to_cpu(pptable->usSclkDependencyTableOffset)); | |
1208 | const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table = (ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long)pptable) | |
1209 | + le16_to_cpu(pptable->usMclkDependencyTableOffset)); | |
1210 | const ATOM_Tonga_MM_Dependency_Table *mm_dep_table = (ATOM_Tonga_MM_Dependency_Table *)(((unsigned long)pptable) | |
1211 | + le16_to_cpu(pptable->usMMDependencyTableOffset)); | |
1212 | ||
1213 | PP_ASSERT_WITH_CODE((i < vce_state_table->ucNumEntries), | |
1214 | "Requested state entry ID is out of range!", | |
1215 | return -EINVAL); | |
1216 | ||
519df8a6 RZ |
1217 | vce_state_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( |
1218 | ATOM_Tonga_VCE_State_Record, | |
1219 | entries, vce_state_table, i); | |
1220 | sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( | |
1221 | ATOM_Tonga_SCLK_Dependency_Record, | |
1222 | entries, sclk_dep_table, | |
1223 | vce_state_record->ucSCLKIndex); | |
1224 | mm_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( | |
1225 | ATOM_Tonga_MM_Dependency_Record, | |
1226 | entries, mm_dep_table, | |
1227 | vce_state_record->ucVCEClockIndex); | |
48d7b759 RZ |
1228 | *flag = vce_state_record->ucFlag; |
1229 | ||
519df8a6 RZ |
1230 | vce_state->evclk = mm_dep_record->ulEClk; |
1231 | vce_state->ecclk = mm_dep_record->ulEClk; | |
1232 | vce_state->sclk = sclk_dep_record->ulSclk; | |
48d7b759 RZ |
1233 | |
1234 | if (vce_state_record->ucMCLKIndex >= mclk_dep_table->ucNumEntries) | |
519df8a6 RZ |
1235 | mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( |
1236 | ATOM_Tonga_MCLK_Dependency_Record, | |
1237 | entries, mclk_dep_table, | |
1238 | mclk_dep_table->ucNumEntries - 1); | |
48d7b759 | 1239 | else |
519df8a6 RZ |
1240 | mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( |
1241 | ATOM_Tonga_MCLK_Dependency_Record, | |
1242 | entries, mclk_dep_table, | |
1243 | vce_state_record->ucMCLKIndex); | |
48d7b759 | 1244 | |
519df8a6 | 1245 | vce_state->mclk = mclk_dep_record->ulMclk; |
48d7b759 RZ |
1246 | return 0; |
1247 | } | |
1248 | ||
c82baa28 | 1249 | /** |
1250 | * Create a Power State out of an entry in the PowerPlay table. | |
1251 | * This function is called by the hardware back-end. | |
1252 | * @param hwmgr Pointer to the hardware manager. | |
1253 | * @param entry_index The index of the entry to be extracted from the table. | |
1254 | * @param power_state The address of the PowerState instance being created. | |
1255 | * @return -1 if the entry cannot be retrieved. | |
1256 | */ | |
e1aa5715 | 1257 | int get_powerplay_table_entry_v1_0(struct pp_hwmgr *hwmgr, |
c82baa28 | 1258 | uint32_t entry_index, struct pp_power_state *power_state, |
1259 | int (*call_back_func)(struct pp_hwmgr *, void *, | |
1260 | struct pp_power_state *, void *, uint32_t)) | |
1261 | { | |
1262 | int result = 0; | |
519df8a6 | 1263 | const ATOM_Tonga_State_Array *state_arrays; |
c82baa28 | 1264 | const ATOM_Tonga_State *state_entry; |
1265 | const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr); | |
48d7b759 RZ |
1266 | int i, j; |
1267 | uint32_t flags = 0; | |
c82baa28 | 1268 | |
1269 | PP_ASSERT_WITH_CODE((NULL != pp_table), "Missing PowerPlay Table!", return -1;); | |
1270 | power_state->classification.bios_index = entry_index; | |
1271 | ||
1272 | if (pp_table->sHeader.ucTableFormatRevision >= | |
1273 | ATOM_Tonga_TABLE_REVISION_TONGA) { | |
1274 | state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) + | |
1275 | le16_to_cpu(pp_table->usStateArrayOffset)); | |
1276 | ||
1277 | PP_ASSERT_WITH_CODE((0 < pp_table->usStateArrayOffset), | |
1278 | "Invalid PowerPlay Table State Array Offset.", return -1); | |
1279 | PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries), | |
1280 | "Invalid PowerPlay Table State Array.", return -1); | |
1281 | PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries), | |
1282 | "Invalid PowerPlay Table State Array Entry.", return -1); | |
1283 | ||
519df8a6 RZ |
1284 | state_entry = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( |
1285 | ATOM_Tonga_State, entries, | |
1286 | state_arrays, entry_index); | |
c82baa28 | 1287 | |
1288 | result = call_back_func(hwmgr, (void *)state_entry, power_state, | |
1289 | (void *)pp_table, | |
1290 | make_classification_flags(hwmgr, | |
1291 | le16_to_cpu(state_entry->usClassification), | |
1292 | le16_to_cpu(state_entry->usClassification2))); | |
1293 | } | |
1294 | ||
1295 | if (!result && (power_state->classification.flags & | |
1296 | PP_StateClassificationFlag_Boot)) | |
1297 | result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(power_state->hardware)); | |
1298 | ||
48d7b759 RZ |
1299 | hwmgr->num_vce_state_tables = i = ppt_get_num_of_vce_state_table_entries_v1_0(hwmgr); |
1300 | ||
0d8de7ca | 1301 | if ((i != 0) && (i <= AMD_MAX_VCE_LEVELS)) { |
48d7b759 RZ |
1302 | for (j = 0; j < i; j++) |
1303 | ppt_get_vce_state_table_entry_v1_0(hwmgr, j, &(hwmgr->vce_states[j]), NULL, &flags); | |
1304 | } | |
1305 | ||
c82baa28 | 1306 | return result; |
1307 | } | |
48d7b759 | 1308 |