2 * Copyright 2017 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 "vega12/smu9_driver_if.h"
28 #include "vega12_processpptables.h"
29 #include "ppatomfwctrl.h"
30 #include "atomfirmware.h"
32 #include "cgs_common.h"
33 #include "vega12_pptable.h"
35 static void set_hw_cap(struct pp_hwmgr
*hwmgr
, bool enable
,
36 enum phm_platform_caps cap
)
39 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
, cap
);
41 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
, cap
);
44 static const void *get_powerplay_table(struct pp_hwmgr
*hwmgr
)
46 int index
= GetIndexIntoMasterDataTable(powerplayinfo
);
50 const void *table_address
= hwmgr
->soft_pp_table
;
53 table_address
= (ATOM_Vega12_POWERPLAYTABLE
*)
54 smu_atom_get_data_table(hwmgr
->adev
, index
,
57 hwmgr
->soft_pp_table
= table_address
; /*Cache the result in RAM.*/
58 hwmgr
->soft_pp_table_size
= size
;
64 static int check_powerplay_tables(
65 struct pp_hwmgr
*hwmgr
,
66 const ATOM_Vega12_POWERPLAYTABLE
*powerplay_table
)
68 PP_ASSERT_WITH_CODE((powerplay_table
->sHeader
.format_revision
>=
69 ATOM_VEGA12_TABLE_REVISION_VEGA12
),
70 "Unsupported PPTable format!", return -1);
71 PP_ASSERT_WITH_CODE(powerplay_table
->sHeader
.structuresize
> 0,
72 "Invalid PowerPlay Table!", return -1);
77 static int set_platform_caps(struct pp_hwmgr
*hwmgr
, uint32_t powerplay_caps
)
81 0 != (powerplay_caps
& ATOM_VEGA12_PP_PLATFORM_CAP_POWERPLAY
),
82 PHM_PlatformCaps_PowerPlaySupport
);
86 0 != (powerplay_caps
& ATOM_VEGA12_PP_PLATFORM_CAP_SBIOSPOWERSOURCE
),
87 PHM_PlatformCaps_BiosPowerSourceControl
);
91 0 != (powerplay_caps
& ATOM_VEGA12_PP_PLATFORM_CAP_BACO
),
92 PHM_PlatformCaps_BACO
);
96 0 != (powerplay_caps
& ATOM_VEGA12_PP_PLATFORM_CAP_BAMACO
),
97 PHM_PlatformCaps_BAMACO
);
102 static int copy_clock_limits_array(
103 struct pp_hwmgr
*hwmgr
,
104 uint32_t **pptable_info_array
,
105 const uint32_t *pptable_array
)
107 uint32_t array_size
, i
;
110 array_size
= sizeof(uint32_t) * ATOM_VEGA12_PPCLOCK_COUNT
;
112 table
= kzalloc(array_size
, GFP_KERNEL
);
116 for (i
= 0; i
< ATOM_VEGA12_PPCLOCK_COUNT
; i
++)
117 table
[i
] = pptable_array
[i
];
119 *pptable_info_array
= table
;
124 static int copy_overdrive_settings_limits_array(
125 struct pp_hwmgr
*hwmgr
,
126 uint32_t **pptable_info_array
,
127 const uint32_t *pptable_array
)
129 uint32_t array_size
, i
;
132 array_size
= sizeof(uint32_t) * ATOM_VEGA12_ODSETTING_COUNT
;
134 table
= kzalloc(array_size
, GFP_KERNEL
);
138 for (i
= 0; i
< ATOM_VEGA12_ODSETTING_COUNT
; i
++)
139 table
[i
] = pptable_array
[i
];
141 *pptable_info_array
= table
;
146 static int append_vbios_pptable(struct pp_hwmgr
*hwmgr
, PPTable_t
*ppsmc_pptable
)
148 struct pp_atomfwctrl_smc_dpm_parameters smc_dpm_table
;
151 pp_atomfwctrl_get_smc_dpm_information(hwmgr
, &smc_dpm_table
) == 0,
152 "[appendVbiosPPTable] Failed to retrieve Smc Dpm Table from VBIOS!",
155 ppsmc_pptable
->Liquid1_I2C_address
= smc_dpm_table
.liquid1_i2c_address
;
156 ppsmc_pptable
->Liquid2_I2C_address
= smc_dpm_table
.liquid2_i2c_address
;
157 ppsmc_pptable
->Vr_I2C_address
= smc_dpm_table
.vr_i2c_address
;
158 ppsmc_pptable
->Plx_I2C_address
= smc_dpm_table
.plx_i2c_address
;
160 ppsmc_pptable
->Liquid_I2C_LineSCL
= smc_dpm_table
.liquid_i2c_linescl
;
161 ppsmc_pptable
->Liquid_I2C_LineSDA
= smc_dpm_table
.liquid_i2c_linesda
;
162 ppsmc_pptable
->Vr_I2C_LineSCL
= smc_dpm_table
.vr_i2c_linescl
;
163 ppsmc_pptable
->Vr_I2C_LineSDA
= smc_dpm_table
.vr_i2c_linesda
;
165 ppsmc_pptable
->Plx_I2C_LineSCL
= smc_dpm_table
.plx_i2c_linescl
;
166 ppsmc_pptable
->Plx_I2C_LineSDA
= smc_dpm_table
.plx_i2c_linesda
;
167 ppsmc_pptable
->VrSensorPresent
= smc_dpm_table
.vrsensorpresent
;
168 ppsmc_pptable
->LiquidSensorPresent
= smc_dpm_table
.liquidsensorpresent
;
170 ppsmc_pptable
->MaxVoltageStepGfx
= smc_dpm_table
.maxvoltagestepgfx
;
171 ppsmc_pptable
->MaxVoltageStepSoc
= smc_dpm_table
.maxvoltagestepsoc
;
173 ppsmc_pptable
->VddGfxVrMapping
= smc_dpm_table
.vddgfxvrmapping
;
174 ppsmc_pptable
->VddSocVrMapping
= smc_dpm_table
.vddsocvrmapping
;
175 ppsmc_pptable
->VddMem0VrMapping
= smc_dpm_table
.vddmem0vrmapping
;
176 ppsmc_pptable
->VddMem1VrMapping
= smc_dpm_table
.vddmem1vrmapping
;
178 ppsmc_pptable
->GfxUlvPhaseSheddingMask
= smc_dpm_table
.gfxulvphasesheddingmask
;
179 ppsmc_pptable
->SocUlvPhaseSheddingMask
= smc_dpm_table
.soculvphasesheddingmask
;
181 ppsmc_pptable
->GfxMaxCurrent
= smc_dpm_table
.gfxmaxcurrent
;
182 ppsmc_pptable
->GfxOffset
= smc_dpm_table
.gfxoffset
;
183 ppsmc_pptable
->Padding_TelemetryGfx
= smc_dpm_table
.padding_telemetrygfx
;
185 ppsmc_pptable
->SocMaxCurrent
= smc_dpm_table
.socmaxcurrent
;
186 ppsmc_pptable
->SocOffset
= smc_dpm_table
.socoffset
;
187 ppsmc_pptable
->Padding_TelemetrySoc
= smc_dpm_table
.padding_telemetrysoc
;
189 ppsmc_pptable
->Mem0MaxCurrent
= smc_dpm_table
.mem0maxcurrent
;
190 ppsmc_pptable
->Mem0Offset
= smc_dpm_table
.mem0offset
;
191 ppsmc_pptable
->Padding_TelemetryMem0
= smc_dpm_table
.padding_telemetrymem0
;
193 ppsmc_pptable
->Mem1MaxCurrent
= smc_dpm_table
.mem1maxcurrent
;
194 ppsmc_pptable
->Mem1Offset
= smc_dpm_table
.mem1offset
;
195 ppsmc_pptable
->Padding_TelemetryMem1
= smc_dpm_table
.padding_telemetrymem1
;
197 ppsmc_pptable
->AcDcGpio
= smc_dpm_table
.acdcgpio
;
198 ppsmc_pptable
->AcDcPolarity
= smc_dpm_table
.acdcpolarity
;
199 ppsmc_pptable
->VR0HotGpio
= smc_dpm_table
.vr0hotgpio
;
200 ppsmc_pptable
->VR0HotPolarity
= smc_dpm_table
.vr0hotpolarity
;
202 ppsmc_pptable
->VR1HotGpio
= smc_dpm_table
.vr1hotgpio
;
203 ppsmc_pptable
->VR1HotPolarity
= smc_dpm_table
.vr1hotpolarity
;
204 ppsmc_pptable
->Padding1
= smc_dpm_table
.padding1
;
205 ppsmc_pptable
->Padding2
= smc_dpm_table
.padding2
;
207 ppsmc_pptable
->LedPin0
= smc_dpm_table
.ledpin0
;
208 ppsmc_pptable
->LedPin1
= smc_dpm_table
.ledpin1
;
209 ppsmc_pptable
->LedPin2
= smc_dpm_table
.ledpin2
;
211 ppsmc_pptable
->PllGfxclkSpreadEnabled
= smc_dpm_table
.pllgfxclkspreadenabled
;
212 ppsmc_pptable
->PllGfxclkSpreadPercent
= smc_dpm_table
.pllgfxclkspreadpercent
;
213 ppsmc_pptable
->PllGfxclkSpreadFreq
= smc_dpm_table
.pllgfxclkspreadfreq
;
215 ppsmc_pptable
->UclkSpreadEnabled
= 0;
216 ppsmc_pptable
->UclkSpreadPercent
= smc_dpm_table
.uclkspreadpercent
;
217 ppsmc_pptable
->UclkSpreadFreq
= smc_dpm_table
.uclkspreadfreq
;
219 ppsmc_pptable
->SocclkSpreadEnabled
= 0;
220 ppsmc_pptable
->SocclkSpreadPercent
= smc_dpm_table
.socclkspreadpercent
;
221 ppsmc_pptable
->SocclkSpreadFreq
= smc_dpm_table
.socclkspreadfreq
;
223 ppsmc_pptable
->AcgGfxclkSpreadEnabled
= smc_dpm_table
.acggfxclkspreadenabled
;
224 ppsmc_pptable
->AcgGfxclkSpreadPercent
= smc_dpm_table
.acggfxclkspreadpercent
;
225 ppsmc_pptable
->AcgGfxclkSpreadFreq
= smc_dpm_table
.acggfxclkspreadfreq
;
227 ppsmc_pptable
->Vr2_I2C_address
= smc_dpm_table
.Vr2_I2C_address
;
229 ppsmc_pptable
->Vr2_I2C_address
= smc_dpm_table
.Vr2_I2C_address
;
234 #define VEGA12_ENGINECLOCK_HARDMAX 198000
235 static int init_powerplay_table_information(
236 struct pp_hwmgr
*hwmgr
,
237 const ATOM_Vega12_POWERPLAYTABLE
*powerplay_table
)
239 struct phm_ppt_v3_information
*pptable_information
=
240 (struct phm_ppt_v3_information
*)hwmgr
->pptable
;
241 uint32_t disable_power_control
= 0;
244 hwmgr
->thermal_controller
.ucType
= powerplay_table
->ucThermalControllerType
;
245 pptable_information
->uc_thermal_controller_type
= powerplay_table
->ucThermalControllerType
;
248 ATOM_VEGA12_PP_THERMALCONTROLLER_NONE
!= hwmgr
->thermal_controller
.ucType
,
249 PHM_PlatformCaps_ThermalController
);
251 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_MicrocodeFanControl
);
253 if (powerplay_table
->ODSettingsMax
[ATOM_VEGA12_ODSETTING_GFXCLKFMAX
] > VEGA12_ENGINECLOCK_HARDMAX
)
254 hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
= VEGA12_ENGINECLOCK_HARDMAX
;
256 hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
= powerplay_table
->ODSettingsMax
[ATOM_VEGA12_ODSETTING_GFXCLKFMAX
];
257 hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
= powerplay_table
->ODSettingsMax
[ATOM_VEGA12_ODSETTING_UCLKFMAX
];
259 copy_overdrive_settings_limits_array(hwmgr
, &pptable_information
->od_settings_max
, powerplay_table
->ODSettingsMax
);
260 copy_overdrive_settings_limits_array(hwmgr
, &pptable_information
->od_settings_min
, powerplay_table
->ODSettingsMin
);
262 /* hwmgr->platformDescriptor.minOverdriveVDDC = 0;
263 hwmgr->platformDescriptor.maxOverdriveVDDC = 0;
264 hwmgr->platformDescriptor.overdriveVDDCStep = 0; */
266 if (hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
> 0
267 && hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
> 0)
268 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_ACOverdriveSupport
);
270 pptable_information
->us_small_power_limit1
= powerplay_table
->usSmallPowerLimit1
;
271 pptable_information
->us_small_power_limit2
= powerplay_table
->usSmallPowerLimit2
;
272 pptable_information
->us_boost_power_limit
= powerplay_table
->usBoostPowerLimit
;
273 pptable_information
->us_od_turbo_power_limit
= powerplay_table
->usODTurboPowerLimit
;
274 pptable_information
->us_od_powersave_power_limit
= powerplay_table
->usODPowerSavePowerLimit
;
276 pptable_information
->us_software_shutdown_temp
= powerplay_table
->usSoftwareShutdownTemp
;
278 hwmgr
->platform_descriptor
.TDPODLimit
= (uint16_t)powerplay_table
->ODSettingsMax
[ATOM_VEGA12_ODSETTING_POWERPERCENTAGE
];
280 disable_power_control
= 0;
281 if (!disable_power_control
) {
282 /* enable TDP overdrive (PowerControl) feature as well if supported */
283 if (hwmgr
->platform_descriptor
.TDPODLimit
)
284 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
285 PHM_PlatformCaps_PowerControl
);
288 copy_clock_limits_array(hwmgr
, &pptable_information
->power_saving_clock_max
, powerplay_table
->PowerSavingClockMax
);
289 copy_clock_limits_array(hwmgr
, &pptable_information
->power_saving_clock_min
, powerplay_table
->PowerSavingClockMin
);
291 pptable_information
->smc_pptable
= (PPTable_t
*)kmalloc(sizeof(PPTable_t
), GFP_KERNEL
);
292 if (pptable_information
->smc_pptable
== NULL
)
295 memcpy(pptable_information
->smc_pptable
, &(powerplay_table
->smcPPTable
), sizeof(PPTable_t
));
297 result
= append_vbios_pptable(hwmgr
, (pptable_information
->smc_pptable
));
302 int vega12_pp_tables_initialize(struct pp_hwmgr
*hwmgr
)
305 const ATOM_Vega12_POWERPLAYTABLE
*powerplay_table
;
307 hwmgr
->pptable
= kzalloc(sizeof(struct phm_ppt_v3_information
), GFP_KERNEL
);
308 PP_ASSERT_WITH_CODE((hwmgr
->pptable
!= NULL
),
309 "Failed to allocate hwmgr->pptable!", return -ENOMEM
);
311 powerplay_table
= get_powerplay_table(hwmgr
);
312 PP_ASSERT_WITH_CODE((powerplay_table
!= NULL
),
313 "Missing PowerPlay Table!", return -1);
315 result
= check_powerplay_tables(hwmgr
, powerplay_table
);
316 PP_ASSERT_WITH_CODE((result
== 0),
317 "check_powerplay_tables failed", return result
);
319 result
= set_platform_caps(hwmgr
,
320 le32_to_cpu(powerplay_table
->ulPlatformCaps
));
321 PP_ASSERT_WITH_CODE((result
== 0),
322 "set_platform_caps failed", return result
);
324 result
= init_powerplay_table_information(hwmgr
, powerplay_table
);
325 PP_ASSERT_WITH_CODE((result
== 0),
326 "init_powerplay_table_information failed", return result
);
331 static int vega12_pp_tables_uninitialize(struct pp_hwmgr
*hwmgr
)
333 struct phm_ppt_v3_information
*pp_table_info
=
334 (struct phm_ppt_v3_information
*)(hwmgr
->pptable
);
336 kfree(pp_table_info
->power_saving_clock_max
);
337 pp_table_info
->power_saving_clock_max
= NULL
;
339 kfree(pp_table_info
->power_saving_clock_min
);
340 pp_table_info
->power_saving_clock_min
= NULL
;
342 kfree(pp_table_info
->od_settings_max
);
343 pp_table_info
->od_settings_max
= NULL
;
345 kfree(pp_table_info
->od_settings_min
);
346 pp_table_info
->od_settings_min
= NULL
;
348 kfree(pp_table_info
->smc_pptable
);
349 pp_table_info
->smc_pptable
= NULL
;
351 kfree(hwmgr
->pptable
);
352 hwmgr
->pptable
= NULL
;
357 const struct pp_table_func vega12_pptable_funcs
= {
358 .pptable_init
= vega12_pp_tables_initialize
,
359 .pptable_fini
= vega12_pp_tables_uninitialize
,
363 static uint32_t make_classification_flags(struct pp_hwmgr
*hwmgr
,
364 uint16_t classification
, uint16_t classification2
)
368 if (classification
& ATOM_PPLIB_CLASSIFICATION_BOOT
)
369 result
|= PP_StateClassificationFlag_Boot
;
371 if (classification
& ATOM_PPLIB_CLASSIFICATION_THERMAL
)
372 result
|= PP_StateClassificationFlag_Thermal
;
374 if (classification
& ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE
)
375 result
|= PP_StateClassificationFlag_LimitedPowerSource
;
377 if (classification
& ATOM_PPLIB_CLASSIFICATION_REST
)
378 result
|= PP_StateClassificationFlag_Rest
;
380 if (classification
& ATOM_PPLIB_CLASSIFICATION_FORCED
)
381 result
|= PP_StateClassificationFlag_Forced
;
383 if (classification
& ATOM_PPLIB_CLASSIFICATION_ACPI
)
384 result
|= PP_StateClassificationFlag_ACPI
;
386 if (classification2
& ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2
)
387 result
|= PP_StateClassificationFlag_LimitedPowerSource_2
;
392 int vega12_get_powerplay_table_entry(struct pp_hwmgr
*hwmgr
,
393 uint32_t entry_index
, struct pp_power_state
*power_state
,
394 int (*call_back_func
)(struct pp_hwmgr
*, void *,
395 struct pp_power_state
*, void *, uint32_t))
398 const ATOM_Vega12_State_Array
*state_arrays
;
399 const ATOM_Vega12_State
*state_entry
;
400 const ATOM_Vega12_POWERPLAYTABLE
*pp_table
=
401 get_powerplay_table(hwmgr
);
403 PP_ASSERT_WITH_CODE(pp_table
, "Missing PowerPlay Table!",
405 power_state
->classification
.bios_index
= entry_index
;
407 if (pp_table
->sHeader
.format_revision
>=
408 ATOM_Vega12_TABLE_REVISION_VEGA12
) {
409 state_arrays
= (ATOM_Vega12_State_Array
*)
410 (((unsigned long)pp_table
) +
411 le16_to_cpu(pp_table
->usStateArrayOffset
));
413 PP_ASSERT_WITH_CODE(pp_table
->usStateArrayOffset
> 0,
414 "Invalid PowerPlay Table State Array Offset.",
416 PP_ASSERT_WITH_CODE(state_arrays
->ucNumEntries
> 0,
417 "Invalid PowerPlay Table State Array.",
419 PP_ASSERT_WITH_CODE((entry_index
<= state_arrays
->ucNumEntries
),
420 "Invalid PowerPlay Table State Array Entry.",
423 state_entry
= &(state_arrays
->states
[entry_index
]);
425 result
= call_back_func(hwmgr
, (void *)state_entry
, power_state
,
427 make_classification_flags(hwmgr
,
428 le16_to_cpu(state_entry
->usClassification
),
429 le16_to_cpu(state_entry
->usClassification2
)));
432 if (!result
&& (power_state
->classification
.flags
&
433 PP_StateClassificationFlag_Boot
))
434 result
= hwmgr
->hwmgr_func
->patch_boot_state(hwmgr
, &(power_state
->hardware
));