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 | |
945 | if (NULL == hwmgr->pptable) |
946 | return -1; |
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 | |
957 | if (0 == result) |
958 | result = set_platform_caps(hwmgr, |
959 | le32_to_cpu(powerplay_table->ulPlatformCaps)); |
960 | |
961 | if (0 == result) |
962 | result = init_thermal_controller(hwmgr, powerplay_table); |
963 | |
964 | if (0 == result) |
965 | result = init_over_drive_limits(hwmgr, powerplay_table); |
966 | |
967 | if (0 == result) |
968 | result = init_clock_voltage_dependency(hwmgr, powerplay_table); |
969 | |
970 | if (0 == result) |
971 | result = init_dpm_2_parameters(hwmgr, powerplay_table); |
972 | |
973 | return result; |
974 | } |
975 | |
976 | int tonga_pp_tables_uninitialize(struct pp_hwmgr *hwmgr) |
977 | { |
978 | int result = 0; |
979 | struct phm_ppt_v1_information *pp_table_information = |
980 | (struct phm_ppt_v1_information *)(hwmgr->pptable); |
981 | |
982 | if (NULL != hwmgr->soft_pp_table) { |
983 | kfree(hwmgr->soft_pp_table); |
984 | hwmgr->soft_pp_table = NULL; |
985 | } |
986 | |
987 | if (NULL != pp_table_information->vdd_dep_on_sclk) |
988 | pp_table_information->vdd_dep_on_sclk = NULL; |
989 | |
990 | if (NULL != pp_table_information->vdd_dep_on_mclk) |
991 | pp_table_information->vdd_dep_on_mclk = NULL; |
992 | |
993 | if (NULL != pp_table_information->valid_mclk_values) |
994 | pp_table_information->valid_mclk_values = NULL; |
995 | |
996 | if (NULL != pp_table_information->valid_sclk_values) |
997 | pp_table_information->valid_sclk_values = NULL; |
998 | |
999 | if (NULL != pp_table_information->vddc_lookup_table) |
1000 | pp_table_information->vddc_lookup_table = NULL; |
1001 | |
1002 | if (NULL != pp_table_information->vddgfx_lookup_table) |
1003 | pp_table_information->vddgfx_lookup_table = NULL; |
1004 | |
1005 | if (NULL != pp_table_information->mm_dep_table) |
1006 | pp_table_information->mm_dep_table = NULL; |
1007 | |
1008 | if (NULL != pp_table_information->cac_dtp_table) |
1009 | pp_table_information->cac_dtp_table = NULL; |
1010 | |
1011 | if (NULL != hwmgr->dyn_state.cac_dtp_table) |
1012 | hwmgr->dyn_state.cac_dtp_table = NULL; |
1013 | |
1014 | if (NULL != pp_table_information->ppm_parameter_table) |
1015 | pp_table_information->ppm_parameter_table = NULL; |
1016 | |
1017 | if (NULL != pp_table_information->pcie_table) |
1018 | pp_table_information->pcie_table = NULL; |
1019 | |
1020 | if (NULL != hwmgr->pptable) { |
1021 | kfree(hwmgr->pptable); |
1022 | hwmgr->pptable = NULL; |
1023 | } |
1024 | |
1025 | return result; |
1026 | } |
1027 | |
1028 | const struct pp_table_func tonga_pptable_funcs = { |
1029 | .pptable_init = tonga_pp_tables_initialize, |
1030 | .pptable_fini = tonga_pp_tables_uninitialize, |
1031 | }; |
1032 | |
1033 | int tonga_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr) |
1034 | { |
1035 | const ATOM_Tonga_State_Array * state_arrays; |
1036 | const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr); |
1037 | |
1038 | PP_ASSERT_WITH_CODE((NULL != pp_table), |
1039 | "Missing PowerPlay Table!", return -1); |
1040 | PP_ASSERT_WITH_CODE((pp_table->sHeader.ucTableFormatRevision >= |
1041 | ATOM_Tonga_TABLE_REVISION_TONGA), |
1042 | "Incorrect PowerPlay table revision!", return -1); |
1043 | |
1044 | state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) + |
1045 | le16_to_cpu(pp_table->usStateArrayOffset)); |
1046 | |
1047 | return (uint32_t)(state_arrays->ucNumEntries); |
1048 | } |
1049 | |
1050 | /** |
1051 | * Private function to convert flags stored in the BIOS to software flags in PowerPlay. |
1052 | */ |
1053 | static uint32_t make_classification_flags(struct pp_hwmgr *hwmgr, |
1054 | uint16_t classification, uint16_t classification2) |
1055 | { |
1056 | uint32_t result = 0; |
1057 | |
1058 | if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT) |
1059 | result |= PP_StateClassificationFlag_Boot; |
1060 | |
1061 | if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL) |
1062 | result |= PP_StateClassificationFlag_Thermal; |
1063 | |
1064 | if (classification & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE) |
1065 | result |= PP_StateClassificationFlag_LimitedPowerSource; |
1066 | |
1067 | if (classification & ATOM_PPLIB_CLASSIFICATION_REST) |
1068 | result |= PP_StateClassificationFlag_Rest; |
1069 | |
1070 | if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED) |
1071 | result |= PP_StateClassificationFlag_Forced; |
1072 | |
1073 | if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI) |
1074 | result |= PP_StateClassificationFlag_ACPI; |
1075 | |
1076 | if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2) |
1077 | result |= PP_StateClassificationFlag_LimitedPowerSource_2; |
1078 | |
1079 | return result; |
1080 | } |
1081 | |
1082 | /** |
1083 | * Create a Power State out of an entry in the PowerPlay table. |
1084 | * This function is called by the hardware back-end. |
1085 | * @param hwmgr Pointer to the hardware manager. |
1086 | * @param entry_index The index of the entry to be extracted from the table. |
1087 | * @param power_state The address of the PowerState instance being created. |
1088 | * @return -1 if the entry cannot be retrieved. |
1089 | */ |
1090 | int tonga_get_powerplay_table_entry(struct pp_hwmgr *hwmgr, |
1091 | uint32_t entry_index, struct pp_power_state *power_state, |
1092 | int (*call_back_func)(struct pp_hwmgr *, void *, |
1093 | struct pp_power_state *, void *, uint32_t)) |
1094 | { |
1095 | int result = 0; |
1096 | const ATOM_Tonga_State_Array * state_arrays; |
1097 | const ATOM_Tonga_State *state_entry; |
1098 | const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr); |
1099 | |
1100 | PP_ASSERT_WITH_CODE((NULL != pp_table), "Missing PowerPlay Table!", return -1;); |
1101 | power_state->classification.bios_index = entry_index; |
1102 | |
1103 | if (pp_table->sHeader.ucTableFormatRevision >= |
1104 | ATOM_Tonga_TABLE_REVISION_TONGA) { |
1105 | state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) + |
1106 | le16_to_cpu(pp_table->usStateArrayOffset)); |
1107 | |
1108 | PP_ASSERT_WITH_CODE((0 < pp_table->usStateArrayOffset), |
1109 | "Invalid PowerPlay Table State Array Offset.", return -1); |
1110 | PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries), |
1111 | "Invalid PowerPlay Table State Array.", return -1); |
1112 | PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries), |
1113 | "Invalid PowerPlay Table State Array Entry.", return -1); |
1114 | |
1115 | state_entry = &(state_arrays->states[entry_index]); |
1116 | |
1117 | result = call_back_func(hwmgr, (void *)state_entry, power_state, |
1118 | (void *)pp_table, |
1119 | make_classification_flags(hwmgr, |
1120 | le16_to_cpu(state_entry->usClassification), |
1121 | le16_to_cpu(state_entry->usClassification2))); |
1122 | } |
1123 | |
1124 | if (!result && (power_state->classification.flags & |
1125 | PP_StateClassificationFlag_Boot)) |
1126 | result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(power_state->hardware)); |
1127 | |
1128 | return result; |
1129 | } |