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 append_vbios_pptable(struct pp_hwmgr
*hwmgr
, PPTable_t
*ppsmc_pptable
)
104 struct pp_atomfwctrl_smc_dpm_parameters smc_dpm_table
;
107 pp_atomfwctrl_get_smc_dpm_information(hwmgr
, &smc_dpm_table
) == 0,
108 "[appendVbiosPPTable] Failed to retrieve Smc Dpm Table from VBIOS!",
111 ppsmc_pptable
->Liquid1_I2C_address
= smc_dpm_table
.liquid1_i2c_address
;
112 ppsmc_pptable
->Liquid2_I2C_address
= smc_dpm_table
.liquid2_i2c_address
;
113 ppsmc_pptable
->Vr_I2C_address
= smc_dpm_table
.vr_i2c_address
;
114 ppsmc_pptable
->Plx_I2C_address
= smc_dpm_table
.plx_i2c_address
;
116 ppsmc_pptable
->Liquid_I2C_LineSCL
= smc_dpm_table
.liquid_i2c_linescl
;
117 ppsmc_pptable
->Liquid_I2C_LineSDA
= smc_dpm_table
.liquid_i2c_linesda
;
118 ppsmc_pptable
->Vr_I2C_LineSCL
= smc_dpm_table
.vr_i2c_linescl
;
119 ppsmc_pptable
->Vr_I2C_LineSDA
= smc_dpm_table
.vr_i2c_linesda
;
121 ppsmc_pptable
->Plx_I2C_LineSCL
= smc_dpm_table
.plx_i2c_linescl
;
122 ppsmc_pptable
->Plx_I2C_LineSDA
= smc_dpm_table
.plx_i2c_linesda
;
123 ppsmc_pptable
->VrSensorPresent
= smc_dpm_table
.vrsensorpresent
;
124 ppsmc_pptable
->LiquidSensorPresent
= smc_dpm_table
.liquidsensorpresent
;
126 ppsmc_pptable
->MaxVoltageStepGfx
= smc_dpm_table
.maxvoltagestepgfx
;
127 ppsmc_pptable
->MaxVoltageStepSoc
= smc_dpm_table
.maxvoltagestepsoc
;
129 ppsmc_pptable
->VddGfxVrMapping
= smc_dpm_table
.vddgfxvrmapping
;
130 ppsmc_pptable
->VddSocVrMapping
= smc_dpm_table
.vddsocvrmapping
;
131 ppsmc_pptable
->VddMem0VrMapping
= smc_dpm_table
.vddmem0vrmapping
;
132 ppsmc_pptable
->VddMem1VrMapping
= smc_dpm_table
.vddmem1vrmapping
;
134 ppsmc_pptable
->GfxUlvPhaseSheddingMask
= smc_dpm_table
.gfxulvphasesheddingmask
;
135 ppsmc_pptable
->SocUlvPhaseSheddingMask
= smc_dpm_table
.soculvphasesheddingmask
;
137 ppsmc_pptable
->GfxMaxCurrent
= smc_dpm_table
.gfxmaxcurrent
;
138 ppsmc_pptable
->GfxOffset
= smc_dpm_table
.gfxoffset
;
139 ppsmc_pptable
->Padding_TelemetryGfx
= smc_dpm_table
.padding_telemetrygfx
;
141 ppsmc_pptable
->SocMaxCurrent
= smc_dpm_table
.socmaxcurrent
;
142 ppsmc_pptable
->SocOffset
= smc_dpm_table
.socoffset
;
143 ppsmc_pptable
->Padding_TelemetrySoc
= smc_dpm_table
.padding_telemetrysoc
;
145 ppsmc_pptable
->Mem0MaxCurrent
= smc_dpm_table
.mem0maxcurrent
;
146 ppsmc_pptable
->Mem0Offset
= smc_dpm_table
.mem0offset
;
147 ppsmc_pptable
->Padding_TelemetryMem0
= smc_dpm_table
.padding_telemetrymem0
;
149 ppsmc_pptable
->Mem1MaxCurrent
= smc_dpm_table
.mem1maxcurrent
;
150 ppsmc_pptable
->Mem1Offset
= smc_dpm_table
.mem1offset
;
151 ppsmc_pptable
->Padding_TelemetryMem1
= smc_dpm_table
.padding_telemetrymem1
;
153 ppsmc_pptable
->AcDcGpio
= smc_dpm_table
.acdcgpio
;
154 ppsmc_pptable
->AcDcPolarity
= smc_dpm_table
.acdcpolarity
;
155 ppsmc_pptable
->VR0HotGpio
= smc_dpm_table
.vr0hotgpio
;
156 ppsmc_pptable
->VR0HotPolarity
= smc_dpm_table
.vr0hotpolarity
;
158 ppsmc_pptable
->VR1HotGpio
= smc_dpm_table
.vr1hotgpio
;
159 ppsmc_pptable
->VR1HotPolarity
= smc_dpm_table
.vr1hotpolarity
;
160 ppsmc_pptable
->Padding1
= smc_dpm_table
.padding1
;
161 ppsmc_pptable
->Padding2
= smc_dpm_table
.padding2
;
163 ppsmc_pptable
->LedPin0
= smc_dpm_table
.ledpin0
;
164 ppsmc_pptable
->LedPin1
= smc_dpm_table
.ledpin1
;
165 ppsmc_pptable
->LedPin2
= smc_dpm_table
.ledpin2
;
167 ppsmc_pptable
->PllGfxclkSpreadEnabled
= smc_dpm_table
.pllgfxclkspreadenabled
;
168 ppsmc_pptable
->PllGfxclkSpreadPercent
= smc_dpm_table
.pllgfxclkspreadpercent
;
169 ppsmc_pptable
->PllGfxclkSpreadFreq
= smc_dpm_table
.pllgfxclkspreadfreq
;
171 ppsmc_pptable
->UclkSpreadEnabled
= 0;
172 ppsmc_pptable
->UclkSpreadPercent
= smc_dpm_table
.uclkspreadpercent
;
173 ppsmc_pptable
->UclkSpreadFreq
= smc_dpm_table
.uclkspreadfreq
;
175 ppsmc_pptable
->SocclkSpreadEnabled
= 0;
176 ppsmc_pptable
->SocclkSpreadPercent
= smc_dpm_table
.socclkspreadpercent
;
177 ppsmc_pptable
->SocclkSpreadFreq
= smc_dpm_table
.socclkspreadfreq
;
179 ppsmc_pptable
->AcgGfxclkSpreadEnabled
= smc_dpm_table
.acggfxclkspreadenabled
;
180 ppsmc_pptable
->AcgGfxclkSpreadPercent
= smc_dpm_table
.acggfxclkspreadpercent
;
181 ppsmc_pptable
->AcgGfxclkSpreadFreq
= smc_dpm_table
.acggfxclkspreadfreq
;
183 ppsmc_pptable
->Vr2_I2C_address
= smc_dpm_table
.Vr2_I2C_address
;
185 ppsmc_pptable
->Vr2_I2C_address
= smc_dpm_table
.Vr2_I2C_address
;
190 #define VEGA12_ENGINECLOCK_HARDMAX 198000
191 static int init_powerplay_table_information(
192 struct pp_hwmgr
*hwmgr
,
193 const ATOM_Vega12_POWERPLAYTABLE
*powerplay_table
)
195 struct phm_ppt_v3_information
*pptable_information
=
196 (struct phm_ppt_v3_information
*)hwmgr
->pptable
;
197 uint32_t disable_power_control
= 0;
200 hwmgr
->thermal_controller
.ucType
= powerplay_table
->ucThermalControllerType
;
201 pptable_information
->uc_thermal_controller_type
= powerplay_table
->ucThermalControllerType
;
204 ATOM_VEGA12_PP_THERMALCONTROLLER_NONE
!= hwmgr
->thermal_controller
.ucType
,
205 PHM_PlatformCaps_ThermalController
);
207 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_MicrocodeFanControl
);
209 if (le32_to_cpu(powerplay_table
->ODSettingsMax
[ATOM_VEGA12_ODSETTING_GFXCLKFMAX
]) > VEGA12_ENGINECLOCK_HARDMAX
)
210 hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
= VEGA12_ENGINECLOCK_HARDMAX
;
212 hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
=
213 le32_to_cpu(powerplay_table
->ODSettingsMax
[ATOM_VEGA12_ODSETTING_GFXCLKFMAX
]);
214 hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
=
215 le32_to_cpu(powerplay_table
->ODSettingsMax
[ATOM_VEGA12_ODSETTING_UCLKFMAX
]);
217 phm_copy_overdrive_settings_limits_array(hwmgr
,
218 &pptable_information
->od_settings_max
,
219 powerplay_table
->ODSettingsMax
,
220 ATOM_VEGA12_ODSETTING_COUNT
);
221 phm_copy_overdrive_settings_limits_array(hwmgr
,
222 &pptable_information
->od_settings_min
,
223 powerplay_table
->ODSettingsMin
,
224 ATOM_VEGA12_ODSETTING_COUNT
);
226 /* hwmgr->platformDescriptor.minOverdriveVDDC = 0;
227 hwmgr->platformDescriptor.maxOverdriveVDDC = 0;
228 hwmgr->platformDescriptor.overdriveVDDCStep = 0; */
230 if (hwmgr
->platform_descriptor
.overdriveLimit
.engineClock
> 0
231 && hwmgr
->platform_descriptor
.overdriveLimit
.memoryClock
> 0)
232 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_ACOverdriveSupport
);
234 pptable_information
->us_small_power_limit1
= le16_to_cpu(powerplay_table
->usSmallPowerLimit1
);
235 pptable_information
->us_small_power_limit2
= le16_to_cpu(powerplay_table
->usSmallPowerLimit2
);
236 pptable_information
->us_boost_power_limit
= le16_to_cpu(powerplay_table
->usBoostPowerLimit
);
237 pptable_information
->us_od_turbo_power_limit
= le16_to_cpu(powerplay_table
->usODTurboPowerLimit
);
238 pptable_information
->us_od_powersave_power_limit
= le16_to_cpu(powerplay_table
->usODPowerSavePowerLimit
);
240 pptable_information
->us_software_shutdown_temp
= le16_to_cpu(powerplay_table
->usSoftwareShutdownTemp
);
242 hwmgr
->platform_descriptor
.TDPODLimit
= le32_to_cpu(powerplay_table
->ODSettingsMax
[ATOM_VEGA12_ODSETTING_POWERPERCENTAGE
]);
244 disable_power_control
= 0;
245 if (!disable_power_control
) {
246 /* enable TDP overdrive (PowerControl) feature as well if supported */
247 if (hwmgr
->platform_descriptor
.TDPODLimit
)
248 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
249 PHM_PlatformCaps_PowerControl
);
252 phm_copy_clock_limits_array(hwmgr
, &pptable_information
->power_saving_clock_max
, powerplay_table
->PowerSavingClockMax
, ATOM_VEGA12_PPCLOCK_COUNT
);
253 phm_copy_clock_limits_array(hwmgr
, &pptable_information
->power_saving_clock_min
, powerplay_table
->PowerSavingClockMin
, ATOM_VEGA12_PPCLOCK_COUNT
);
255 pptable_information
->smc_pptable
= (PPTable_t
*)kmalloc(sizeof(PPTable_t
), GFP_KERNEL
);
256 if (pptable_information
->smc_pptable
== NULL
)
259 memcpy(pptable_information
->smc_pptable
, &(powerplay_table
->smcPPTable
), sizeof(PPTable_t
));
261 result
= append_vbios_pptable(hwmgr
, (pptable_information
->smc_pptable
));
266 int vega12_pp_tables_initialize(struct pp_hwmgr
*hwmgr
)
269 const ATOM_Vega12_POWERPLAYTABLE
*powerplay_table
;
271 hwmgr
->pptable
= kzalloc(sizeof(struct phm_ppt_v3_information
), GFP_KERNEL
);
272 PP_ASSERT_WITH_CODE((hwmgr
->pptable
!= NULL
),
273 "Failed to allocate hwmgr->pptable!", return -ENOMEM
);
275 powerplay_table
= get_powerplay_table(hwmgr
);
276 PP_ASSERT_WITH_CODE((powerplay_table
!= NULL
),
277 "Missing PowerPlay Table!", return -1);
279 result
= check_powerplay_tables(hwmgr
, powerplay_table
);
280 PP_ASSERT_WITH_CODE((result
== 0),
281 "check_powerplay_tables failed", return result
);
283 result
= set_platform_caps(hwmgr
,
284 le32_to_cpu(powerplay_table
->ulPlatformCaps
));
285 PP_ASSERT_WITH_CODE((result
== 0),
286 "set_platform_caps failed", return result
);
288 result
= init_powerplay_table_information(hwmgr
, powerplay_table
);
289 PP_ASSERT_WITH_CODE((result
== 0),
290 "init_powerplay_table_information failed", return result
);
295 static int vega12_pp_tables_uninitialize(struct pp_hwmgr
*hwmgr
)
297 struct phm_ppt_v3_information
*pp_table_info
=
298 (struct phm_ppt_v3_information
*)(hwmgr
->pptable
);
300 kfree(pp_table_info
->power_saving_clock_max
);
301 pp_table_info
->power_saving_clock_max
= NULL
;
303 kfree(pp_table_info
->power_saving_clock_min
);
304 pp_table_info
->power_saving_clock_min
= NULL
;
306 kfree(pp_table_info
->od_settings_max
);
307 pp_table_info
->od_settings_max
= NULL
;
309 kfree(pp_table_info
->od_settings_min
);
310 pp_table_info
->od_settings_min
= NULL
;
312 kfree(pp_table_info
->smc_pptable
);
313 pp_table_info
->smc_pptable
= NULL
;
315 kfree(hwmgr
->pptable
);
316 hwmgr
->pptable
= NULL
;
321 const struct pp_table_func vega12_pptable_funcs
= {
322 .pptable_init
= vega12_pp_tables_initialize
,
323 .pptable_fini
= vega12_pp_tables_uninitialize
,
327 static uint32_t make_classification_flags(struct pp_hwmgr
*hwmgr
,
328 uint16_t classification
, uint16_t classification2
)
332 if (classification
& ATOM_PPLIB_CLASSIFICATION_BOOT
)
333 result
|= PP_StateClassificationFlag_Boot
;
335 if (classification
& ATOM_PPLIB_CLASSIFICATION_THERMAL
)
336 result
|= PP_StateClassificationFlag_Thermal
;
338 if (classification
& ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE
)
339 result
|= PP_StateClassificationFlag_LimitedPowerSource
;
341 if (classification
& ATOM_PPLIB_CLASSIFICATION_REST
)
342 result
|= PP_StateClassificationFlag_Rest
;
344 if (classification
& ATOM_PPLIB_CLASSIFICATION_FORCED
)
345 result
|= PP_StateClassificationFlag_Forced
;
347 if (classification
& ATOM_PPLIB_CLASSIFICATION_ACPI
)
348 result
|= PP_StateClassificationFlag_ACPI
;
350 if (classification2
& ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2
)
351 result
|= PP_StateClassificationFlag_LimitedPowerSource_2
;
356 int vega12_get_powerplay_table_entry(struct pp_hwmgr
*hwmgr
,
357 uint32_t entry_index
, struct pp_power_state
*power_state
,
358 int (*call_back_func
)(struct pp_hwmgr
*, void *,
359 struct pp_power_state
*, void *, uint32_t))
362 const ATOM_Vega12_State_Array
*state_arrays
;
363 const ATOM_Vega12_State
*state_entry
;
364 const ATOM_Vega12_POWERPLAYTABLE
*pp_table
=
365 get_powerplay_table(hwmgr
);
367 PP_ASSERT_WITH_CODE(pp_table
, "Missing PowerPlay Table!",
369 power_state
->classification
.bios_index
= entry_index
;
371 if (pp_table
->sHeader
.format_revision
>=
372 ATOM_Vega12_TABLE_REVISION_VEGA12
) {
373 state_arrays
= (ATOM_Vega12_State_Array
*)
374 (((unsigned long)pp_table
) +
375 le16_to_cpu(pp_table
->usStateArrayOffset
));
377 PP_ASSERT_WITH_CODE(pp_table
->usStateArrayOffset
> 0,
378 "Invalid PowerPlay Table State Array Offset.",
380 PP_ASSERT_WITH_CODE(state_arrays
->ucNumEntries
> 0,
381 "Invalid PowerPlay Table State Array.",
383 PP_ASSERT_WITH_CODE((entry_index
<= state_arrays
->ucNumEntries
),
384 "Invalid PowerPlay Table State Array Entry.",
387 state_entry
= &(state_arrays
->states
[entry_index
]);
389 result
= call_back_func(hwmgr
, (void *)state_entry
, power_state
,
391 make_classification_flags(hwmgr
,
392 le16_to_cpu(state_entry
->usClassification
),
393 le16_to_cpu(state_entry
->usClassification2
)));
396 if (!result
&& (power_state
->classification
.flags
&
397 PP_StateClassificationFlag_Boot
))
398 result
= hwmgr
->hwmgr_func
->patch_boot_state(hwmgr
, &(power_state
->hardware
));