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