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