2 * Copyright 2015 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
23 #include <linux/module.h>
24 #include <linux/slab.h>
27 #include "process_pptables_v1_0.h"
28 #include "ppatomctrl.h"
32 #include "cgs_common.h"
33 #include "pptable_v1_0.h"
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.
41 static void set_hw_cap(struct pp_hwmgr *hwmgr, bool setIt, enum phm_platform_caps cap)
44 phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap);
46 phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap);
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.
56 static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps)
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);
71 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_POWERPLAY),
72 PHM_PlatformCaps_PowerPlaySupport
77 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_SBIOSPOWERSOURCE),
78 PHM_PlatformCaps_BiosPowerSourceControl
83 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_HARDWAREDC),
84 PHM_PlatformCaps_AutomaticDCTransition
89 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_MVDD_CONTROL),
90 PHM_PlatformCaps_EnableMVDDControl
95 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDCI_CONTROL),
96 PHM_PlatformCaps_ControlVDDCI
101 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDGFX_CONTROL),
102 PHM_PlatformCaps_ControlVDDGFX
107 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_BACO),
108 PHM_PlatformCaps_BACO
113 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_DISABLE_VOLTAGE_ISLAND),
114 PHM_PlatformCaps_DisableVoltageIsland
119 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL),
120 PHM_PlatformCaps_CombinePCCWithThermalSignal
125 0 != (powerplay_caps & ATOM_TONGA_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE),
126 PHM_PlatformCaps_LoadPostProductionFirmware
133 * Private Function to get the PowerPlay Table Address.
135 const void *get_powerplay_table(struct pp_hwmgr *hwmgr)
137 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
141 void *table_address = (void *)hwmgr->soft_pp_table;
143 if (!table_address) {
144 table_address = (ATOM_Tonga_POWERPLAYTABLE *)
145 cgs_atom_get_data_table(hwmgr->device,
146 index, &size, &frev, &crev);
147 hwmgr->soft_pp_table = table_address; /*Cache the result in RAM.*/
148 hwmgr->soft_pp_table_size = size;
151 return table_address;
154 static int get_vddc_lookup_table(
155 struct pp_hwmgr *hwmgr,
156 phm_ppt_v1_voltage_lookup_table **lookup_table,
157 const ATOM_Tonga_Voltage_Lookup_Table *vddc_lookup_pp_tables,
161 uint32_t table_size, i;
162 phm_ppt_v1_voltage_lookup_table *table;
163 phm_ppt_v1_voltage_lookup_record *record;
164 ATOM_Tonga_Voltage_Lookup_Record *atom_record;
166 PP_ASSERT_WITH_CODE((0 != vddc_lookup_pp_tables->ucNumEntries),
167 "Invalid CAC Leakage PowerPlay Table!", return 1);
169 table_size = sizeof(uint32_t) +
170 sizeof(phm_ppt_v1_voltage_lookup_record) * max_levels;
172 table = kzalloc(table_size, GFP_KERNEL);
177 memset(table, 0x00, table_size);
179 table->count = vddc_lookup_pp_tables->ucNumEntries;
181 for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) {
182 record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
183 phm_ppt_v1_voltage_lookup_record,
185 atom_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
186 ATOM_Tonga_Voltage_Lookup_Record,
187 entries, vddc_lookup_pp_tables, i);
188 record->us_calculated = 0;
189 record->us_vdd = atom_record->usVdd;
190 record->us_cac_low = atom_record->usCACLow;
191 record->us_cac_mid = atom_record->usCACMid;
192 record->us_cac_high = atom_record->usCACHigh;
195 *lookup_table = table;
201 * Private Function used during initialization.
202 * Initialize Platform Power Management Parameter table
203 * @param hwmgr Pointer to the hardware manager.
204 * @param atom_ppm_table Pointer to PPM table in VBIOS
206 static int get_platform_power_management_table(
207 struct pp_hwmgr *hwmgr,
208 ATOM_Tonga_PPM_Table *atom_ppm_table)
210 struct phm_ppm_table *ptr = kzalloc(sizeof(ATOM_Tonga_PPM_Table), GFP_KERNEL);
211 struct phm_ppt_v1_information *pp_table_information =
212 (struct phm_ppt_v1_information *)(hwmgr->pptable);
218 = atom_ppm_table->ucPpmDesign;
220 = atom_ppm_table->usCpuCoreNumber;
222 = atom_ppm_table->ulPlatformTDP;
223 ptr->small_ac_platform_tdp
224 = atom_ppm_table->ulSmallACPlatformTDP;
226 = atom_ppm_table->ulPlatformTDC;
227 ptr->small_ac_platform_tdc
228 = atom_ppm_table->ulSmallACPlatformTDC;
230 = atom_ppm_table->ulApuTDP;
232 = atom_ppm_table->ulDGpuTDP;
234 = atom_ppm_table->ulDGpuUlvPower;
236 = atom_ppm_table->ulTjmax;
238 pp_table_information->ppm_parameter_table = ptr;
244 * Private Function used during initialization.
245 * Initialize TDP limits for DPM2
246 * @param hwmgr Pointer to the hardware manager.
247 * @param powerplay_table Pointer to the PowerPlay Table.
249 static int init_dpm_2_parameters(
250 struct pp_hwmgr *hwmgr,
251 const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
255 struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable);
256 ATOM_Tonga_PPM_Table *atom_ppm_table;
257 uint32_t disable_ppm = 0;
258 uint32_t disable_power_control = 0;
260 pp_table_information->us_ulv_voltage_offset =
261 le16_to_cpu(powerplay_table->usUlvVoltageOffset);
263 pp_table_information->ppm_parameter_table = NULL;
264 pp_table_information->vddc_lookup_table = NULL;
265 pp_table_information->vddgfx_lookup_table = NULL;
267 hwmgr->platform_descriptor.TDPODLimit =
268 le16_to_cpu(powerplay_table->usPowerControlLimit);
269 hwmgr->platform_descriptor.TDPAdjustment = 0;
270 hwmgr->platform_descriptor.VidAdjustment = 0;
271 hwmgr->platform_descriptor.VidAdjustmentPolarity = 0;
272 hwmgr->platform_descriptor.VidMinLimit = 0;
273 hwmgr->platform_descriptor.VidMaxLimit = 1500000;
274 hwmgr->platform_descriptor.VidStep = 6250;
276 disable_power_control = 0;
277 if (0 == disable_power_control) {
278 /* enable TDP overdrive (PowerControl) feature as well if supported */
279 if (hwmgr->platform_descriptor.TDPODLimit != 0)
280 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
281 PHM_PlatformCaps_PowerControl);
284 if (0 != powerplay_table->usVddcLookupTableOffset) {
285 const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable =
286 (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
287 le16_to_cpu(powerplay_table->usVddcLookupTableOffset));
289 result = get_vddc_lookup_table(hwmgr,
290 &pp_table_information->vddc_lookup_table, pVddcCACTable, 16);
293 if (0 != powerplay_table->usVddgfxLookupTableOffset) {
294 const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable =
295 (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
296 le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset));
298 result = get_vddc_lookup_table(hwmgr,
299 &pp_table_information->vddgfx_lookup_table, pVddgfxCACTable, 16);
303 if (0 == disable_ppm) {
304 atom_ppm_table = (ATOM_Tonga_PPM_Table *)
305 (((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usPPMTableOffset));
307 if (0 != powerplay_table->usPPMTableOffset) {
308 if (get_platform_power_management_table(hwmgr, atom_ppm_table) == 0) {
309 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
310 PHM_PlatformCaps_EnablePlatformPowerManagement);
318 static int get_valid_clk(
319 struct pp_hwmgr *hwmgr,
320 struct phm_clock_array **clk_table,
321 phm_ppt_v1_clock_voltage_dependency_table const *clk_volt_pp_table
324 uint32_t table_size, i;
325 struct phm_clock_array *table;
326 phm_ppt_v1_clock_voltage_dependency_record *dep_record;
328 PP_ASSERT_WITH_CODE((0 != clk_volt_pp_table->count),
329 "Invalid PowerPlay Table!", return -1);
331 table_size = sizeof(uint32_t) +
332 sizeof(uint32_t) * clk_volt_pp_table->count;
334 table = kzalloc(table_size, GFP_KERNEL);
339 memset(table, 0x00, table_size);
341 table->count = (uint32_t)clk_volt_pp_table->count;
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;
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
360 PP_ASSERT_WITH_CODE((0 != limitable->ucNumEntries), "Invalid PowerPlay Table!", return -1);
362 /* currently we always take entries[0] parameters */
363 limits->sclk = (uint32_t)limitable->entries[0].ulSCLKLimit;
364 limits->mclk = (uint32_t)limitable->entries[0].ulMCLKLimit;
365 limits->vddc = (uint16_t)limitable->entries[0].usVddcLimit;
366 limits->vddci = (uint16_t)limitable->entries[0].usVddciLimit;
367 limits->vddgfx = (uint16_t)limitable->entries[0].usVddgfxLimit;
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
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;
383 PP_ASSERT_WITH_CODE((0 != mclk_dep_table->ucNumEntries),
384 "Invalid PowerPlay Table!", return -1);
386 table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
387 * mclk_dep_table->ucNumEntries;
389 mclk_table = kzalloc(table_size, GFP_KERNEL);
391 if (NULL == mclk_table)
394 memset(mclk_table, 0x00, table_size);
396 mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries;
398 for (i = 0; i < mclk_dep_table->ucNumEntries; i++) {
399 mclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
400 phm_ppt_v1_clock_voltage_dependency_record,
401 entries, mclk_table, i);
402 mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
403 ATOM_Tonga_MCLK_Dependency_Record,
404 entries, mclk_dep_table, i);
405 mclk_table_record->vddInd = mclk_dep_record->ucVddcInd;
406 mclk_table_record->vdd_offset = mclk_dep_record->usVddgfxOffset;
407 mclk_table_record->vddci = mclk_dep_record->usVddci;
408 mclk_table_record->mvdd = mclk_dep_record->usMvdd;
409 mclk_table_record->clk = mclk_dep_record->ulMclk;
412 *pp_tonga_mclk_dep_table = mclk_table;
417 static int get_sclk_voltage_dependency_table(
418 struct pp_hwmgr *hwmgr,
419 phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_sclk_dep_table,
420 PPTable_Generic_SubTable_Header const *sclk_dep_table
423 uint32_t table_size, i;
424 phm_ppt_v1_clock_voltage_dependency_table *sclk_table;
425 phm_ppt_v1_clock_voltage_dependency_record *sclk_table_record;
427 if (sclk_dep_table->ucRevId < 1) {
428 const ATOM_Tonga_SCLK_Dependency_Table *tonga_table =
429 (ATOM_Tonga_SCLK_Dependency_Table *)sclk_dep_table;
430 ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record;
432 PP_ASSERT_WITH_CODE((0 != tonga_table->ucNumEntries),
433 "Invalid PowerPlay Table!", return -1);
435 table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
436 * tonga_table->ucNumEntries;
438 sclk_table = kzalloc(table_size, GFP_KERNEL);
440 if (NULL == sclk_table)
443 memset(sclk_table, 0x00, table_size);
445 sclk_table->count = (uint32_t)tonga_table->ucNumEntries;
447 for (i = 0; i < tonga_table->ucNumEntries; i++) {
448 sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
449 ATOM_Tonga_SCLK_Dependency_Record,
450 entries, tonga_table, i);
451 sclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
452 phm_ppt_v1_clock_voltage_dependency_record,
453 entries, sclk_table, i);
454 sclk_table_record->vddInd = sclk_dep_record->ucVddInd;
455 sclk_table_record->vdd_offset = sclk_dep_record->usVddcOffset;
456 sclk_table_record->clk = sclk_dep_record->ulSclk;
457 sclk_table_record->cks_enable =
458 (((sclk_dep_record->ucCKSVOffsetandDisable & 0x80) >> 7) == 0) ? 1 : 0;
459 sclk_table_record->cks_voffset = (sclk_dep_record->ucCKSVOffsetandDisable & 0x7F);
462 const ATOM_Polaris_SCLK_Dependency_Table *polaris_table =
463 (ATOM_Polaris_SCLK_Dependency_Table *)sclk_dep_table;
464 ATOM_Polaris_SCLK_Dependency_Record *sclk_dep_record;
466 PP_ASSERT_WITH_CODE((0 != polaris_table->ucNumEntries),
467 "Invalid PowerPlay Table!", return -1);
469 table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
470 * polaris_table->ucNumEntries;
472 sclk_table = kzalloc(table_size, GFP_KERNEL);
474 if (NULL == sclk_table)
477 memset(sclk_table, 0x00, table_size);
479 sclk_table->count = (uint32_t)polaris_table->ucNumEntries;
481 for (i = 0; i < polaris_table->ucNumEntries; i++) {
482 sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
483 ATOM_Polaris_SCLK_Dependency_Record,
484 entries, polaris_table, i);
485 sclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
486 phm_ppt_v1_clock_voltage_dependency_record,
487 entries, sclk_table, i);
488 sclk_table_record->vddInd = sclk_dep_record->ucVddInd;
489 sclk_table_record->vdd_offset = sclk_dep_record->usVddcOffset;
490 sclk_table_record->clk = sclk_dep_record->ulSclk;
491 sclk_table_record->cks_enable =
492 (((sclk_dep_record->ucCKSVOffsetandDisable & 0x80) >> 7) == 0) ? 1 : 0;
493 sclk_table_record->cks_voffset = (sclk_dep_record->ucCKSVOffsetandDisable & 0x7F);
494 sclk_table_record->sclk_offset = sclk_dep_record->ulSclkOffset;
497 *pp_tonga_sclk_dep_table = sclk_table;
502 static int get_pcie_table(
503 struct pp_hwmgr *hwmgr,
504 phm_ppt_v1_pcie_table **pp_tonga_pcie_table,
505 PPTable_Generic_SubTable_Header const *ptable
508 uint32_t table_size, i, pcie_count;
509 phm_ppt_v1_pcie_table *pcie_table;
510 struct phm_ppt_v1_information *pp_table_information =
511 (struct phm_ppt_v1_information *)(hwmgr->pptable);
512 phm_ppt_v1_pcie_record *pcie_record;
514 if (ptable->ucRevId < 1) {
515 const ATOM_Tonga_PCIE_Table *atom_pcie_table = (ATOM_Tonga_PCIE_Table *)ptable;
516 ATOM_Tonga_PCIE_Record *atom_pcie_record;
518 PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0),
519 "Invalid PowerPlay Table!", return -1);
521 table_size = sizeof(uint32_t) +
522 sizeof(phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries;
524 pcie_table = kzalloc(table_size, GFP_KERNEL);
526 if (pcie_table == NULL)
529 memset(pcie_table, 0x00, table_size);
532 * Make sure the number of pcie entries are less than or equal to sclk dpm levels.
533 * Since first PCIE entry is for ULV, #pcie has to be <= SclkLevel + 1.
535 pcie_count = (pp_table_information->vdd_dep_on_sclk->count) + 1;
536 if ((uint32_t)atom_pcie_table->ucNumEntries <= pcie_count)
537 pcie_count = (uint32_t)atom_pcie_table->ucNumEntries;
539 printk(KERN_ERR "[ powerplay ] Number of Pcie Entries exceed the number of SCLK Dpm Levels! \
540 Disregarding the excess entries... \n");
542 pcie_table->count = pcie_count;
543 for (i = 0; i < pcie_count; i++) {
544 pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
545 phm_ppt_v1_pcie_record,
546 entries, pcie_table, i);
547 atom_pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
548 ATOM_Tonga_PCIE_Record,
549 entries, atom_pcie_table, i);
550 pcie_record->gen_speed = atom_pcie_record->ucPCIEGenSpeed;
551 pcie_record->lane_width = atom_pcie_record->usPCIELaneWidth;
554 *pp_tonga_pcie_table = pcie_table;
556 /* Polaris10/Polaris11 and newer. */
557 const ATOM_Polaris10_PCIE_Table *atom_pcie_table = (ATOM_Polaris10_PCIE_Table *)ptable;
558 ATOM_Polaris10_PCIE_Record *atom_pcie_record;
560 PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0),
561 "Invalid PowerPlay Table!", return -1);
563 table_size = sizeof(uint32_t) +
564 sizeof(phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries;
566 pcie_table = kzalloc(table_size, GFP_KERNEL);
568 if (pcie_table == NULL)
571 memset(pcie_table, 0x00, table_size);
574 * Make sure the number of pcie entries are less than or equal to sclk dpm levels.
575 * Since first PCIE entry is for ULV, #pcie has to be <= SclkLevel + 1.
577 pcie_count = (pp_table_information->vdd_dep_on_sclk->count) + 1;
578 if ((uint32_t)atom_pcie_table->ucNumEntries <= pcie_count)
579 pcie_count = (uint32_t)atom_pcie_table->ucNumEntries;
581 printk(KERN_ERR "[ powerplay ] Number of Pcie Entries exceed the number of SCLK Dpm Levels! \
582 Disregarding the excess entries... \n");
584 pcie_table->count = pcie_count;
586 for (i = 0; i < pcie_count; i++) {
587 pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
588 phm_ppt_v1_pcie_record,
589 entries, pcie_table, i);
590 atom_pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
591 ATOM_Polaris10_PCIE_Record,
592 entries, atom_pcie_table, i);
593 pcie_record->gen_speed = atom_pcie_record->ucPCIEGenSpeed;
594 pcie_record->lane_width = atom_pcie_record->usPCIELaneWidth;
595 pcie_record->pcie_sclk = atom_pcie_record->ulPCIE_Sclk;
598 *pp_tonga_pcie_table = pcie_table;
604 static int get_cac_tdp_table(
605 struct pp_hwmgr *hwmgr,
606 struct phm_cac_tdp_table **cac_tdp_table,
607 const PPTable_Generic_SubTable_Header * table
611 struct phm_cac_tdp_table *tdp_table;
613 table_size = sizeof(uint32_t) + sizeof(struct phm_cac_tdp_table);
614 tdp_table = kzalloc(table_size, GFP_KERNEL);
616 if (NULL == tdp_table)
619 memset(tdp_table, 0x00, table_size);
621 hwmgr->dyn_state.cac_dtp_table = kzalloc(table_size, GFP_KERNEL);
623 if (NULL == hwmgr->dyn_state.cac_dtp_table) {
628 memset(hwmgr->dyn_state.cac_dtp_table, 0x00, table_size);
630 if (table->ucRevId < 3) {
631 const ATOM_Tonga_PowerTune_Table *tonga_table =
632 (ATOM_Tonga_PowerTune_Table *)table;
633 tdp_table->usTDP = tonga_table->usTDP;
634 tdp_table->usConfigurableTDP =
635 tonga_table->usConfigurableTDP;
636 tdp_table->usTDC = tonga_table->usTDC;
637 tdp_table->usBatteryPowerLimit =
638 tonga_table->usBatteryPowerLimit;
639 tdp_table->usSmallPowerLimit =
640 tonga_table->usSmallPowerLimit;
641 tdp_table->usLowCACLeakage =
642 tonga_table->usLowCACLeakage;
643 tdp_table->usHighCACLeakage =
644 tonga_table->usHighCACLeakage;
645 tdp_table->usMaximumPowerDeliveryLimit =
646 tonga_table->usMaximumPowerDeliveryLimit;
647 tdp_table->usDefaultTargetOperatingTemp =
648 tonga_table->usTjMax;
649 tdp_table->usTargetOperatingTemp =
650 tonga_table->usTjMax; /*Set the initial temp to the same as default */
651 tdp_table->usPowerTuneDataSetID =
652 tonga_table->usPowerTuneDataSetID;
653 tdp_table->usSoftwareShutdownTemp =
654 tonga_table->usSoftwareShutdownTemp;
655 tdp_table->usClockStretchAmount =
656 tonga_table->usClockStretchAmount;
657 } else { /* Fiji and newer */
658 const ATOM_Fiji_PowerTune_Table *fijitable =
659 (ATOM_Fiji_PowerTune_Table *)table;
660 tdp_table->usTDP = fijitable->usTDP;
661 tdp_table->usConfigurableTDP = fijitable->usConfigurableTDP;
662 tdp_table->usTDC = fijitable->usTDC;
663 tdp_table->usBatteryPowerLimit = fijitable->usBatteryPowerLimit;
664 tdp_table->usSmallPowerLimit = fijitable->usSmallPowerLimit;
665 tdp_table->usLowCACLeakage = fijitable->usLowCACLeakage;
666 tdp_table->usHighCACLeakage = fijitable->usHighCACLeakage;
667 tdp_table->usMaximumPowerDeliveryLimit =
668 fijitable->usMaximumPowerDeliveryLimit;
669 tdp_table->usDefaultTargetOperatingTemp =
671 tdp_table->usTargetOperatingTemp =
672 fijitable->usTjMax; /*Set the initial temp to the same as default */
673 tdp_table->usPowerTuneDataSetID =
674 fijitable->usPowerTuneDataSetID;
675 tdp_table->usSoftwareShutdownTemp =
676 fijitable->usSoftwareShutdownTemp;
677 tdp_table->usClockStretchAmount =
678 fijitable->usClockStretchAmount;
679 tdp_table->usTemperatureLimitHotspot =
680 fijitable->usTemperatureLimitHotspot;
681 tdp_table->usTemperatureLimitLiquid1 =
682 fijitable->usTemperatureLimitLiquid1;
683 tdp_table->usTemperatureLimitLiquid2 =
684 fijitable->usTemperatureLimitLiquid2;
685 tdp_table->usTemperatureLimitVrVddc =
686 fijitable->usTemperatureLimitVrVddc;
687 tdp_table->usTemperatureLimitVrMvdd =
688 fijitable->usTemperatureLimitVrMvdd;
689 tdp_table->usTemperatureLimitPlx =
690 fijitable->usTemperatureLimitPlx;
691 tdp_table->ucLiquid1_I2C_address =
692 fijitable->ucLiquid1_I2C_address;
693 tdp_table->ucLiquid2_I2C_address =
694 fijitable->ucLiquid2_I2C_address;
695 tdp_table->ucLiquid_I2C_Line =
696 fijitable->ucLiquid_I2C_Line;
697 tdp_table->ucVr_I2C_address = fijitable->ucVr_I2C_address;
698 tdp_table->ucVr_I2C_Line = fijitable->ucVr_I2C_Line;
699 tdp_table->ucPlx_I2C_address = fijitable->ucPlx_I2C_address;
700 tdp_table->ucPlx_I2C_Line = fijitable->ucPlx_I2C_Line;
703 *cac_tdp_table = tdp_table;
708 static int get_mm_clock_voltage_table(
709 struct pp_hwmgr *hwmgr,
710 phm_ppt_v1_mm_clock_voltage_dependency_table **tonga_mm_table,
711 const ATOM_Tonga_MM_Dependency_Table * mm_dependency_table
714 uint32_t table_size, i;
715 const ATOM_Tonga_MM_Dependency_Record *mm_dependency_record;
716 phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table;
717 phm_ppt_v1_mm_clock_voltage_dependency_record *mm_table_record;
719 PP_ASSERT_WITH_CODE((0 != mm_dependency_table->ucNumEntries),
720 "Invalid PowerPlay Table!", return -1);
721 table_size = sizeof(uint32_t) +
722 sizeof(phm_ppt_v1_mm_clock_voltage_dependency_record)
723 * mm_dependency_table->ucNumEntries;
724 mm_table = kzalloc(table_size, GFP_KERNEL);
726 if (NULL == mm_table)
729 memset(mm_table, 0x00, table_size);
731 mm_table->count = mm_dependency_table->ucNumEntries;
733 for (i = 0; i < mm_dependency_table->ucNumEntries; i++) {
734 mm_dependency_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
735 ATOM_Tonga_MM_Dependency_Record,
736 entries, mm_dependency_table, i);
737 mm_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
738 phm_ppt_v1_mm_clock_voltage_dependency_record,
739 entries, mm_table, i);
740 mm_table_record->vddcInd = mm_dependency_record->ucVddcInd;
741 mm_table_record->vddgfx_offset = mm_dependency_record->usVddgfxOffset;
742 mm_table_record->aclk = mm_dependency_record->ulAClk;
743 mm_table_record->samclock = mm_dependency_record->ulSAMUClk;
744 mm_table_record->eclk = mm_dependency_record->ulEClk;
745 mm_table_record->vclk = mm_dependency_record->ulVClk;
746 mm_table_record->dclk = mm_dependency_record->ulDClk;
749 *tonga_mm_table = mm_table;
755 * Private Function used during initialization.
756 * Initialize clock voltage dependency
757 * @param hwmgr Pointer to the hardware manager.
758 * @param powerplay_table Pointer to the PowerPlay Table.
760 static int init_clock_voltage_dependency(
761 struct pp_hwmgr *hwmgr,
762 const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
766 struct phm_ppt_v1_information *pp_table_information =
767 (struct phm_ppt_v1_information *)(hwmgr->pptable);
769 const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table =
770 (const ATOM_Tonga_MM_Dependency_Table *)(((unsigned long) powerplay_table) +
771 le16_to_cpu(powerplay_table->usMMDependencyTableOffset));
772 const PPTable_Generic_SubTable_Header *pPowerTuneTable =
773 (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
774 le16_to_cpu(powerplay_table->usPowerTuneTableOffset));
775 const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
776 (const ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long) powerplay_table) +
777 le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
778 const PPTable_Generic_SubTable_Header *sclk_dep_table =
779 (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
780 le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
781 const ATOM_Tonga_Hard_Limit_Table *pHardLimits =
782 (const ATOM_Tonga_Hard_Limit_Table *)(((unsigned long) powerplay_table) +
783 le16_to_cpu(powerplay_table->usHardLimitTableOffset));
784 const PPTable_Generic_SubTable_Header *pcie_table =
785 (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
786 le16_to_cpu(powerplay_table->usPCIETableOffset));
788 pp_table_information->vdd_dep_on_sclk = NULL;
789 pp_table_information->vdd_dep_on_mclk = NULL;
790 pp_table_information->mm_dep_table = NULL;
791 pp_table_information->pcie_table = NULL;
793 if (powerplay_table->usMMDependencyTableOffset != 0)
794 result = get_mm_clock_voltage_table(hwmgr,
795 &pp_table_information->mm_dep_table, mm_dependency_table);
797 if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0)
798 result = get_cac_tdp_table(hwmgr,
799 &pp_table_information->cac_dtp_table, pPowerTuneTable);
801 if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0)
802 result = get_sclk_voltage_dependency_table(hwmgr,
803 &pp_table_information->vdd_dep_on_sclk, sclk_dep_table);
805 if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0)
806 result = get_mclk_voltage_dependency_table(hwmgr,
807 &pp_table_information->vdd_dep_on_mclk, mclk_dep_table);
809 if (result == 0 && powerplay_table->usPCIETableOffset != 0)
810 result = get_pcie_table(hwmgr,
811 &pp_table_information->pcie_table, pcie_table);
813 if (result == 0 && powerplay_table->usHardLimitTableOffset != 0)
814 result = get_hard_limits(hwmgr,
815 &pp_table_information->max_clock_voltage_on_dc, pHardLimits);
817 hwmgr->dyn_state.max_clock_voltage_on_dc.sclk =
818 pp_table_information->max_clock_voltage_on_dc.sclk;
819 hwmgr->dyn_state.max_clock_voltage_on_dc.mclk =
820 pp_table_information->max_clock_voltage_on_dc.mclk;
821 hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
822 pp_table_information->max_clock_voltage_on_dc.vddc;
823 hwmgr->dyn_state.max_clock_voltage_on_dc.vddci =
824 pp_table_information->max_clock_voltage_on_dc.vddci;
826 if (result == 0 && (NULL != pp_table_information->vdd_dep_on_mclk)
827 && (0 != pp_table_information->vdd_dep_on_mclk->count))
828 result = get_valid_clk(hwmgr, &pp_table_information->valid_mclk_values,
829 pp_table_information->vdd_dep_on_mclk);
831 if (result == 0 && (NULL != pp_table_information->vdd_dep_on_sclk)
832 && (0 != pp_table_information->vdd_dep_on_sclk->count))
833 result = get_valid_clk(hwmgr, &pp_table_information->valid_sclk_values,
834 pp_table_information->vdd_dep_on_sclk);
839 /** Retrieves the (signed) Overdrive limits from VBIOS.
840 * The max engine clock, memory clock and max temperature come from the firmware info table.
842 * The information is placed into the platform descriptor.
844 * @param hwmgr source of the VBIOS table and owner of the platform descriptor to be updated.
845 * @param powerplay_table the address of the PowerPlay table.
847 * @return 1 as long as the firmware info table was present and of a supported version.
849 static int init_over_drive_limits(
850 struct pp_hwmgr *hwmgr,
851 const ATOM_Tonga_POWERPLAYTABLE *powerplay_table)
853 hwmgr->platform_descriptor.overdriveLimit.engineClock =
854 le16_to_cpu(powerplay_table->ulMaxODEngineClock);
855 hwmgr->platform_descriptor.overdriveLimit.memoryClock =
856 le16_to_cpu(powerplay_table->ulMaxODMemoryClock);
858 hwmgr->platform_descriptor.minOverdriveVDDC = 0;
859 hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
860 hwmgr->platform_descriptor.overdriveVDDCStep = 0;
862 if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0 \
863 && hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0) {
864 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
865 PHM_PlatformCaps_ACOverdriveSupport);
872 * Private Function used during initialization.
873 * Inspect the PowerPlay table for obvious signs of corruption.
874 * @param hwmgr Pointer to the hardware manager.
875 * @param powerplay_table Pointer to the PowerPlay Table.
876 * @exception This implementation always returns 1.
878 static int init_thermal_controller(
879 struct pp_hwmgr *hwmgr,
880 const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
883 const PPTable_Generic_SubTable_Header *fan_table;
884 ATOM_Tonga_Thermal_Controller *thermal_controller;
886 thermal_controller = (ATOM_Tonga_Thermal_Controller *)
887 (((unsigned long)powerplay_table) +
888 le16_to_cpu(powerplay_table->usThermalControllerOffset));
889 PP_ASSERT_WITH_CODE((0 != powerplay_table->usThermalControllerOffset),
890 "Thermal controller table not set!", return -1);
892 hwmgr->thermal_controller.ucType = thermal_controller->ucType;
893 hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine;
894 hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress;
896 hwmgr->thermal_controller.fanInfo.bNoFan =
897 (0 != (thermal_controller->ucFanParameters & ATOM_TONGA_PP_FANPARAMETERS_NOFAN));
899 hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution =
900 thermal_controller->ucFanParameters &
901 ATOM_TONGA_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
903 hwmgr->thermal_controller.fanInfo.ulMinRPM
904 = thermal_controller->ucFanMinRPM * 100UL;
905 hwmgr->thermal_controller.fanInfo.ulMaxRPM
906 = thermal_controller->ucFanMaxRPM * 100UL;
910 ATOM_TONGA_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType,
911 PHM_PlatformCaps_ThermalController
914 if (0 == powerplay_table->usFanTableOffset)
917 fan_table = (const PPTable_Generic_SubTable_Header *)
918 (((unsigned long)powerplay_table) +
919 le16_to_cpu(powerplay_table->usFanTableOffset));
921 PP_ASSERT_WITH_CODE((0 != powerplay_table->usFanTableOffset),
922 "Fan table not set!", return -1);
923 PP_ASSERT_WITH_CODE((0 < fan_table->ucRevId),
924 "Unsupported fan table format!", return -1);
926 hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay
928 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
929 PHM_PlatformCaps_MicrocodeFanControl);
931 if (fan_table->ucRevId < 8) {
932 const ATOM_Tonga_Fan_Table *tonga_fan_table =
933 (ATOM_Tonga_Fan_Table *)fan_table;
934 hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst
935 = tonga_fan_table->ucTHyst;
936 hwmgr->thermal_controller.advanceFanControlParameters.usTMin
937 = tonga_fan_table->usTMin;
938 hwmgr->thermal_controller.advanceFanControlParameters.usTMed
939 = tonga_fan_table->usTMed;
940 hwmgr->thermal_controller.advanceFanControlParameters.usTHigh
941 = tonga_fan_table->usTHigh;
942 hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin
943 = tonga_fan_table->usPWMMin;
944 hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed
945 = tonga_fan_table->usPWMMed;
946 hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh
947 = tonga_fan_table->usPWMHigh;
948 hwmgr->thermal_controller.advanceFanControlParameters.usTMax
949 = 10900; /* hard coded */
950 hwmgr->thermal_controller.advanceFanControlParameters.usTMax
951 = tonga_fan_table->usTMax;
952 hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode
953 = tonga_fan_table->ucFanControlMode;
954 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM
955 = tonga_fan_table->usFanPWMMax;
956 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity
958 hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity
959 = tonga_fan_table->usFanOutputSensitivity;
960 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM
961 = tonga_fan_table->usFanRPMMax;
962 hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit
963 = (tonga_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places. SMC wants MHz. */
964 hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature
965 = tonga_fan_table->ucTargetTemperature;
966 hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit
967 = tonga_fan_table->ucMinimumPWMLimit;
969 const ATOM_Fiji_Fan_Table *fiji_fan_table =
970 (ATOM_Fiji_Fan_Table *)fan_table;
971 hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst
972 = fiji_fan_table->ucTHyst;
973 hwmgr->thermal_controller.advanceFanControlParameters.usTMin
974 = fiji_fan_table->usTMin;
975 hwmgr->thermal_controller.advanceFanControlParameters.usTMed
976 = fiji_fan_table->usTMed;
977 hwmgr->thermal_controller.advanceFanControlParameters.usTHigh
978 = fiji_fan_table->usTHigh;
979 hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin
980 = fiji_fan_table->usPWMMin;
981 hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed
982 = fiji_fan_table->usPWMMed;
983 hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh
984 = fiji_fan_table->usPWMHigh;
985 hwmgr->thermal_controller.advanceFanControlParameters.usTMax
986 = fiji_fan_table->usTMax;
987 hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode
988 = fiji_fan_table->ucFanControlMode;
989 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM
990 = fiji_fan_table->usFanPWMMax;
991 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity
993 hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity
994 = fiji_fan_table->usFanOutputSensitivity;
995 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM
996 = fiji_fan_table->usFanRPMMax;
997 hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit
998 = (fiji_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places. SMC wants MHz. */
999 hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature
1000 = fiji_fan_table->ucTargetTemperature;
1001 hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit
1002 = fiji_fan_table->ucMinimumPWMLimit;
1004 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainEdge
1005 = fiji_fan_table->usFanGainEdge;
1006 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHotspot
1007 = fiji_fan_table->usFanGainHotspot;
1008 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainLiquid
1009 = fiji_fan_table->usFanGainLiquid;
1010 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrVddc
1011 = fiji_fan_table->usFanGainVrVddc;
1012 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrMvdd
1013 = fiji_fan_table->usFanGainVrMvdd;
1014 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainPlx
1015 = fiji_fan_table->usFanGainPlx;
1016 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHbm
1017 = fiji_fan_table->usFanGainHbm;
1024 * Private Function used during initialization.
1025 * Inspect the PowerPlay table for obvious signs of corruption.
1026 * @param hwmgr Pointer to the hardware manager.
1027 * @param powerplay_table Pointer to the PowerPlay Table.
1028 * @exception 2 if the powerplay table is incorrect.
1030 static int check_powerplay_tables(
1031 struct pp_hwmgr *hwmgr,
1032 const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
1035 const ATOM_Tonga_State_Array *state_arrays;
1037 state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)powerplay_table) +
1038 le16_to_cpu(powerplay_table->usStateArrayOffset));
1040 PP_ASSERT_WITH_CODE((ATOM_Tonga_TABLE_REVISION_TONGA <=
1041 powerplay_table->sHeader.ucTableFormatRevision),
1042 "Unsupported PPTable format!", return -1);
1043 PP_ASSERT_WITH_CODE((0 != powerplay_table->usStateArrayOffset),
1044 "State table is not set!", return -1);
1045 PP_ASSERT_WITH_CODE((0 < powerplay_table->sHeader.usStructureSize),
1046 "Invalid PowerPlay Table!", return -1);
1047 PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
1048 "Invalid PowerPlay Table!", return -1);
1053 int pp_tables_v1_0_initialize(struct pp_hwmgr *hwmgr)
1056 const ATOM_Tonga_POWERPLAYTABLE *powerplay_table;
1058 hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v1_information), GFP_KERNEL);
1060 PP_ASSERT_WITH_CODE((NULL != hwmgr->pptable),
1061 "Failed to allocate hwmgr->pptable!", return -ENOMEM);
1063 memset(hwmgr->pptable, 0x00, sizeof(struct phm_ppt_v1_information));
1065 powerplay_table = get_powerplay_table(hwmgr);
1067 PP_ASSERT_WITH_CODE((NULL != powerplay_table),
1068 "Missing PowerPlay Table!", return -1);
1070 result = check_powerplay_tables(hwmgr, powerplay_table);
1072 PP_ASSERT_WITH_CODE((result == 0),
1073 "check_powerplay_tables failed", return result);
1075 result = set_platform_caps(hwmgr,
1076 le32_to_cpu(powerplay_table->ulPlatformCaps));
1078 PP_ASSERT_WITH_CODE((result == 0),
1079 "set_platform_caps failed", return result);
1081 result = init_thermal_controller(hwmgr, powerplay_table);
1083 PP_ASSERT_WITH_CODE((result == 0),
1084 "init_thermal_controller failed", return result);
1086 result = init_over_drive_limits(hwmgr, powerplay_table);
1088 PP_ASSERT_WITH_CODE((result == 0),
1089 "init_over_drive_limits failed", return result);
1091 result = init_clock_voltage_dependency(hwmgr, powerplay_table);
1093 PP_ASSERT_WITH_CODE((result == 0),
1094 "init_clock_voltage_dependency failed", return result);
1096 result = init_dpm_2_parameters(hwmgr, powerplay_table);
1098 PP_ASSERT_WITH_CODE((result == 0),
1099 "init_dpm_2_parameters failed", return result);
1104 int pp_tables_v1_0_uninitialize(struct pp_hwmgr *hwmgr)
1106 struct phm_ppt_v1_information *pp_table_information =
1107 (struct phm_ppt_v1_information *)(hwmgr->pptable);
1109 kfree(pp_table_information->vdd_dep_on_sclk);
1110 pp_table_information->vdd_dep_on_sclk = NULL;
1112 kfree(pp_table_information->vdd_dep_on_mclk);
1113 pp_table_information->vdd_dep_on_mclk = NULL;
1115 kfree(pp_table_information->valid_mclk_values);
1116 pp_table_information->valid_mclk_values = NULL;
1118 kfree(pp_table_information->valid_sclk_values);
1119 pp_table_information->valid_sclk_values = NULL;
1121 kfree(pp_table_information->vddc_lookup_table);
1122 pp_table_information->vddc_lookup_table = NULL;
1124 kfree(pp_table_information->vddgfx_lookup_table);
1125 pp_table_information->vddgfx_lookup_table = NULL;
1127 kfree(pp_table_information->mm_dep_table);
1128 pp_table_information->mm_dep_table = NULL;
1130 kfree(pp_table_information->cac_dtp_table);
1131 pp_table_information->cac_dtp_table = NULL;
1133 kfree(hwmgr->dyn_state.cac_dtp_table);
1134 hwmgr->dyn_state.cac_dtp_table = NULL;
1136 kfree(pp_table_information->ppm_parameter_table);
1137 pp_table_information->ppm_parameter_table = NULL;
1139 kfree(pp_table_information->pcie_table);
1140 pp_table_information->pcie_table = NULL;
1142 kfree(hwmgr->pptable);
1143 hwmgr->pptable = NULL;
1148 const struct pp_table_func pptable_v1_0_funcs = {
1149 .pptable_init = pp_tables_v1_0_initialize,
1150 .pptable_fini = pp_tables_v1_0_uninitialize,
1153 int get_number_of_powerplay_table_entries_v1_0(struct pp_hwmgr *hwmgr)
1155 ATOM_Tonga_State_Array const *state_arrays;
1156 const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
1158 PP_ASSERT_WITH_CODE((NULL != pp_table),
1159 "Missing PowerPlay Table!", return -1);
1160 PP_ASSERT_WITH_CODE((pp_table->sHeader.ucTableFormatRevision >=
1161 ATOM_Tonga_TABLE_REVISION_TONGA),
1162 "Incorrect PowerPlay table revision!", return -1);
1164 state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
1165 le16_to_cpu(pp_table->usStateArrayOffset));
1167 return (uint32_t)(state_arrays->ucNumEntries);
1171 * Private function to convert flags stored in the BIOS to software flags in PowerPlay.
1173 static uint32_t make_classification_flags(struct pp_hwmgr *hwmgr,
1174 uint16_t classification, uint16_t classification2)
1176 uint32_t result = 0;
1178 if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT)
1179 result |= PP_StateClassificationFlag_Boot;
1181 if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL)
1182 result |= PP_StateClassificationFlag_Thermal;
1184 if (classification & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
1185 result |= PP_StateClassificationFlag_LimitedPowerSource;
1187 if (classification & ATOM_PPLIB_CLASSIFICATION_REST)
1188 result |= PP_StateClassificationFlag_Rest;
1190 if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED)
1191 result |= PP_StateClassificationFlag_Forced;
1193 if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI)
1194 result |= PP_StateClassificationFlag_ACPI;
1196 if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
1197 result |= PP_StateClassificationFlag_LimitedPowerSource_2;
1202 static int ppt_get_num_of_vce_state_table_entries_v1_0(struct pp_hwmgr *hwmgr)
1204 const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
1205 const ATOM_Tonga_VCE_State_Table *vce_state_table =
1206 (ATOM_Tonga_VCE_State_Table *)(((unsigned long)pp_table) + le16_to_cpu(pp_table->usVCEStateTableOffset));
1208 if (vce_state_table == NULL)
1211 return vce_state_table->ucNumEntries;
1214 static int ppt_get_vce_state_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t i,
1215 struct pp_vce_state *vce_state, void **clock_info, uint32_t *flag)
1217 const ATOM_Tonga_VCE_State_Record *vce_state_record;
1218 ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record;
1219 ATOM_Tonga_MCLK_Dependency_Record *mclk_dep_record;
1220 ATOM_Tonga_MM_Dependency_Record *mm_dep_record;
1221 const ATOM_Tonga_POWERPLAYTABLE *pptable = get_powerplay_table(hwmgr);
1222 const ATOM_Tonga_VCE_State_Table *vce_state_table = (ATOM_Tonga_VCE_State_Table *)(((unsigned long)pptable)
1223 + le16_to_cpu(pptable->usVCEStateTableOffset));
1224 const ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table = (ATOM_Tonga_SCLK_Dependency_Table *)(((unsigned long)pptable)
1225 + le16_to_cpu(pptable->usSclkDependencyTableOffset));
1226 const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table = (ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long)pptable)
1227 + le16_to_cpu(pptable->usMclkDependencyTableOffset));
1228 const ATOM_Tonga_MM_Dependency_Table *mm_dep_table = (ATOM_Tonga_MM_Dependency_Table *)(((unsigned long)pptable)
1229 + le16_to_cpu(pptable->usMMDependencyTableOffset));
1231 PP_ASSERT_WITH_CODE((i < vce_state_table->ucNumEntries),
1232 "Requested state entry ID is out of range!",
1235 vce_state_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
1236 ATOM_Tonga_VCE_State_Record,
1237 entries, vce_state_table, i);
1238 sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
1239 ATOM_Tonga_SCLK_Dependency_Record,
1240 entries, sclk_dep_table,
1241 vce_state_record->ucSCLKIndex);
1242 mm_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
1243 ATOM_Tonga_MM_Dependency_Record,
1244 entries, mm_dep_table,
1245 vce_state_record->ucVCEClockIndex);
1246 *flag = vce_state_record->ucFlag;
1248 vce_state->evclk = mm_dep_record->ulEClk;
1249 vce_state->ecclk = mm_dep_record->ulEClk;
1250 vce_state->sclk = sclk_dep_record->ulSclk;
1252 if (vce_state_record->ucMCLKIndex >= mclk_dep_table->ucNumEntries)
1253 mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
1254 ATOM_Tonga_MCLK_Dependency_Record,
1255 entries, mclk_dep_table,
1256 mclk_dep_table->ucNumEntries - 1);
1258 mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
1259 ATOM_Tonga_MCLK_Dependency_Record,
1260 entries, mclk_dep_table,
1261 vce_state_record->ucMCLKIndex);
1263 vce_state->mclk = mclk_dep_record->ulMclk;
1268 * Create a Power State out of an entry in the PowerPlay table.
1269 * This function is called by the hardware back-end.
1270 * @param hwmgr Pointer to the hardware manager.
1271 * @param entry_index The index of the entry to be extracted from the table.
1272 * @param power_state The address of the PowerState instance being created.
1273 * @return -1 if the entry cannot be retrieved.
1275 int get_powerplay_table_entry_v1_0(struct pp_hwmgr *hwmgr,
1276 uint32_t entry_index, struct pp_power_state *power_state,
1277 int (*call_back_func)(struct pp_hwmgr *, void *,
1278 struct pp_power_state *, void *, uint32_t))
1281 const ATOM_Tonga_State_Array *state_arrays;
1282 const ATOM_Tonga_State *state_entry;
1283 const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
1287 PP_ASSERT_WITH_CODE((NULL != pp_table), "Missing PowerPlay Table!", return -1;);
1288 power_state->classification.bios_index = entry_index;
1290 if (pp_table->sHeader.ucTableFormatRevision >=
1291 ATOM_Tonga_TABLE_REVISION_TONGA) {
1292 state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
1293 le16_to_cpu(pp_table->usStateArrayOffset));
1295 PP_ASSERT_WITH_CODE((0 < pp_table->usStateArrayOffset),
1296 "Invalid PowerPlay Table State Array Offset.", return -1);
1297 PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
1298 "Invalid PowerPlay Table State Array.", return -1);
1299 PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries),
1300 "Invalid PowerPlay Table State Array Entry.", return -1);
1302 state_entry = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
1303 ATOM_Tonga_State, entries,
1304 state_arrays, entry_index);
1306 result = call_back_func(hwmgr, (void *)state_entry, power_state,
1308 make_classification_flags(hwmgr,
1309 le16_to_cpu(state_entry->usClassification),
1310 le16_to_cpu(state_entry->usClassification2)));
1313 if (!result && (power_state->classification.flags &
1314 PP_StateClassificationFlag_Boot))
1315 result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(power_state->hardware));
1317 hwmgr->num_vce_state_tables = i = ppt_get_num_of_vce_state_table_entries_v1_0(hwmgr);
1319 if ((i != 0) && (i <= PP_MAX_VCE_LEVELS)) {
1320 for (j = 0; j < i; j++)
1321 ppt_get_vce_state_table_entry_v1_0(hwmgr, j, &(hwmgr->vce_states[j]), NULL, &flags);