diff options
20 files changed, 8106 insertions, 2 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c index 96a5113b948f..f5ae871aa11c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c | |||
@@ -71,6 +71,7 @@ static int amdgpu_pp_early_init(void *handle) | |||
71 | case CHIP_TOPAZ: | 71 | case CHIP_TOPAZ: |
72 | case CHIP_CARRIZO: | 72 | case CHIP_CARRIZO: |
73 | case CHIP_STONEY: | 73 | case CHIP_STONEY: |
74 | case CHIP_VEGA10: | ||
74 | adev->pp_enabled = true; | 75 | adev->pp_enabled = true; |
75 | if (amdgpu_create_pp_handle(adev)) | 76 | if (amdgpu_create_pp_handle(adev)) |
76 | return -EINVAL; | 77 | return -EINVAL; |
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile index ccb51c28abbe..27db2b77824f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile | |||
@@ -7,7 +7,9 @@ HARDWARE_MGR = hwmgr.o processpptables.o functiontables.o \ | |||
7 | cz_clockpowergating.o pppcielanes.o\ | 7 | cz_clockpowergating.o pppcielanes.o\ |
8 | process_pptables_v1_0.o ppatomctrl.o ppatomfwctrl.o \ | 8 | process_pptables_v1_0.o ppatomctrl.o ppatomfwctrl.o \ |
9 | smu7_hwmgr.o smu7_powertune.o smu7_thermal.o \ | 9 | smu7_hwmgr.o smu7_powertune.o smu7_thermal.o \ |
10 | smu7_clockpowergating.o | 10 | smu7_clockpowergating.o \ |
11 | vega10_processpptables.o vega10_hwmgr.o vega10_powertune.o \ | ||
12 | vega10_thermal.o | ||
11 | 13 | ||
12 | 14 | ||
13 | AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR)) | 15 | AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR)) |
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index 2ea9c0e78689..ff4ae3de6bb6 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | |||
@@ -106,6 +106,15 @@ int hwmgr_early_init(struct pp_instance *handle) | |||
106 | } | 106 | } |
107 | smu7_init_function_pointers(hwmgr); | 107 | smu7_init_function_pointers(hwmgr); |
108 | break; | 108 | break; |
109 | case AMDGPU_FAMILY_AI: | ||
110 | switch (hwmgr->chip_id) { | ||
111 | case CHIP_VEGA10: | ||
112 | vega10_hwmgr_init(hwmgr); | ||
113 | break; | ||
114 | default: | ||
115 | return -EINVAL; | ||
116 | } | ||
117 | break; | ||
109 | default: | 118 | default: |
110 | return -EINVAL; | 119 | return -EINVAL; |
111 | } | 120 | } |
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c new file mode 100644 index 000000000000..83949550edac --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | |||
@@ -0,0 +1,4450 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/fb.h> | ||
26 | #include "linux/delay.h" | ||
27 | |||
28 | #include "hwmgr.h" | ||
29 | #include "amd_powerplay.h" | ||
30 | #include "vega10_smumgr.h" | ||
31 | #include "hardwaremanager.h" | ||
32 | #include "ppatomfwctrl.h" | ||
33 | #include "atomfirmware.h" | ||
34 | #include "cgs_common.h" | ||
35 | #include "vega10_powertune.h" | ||
36 | #include "smu9.h" | ||
37 | #include "smu9_driver_if.h" | ||
38 | #include "vega10_inc.h" | ||
39 | #include "pp_soc15.h" | ||
40 | #include "pppcielanes.h" | ||
41 | #include "vega10_hwmgr.h" | ||
42 | #include "vega10_processpptables.h" | ||
43 | #include "vega10_pptable.h" | ||
44 | #include "vega10_thermal.h" | ||
45 | #include "pp_debug.h" | ||
46 | #include "pp_acpi.h" | ||
47 | #include "amd_pcie_helpers.h" | ||
48 | #include "cgs_linux.h" | ||
49 | #include "ppinterrupt.h" | ||
50 | |||
51 | |||
52 | #define VOLTAGE_SCALE 4 | ||
53 | #define VOLTAGE_VID_OFFSET_SCALE1 625 | ||
54 | #define VOLTAGE_VID_OFFSET_SCALE2 100 | ||
55 | |||
56 | #define HBM_MEMORY_CHANNEL_WIDTH 128 | ||
57 | |||
58 | uint32_t channel_number[] = {1, 2, 0, 4, 0, 8, 0, 16, 2}; | ||
59 | |||
60 | #define MEM_FREQ_LOW_LATENCY 25000 | ||
61 | #define MEM_FREQ_HIGH_LATENCY 80000 | ||
62 | #define MEM_LATENCY_HIGH 245 | ||
63 | #define MEM_LATENCY_LOW 35 | ||
64 | #define MEM_LATENCY_ERR 0xFFFF | ||
65 | |||
66 | #define mmDF_CS_AON0_DramBaseAddress0 0x0044 | ||
67 | #define mmDF_CS_AON0_DramBaseAddress0_BASE_IDX 0 | ||
68 | |||
69 | //DF_CS_AON0_DramBaseAddress0 | ||
70 | #define DF_CS_AON0_DramBaseAddress0__AddrRngVal__SHIFT 0x0 | ||
71 | #define DF_CS_AON0_DramBaseAddress0__LgcyMmioHoleEn__SHIFT 0x1 | ||
72 | #define DF_CS_AON0_DramBaseAddress0__IntLvNumChan__SHIFT 0x4 | ||
73 | #define DF_CS_AON0_DramBaseAddress0__IntLvAddrSel__SHIFT 0x8 | ||
74 | #define DF_CS_AON0_DramBaseAddress0__DramBaseAddr__SHIFT 0xc | ||
75 | #define DF_CS_AON0_DramBaseAddress0__AddrRngVal_MASK 0x00000001L | ||
76 | #define DF_CS_AON0_DramBaseAddress0__LgcyMmioHoleEn_MASK 0x00000002L | ||
77 | #define DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK 0x000000F0L | ||
78 | #define DF_CS_AON0_DramBaseAddress0__IntLvAddrSel_MASK 0x00000700L | ||
79 | #define DF_CS_AON0_DramBaseAddress0__DramBaseAddr_MASK 0xFFFFF000L | ||
80 | |||
81 | const ULONG PhwVega10_Magic = (ULONG)(PHM_VIslands_Magic); | ||
82 | |||
83 | struct vega10_power_state *cast_phw_vega10_power_state( | ||
84 | struct pp_hw_power_state *hw_ps) | ||
85 | { | ||
86 | PP_ASSERT_WITH_CODE((PhwVega10_Magic == hw_ps->magic), | ||
87 | "Invalid Powerstate Type!", | ||
88 | return NULL;); | ||
89 | |||
90 | return (struct vega10_power_state *)hw_ps; | ||
91 | } | ||
92 | |||
93 | const struct vega10_power_state *cast_const_phw_vega10_power_state( | ||
94 | const struct pp_hw_power_state *hw_ps) | ||
95 | { | ||
96 | PP_ASSERT_WITH_CODE((PhwVega10_Magic == hw_ps->magic), | ||
97 | "Invalid Powerstate Type!", | ||
98 | return NULL;); | ||
99 | |||
100 | return (const struct vega10_power_state *)hw_ps; | ||
101 | } | ||
102 | |||
103 | static void vega10_set_default_registry_data(struct pp_hwmgr *hwmgr) | ||
104 | { | ||
105 | struct vega10_hwmgr *data = | ||
106 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
107 | |||
108 | data->registry_data.sclk_dpm_key_disabled = | ||
109 | hwmgr->feature_mask & PP_SCLK_DPM_MASK ? false : true; | ||
110 | data->registry_data.socclk_dpm_key_disabled = | ||
111 | hwmgr->feature_mask & PP_SOCCLK_DPM_MASK ? false : true; | ||
112 | data->registry_data.mclk_dpm_key_disabled = | ||
113 | hwmgr->feature_mask & PP_MCLK_DPM_MASK ? false : true; | ||
114 | |||
115 | data->registry_data.dcefclk_dpm_key_disabled = | ||
116 | hwmgr->feature_mask & PP_DCEFCLK_DPM_MASK ? false : true; | ||
117 | |||
118 | if (hwmgr->feature_mask & PP_POWER_CONTAINMENT_MASK) { | ||
119 | data->registry_data.power_containment_support = 1; | ||
120 | data->registry_data.enable_pkg_pwr_tracking_feature = 1; | ||
121 | data->registry_data.enable_tdc_limit_feature = 1; | ||
122 | } | ||
123 | |||
124 | data->registry_data.pcie_dpm_key_disabled = 1; | ||
125 | data->registry_data.disable_water_mark = 0; | ||
126 | |||
127 | data->registry_data.fan_control_support = 1; | ||
128 | data->registry_data.thermal_support = 1; | ||
129 | data->registry_data.fw_ctf_enabled = 1; | ||
130 | |||
131 | data->registry_data.avfs_support = 1; | ||
132 | data->registry_data.led_dpm_enabled = 1; | ||
133 | |||
134 | data->registry_data.vr0hot_enabled = 1; | ||
135 | data->registry_data.vr1hot_enabled = 1; | ||
136 | data->registry_data.regulator_hot_gpio_support = 1; | ||
137 | |||
138 | data->display_voltage_mode = PPVEGA10_VEGA10DISPLAYVOLTAGEMODE_DFLT; | ||
139 | data->dcef_clk_quad_eqn_a = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT; | ||
140 | data->dcef_clk_quad_eqn_b = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT; | ||
141 | data->dcef_clk_quad_eqn_c = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT; | ||
142 | data->disp_clk_quad_eqn_a = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT; | ||
143 | data->disp_clk_quad_eqn_b = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT; | ||
144 | data->disp_clk_quad_eqn_c = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT; | ||
145 | data->pixel_clk_quad_eqn_a = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT; | ||
146 | data->pixel_clk_quad_eqn_b = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT; | ||
147 | data->pixel_clk_quad_eqn_c = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT; | ||
148 | data->phy_clk_quad_eqn_a = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT; | ||
149 | data->phy_clk_quad_eqn_b = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT; | ||
150 | data->phy_clk_quad_eqn_c = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT; | ||
151 | |||
152 | data->gfxclk_average_alpha = PPVEGA10_VEGA10GFXCLKAVERAGEALPHA_DFLT; | ||
153 | data->socclk_average_alpha = PPVEGA10_VEGA10SOCCLKAVERAGEALPHA_DFLT; | ||
154 | data->uclk_average_alpha = PPVEGA10_VEGA10UCLKCLKAVERAGEALPHA_DFLT; | ||
155 | data->gfx_activity_average_alpha = PPVEGA10_VEGA10GFXACTIVITYAVERAGEALPHA_DFLT; | ||
156 | } | ||
157 | |||
158 | static int vega10_set_features_platform_caps(struct pp_hwmgr *hwmgr) | ||
159 | { | ||
160 | struct vega10_hwmgr *data = | ||
161 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
162 | struct phm_ppt_v2_information *table_info = | ||
163 | (struct phm_ppt_v2_information *)hwmgr->pptable; | ||
164 | struct cgs_system_info sys_info = {0}; | ||
165 | int result; | ||
166 | |||
167 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
168 | PHM_PlatformCaps_SclkDeepSleep); | ||
169 | |||
170 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
171 | PHM_PlatformCaps_DynamicPatchPowerState); | ||
172 | |||
173 | if (data->vddci_control == VEGA10_VOLTAGE_CONTROL_NONE) | ||
174 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
175 | PHM_PlatformCaps_ControlVDDCI); | ||
176 | |||
177 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
178 | PHM_PlatformCaps_TablelessHardwareInterface); | ||
179 | |||
180 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
181 | PHM_PlatformCaps_EnableSMU7ThermalManagement); | ||
182 | |||
183 | sys_info.size = sizeof(struct cgs_system_info); | ||
184 | sys_info.info_id = CGS_SYSTEM_INFO_PG_FLAGS; | ||
185 | result = cgs_query_system_info(hwmgr->device, &sys_info); | ||
186 | |||
187 | if (!result && (sys_info.value & AMD_PG_SUPPORT_UVD)) | ||
188 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
189 | PHM_PlatformCaps_UVDPowerGating); | ||
190 | |||
191 | if (!result && (sys_info.value & AMD_PG_SUPPORT_VCE)) | ||
192 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
193 | PHM_PlatformCaps_VCEPowerGating); | ||
194 | |||
195 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
196 | PHM_PlatformCaps_UnTabledHardwareInterface); | ||
197 | |||
198 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
199 | PHM_PlatformCaps_FanSpeedInTableIsRPM); | ||
200 | |||
201 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
202 | PHM_PlatformCaps_ODFuzzyFanControlSupport); | ||
203 | |||
204 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
205 | PHM_PlatformCaps_DynamicPowerManagement); | ||
206 | |||
207 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
208 | PHM_PlatformCaps_SMC); | ||
209 | |||
210 | /* power tune caps */ | ||
211 | /* assume disabled */ | ||
212 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
213 | PHM_PlatformCaps_PowerContainment); | ||
214 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
215 | PHM_PlatformCaps_SQRamping); | ||
216 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
217 | PHM_PlatformCaps_DBRamping); | ||
218 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
219 | PHM_PlatformCaps_TDRamping); | ||
220 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
221 | PHM_PlatformCaps_TCPRamping); | ||
222 | |||
223 | if (data->registry_data.power_containment_support) | ||
224 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
225 | PHM_PlatformCaps_PowerContainment); | ||
226 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
227 | PHM_PlatformCaps_CAC); | ||
228 | |||
229 | if (table_info->tdp_table->usClockStretchAmount && | ||
230 | data->registry_data.clock_stretcher_support) | ||
231 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
232 | PHM_PlatformCaps_ClockStretcher); | ||
233 | |||
234 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
235 | PHM_PlatformCaps_RegulatorHot); | ||
236 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
237 | PHM_PlatformCaps_AutomaticDCTransition); | ||
238 | |||
239 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
240 | PHM_PlatformCaps_UVDDPM); | ||
241 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
242 | PHM_PlatformCaps_VCEDPM); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static void vega10_init_dpm_defaults(struct pp_hwmgr *hwmgr) | ||
248 | { | ||
249 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
250 | int i; | ||
251 | |||
252 | vega10_initialize_power_tune_defaults(hwmgr); | ||
253 | |||
254 | for (i = 0; i < GNLD_FEATURES_MAX; i++) { | ||
255 | data->smu_features[i].smu_feature_id = 0xffff; | ||
256 | data->smu_features[i].smu_feature_bitmap = 1 << i; | ||
257 | data->smu_features[i].enabled = false; | ||
258 | data->smu_features[i].supported = false; | ||
259 | } | ||
260 | |||
261 | data->smu_features[GNLD_DPM_PREFETCHER].smu_feature_id = | ||
262 | FEATURE_DPM_PREFETCHER_BIT; | ||
263 | data->smu_features[GNLD_DPM_GFXCLK].smu_feature_id = | ||
264 | FEATURE_DPM_GFXCLK_BIT; | ||
265 | data->smu_features[GNLD_DPM_UCLK].smu_feature_id = | ||
266 | FEATURE_DPM_UCLK_BIT; | ||
267 | data->smu_features[GNLD_DPM_SOCCLK].smu_feature_id = | ||
268 | FEATURE_DPM_SOCCLK_BIT; | ||
269 | data->smu_features[GNLD_DPM_UVD].smu_feature_id = | ||
270 | FEATURE_DPM_UVD_BIT; | ||
271 | data->smu_features[GNLD_DPM_VCE].smu_feature_id = | ||
272 | FEATURE_DPM_VCE_BIT; | ||
273 | data->smu_features[GNLD_DPM_MP0CLK].smu_feature_id = | ||
274 | FEATURE_DPM_MP0CLK_BIT; | ||
275 | data->smu_features[GNLD_DPM_LINK].smu_feature_id = | ||
276 | FEATURE_DPM_LINK_BIT; | ||
277 | data->smu_features[GNLD_DPM_DCEFCLK].smu_feature_id = | ||
278 | FEATURE_DPM_DCEFCLK_BIT; | ||
279 | data->smu_features[GNLD_ULV].smu_feature_id = | ||
280 | FEATURE_ULV_BIT; | ||
281 | data->smu_features[GNLD_AVFS].smu_feature_id = | ||
282 | FEATURE_AVFS_BIT; | ||
283 | data->smu_features[GNLD_DS_GFXCLK].smu_feature_id = | ||
284 | FEATURE_DS_GFXCLK_BIT; | ||
285 | data->smu_features[GNLD_DS_SOCCLK].smu_feature_id = | ||
286 | FEATURE_DS_SOCCLK_BIT; | ||
287 | data->smu_features[GNLD_DS_LCLK].smu_feature_id = | ||
288 | FEATURE_DS_LCLK_BIT; | ||
289 | data->smu_features[GNLD_PPT].smu_feature_id = | ||
290 | FEATURE_PPT_BIT; | ||
291 | data->smu_features[GNLD_TDC].smu_feature_id = | ||
292 | FEATURE_TDC_BIT; | ||
293 | data->smu_features[GNLD_THERMAL].smu_feature_id = | ||
294 | FEATURE_THERMAL_BIT; | ||
295 | data->smu_features[GNLD_GFX_PER_CU_CG].smu_feature_id = | ||
296 | FEATURE_GFX_PER_CU_CG_BIT; | ||
297 | data->smu_features[GNLD_RM].smu_feature_id = | ||
298 | FEATURE_RM_BIT; | ||
299 | data->smu_features[GNLD_DS_DCEFCLK].smu_feature_id = | ||
300 | FEATURE_DS_DCEFCLK_BIT; | ||
301 | data->smu_features[GNLD_ACDC].smu_feature_id = | ||
302 | FEATURE_ACDC_BIT; | ||
303 | data->smu_features[GNLD_VR0HOT].smu_feature_id = | ||
304 | FEATURE_VR0HOT_BIT; | ||
305 | data->smu_features[GNLD_VR1HOT].smu_feature_id = | ||
306 | FEATURE_VR1HOT_BIT; | ||
307 | data->smu_features[GNLD_FW_CTF].smu_feature_id = | ||
308 | FEATURE_FW_CTF_BIT; | ||
309 | data->smu_features[GNLD_LED_DISPLAY].smu_feature_id = | ||
310 | FEATURE_LED_DISPLAY_BIT; | ||
311 | data->smu_features[GNLD_FAN_CONTROL].smu_feature_id = | ||
312 | FEATURE_FAN_CONTROL_BIT; | ||
313 | data->smu_features[GNLD_VOLTAGE_CONTROLLER].smu_feature_id = | ||
314 | FEATURE_VOLTAGE_CONTROLLER_BIT; | ||
315 | |||
316 | if (!data->registry_data.prefetcher_dpm_key_disabled) | ||
317 | data->smu_features[GNLD_DPM_PREFETCHER].supported = true; | ||
318 | |||
319 | if (!data->registry_data.sclk_dpm_key_disabled) | ||
320 | data->smu_features[GNLD_DPM_GFXCLK].supported = true; | ||
321 | |||
322 | if (!data->registry_data.mclk_dpm_key_disabled) | ||
323 | data->smu_features[GNLD_DPM_UCLK].supported = true; | ||
324 | |||
325 | if (!data->registry_data.socclk_dpm_key_disabled) | ||
326 | data->smu_features[GNLD_DPM_SOCCLK].supported = true; | ||
327 | |||
328 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
329 | PHM_PlatformCaps_UVDDPM)) | ||
330 | data->smu_features[GNLD_DPM_UVD].supported = true; | ||
331 | |||
332 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
333 | PHM_PlatformCaps_VCEDPM)) | ||
334 | data->smu_features[GNLD_DPM_VCE].supported = true; | ||
335 | |||
336 | if (!data->registry_data.pcie_dpm_key_disabled) | ||
337 | data->smu_features[GNLD_DPM_LINK].supported = true; | ||
338 | |||
339 | if (!data->registry_data.dcefclk_dpm_key_disabled) | ||
340 | data->smu_features[GNLD_DPM_DCEFCLK].supported = true; | ||
341 | |||
342 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
343 | PHM_PlatformCaps_SclkDeepSleep) && | ||
344 | data->registry_data.sclk_deep_sleep_support) { | ||
345 | data->smu_features[GNLD_DS_GFXCLK].supported = true; | ||
346 | data->smu_features[GNLD_DS_SOCCLK].supported = true; | ||
347 | data->smu_features[GNLD_DS_LCLK].supported = true; | ||
348 | } | ||
349 | |||
350 | if (data->registry_data.enable_pkg_pwr_tracking_feature) | ||
351 | data->smu_features[GNLD_PPT].supported = true; | ||
352 | |||
353 | if (data->registry_data.enable_tdc_limit_feature) | ||
354 | data->smu_features[GNLD_TDC].supported = true; | ||
355 | |||
356 | if (data->registry_data.thermal_support) | ||
357 | data->smu_features[GNLD_THERMAL].supported = true; | ||
358 | |||
359 | if (data->registry_data.fan_control_support) | ||
360 | data->smu_features[GNLD_FAN_CONTROL].supported = true; | ||
361 | |||
362 | if (data->registry_data.fw_ctf_enabled) | ||
363 | data->smu_features[GNLD_FW_CTF].supported = true; | ||
364 | |||
365 | if (data->registry_data.avfs_support) | ||
366 | data->smu_features[GNLD_AVFS].supported = true; | ||
367 | |||
368 | if (data->registry_data.led_dpm_enabled) | ||
369 | data->smu_features[GNLD_LED_DISPLAY].supported = true; | ||
370 | |||
371 | if (data->registry_data.vr1hot_enabled) | ||
372 | data->smu_features[GNLD_VR1HOT].supported = true; | ||
373 | |||
374 | if (data->registry_data.vr0hot_enabled) | ||
375 | data->smu_features[GNLD_VR0HOT].supported = true; | ||
376 | |||
377 | } | ||
378 | |||
379 | #ifdef PPLIB_VEGA10_EVV_SUPPORT | ||
380 | static int vega10_get_socclk_for_voltage_evv(struct pp_hwmgr *hwmgr, | ||
381 | phm_ppt_v1_voltage_lookup_table *lookup_table, | ||
382 | uint16_t virtual_voltage_id, int32_t *socclk) | ||
383 | { | ||
384 | uint8_t entry_id; | ||
385 | uint8_t voltage_id; | ||
386 | struct phm_ppt_v2_information *table_info = | ||
387 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
388 | |||
389 | PP_ASSERT_WITH_CODE(lookup_table->count != 0, | ||
390 | "Lookup table is empty", | ||
391 | return -EINVAL); | ||
392 | |||
393 | /* search for leakage voltage ID 0xff01 ~ 0xff08 and sclk */ | ||
394 | for (entry_id = 0; entry_id < table_info->vdd_dep_on_sclk->count; entry_id++) { | ||
395 | voltage_id = table_info->vdd_dep_on_socclk->entries[entry_id].vddInd; | ||
396 | if (lookup_table->entries[voltage_id].us_vdd == virtual_voltage_id) | ||
397 | break; | ||
398 | } | ||
399 | |||
400 | PP_ASSERT_WITH_CODE(entry_id < table_info->vdd_dep_on_socclk->count, | ||
401 | "Can't find requested voltage id in vdd_dep_on_socclk table!", | ||
402 | return -EINVAL); | ||
403 | |||
404 | *socclk = table_info->vdd_dep_on_socclk->entries[entry_id].clk; | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | #define ATOM_VIRTUAL_VOLTAGE_ID0 0xff01 | ||
410 | /** | ||
411 | * Get Leakage VDDC based on leakage ID. | ||
412 | * | ||
413 | * @param hwmgr the address of the powerplay hardware manager. | ||
414 | * @return always 0. | ||
415 | */ | ||
416 | static int vega10_get_evv_voltages(struct pp_hwmgr *hwmgr) | ||
417 | { | ||
418 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
419 | uint16_t vv_id; | ||
420 | uint32_t vddc = 0; | ||
421 | uint16_t i, j; | ||
422 | uint32_t sclk = 0; | ||
423 | struct phm_ppt_v2_information *table_info = | ||
424 | (struct phm_ppt_v2_information *)hwmgr->pptable; | ||
425 | struct phm_ppt_v1_clock_voltage_dependency_table *socclk_table = | ||
426 | table_info->vdd_dep_on_socclk; | ||
427 | int result; | ||
428 | |||
429 | for (i = 0; i < VEGA10_MAX_LEAKAGE_COUNT; i++) { | ||
430 | vv_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i; | ||
431 | |||
432 | if (!vega10_get_socclk_for_voltage_evv(hwmgr, | ||
433 | table_info->vddc_lookup_table, vv_id, &sclk)) { | ||
434 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
435 | PHM_PlatformCaps_ClockStretcher)) { | ||
436 | for (j = 1; j < socclk_table->count; j++) { | ||
437 | if (socclk_table->entries[j].clk == sclk && | ||
438 | socclk_table->entries[j].cks_enable == 0) { | ||
439 | sclk += 5000; | ||
440 | break; | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | |||
445 | PP_ASSERT_WITH_CODE(!atomctrl_get_voltage_evv_on_sclk_ai(hwmgr, | ||
446 | VOLTAGE_TYPE_VDDC, sclk, vv_id, &vddc), | ||
447 | "Error retrieving EVV voltage value!", | ||
448 | continue); | ||
449 | |||
450 | |||
451 | /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */ | ||
452 | PP_ASSERT_WITH_CODE((vddc < 2000 && vddc != 0), | ||
453 | "Invalid VDDC value", result = -EINVAL;); | ||
454 | |||
455 | /* the voltage should not be zero nor equal to leakage ID */ | ||
456 | if (vddc != 0 && vddc != vv_id) { | ||
457 | data->vddc_leakage.actual_voltage[data->vddc_leakage.count] = (uint16_t)(vddc/100); | ||
458 | data->vddc_leakage.leakage_id[data->vddc_leakage.count] = vv_id; | ||
459 | data->vddc_leakage.count++; | ||
460 | } | ||
461 | } | ||
462 | } | ||
463 | |||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | /** | ||
468 | * Change virtual leakage voltage to actual value. | ||
469 | * | ||
470 | * @param hwmgr the address of the powerplay hardware manager. | ||
471 | * @param pointer to changing voltage | ||
472 | * @param pointer to leakage table | ||
473 | */ | ||
474 | static void vega10_patch_with_vdd_leakage(struct pp_hwmgr *hwmgr, | ||
475 | uint16_t *voltage, struct vega10_leakage_voltage *leakage_table) | ||
476 | { | ||
477 | uint32_t index; | ||
478 | |||
479 | /* search for leakage voltage ID 0xff01 ~ 0xff08 */ | ||
480 | for (index = 0; index < leakage_table->count; index++) { | ||
481 | /* if this voltage matches a leakage voltage ID */ | ||
482 | /* patch with actual leakage voltage */ | ||
483 | if (leakage_table->leakage_id[index] == *voltage) { | ||
484 | *voltage = leakage_table->actual_voltage[index]; | ||
485 | break; | ||
486 | } | ||
487 | } | ||
488 | |||
489 | if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0) | ||
490 | pr_info("Voltage value looks like a Leakage ID \ | ||
491 | but it's not patched\n"); | ||
492 | } | ||
493 | |||
494 | /** | ||
495 | * Patch voltage lookup table by EVV leakages. | ||
496 | * | ||
497 | * @param hwmgr the address of the powerplay hardware manager. | ||
498 | * @param pointer to voltage lookup table | ||
499 | * @param pointer to leakage table | ||
500 | * @return always 0 | ||
501 | */ | ||
502 | static int vega10_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr, | ||
503 | phm_ppt_v1_voltage_lookup_table *lookup_table, | ||
504 | struct vega10_leakage_voltage *leakage_table) | ||
505 | { | ||
506 | uint32_t i; | ||
507 | |||
508 | for (i = 0; i < lookup_table->count; i++) | ||
509 | vega10_patch_with_vdd_leakage(hwmgr, | ||
510 | &lookup_table->entries[i].us_vdd, leakage_table); | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | static int vega10_patch_clock_voltage_limits_with_vddc_leakage( | ||
516 | struct pp_hwmgr *hwmgr, struct vega10_leakage_voltage *leakage_table, | ||
517 | uint16_t *vddc) | ||
518 | { | ||
519 | vega10_patch_with_vdd_leakage(hwmgr, (uint16_t *)vddc, leakage_table); | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | #endif | ||
524 | |||
525 | static int vega10_patch_voltage_dependency_tables_with_lookup_table( | ||
526 | struct pp_hwmgr *hwmgr) | ||
527 | { | ||
528 | uint8_t entry_id; | ||
529 | uint8_t voltage_id; | ||
530 | struct phm_ppt_v2_information *table_info = | ||
531 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
532 | struct phm_ppt_v1_clock_voltage_dependency_table *socclk_table = | ||
533 | table_info->vdd_dep_on_socclk; | ||
534 | struct phm_ppt_v1_clock_voltage_dependency_table *gfxclk_table = | ||
535 | table_info->vdd_dep_on_sclk; | ||
536 | struct phm_ppt_v1_clock_voltage_dependency_table *dcefclk_table = | ||
537 | table_info->vdd_dep_on_dcefclk; | ||
538 | struct phm_ppt_v1_clock_voltage_dependency_table *pixclk_table = | ||
539 | table_info->vdd_dep_on_pixclk; | ||
540 | struct phm_ppt_v1_clock_voltage_dependency_table *dspclk_table = | ||
541 | table_info->vdd_dep_on_dispclk; | ||
542 | struct phm_ppt_v1_clock_voltage_dependency_table *phyclk_table = | ||
543 | table_info->vdd_dep_on_phyclk; | ||
544 | struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table = | ||
545 | table_info->vdd_dep_on_mclk; | ||
546 | struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = | ||
547 | table_info->mm_dep_table; | ||
548 | |||
549 | for (entry_id = 0; entry_id < socclk_table->count; entry_id++) { | ||
550 | voltage_id = socclk_table->entries[entry_id].vddInd; | ||
551 | socclk_table->entries[entry_id].vddc = | ||
552 | table_info->vddc_lookup_table->entries[voltage_id].us_vdd; | ||
553 | } | ||
554 | |||
555 | for (entry_id = 0; entry_id < gfxclk_table->count; entry_id++) { | ||
556 | voltage_id = gfxclk_table->entries[entry_id].vddInd; | ||
557 | gfxclk_table->entries[entry_id].vddc = | ||
558 | table_info->vddc_lookup_table->entries[voltage_id].us_vdd; | ||
559 | } | ||
560 | |||
561 | for (entry_id = 0; entry_id < dcefclk_table->count; entry_id++) { | ||
562 | voltage_id = dcefclk_table->entries[entry_id].vddInd; | ||
563 | dcefclk_table->entries[entry_id].vddc = | ||
564 | table_info->vddc_lookup_table->entries[voltage_id].us_vdd; | ||
565 | } | ||
566 | |||
567 | for (entry_id = 0; entry_id < pixclk_table->count; entry_id++) { | ||
568 | voltage_id = pixclk_table->entries[entry_id].vddInd; | ||
569 | pixclk_table->entries[entry_id].vddc = | ||
570 | table_info->vddc_lookup_table->entries[voltage_id].us_vdd; | ||
571 | } | ||
572 | |||
573 | for (entry_id = 0; entry_id < dspclk_table->count; entry_id++) { | ||
574 | voltage_id = dspclk_table->entries[entry_id].vddInd; | ||
575 | dspclk_table->entries[entry_id].vddc = | ||
576 | table_info->vddc_lookup_table->entries[voltage_id].us_vdd; | ||
577 | } | ||
578 | |||
579 | for (entry_id = 0; entry_id < phyclk_table->count; entry_id++) { | ||
580 | voltage_id = phyclk_table->entries[entry_id].vddInd; | ||
581 | phyclk_table->entries[entry_id].vddc = | ||
582 | table_info->vddc_lookup_table->entries[voltage_id].us_vdd; | ||
583 | } | ||
584 | |||
585 | for (entry_id = 0; entry_id < mclk_table->count; ++entry_id) { | ||
586 | voltage_id = mclk_table->entries[entry_id].vddInd; | ||
587 | mclk_table->entries[entry_id].vddc = | ||
588 | table_info->vddc_lookup_table->entries[voltage_id].us_vdd; | ||
589 | voltage_id = mclk_table->entries[entry_id].vddciInd; | ||
590 | mclk_table->entries[entry_id].vddci = | ||
591 | table_info->vddci_lookup_table->entries[voltage_id].us_vdd; | ||
592 | voltage_id = mclk_table->entries[entry_id].mvddInd; | ||
593 | mclk_table->entries[entry_id].mvdd = | ||
594 | table_info->vddmem_lookup_table->entries[voltage_id].us_vdd; | ||
595 | } | ||
596 | |||
597 | for (entry_id = 0; entry_id < mm_table->count; ++entry_id) { | ||
598 | voltage_id = mm_table->entries[entry_id].vddcInd; | ||
599 | mm_table->entries[entry_id].vddc = | ||
600 | table_info->vddc_lookup_table->entries[voltage_id].us_vdd; | ||
601 | } | ||
602 | |||
603 | return 0; | ||
604 | |||
605 | } | ||
606 | |||
607 | static int vega10_sort_lookup_table(struct pp_hwmgr *hwmgr, | ||
608 | struct phm_ppt_v1_voltage_lookup_table *lookup_table) | ||
609 | { | ||
610 | uint32_t table_size, i, j; | ||
611 | struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record; | ||
612 | |||
613 | PP_ASSERT_WITH_CODE(lookup_table && lookup_table->count, | ||
614 | "Lookup table is empty", return -EINVAL); | ||
615 | |||
616 | table_size = lookup_table->count; | ||
617 | |||
618 | /* Sorting voltages */ | ||
619 | for (i = 0; i < table_size - 1; i++) { | ||
620 | for (j = i + 1; j > 0; j--) { | ||
621 | if (lookup_table->entries[j].us_vdd < | ||
622 | lookup_table->entries[j - 1].us_vdd) { | ||
623 | tmp_voltage_lookup_record = lookup_table->entries[j - 1]; | ||
624 | lookup_table->entries[j - 1] = lookup_table->entries[j]; | ||
625 | lookup_table->entries[j] = tmp_voltage_lookup_record; | ||
626 | } | ||
627 | } | ||
628 | } | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | static int vega10_complete_dependency_tables(struct pp_hwmgr *hwmgr) | ||
634 | { | ||
635 | int result = 0; | ||
636 | int tmp_result; | ||
637 | struct phm_ppt_v2_information *table_info = | ||
638 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
639 | #ifdef PPLIB_VEGA10_EVV_SUPPORT | ||
640 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
641 | |||
642 | tmp_result = vega10_patch_lookup_table_with_leakage(hwmgr, | ||
643 | table_info->vddc_lookup_table, &(data->vddc_leakage)); | ||
644 | if (tmp_result) | ||
645 | result = tmp_result; | ||
646 | |||
647 | tmp_result = vega10_patch_clock_voltage_limits_with_vddc_leakage(hwmgr, | ||
648 | &(data->vddc_leakage), &table_info->max_clock_voltage_on_dc.vddc); | ||
649 | if (tmp_result) | ||
650 | result = tmp_result; | ||
651 | #endif | ||
652 | |||
653 | tmp_result = vega10_patch_voltage_dependency_tables_with_lookup_table(hwmgr); | ||
654 | if (tmp_result) | ||
655 | result = tmp_result; | ||
656 | |||
657 | tmp_result = vega10_sort_lookup_table(hwmgr, table_info->vddc_lookup_table); | ||
658 | if (tmp_result) | ||
659 | result = tmp_result; | ||
660 | |||
661 | return result; | ||
662 | } | ||
663 | |||
664 | static int vega10_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr) | ||
665 | { | ||
666 | struct phm_ppt_v2_information *table_info = | ||
667 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
668 | struct phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table = | ||
669 | table_info->vdd_dep_on_socclk; | ||
670 | struct phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table = | ||
671 | table_info->vdd_dep_on_mclk; | ||
672 | |||
673 | PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table, | ||
674 | "VDD dependency on SCLK table is missing. \ | ||
675 | This table is mandatory", return -EINVAL); | ||
676 | PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1, | ||
677 | "VDD dependency on SCLK table is empty. \ | ||
678 | This table is mandatory", return -EINVAL); | ||
679 | |||
680 | PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table, | ||
681 | "VDD dependency on MCLK table is missing. \ | ||
682 | This table is mandatory", return -EINVAL); | ||
683 | PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1, | ||
684 | "VDD dependency on MCLK table is empty. \ | ||
685 | This table is mandatory", return -EINVAL); | ||
686 | |||
687 | table_info->max_clock_voltage_on_ac.sclk = | ||
688 | allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk; | ||
689 | table_info->max_clock_voltage_on_ac.mclk = | ||
690 | allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk; | ||
691 | table_info->max_clock_voltage_on_ac.vddc = | ||
692 | allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc; | ||
693 | table_info->max_clock_voltage_on_ac.vddci = | ||
694 | allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci; | ||
695 | |||
696 | hwmgr->dyn_state.max_clock_voltage_on_ac.sclk = | ||
697 | table_info->max_clock_voltage_on_ac.sclk; | ||
698 | hwmgr->dyn_state.max_clock_voltage_on_ac.mclk = | ||
699 | table_info->max_clock_voltage_on_ac.mclk; | ||
700 | hwmgr->dyn_state.max_clock_voltage_on_ac.vddc = | ||
701 | table_info->max_clock_voltage_on_ac.vddc; | ||
702 | hwmgr->dyn_state.max_clock_voltage_on_ac.vddci = | ||
703 | table_info->max_clock_voltage_on_ac.vddci; | ||
704 | |||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | static int vega10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) | ||
709 | { | ||
710 | kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); | ||
711 | hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; | ||
712 | |||
713 | kfree(hwmgr->backend); | ||
714 | hwmgr->backend = NULL; | ||
715 | |||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr) | ||
720 | { | ||
721 | int result = 0; | ||
722 | struct vega10_hwmgr *data; | ||
723 | uint32_t config_telemetry = 0; | ||
724 | struct pp_atomfwctrl_voltage_table vol_table; | ||
725 | struct cgs_system_info sys_info = {0}; | ||
726 | |||
727 | data = kzalloc(sizeof(struct vega10_hwmgr), GFP_KERNEL); | ||
728 | if (data == NULL) | ||
729 | return -ENOMEM; | ||
730 | |||
731 | hwmgr->backend = data; | ||
732 | |||
733 | vega10_set_default_registry_data(hwmgr); | ||
734 | |||
735 | data->disable_dpm_mask = 0xff; | ||
736 | data->workload_mask = 0xff; | ||
737 | |||
738 | /* need to set voltage control types before EVV patching */ | ||
739 | data->vddc_control = VEGA10_VOLTAGE_CONTROL_NONE; | ||
740 | data->mvdd_control = VEGA10_VOLTAGE_CONTROL_NONE; | ||
741 | data->vddci_control = VEGA10_VOLTAGE_CONTROL_NONE; | ||
742 | |||
743 | /* VDDCR_SOC */ | ||
744 | if (pp_atomfwctrl_is_voltage_controlled_by_gpio_v4(hwmgr, | ||
745 | VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2)) { | ||
746 | if (!pp_atomfwctrl_get_voltage_table_v4(hwmgr, | ||
747 | VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2, | ||
748 | &vol_table)) { | ||
749 | config_telemetry = ((vol_table.telemetry_slope << 8) & 0xff00) | | ||
750 | (vol_table.telemetry_offset & 0xff); | ||
751 | data->vddc_control = VEGA10_VOLTAGE_CONTROL_BY_SVID2; | ||
752 | } | ||
753 | } else { | ||
754 | kfree(hwmgr->backend); | ||
755 | hwmgr->backend = NULL; | ||
756 | PP_ASSERT_WITH_CODE(false, | ||
757 | "VDDCR_SOC is not SVID2!", | ||
758 | return -1); | ||
759 | } | ||
760 | |||
761 | /* MVDDC */ | ||
762 | if (pp_atomfwctrl_is_voltage_controlled_by_gpio_v4(hwmgr, | ||
763 | VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2)) { | ||
764 | if (!pp_atomfwctrl_get_voltage_table_v4(hwmgr, | ||
765 | VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2, | ||
766 | &vol_table)) { | ||
767 | config_telemetry |= | ||
768 | ((vol_table.telemetry_slope << 24) & 0xff000000) | | ||
769 | ((vol_table.telemetry_offset << 16) & 0xff0000); | ||
770 | data->mvdd_control = VEGA10_VOLTAGE_CONTROL_BY_SVID2; | ||
771 | } | ||
772 | } | ||
773 | |||
774 | /* VDDCI_MEM */ | ||
775 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
776 | PHM_PlatformCaps_ControlVDDCI)) { | ||
777 | if (pp_atomfwctrl_is_voltage_controlled_by_gpio_v4(hwmgr, | ||
778 | VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT)) | ||
779 | data->vddci_control = VEGA10_VOLTAGE_CONTROL_BY_GPIO; | ||
780 | } | ||
781 | |||
782 | data->config_telemetry = config_telemetry; | ||
783 | |||
784 | vega10_set_features_platform_caps(hwmgr); | ||
785 | |||
786 | vega10_init_dpm_defaults(hwmgr); | ||
787 | |||
788 | #ifdef PPLIB_VEGA10_EVV_SUPPORT | ||
789 | /* Get leakage voltage based on leakage ID. */ | ||
790 | PP_ASSERT_WITH_CODE(!vega10_get_evv_voltages(hwmgr), | ||
791 | "Get EVV Voltage Failed. Abort Driver loading!", | ||
792 | return -1); | ||
793 | #endif | ||
794 | |||
795 | /* Patch our voltage dependency table with actual leakage voltage | ||
796 | * We need to perform leakage translation before it's used by other functions | ||
797 | */ | ||
798 | vega10_complete_dependency_tables(hwmgr); | ||
799 | |||
800 | /* Parse pptable data read from VBIOS */ | ||
801 | vega10_set_private_data_based_on_pptable(hwmgr); | ||
802 | |||
803 | data->is_tlu_enabled = false; | ||
804 | |||
805 | hwmgr->platform_descriptor.hardwareActivityPerformanceLevels = | ||
806 | VEGA10_MAX_HARDWARE_POWERLEVELS; | ||
807 | hwmgr->platform_descriptor.hardwarePerformanceLevels = 2; | ||
808 | hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50; | ||
809 | |||
810 | hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */ | ||
811 | /* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */ | ||
812 | hwmgr->platform_descriptor.clockStep.engineClock = 500; | ||
813 | hwmgr->platform_descriptor.clockStep.memoryClock = 500; | ||
814 | |||
815 | sys_info.size = sizeof(struct cgs_system_info); | ||
816 | sys_info.info_id = CGS_SYSTEM_INFO_GFX_CU_INFO; | ||
817 | result = cgs_query_system_info(hwmgr->device, &sys_info); | ||
818 | data->total_active_cus = sys_info.value; | ||
819 | /* Setup default Overdrive Fan control settings */ | ||
820 | data->odn_fan_table.target_fan_speed = | ||
821 | hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM; | ||
822 | data->odn_fan_table.target_temperature = | ||
823 | hwmgr->thermal_controller. | ||
824 | advanceFanControlParameters.ucTargetTemperature; | ||
825 | data->odn_fan_table.min_performance_clock = | ||
826 | hwmgr->thermal_controller.advanceFanControlParameters. | ||
827 | ulMinFanSCLKAcousticLimit; | ||
828 | data->odn_fan_table.min_fan_limit = | ||
829 | hwmgr->thermal_controller. | ||
830 | advanceFanControlParameters.usFanPWMMinLimit * | ||
831 | hwmgr->thermal_controller.fanInfo.ulMaxRPM / 100; | ||
832 | |||
833 | return result; | ||
834 | } | ||
835 | |||
836 | static int vega10_init_sclk_threshold(struct pp_hwmgr *hwmgr) | ||
837 | { | ||
838 | struct vega10_hwmgr *data = | ||
839 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
840 | |||
841 | data->low_sclk_interrupt_threshold = 0; | ||
842 | |||
843 | return 0; | ||
844 | } | ||
845 | |||
846 | static int vega10_setup_dpm_led_config(struct pp_hwmgr *hwmgr) | ||
847 | { | ||
848 | struct vega10_hwmgr *data = | ||
849 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
850 | PPTable_t *pp_table = &(data->smc_state_table.pp_table); | ||
851 | |||
852 | struct pp_atomfwctrl_voltage_table table; | ||
853 | uint8_t i, j; | ||
854 | uint32_t mask = 0; | ||
855 | uint32_t tmp; | ||
856 | int32_t ret = 0; | ||
857 | |||
858 | ret = pp_atomfwctrl_get_voltage_table_v4(hwmgr, VOLTAGE_TYPE_LEDDPM, | ||
859 | VOLTAGE_OBJ_GPIO_LUT, &table); | ||
860 | |||
861 | if (!ret) { | ||
862 | tmp = table.mask_low; | ||
863 | for (i = 0, j = 0; i < 32; i++) { | ||
864 | if (tmp & 1) { | ||
865 | mask |= (uint32_t)(i << (8 * j)); | ||
866 | if (++j >= 3) | ||
867 | break; | ||
868 | } | ||
869 | tmp >>= 1; | ||
870 | } | ||
871 | } | ||
872 | |||
873 | pp_table->LedPin0 = (uint8_t)(mask & 0xff); | ||
874 | pp_table->LedPin1 = (uint8_t)((mask >> 8) & 0xff); | ||
875 | pp_table->LedPin2 = (uint8_t)((mask >> 16) & 0xff); | ||
876 | return 0; | ||
877 | } | ||
878 | |||
879 | static int vega10_setup_asic_task(struct pp_hwmgr *hwmgr) | ||
880 | { | ||
881 | PP_ASSERT_WITH_CODE(!vega10_init_sclk_threshold(hwmgr), | ||
882 | "Failed to init sclk threshold!", | ||
883 | return -EINVAL); | ||
884 | |||
885 | PP_ASSERT_WITH_CODE(!vega10_setup_dpm_led_config(hwmgr), | ||
886 | "Failed to set up led dpm config!", | ||
887 | return -EINVAL); | ||
888 | |||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | static bool vega10_is_dpm_running(struct pp_hwmgr *hwmgr) | ||
893 | { | ||
894 | uint32_t features_enabled; | ||
895 | |||
896 | if (!vega10_get_smc_features(hwmgr->smumgr, &features_enabled)) { | ||
897 | if (features_enabled & SMC_DPM_FEATURES) | ||
898 | return true; | ||
899 | } | ||
900 | return false; | ||
901 | } | ||
902 | |||
903 | /** | ||
904 | * Remove repeated voltage values and create table with unique values. | ||
905 | * | ||
906 | * @param hwmgr the address of the powerplay hardware manager. | ||
907 | * @param vol_table the pointer to changing voltage table | ||
908 | * @return 0 in success | ||
909 | */ | ||
910 | |||
911 | static int vega10_trim_voltage_table(struct pp_hwmgr *hwmgr, | ||
912 | struct pp_atomfwctrl_voltage_table *vol_table) | ||
913 | { | ||
914 | uint32_t i, j; | ||
915 | uint16_t vvalue; | ||
916 | bool found = false; | ||
917 | struct pp_atomfwctrl_voltage_table *table; | ||
918 | |||
919 | PP_ASSERT_WITH_CODE(vol_table, | ||
920 | "Voltage Table empty.", return -EINVAL); | ||
921 | table = kzalloc(sizeof(struct pp_atomfwctrl_voltage_table), | ||
922 | GFP_KERNEL); | ||
923 | |||
924 | if (!table) | ||
925 | return -ENOMEM; | ||
926 | |||
927 | table->mask_low = vol_table->mask_low; | ||
928 | table->phase_delay = vol_table->phase_delay; | ||
929 | |||
930 | for (i = 0; i < vol_table->count; i++) { | ||
931 | vvalue = vol_table->entries[i].value; | ||
932 | found = false; | ||
933 | |||
934 | for (j = 0; j < table->count; j++) { | ||
935 | if (vvalue == table->entries[j].value) { | ||
936 | found = true; | ||
937 | break; | ||
938 | } | ||
939 | } | ||
940 | |||
941 | if (!found) { | ||
942 | table->entries[table->count].value = vvalue; | ||
943 | table->entries[table->count].smio_low = | ||
944 | vol_table->entries[i].smio_low; | ||
945 | table->count++; | ||
946 | } | ||
947 | } | ||
948 | |||
949 | memcpy(vol_table, table, sizeof(struct pp_atomfwctrl_voltage_table)); | ||
950 | kfree(table); | ||
951 | |||
952 | return 0; | ||
953 | } | ||
954 | |||
955 | static int vega10_get_mvdd_voltage_table(struct pp_hwmgr *hwmgr, | ||
956 | phm_ppt_v1_clock_voltage_dependency_table *dep_table, | ||
957 | struct pp_atomfwctrl_voltage_table *vol_table) | ||
958 | { | ||
959 | int i; | ||
960 | |||
961 | PP_ASSERT_WITH_CODE(dep_table->count, | ||
962 | "Voltage Dependency Table empty.", | ||
963 | return -EINVAL); | ||
964 | |||
965 | vol_table->mask_low = 0; | ||
966 | vol_table->phase_delay = 0; | ||
967 | vol_table->count = dep_table->count; | ||
968 | |||
969 | for (i = 0; i < vol_table->count; i++) { | ||
970 | vol_table->entries[i].value = dep_table->entries[i].mvdd; | ||
971 | vol_table->entries[i].smio_low = 0; | ||
972 | } | ||
973 | |||
974 | PP_ASSERT_WITH_CODE(!vega10_trim_voltage_table(hwmgr, | ||
975 | vol_table), | ||
976 | "Failed to trim MVDD Table!", | ||
977 | return -1); | ||
978 | |||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | static int vega10_get_vddci_voltage_table(struct pp_hwmgr *hwmgr, | ||
983 | phm_ppt_v1_clock_voltage_dependency_table *dep_table, | ||
984 | struct pp_atomfwctrl_voltage_table *vol_table) | ||
985 | { | ||
986 | uint32_t i; | ||
987 | |||
988 | PP_ASSERT_WITH_CODE(dep_table->count, | ||
989 | "Voltage Dependency Table empty.", | ||
990 | return -EINVAL); | ||
991 | |||
992 | vol_table->mask_low = 0; | ||
993 | vol_table->phase_delay = 0; | ||
994 | vol_table->count = dep_table->count; | ||
995 | |||
996 | for (i = 0; i < dep_table->count; i++) { | ||
997 | vol_table->entries[i].value = dep_table->entries[i].vddci; | ||
998 | vol_table->entries[i].smio_low = 0; | ||
999 | } | ||
1000 | |||
1001 | PP_ASSERT_WITH_CODE(!vega10_trim_voltage_table(hwmgr, vol_table), | ||
1002 | "Failed to trim VDDCI table.", | ||
1003 | return -1); | ||
1004 | |||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
1008 | static int vega10_get_vdd_voltage_table(struct pp_hwmgr *hwmgr, | ||
1009 | phm_ppt_v1_clock_voltage_dependency_table *dep_table, | ||
1010 | struct pp_atomfwctrl_voltage_table *vol_table) | ||
1011 | { | ||
1012 | int i; | ||
1013 | |||
1014 | PP_ASSERT_WITH_CODE(dep_table->count, | ||
1015 | "Voltage Dependency Table empty.", | ||
1016 | return -EINVAL); | ||
1017 | |||
1018 | vol_table->mask_low = 0; | ||
1019 | vol_table->phase_delay = 0; | ||
1020 | vol_table->count = dep_table->count; | ||
1021 | |||
1022 | for (i = 0; i < vol_table->count; i++) { | ||
1023 | vol_table->entries[i].value = dep_table->entries[i].vddc; | ||
1024 | vol_table->entries[i].smio_low = 0; | ||
1025 | } | ||
1026 | |||
1027 | return 0; | ||
1028 | } | ||
1029 | |||
1030 | /* ---- Voltage Tables ---- | ||
1031 | * If the voltage table would be bigger than | ||
1032 | * what will fit into the state table on | ||
1033 | * the SMC keep only the higher entries. | ||
1034 | */ | ||
1035 | static void vega10_trim_voltage_table_to_fit_state_table( | ||
1036 | struct pp_hwmgr *hwmgr, | ||
1037 | uint32_t max_vol_steps, | ||
1038 | struct pp_atomfwctrl_voltage_table *vol_table) | ||
1039 | { | ||
1040 | unsigned int i, diff; | ||
1041 | |||
1042 | if (vol_table->count <= max_vol_steps) | ||
1043 | return; | ||
1044 | |||
1045 | diff = vol_table->count - max_vol_steps; | ||
1046 | |||
1047 | for (i = 0; i < max_vol_steps; i++) | ||
1048 | vol_table->entries[i] = vol_table->entries[i + diff]; | ||
1049 | |||
1050 | vol_table->count = max_vol_steps; | ||
1051 | } | ||
1052 | |||
1053 | /** | ||
1054 | * Create Voltage Tables. | ||
1055 | * | ||
1056 | * @param hwmgr the address of the powerplay hardware manager. | ||
1057 | * @return always 0 | ||
1058 | */ | ||
1059 | static int vega10_construct_voltage_tables(struct pp_hwmgr *hwmgr) | ||
1060 | { | ||
1061 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
1062 | struct phm_ppt_v2_information *table_info = | ||
1063 | (struct phm_ppt_v2_information *)hwmgr->pptable; | ||
1064 | int result; | ||
1065 | |||
1066 | if (data->mvdd_control == VEGA10_VOLTAGE_CONTROL_BY_SVID2 || | ||
1067 | data->mvdd_control == VEGA10_VOLTAGE_CONTROL_NONE) { | ||
1068 | result = vega10_get_mvdd_voltage_table(hwmgr, | ||
1069 | table_info->vdd_dep_on_mclk, | ||
1070 | &(data->mvdd_voltage_table)); | ||
1071 | PP_ASSERT_WITH_CODE(!result, | ||
1072 | "Failed to retrieve MVDDC table!", | ||
1073 | return result); | ||
1074 | } | ||
1075 | |||
1076 | if (data->vddci_control == VEGA10_VOLTAGE_CONTROL_NONE) { | ||
1077 | result = vega10_get_vddci_voltage_table(hwmgr, | ||
1078 | table_info->vdd_dep_on_mclk, | ||
1079 | &(data->vddci_voltage_table)); | ||
1080 | PP_ASSERT_WITH_CODE(!result, | ||
1081 | "Failed to retrieve VDDCI_MEM table!", | ||
1082 | return result); | ||
1083 | } | ||
1084 | |||
1085 | if (data->vddc_control == VEGA10_VOLTAGE_CONTROL_BY_SVID2 || | ||
1086 | data->vddc_control == VEGA10_VOLTAGE_CONTROL_NONE) { | ||
1087 | result = vega10_get_vdd_voltage_table(hwmgr, | ||
1088 | table_info->vdd_dep_on_sclk, | ||
1089 | &(data->vddc_voltage_table)); | ||
1090 | PP_ASSERT_WITH_CODE(!result, | ||
1091 | "Failed to retrieve VDDCR_SOC table!", | ||
1092 | return result); | ||
1093 | } | ||
1094 | |||
1095 | PP_ASSERT_WITH_CODE(data->vddc_voltage_table.count <= 16, | ||
1096 | "Too many voltage values for VDDC. Trimming to fit state table.", | ||
1097 | vega10_trim_voltage_table_to_fit_state_table(hwmgr, | ||
1098 | 16, &(data->vddc_voltage_table))); | ||
1099 | |||
1100 | PP_ASSERT_WITH_CODE(data->vddci_voltage_table.count <= 16, | ||
1101 | "Too many voltage values for VDDCI. Trimming to fit state table.", | ||
1102 | vega10_trim_voltage_table_to_fit_state_table(hwmgr, | ||
1103 | 16, &(data->vddci_voltage_table))); | ||
1104 | |||
1105 | PP_ASSERT_WITH_CODE(data->mvdd_voltage_table.count <= 16, | ||
1106 | "Too many voltage values for MVDD. Trimming to fit state table.", | ||
1107 | vega10_trim_voltage_table_to_fit_state_table(hwmgr, | ||
1108 | 16, &(data->mvdd_voltage_table))); | ||
1109 | |||
1110 | |||
1111 | return 0; | ||
1112 | } | ||
1113 | |||
1114 | /* | ||
1115 | * @fn vega10_init_dpm_state | ||
1116 | * @brief Function to initialize all Soft Min/Max and Hard Min/Max to 0xff. | ||
1117 | * | ||
1118 | * @param dpm_state - the address of the DPM Table to initiailize. | ||
1119 | * @return None. | ||
1120 | */ | ||
1121 | static void vega10_init_dpm_state(struct vega10_dpm_state *dpm_state) | ||
1122 | { | ||
1123 | dpm_state->soft_min_level = 0xff; | ||
1124 | dpm_state->soft_max_level = 0xff; | ||
1125 | dpm_state->hard_min_level = 0xff; | ||
1126 | dpm_state->hard_max_level = 0xff; | ||
1127 | } | ||
1128 | |||
1129 | static void vega10_setup_default_single_dpm_table(struct pp_hwmgr *hwmgr, | ||
1130 | struct vega10_single_dpm_table *dpm_table, | ||
1131 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_table) | ||
1132 | { | ||
1133 | int i; | ||
1134 | |||
1135 | for (i = 0; i < dep_table->count; i++) { | ||
1136 | if (i == 0 || dpm_table->dpm_levels[dpm_table->count - 1].value != | ||
1137 | dep_table->entries[i].clk) { | ||
1138 | dpm_table->dpm_levels[dpm_table->count].value = | ||
1139 | dep_table->entries[i].clk; | ||
1140 | dpm_table->dpm_levels[dpm_table->count].enabled = true; | ||
1141 | dpm_table->count++; | ||
1142 | } | ||
1143 | } | ||
1144 | } | ||
1145 | static int vega10_setup_default_pcie_table(struct pp_hwmgr *hwmgr) | ||
1146 | { | ||
1147 | struct vega10_hwmgr *data = | ||
1148 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
1149 | struct vega10_pcie_table *pcie_table = &(data->dpm_table.pcie_table); | ||
1150 | struct phm_ppt_v2_information *table_info = | ||
1151 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
1152 | struct phm_ppt_v1_pcie_table *bios_pcie_table = | ||
1153 | table_info->pcie_table; | ||
1154 | uint32_t i; | ||
1155 | |||
1156 | PP_ASSERT_WITH_CODE(bios_pcie_table->count, | ||
1157 | "Incorrect number of PCIE States from VBIOS!", | ||
1158 | return -1); | ||
1159 | |||
1160 | for (i = 0; i < NUM_LINK_LEVELS - 1; i++) { | ||
1161 | if (data->registry_data.pcieSpeedOverride) | ||
1162 | pcie_table->pcie_gen[i] = | ||
1163 | data->registry_data.pcieSpeedOverride; | ||
1164 | else | ||
1165 | pcie_table->pcie_gen[i] = | ||
1166 | bios_pcie_table->entries[i].gen_speed; | ||
1167 | |||
1168 | if (data->registry_data.pcieLaneOverride) | ||
1169 | pcie_table->pcie_lane[i] = | ||
1170 | data->registry_data.pcieLaneOverride; | ||
1171 | else | ||
1172 | pcie_table->pcie_lane[i] = | ||
1173 | bios_pcie_table->entries[i].lane_width; | ||
1174 | |||
1175 | if (data->registry_data.pcieClockOverride) | ||
1176 | pcie_table->lclk[i] = | ||
1177 | data->registry_data.pcieClockOverride; | ||
1178 | else | ||
1179 | pcie_table->lclk[i] = | ||
1180 | bios_pcie_table->entries[i].pcie_sclk; | ||
1181 | |||
1182 | pcie_table->count++; | ||
1183 | } | ||
1184 | |||
1185 | if (data->registry_data.pcieSpeedOverride) | ||
1186 | pcie_table->pcie_gen[i] = data->registry_data.pcieSpeedOverride; | ||
1187 | else | ||
1188 | pcie_table->pcie_gen[i] = | ||
1189 | bios_pcie_table->entries[bios_pcie_table->count - 1].gen_speed; | ||
1190 | |||
1191 | if (data->registry_data.pcieLaneOverride) | ||
1192 | pcie_table->pcie_lane[i] = data->registry_data.pcieLaneOverride; | ||
1193 | else | ||
1194 | pcie_table->pcie_lane[i] = | ||
1195 | bios_pcie_table->entries[bios_pcie_table->count - 1].lane_width; | ||
1196 | |||
1197 | if (data->registry_data.pcieClockOverride) | ||
1198 | pcie_table->lclk[i] = data->registry_data.pcieClockOverride; | ||
1199 | else | ||
1200 | pcie_table->lclk[i] = | ||
1201 | bios_pcie_table->entries[bios_pcie_table->count - 1].pcie_sclk; | ||
1202 | |||
1203 | pcie_table->count++; | ||
1204 | |||
1205 | return 0; | ||
1206 | } | ||
1207 | |||
1208 | /* | ||
1209 | * This function is to initialize all DPM state tables | ||
1210 | * for SMU based on the dependency table. | ||
1211 | * Dynamic state patching function will then trim these | ||
1212 | * state tables to the allowed range based | ||
1213 | * on the power policy or external client requests, | ||
1214 | * such as UVD request, etc. | ||
1215 | */ | ||
1216 | static int vega10_setup_default_dpm_tables(struct pp_hwmgr *hwmgr) | ||
1217 | { | ||
1218 | struct vega10_hwmgr *data = | ||
1219 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
1220 | struct phm_ppt_v2_information *table_info = | ||
1221 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
1222 | struct vega10_single_dpm_table *dpm_table; | ||
1223 | uint32_t i; | ||
1224 | |||
1225 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_soc_table = | ||
1226 | table_info->vdd_dep_on_socclk; | ||
1227 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_gfx_table = | ||
1228 | table_info->vdd_dep_on_sclk; | ||
1229 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table = | ||
1230 | table_info->vdd_dep_on_mclk; | ||
1231 | struct phm_ppt_v1_mm_clock_voltage_dependency_table *dep_mm_table = | ||
1232 | table_info->mm_dep_table; | ||
1233 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_dcef_table = | ||
1234 | table_info->vdd_dep_on_dcefclk; | ||
1235 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_pix_table = | ||
1236 | table_info->vdd_dep_on_pixclk; | ||
1237 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_disp_table = | ||
1238 | table_info->vdd_dep_on_dispclk; | ||
1239 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_phy_table = | ||
1240 | table_info->vdd_dep_on_phyclk; | ||
1241 | |||
1242 | PP_ASSERT_WITH_CODE(dep_soc_table, | ||
1243 | "SOCCLK dependency table is missing. This table is mandatory", | ||
1244 | return -EINVAL); | ||
1245 | PP_ASSERT_WITH_CODE(dep_soc_table->count >= 1, | ||
1246 | "SOCCLK dependency table is empty. This table is mandatory", | ||
1247 | return -EINVAL); | ||
1248 | |||
1249 | PP_ASSERT_WITH_CODE(dep_gfx_table, | ||
1250 | "GFXCLK dependency table is missing. This table is mandatory", | ||
1251 | return -EINVAL); | ||
1252 | PP_ASSERT_WITH_CODE(dep_gfx_table->count >= 1, | ||
1253 | "GFXCLK dependency table is empty. This table is mandatory", | ||
1254 | return -EINVAL); | ||
1255 | |||
1256 | PP_ASSERT_WITH_CODE(dep_mclk_table, | ||
1257 | "MCLK dependency table is missing. This table is mandatory", | ||
1258 | return -EINVAL); | ||
1259 | PP_ASSERT_WITH_CODE(dep_mclk_table->count >= 1, | ||
1260 | "MCLK dependency table has to have is missing. This table is mandatory", | ||
1261 | return -EINVAL); | ||
1262 | |||
1263 | /* Initialize Sclk DPM table based on allow Sclk values */ | ||
1264 | data->dpm_table.soc_table.count = 0; | ||
1265 | data->dpm_table.gfx_table.count = 0; | ||
1266 | data->dpm_table.dcef_table.count = 0; | ||
1267 | |||
1268 | dpm_table = &(data->dpm_table.soc_table); | ||
1269 | vega10_setup_default_single_dpm_table(hwmgr, | ||
1270 | dpm_table, | ||
1271 | dep_soc_table); | ||
1272 | |||
1273 | vega10_init_dpm_state(&(dpm_table->dpm_state)); | ||
1274 | |||
1275 | dpm_table = &(data->dpm_table.gfx_table); | ||
1276 | vega10_setup_default_single_dpm_table(hwmgr, | ||
1277 | dpm_table, | ||
1278 | dep_gfx_table); | ||
1279 | vega10_init_dpm_state(&(dpm_table->dpm_state)); | ||
1280 | |||
1281 | /* Initialize Mclk DPM table based on allow Mclk values */ | ||
1282 | data->dpm_table.mem_table.count = 0; | ||
1283 | dpm_table = &(data->dpm_table.mem_table); | ||
1284 | vega10_setup_default_single_dpm_table(hwmgr, | ||
1285 | dpm_table, | ||
1286 | dep_mclk_table); | ||
1287 | vega10_init_dpm_state(&(dpm_table->dpm_state)); | ||
1288 | |||
1289 | data->dpm_table.eclk_table.count = 0; | ||
1290 | dpm_table = &(data->dpm_table.eclk_table); | ||
1291 | for (i = 0; i < dep_mm_table->count; i++) { | ||
1292 | if (i == 0 || dpm_table->dpm_levels | ||
1293 | [dpm_table->count - 1].value != | ||
1294 | dep_mm_table->entries[i].eclk) { | ||
1295 | dpm_table->dpm_levels[dpm_table->count].value = | ||
1296 | dep_mm_table->entries[i].eclk; | ||
1297 | dpm_table->dpm_levels[dpm_table->count].enabled = | ||
1298 | (i == 0) ? true : false; | ||
1299 | dpm_table->count++; | ||
1300 | } | ||
1301 | } | ||
1302 | vega10_init_dpm_state(&(dpm_table->dpm_state)); | ||
1303 | |||
1304 | data->dpm_table.vclk_table.count = 0; | ||
1305 | data->dpm_table.dclk_table.count = 0; | ||
1306 | dpm_table = &(data->dpm_table.vclk_table); | ||
1307 | for (i = 0; i < dep_mm_table->count; i++) { | ||
1308 | if (i == 0 || dpm_table->dpm_levels | ||
1309 | [dpm_table->count - 1].value != | ||
1310 | dep_mm_table->entries[i].vclk) { | ||
1311 | dpm_table->dpm_levels[dpm_table->count].value = | ||
1312 | dep_mm_table->entries[i].vclk; | ||
1313 | dpm_table->dpm_levels[dpm_table->count].enabled = | ||
1314 | (i == 0) ? true : false; | ||
1315 | dpm_table->count++; | ||
1316 | } | ||
1317 | } | ||
1318 | vega10_init_dpm_state(&(dpm_table->dpm_state)); | ||
1319 | |||
1320 | dpm_table = &(data->dpm_table.dclk_table); | ||
1321 | for (i = 0; i < dep_mm_table->count; i++) { | ||
1322 | if (i == 0 || dpm_table->dpm_levels | ||
1323 | [dpm_table->count - 1].value != | ||
1324 | dep_mm_table->entries[i].dclk) { | ||
1325 | dpm_table->dpm_levels[dpm_table->count].value = | ||
1326 | dep_mm_table->entries[i].dclk; | ||
1327 | dpm_table->dpm_levels[dpm_table->count].enabled = | ||
1328 | (i == 0) ? true : false; | ||
1329 | dpm_table->count++; | ||
1330 | } | ||
1331 | } | ||
1332 | vega10_init_dpm_state(&(dpm_table->dpm_state)); | ||
1333 | |||
1334 | /* Assume there is no headless Vega10 for now */ | ||
1335 | dpm_table = &(data->dpm_table.dcef_table); | ||
1336 | vega10_setup_default_single_dpm_table(hwmgr, | ||
1337 | dpm_table, | ||
1338 | dep_dcef_table); | ||
1339 | |||
1340 | vega10_init_dpm_state(&(dpm_table->dpm_state)); | ||
1341 | |||
1342 | dpm_table = &(data->dpm_table.pixel_table); | ||
1343 | vega10_setup_default_single_dpm_table(hwmgr, | ||
1344 | dpm_table, | ||
1345 | dep_pix_table); | ||
1346 | |||
1347 | vega10_init_dpm_state(&(dpm_table->dpm_state)); | ||
1348 | |||
1349 | dpm_table = &(data->dpm_table.display_table); | ||
1350 | vega10_setup_default_single_dpm_table(hwmgr, | ||
1351 | dpm_table, | ||
1352 | dep_disp_table); | ||
1353 | |||
1354 | vega10_init_dpm_state(&(dpm_table->dpm_state)); | ||
1355 | |||
1356 | dpm_table = &(data->dpm_table.phy_table); | ||
1357 | vega10_setup_default_single_dpm_table(hwmgr, | ||
1358 | dpm_table, | ||
1359 | dep_phy_table); | ||
1360 | |||
1361 | vega10_init_dpm_state(&(dpm_table->dpm_state)); | ||
1362 | |||
1363 | vega10_setup_default_pcie_table(hwmgr); | ||
1364 | |||
1365 | /* save a copy of the default DPM table */ | ||
1366 | memcpy(&(data->golden_dpm_table), &(data->dpm_table), | ||
1367 | sizeof(struct vega10_dpm_table)); | ||
1368 | |||
1369 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
1370 | PHM_PlatformCaps_ODNinACSupport) || | ||
1371 | phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
1372 | PHM_PlatformCaps_ODNinDCSupport)) { | ||
1373 | data->odn_dpm_table.odn_core_clock_dpm_levels. | ||
1374 | number_of_performance_levels = data->dpm_table.gfx_table.count; | ||
1375 | for (i = 0; i < data->dpm_table.gfx_table.count; i++) { | ||
1376 | data->odn_dpm_table.odn_core_clock_dpm_levels. | ||
1377 | performance_level_entries[i].clock = | ||
1378 | data->dpm_table.gfx_table.dpm_levels[i].value; | ||
1379 | data->odn_dpm_table.odn_core_clock_dpm_levels. | ||
1380 | performance_level_entries[i].enabled = true; | ||
1381 | } | ||
1382 | |||
1383 | data->odn_dpm_table.vdd_dependency_on_sclk.count = | ||
1384 | dep_gfx_table->count; | ||
1385 | for (i = 0; i < dep_gfx_table->count; i++) { | ||
1386 | data->odn_dpm_table.vdd_dependency_on_sclk.entries[i].clk = | ||
1387 | dep_gfx_table->entries[i].clk; | ||
1388 | data->odn_dpm_table.vdd_dependency_on_sclk.entries[i].vddInd = | ||
1389 | dep_gfx_table->entries[i].vddInd; | ||
1390 | data->odn_dpm_table.vdd_dependency_on_sclk.entries[i].cks_enable = | ||
1391 | dep_gfx_table->entries[i].cks_enable; | ||
1392 | data->odn_dpm_table.vdd_dependency_on_sclk.entries[i].cks_voffset = | ||
1393 | dep_gfx_table->entries[i].cks_voffset; | ||
1394 | } | ||
1395 | |||
1396 | data->odn_dpm_table.odn_memory_clock_dpm_levels. | ||
1397 | number_of_performance_levels = data->dpm_table.mem_table.count; | ||
1398 | for (i = 0; i < data->dpm_table.mem_table.count; i++) { | ||
1399 | data->odn_dpm_table.odn_memory_clock_dpm_levels. | ||
1400 | performance_level_entries[i].clock = | ||
1401 | data->dpm_table.mem_table.dpm_levels[i].value; | ||
1402 | data->odn_dpm_table.odn_memory_clock_dpm_levels. | ||
1403 | performance_level_entries[i].enabled = true; | ||
1404 | } | ||
1405 | |||
1406 | data->odn_dpm_table.vdd_dependency_on_mclk.count = dep_mclk_table->count; | ||
1407 | for (i = 0; i < dep_mclk_table->count; i++) { | ||
1408 | data->odn_dpm_table.vdd_dependency_on_mclk.entries[i].clk = | ||
1409 | dep_mclk_table->entries[i].clk; | ||
1410 | data->odn_dpm_table.vdd_dependency_on_mclk.entries[i].vddInd = | ||
1411 | dep_mclk_table->entries[i].vddInd; | ||
1412 | data->odn_dpm_table.vdd_dependency_on_mclk.entries[i].vddci = | ||
1413 | dep_mclk_table->entries[i].vddci; | ||
1414 | } | ||
1415 | } | ||
1416 | |||
1417 | return 0; | ||
1418 | } | ||
1419 | |||
1420 | /* | ||
1421 | * @fn vega10_populate_ulv_state | ||
1422 | * @brief Function to provide parameters for Utral Low Voltage state to SMC. | ||
1423 | * | ||
1424 | * @param hwmgr - the address of the hardware manager. | ||
1425 | * @return Always 0. | ||
1426 | */ | ||
1427 | static int vega10_populate_ulv_state(struct pp_hwmgr *hwmgr) | ||
1428 | { | ||
1429 | struct vega10_hwmgr *data = | ||
1430 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
1431 | struct phm_ppt_v2_information *table_info = | ||
1432 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
1433 | |||
1434 | data->smc_state_table.pp_table.UlvOffsetVid = | ||
1435 | (uint8_t)(table_info->us_ulv_voltage_offset * | ||
1436 | VOLTAGE_VID_OFFSET_SCALE2 / | ||
1437 | VOLTAGE_VID_OFFSET_SCALE1); | ||
1438 | |||
1439 | data->smc_state_table.pp_table.UlvSmnclkDid = | ||
1440 | (uint8_t)(table_info->us_ulv_smnclk_did); | ||
1441 | data->smc_state_table.pp_table.UlvMp1clkDid = | ||
1442 | (uint8_t)(table_info->us_ulv_mp1clk_did); | ||
1443 | data->smc_state_table.pp_table.UlvGfxclkBypass = | ||
1444 | (uint8_t)(table_info->us_ulv_gfxclk_bypass); | ||
1445 | data->smc_state_table.pp_table.UlvPhaseSheddingPsi0 = | ||
1446 | (uint8_t)(data->vddc_voltage_table.psi0_enable); | ||
1447 | data->smc_state_table.pp_table.UlvPhaseSheddingPsi1 = | ||
1448 | (uint8_t)(data->vddc_voltage_table.psi1_enable); | ||
1449 | |||
1450 | return 0; | ||
1451 | } | ||
1452 | |||
1453 | static int vega10_populate_single_lclk_level(struct pp_hwmgr *hwmgr, | ||
1454 | uint32_t lclock, uint8_t *curr_lclk_did) | ||
1455 | { | ||
1456 | struct pp_atomfwctrl_clock_dividers_soc15 dividers; | ||
1457 | |||
1458 | PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10( | ||
1459 | hwmgr, | ||
1460 | COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, | ||
1461 | lclock, ÷rs), | ||
1462 | "Failed to get LCLK clock settings from VBIOS!", | ||
1463 | return -1); | ||
1464 | |||
1465 | *curr_lclk_did = dividers.ulDid; | ||
1466 | |||
1467 | return 0; | ||
1468 | } | ||
1469 | |||
1470 | static int vega10_populate_smc_link_levels(struct pp_hwmgr *hwmgr) | ||
1471 | { | ||
1472 | int result = -1; | ||
1473 | struct vega10_hwmgr *data = | ||
1474 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
1475 | PPTable_t *pp_table = &(data->smc_state_table.pp_table); | ||
1476 | struct vega10_pcie_table *pcie_table = | ||
1477 | &(data->dpm_table.pcie_table); | ||
1478 | uint32_t i, j; | ||
1479 | |||
1480 | for (i = 0; i < pcie_table->count; i++) { | ||
1481 | pp_table->PcieGenSpeed[i] = pcie_table->pcie_gen[i]; | ||
1482 | pp_table->PcieLaneCount[i] = pcie_table->pcie_lane[i]; | ||
1483 | |||
1484 | result = vega10_populate_single_lclk_level(hwmgr, | ||
1485 | pcie_table->lclk[i], &(pp_table->LclkDid[i])); | ||
1486 | if (result) { | ||
1487 | pr_info("Populate LClock Level %d Failed!\n", i); | ||
1488 | return result; | ||
1489 | } | ||
1490 | } | ||
1491 | |||
1492 | j = i - 1; | ||
1493 | while (i < NUM_LINK_LEVELS) { | ||
1494 | pp_table->PcieGenSpeed[i] = pcie_table->pcie_gen[j]; | ||
1495 | pp_table->PcieLaneCount[i] = pcie_table->pcie_lane[j]; | ||
1496 | |||
1497 | result = vega10_populate_single_lclk_level(hwmgr, | ||
1498 | pcie_table->lclk[j], &(pp_table->LclkDid[i])); | ||
1499 | if (result) { | ||
1500 | pr_info("Populate LClock Level %d Failed!\n", i); | ||
1501 | return result; | ||
1502 | } | ||
1503 | i++; | ||
1504 | } | ||
1505 | |||
1506 | return result; | ||
1507 | } | ||
1508 | |||
1509 | /** | ||
1510 | * Populates single SMC GFXSCLK structure using the provided engine clock | ||
1511 | * | ||
1512 | * @param hwmgr the address of the hardware manager | ||
1513 | * @param gfx_clock the GFX clock to use to populate the structure. | ||
1514 | * @param current_gfxclk_level location in PPTable for the SMC GFXCLK structure. | ||
1515 | */ | ||
1516 | |||
1517 | static int vega10_populate_single_gfx_level(struct pp_hwmgr *hwmgr, | ||
1518 | uint32_t gfx_clock, PllSetting_t *current_gfxclk_level) | ||
1519 | { | ||
1520 | struct phm_ppt_v2_information *table_info = | ||
1521 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
1522 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_sclk = | ||
1523 | table_info->vdd_dep_on_sclk; | ||
1524 | struct vega10_hwmgr *data = | ||
1525 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
1526 | struct pp_atomfwctrl_clock_dividers_soc15 dividers; | ||
1527 | uint32_t i; | ||
1528 | |||
1529 | if (data->apply_overdrive_next_settings_mask & | ||
1530 | DPMTABLE_OD_UPDATE_VDDC) | ||
1531 | dep_on_sclk = (struct phm_ppt_v1_clock_voltage_dependency_table *) | ||
1532 | &(data->odn_dpm_table.vdd_dependency_on_sclk); | ||
1533 | |||
1534 | PP_ASSERT_WITH_CODE(dep_on_sclk, | ||
1535 | "Invalid SOC_VDD-GFX_CLK Dependency Table!", | ||
1536 | return -EINVAL); | ||
1537 | |||
1538 | for (i = 0; i < dep_on_sclk->count; i++) { | ||
1539 | if (dep_on_sclk->entries[i].clk == gfx_clock) | ||
1540 | break; | ||
1541 | } | ||
1542 | |||
1543 | PP_ASSERT_WITH_CODE(dep_on_sclk->count > i, | ||
1544 | "Cannot find gfx_clk in SOC_VDD-GFX_CLK!", | ||
1545 | return -EINVAL); | ||
1546 | PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr, | ||
1547 | COMPUTE_GPUCLK_INPUT_FLAG_GFXCLK, | ||
1548 | gfx_clock, ÷rs), | ||
1549 | "Failed to get GFX Clock settings from VBIOS!", | ||
1550 | return -EINVAL); | ||
1551 | |||
1552 | /* Feedback Multiplier: bit 0:8 int, bit 15:12 post_div, bit 31:16 frac */ | ||
1553 | current_gfxclk_level->FbMult = | ||
1554 | cpu_to_le32(dividers.ulPll_fb_mult); | ||
1555 | /* Spread FB Multiplier bit: bit 0:8 int, bit 31:16 frac */ | ||
1556 | current_gfxclk_level->SsOn = dividers.ucPll_ss_enable; | ||
1557 | current_gfxclk_level->SsFbMult = | ||
1558 | cpu_to_le32(dividers.ulPll_ss_fbsmult); | ||
1559 | current_gfxclk_level->SsSlewFrac = | ||
1560 | cpu_to_le16(dividers.usPll_ss_slew_frac); | ||
1561 | current_gfxclk_level->Did = (uint8_t)(dividers.ulDid); | ||
1562 | |||
1563 | return 0; | ||
1564 | } | ||
1565 | |||
1566 | /** | ||
1567 | * @brief Populates single SMC SOCCLK structure using the provided clock. | ||
1568 | * | ||
1569 | * @param hwmgr - the address of the hardware manager. | ||
1570 | * @param soc_clock - the SOC clock to use to populate the structure. | ||
1571 | * @param current_socclk_level - location in PPTable for the SMC SOCCLK structure. | ||
1572 | * @return 0 on success.. | ||
1573 | */ | ||
1574 | static int vega10_populate_single_soc_level(struct pp_hwmgr *hwmgr, | ||
1575 | uint32_t soc_clock, uint8_t *current_soc_did, | ||
1576 | uint8_t *current_vol_index) | ||
1577 | { | ||
1578 | struct phm_ppt_v2_information *table_info = | ||
1579 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
1580 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_soc = | ||
1581 | table_info->vdd_dep_on_socclk; | ||
1582 | struct pp_atomfwctrl_clock_dividers_soc15 dividers; | ||
1583 | uint32_t i; | ||
1584 | |||
1585 | PP_ASSERT_WITH_CODE(dep_on_soc, | ||
1586 | "Invalid SOC_VDD-SOC_CLK Dependency Table!", | ||
1587 | return -EINVAL); | ||
1588 | for (i = 0; i < dep_on_soc->count; i++) { | ||
1589 | if (dep_on_soc->entries[i].clk == soc_clock) | ||
1590 | break; | ||
1591 | } | ||
1592 | PP_ASSERT_WITH_CODE(dep_on_soc->count > i, | ||
1593 | "Cannot find SOC_CLK in SOC_VDD-SOC_CLK Dependency Table", | ||
1594 | return -EINVAL); | ||
1595 | PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr, | ||
1596 | COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, | ||
1597 | soc_clock, ÷rs), | ||
1598 | "Failed to get SOC Clock settings from VBIOS!", | ||
1599 | return -EINVAL); | ||
1600 | |||
1601 | *current_soc_did = (uint8_t)dividers.ulDid; | ||
1602 | *current_vol_index = (uint8_t)(dep_on_soc->entries[i].vddInd); | ||
1603 | |||
1604 | return 0; | ||
1605 | } | ||
1606 | |||
1607 | uint16_t vega10_locate_vddc_given_clock(struct pp_hwmgr *hwmgr, | ||
1608 | uint32_t clk, | ||
1609 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_table) | ||
1610 | { | ||
1611 | uint16_t i; | ||
1612 | |||
1613 | for (i = 0; i < dep_table->count; i++) { | ||
1614 | if (dep_table->entries[i].clk == clk) | ||
1615 | return dep_table->entries[i].vddc; | ||
1616 | } | ||
1617 | |||
1618 | pr_info("[LocateVddcGivenClock] Cannot locate SOC Vddc for this clock!"); | ||
1619 | return 0; | ||
1620 | } | ||
1621 | |||
1622 | /** | ||
1623 | * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states | ||
1624 | * | ||
1625 | * @param hwmgr the address of the hardware manager | ||
1626 | */ | ||
1627 | static int vega10_populate_all_graphic_levels(struct pp_hwmgr *hwmgr) | ||
1628 | { | ||
1629 | struct vega10_hwmgr *data = | ||
1630 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
1631 | struct phm_ppt_v2_information *table_info = | ||
1632 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
1633 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_table = | ||
1634 | table_info->vdd_dep_on_socclk; | ||
1635 | PPTable_t *pp_table = &(data->smc_state_table.pp_table); | ||
1636 | struct vega10_single_dpm_table *dpm_table = &(data->dpm_table.gfx_table); | ||
1637 | int result = 0; | ||
1638 | uint32_t i, j; | ||
1639 | |||
1640 | for (i = 0; i < dpm_table->count; i++) { | ||
1641 | result = vega10_populate_single_gfx_level(hwmgr, | ||
1642 | dpm_table->dpm_levels[i].value, | ||
1643 | &(pp_table->GfxclkLevel[i])); | ||
1644 | if (result) | ||
1645 | return result; | ||
1646 | } | ||
1647 | |||
1648 | j = i - 1; | ||
1649 | while (i < NUM_GFXCLK_DPM_LEVELS) { | ||
1650 | result = vega10_populate_single_gfx_level(hwmgr, | ||
1651 | dpm_table->dpm_levels[j].value, | ||
1652 | &(pp_table->GfxclkLevel[i])); | ||
1653 | if (result) | ||
1654 | return result; | ||
1655 | i++; | ||
1656 | } | ||
1657 | |||
1658 | pp_table->GfxclkSlewRate = | ||
1659 | cpu_to_le16(table_info->us_gfxclk_slew_rate); | ||
1660 | |||
1661 | dpm_table = &(data->dpm_table.soc_table); | ||
1662 | for (i = 0; i < dpm_table->count; i++) { | ||
1663 | pp_table->SocVid[i] = | ||
1664 | (uint8_t)convert_to_vid( | ||
1665 | vega10_locate_vddc_given_clock(hwmgr, | ||
1666 | dpm_table->dpm_levels[i].value, | ||
1667 | dep_table)); | ||
1668 | result = vega10_populate_single_soc_level(hwmgr, | ||
1669 | dpm_table->dpm_levels[i].value, | ||
1670 | &(pp_table->SocclkDid[i]), | ||
1671 | &(pp_table->SocDpmVoltageIndex[i])); | ||
1672 | if (result) | ||
1673 | return result; | ||
1674 | } | ||
1675 | |||
1676 | j = i - 1; | ||
1677 | while (i < NUM_SOCCLK_DPM_LEVELS) { | ||
1678 | pp_table->SocVid[i] = pp_table->SocVid[j]; | ||
1679 | result = vega10_populate_single_soc_level(hwmgr, | ||
1680 | dpm_table->dpm_levels[j].value, | ||
1681 | &(pp_table->SocclkDid[i]), | ||
1682 | &(pp_table->SocDpmVoltageIndex[i])); | ||
1683 | if (result) | ||
1684 | return result; | ||
1685 | i++; | ||
1686 | } | ||
1687 | |||
1688 | return result; | ||
1689 | } | ||
1690 | |||
1691 | /** | ||
1692 | * @brief Populates single SMC GFXCLK structure using the provided clock. | ||
1693 | * | ||
1694 | * @param hwmgr - the address of the hardware manager. | ||
1695 | * @param mem_clock - the memory clock to use to populate the structure. | ||
1696 | * @return 0 on success.. | ||
1697 | */ | ||
1698 | static int vega10_populate_single_memory_level(struct pp_hwmgr *hwmgr, | ||
1699 | uint32_t mem_clock, uint8_t *current_mem_vid, | ||
1700 | PllSetting_t *current_memclk_level, uint8_t *current_mem_soc_vind) | ||
1701 | { | ||
1702 | struct vega10_hwmgr *data = | ||
1703 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
1704 | struct phm_ppt_v2_information *table_info = | ||
1705 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
1706 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_mclk = | ||
1707 | table_info->vdd_dep_on_mclk; | ||
1708 | struct pp_atomfwctrl_clock_dividers_soc15 dividers; | ||
1709 | uint32_t i; | ||
1710 | |||
1711 | if (data->apply_overdrive_next_settings_mask & | ||
1712 | DPMTABLE_OD_UPDATE_VDDC) | ||
1713 | dep_on_mclk = (struct phm_ppt_v1_clock_voltage_dependency_table *) | ||
1714 | &data->odn_dpm_table.vdd_dependency_on_mclk; | ||
1715 | |||
1716 | PP_ASSERT_WITH_CODE(dep_on_mclk, | ||
1717 | "Invalid SOC_VDD-UCLK Dependency Table!", | ||
1718 | return -EINVAL); | ||
1719 | |||
1720 | for (i = 0; i < dep_on_mclk->count; i++) { | ||
1721 | if (dep_on_mclk->entries[i].clk == mem_clock) | ||
1722 | break; | ||
1723 | } | ||
1724 | |||
1725 | PP_ASSERT_WITH_CODE(dep_on_mclk->count > i, | ||
1726 | "Cannot find UCLK in SOC_VDD-UCLK Dependency Table!", | ||
1727 | return -EINVAL); | ||
1728 | |||
1729 | PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10( | ||
1730 | hwmgr, COMPUTE_GPUCLK_INPUT_FLAG_UCLK, mem_clock, ÷rs), | ||
1731 | "Failed to get UCLK settings from VBIOS!", | ||
1732 | return -1); | ||
1733 | |||
1734 | *current_mem_vid = | ||
1735 | (uint8_t)(convert_to_vid(dep_on_mclk->entries[i].mvdd)); | ||
1736 | *current_mem_soc_vind = | ||
1737 | (uint8_t)(dep_on_mclk->entries[i].vddInd); | ||
1738 | current_memclk_level->FbMult = cpu_to_le32(dividers.ulPll_fb_mult); | ||
1739 | current_memclk_level->Did = (uint8_t)(dividers.ulDid); | ||
1740 | |||
1741 | PP_ASSERT_WITH_CODE(current_memclk_level->Did >= 1, | ||
1742 | "Invalid Divider ID!", | ||
1743 | return -EINVAL); | ||
1744 | |||
1745 | return 0; | ||
1746 | } | ||
1747 | |||
1748 | /** | ||
1749 | * @brief Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states. | ||
1750 | * | ||
1751 | * @param pHwMgr - the address of the hardware manager. | ||
1752 | * @return PP_Result_OK on success. | ||
1753 | */ | ||
1754 | static int vega10_populate_all_memory_levels(struct pp_hwmgr *hwmgr) | ||
1755 | { | ||
1756 | struct vega10_hwmgr *data = | ||
1757 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
1758 | PPTable_t *pp_table = &(data->smc_state_table.pp_table); | ||
1759 | struct vega10_single_dpm_table *dpm_table = | ||
1760 | &(data->dpm_table.mem_table); | ||
1761 | int result = 0; | ||
1762 | uint32_t i, j, reg, mem_channels; | ||
1763 | |||
1764 | for (i = 0; i < dpm_table->count; i++) { | ||
1765 | result = vega10_populate_single_memory_level(hwmgr, | ||
1766 | dpm_table->dpm_levels[i].value, | ||
1767 | &(pp_table->MemVid[i]), | ||
1768 | &(pp_table->UclkLevel[i]), | ||
1769 | &(pp_table->MemSocVoltageIndex[i])); | ||
1770 | if (result) | ||
1771 | return result; | ||
1772 | } | ||
1773 | |||
1774 | j = i - 1; | ||
1775 | while (i < NUM_UCLK_DPM_LEVELS) { | ||
1776 | result = vega10_populate_single_memory_level(hwmgr, | ||
1777 | dpm_table->dpm_levels[j].value, | ||
1778 | &(pp_table->MemVid[i]), | ||
1779 | &(pp_table->UclkLevel[i]), | ||
1780 | &(pp_table->MemSocVoltageIndex[i])); | ||
1781 | if (result) | ||
1782 | return result; | ||
1783 | i++; | ||
1784 | } | ||
1785 | |||
1786 | reg = soc15_get_register_offset(DF_HWID, 0, | ||
1787 | mmDF_CS_AON0_DramBaseAddress0_BASE_IDX, | ||
1788 | mmDF_CS_AON0_DramBaseAddress0); | ||
1789 | mem_channels = (cgs_read_register(hwmgr->device, reg) & | ||
1790 | DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK) >> | ||
1791 | DF_CS_AON0_DramBaseAddress0__IntLvNumChan__SHIFT; | ||
1792 | pp_table->NumMemoryChannels = cpu_to_le16(mem_channels); | ||
1793 | pp_table->MemoryChannelWidth = | ||
1794 | cpu_to_le16(HBM_MEMORY_CHANNEL_WIDTH * | ||
1795 | channel_number[mem_channels]); | ||
1796 | |||
1797 | pp_table->LowestUclkReservedForUlv = | ||
1798 | (uint8_t)(data->lowest_uclk_reserved_for_ulv); | ||
1799 | |||
1800 | return result; | ||
1801 | } | ||
1802 | |||
1803 | static int vega10_populate_single_display_type(struct pp_hwmgr *hwmgr, | ||
1804 | DSPCLK_e disp_clock) | ||
1805 | { | ||
1806 | struct vega10_hwmgr *data = | ||
1807 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
1808 | PPTable_t *pp_table = &(data->smc_state_table.pp_table); | ||
1809 | struct phm_ppt_v2_information *table_info = | ||
1810 | (struct phm_ppt_v2_information *) | ||
1811 | (hwmgr->pptable); | ||
1812 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_table; | ||
1813 | uint32_t i; | ||
1814 | uint16_t clk = 0, vddc = 0; | ||
1815 | uint8_t vid = 0; | ||
1816 | |||
1817 | switch (disp_clock) { | ||
1818 | case DSPCLK_DCEFCLK: | ||
1819 | dep_table = table_info->vdd_dep_on_dcefclk; | ||
1820 | break; | ||
1821 | case DSPCLK_DISPCLK: | ||
1822 | dep_table = table_info->vdd_dep_on_dispclk; | ||
1823 | break; | ||
1824 | case DSPCLK_PIXCLK: | ||
1825 | dep_table = table_info->vdd_dep_on_pixclk; | ||
1826 | break; | ||
1827 | case DSPCLK_PHYCLK: | ||
1828 | dep_table = table_info->vdd_dep_on_phyclk; | ||
1829 | break; | ||
1830 | default: | ||
1831 | return -1; | ||
1832 | } | ||
1833 | |||
1834 | PP_ASSERT_WITH_CODE(dep_table->count <= NUM_DSPCLK_LEVELS, | ||
1835 | "Number Of Entries Exceeded maximum!", | ||
1836 | return -1); | ||
1837 | |||
1838 | for (i = 0; i < dep_table->count; i++) { | ||
1839 | clk = (uint16_t)(dep_table->entries[i].clk / 100); | ||
1840 | vddc = table_info->vddc_lookup_table-> | ||
1841 | entries[dep_table->entries[i].vddInd].us_vdd; | ||
1842 | vid = (uint8_t)convert_to_vid(vddc); | ||
1843 | pp_table->DisplayClockTable[disp_clock][i].Freq = | ||
1844 | cpu_to_le16(clk); | ||
1845 | pp_table->DisplayClockTable[disp_clock][i].Vid = | ||
1846 | cpu_to_le16(vid); | ||
1847 | } | ||
1848 | |||
1849 | while (i < NUM_DSPCLK_LEVELS) { | ||
1850 | pp_table->DisplayClockTable[disp_clock][i].Freq = | ||
1851 | cpu_to_le16(clk); | ||
1852 | pp_table->DisplayClockTable[disp_clock][i].Vid = | ||
1853 | cpu_to_le16(vid); | ||
1854 | i++; | ||
1855 | } | ||
1856 | |||
1857 | return 0; | ||
1858 | } | ||
1859 | |||
1860 | static int vega10_populate_all_display_clock_levels(struct pp_hwmgr *hwmgr) | ||
1861 | { | ||
1862 | uint32_t i; | ||
1863 | |||
1864 | for (i = 0; i < DSPCLK_COUNT; i++) { | ||
1865 | PP_ASSERT_WITH_CODE(!vega10_populate_single_display_type(hwmgr, i), | ||
1866 | "Failed to populate Clock in DisplayClockTable!", | ||
1867 | return -1); | ||
1868 | } | ||
1869 | |||
1870 | return 0; | ||
1871 | } | ||
1872 | |||
1873 | static int vega10_populate_single_eclock_level(struct pp_hwmgr *hwmgr, | ||
1874 | uint32_t eclock, uint8_t *current_eclk_did, | ||
1875 | uint8_t *current_soc_vol) | ||
1876 | { | ||
1877 | struct phm_ppt_v2_information *table_info = | ||
1878 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
1879 | struct phm_ppt_v1_mm_clock_voltage_dependency_table *dep_table = | ||
1880 | table_info->mm_dep_table; | ||
1881 | struct pp_atomfwctrl_clock_dividers_soc15 dividers; | ||
1882 | uint32_t i; | ||
1883 | |||
1884 | PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr, | ||
1885 | COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, | ||
1886 | eclock, ÷rs), | ||
1887 | "Failed to get ECLK clock settings from VBIOS!", | ||
1888 | return -1); | ||
1889 | |||
1890 | *current_eclk_did = (uint8_t)dividers.ulDid; | ||
1891 | |||
1892 | for (i = 0; i < dep_table->count; i++) { | ||
1893 | if (dep_table->entries[i].eclk == eclock) | ||
1894 | *current_soc_vol = dep_table->entries[i].vddcInd; | ||
1895 | } | ||
1896 | |||
1897 | return 0; | ||
1898 | } | ||
1899 | |||
1900 | static int vega10_populate_smc_vce_levels(struct pp_hwmgr *hwmgr) | ||
1901 | { | ||
1902 | struct vega10_hwmgr *data = | ||
1903 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
1904 | PPTable_t *pp_table = &(data->smc_state_table.pp_table); | ||
1905 | struct vega10_single_dpm_table *dpm_table = &(data->dpm_table.eclk_table); | ||
1906 | int result = -EINVAL; | ||
1907 | uint32_t i, j; | ||
1908 | |||
1909 | for (i = 0; i < dpm_table->count; i++) { | ||
1910 | result = vega10_populate_single_eclock_level(hwmgr, | ||
1911 | dpm_table->dpm_levels[i].value, | ||
1912 | &(pp_table->EclkDid[i]), | ||
1913 | &(pp_table->VceDpmVoltageIndex[i])); | ||
1914 | if (result) | ||
1915 | return result; | ||
1916 | } | ||
1917 | |||
1918 | j = i - 1; | ||
1919 | while (i < NUM_VCE_DPM_LEVELS) { | ||
1920 | result = vega10_populate_single_eclock_level(hwmgr, | ||
1921 | dpm_table->dpm_levels[j].value, | ||
1922 | &(pp_table->EclkDid[i]), | ||
1923 | &(pp_table->VceDpmVoltageIndex[i])); | ||
1924 | if (result) | ||
1925 | return result; | ||
1926 | i++; | ||
1927 | } | ||
1928 | |||
1929 | return result; | ||
1930 | } | ||
1931 | |||
1932 | static int vega10_populate_single_vclock_level(struct pp_hwmgr *hwmgr, | ||
1933 | uint32_t vclock, uint8_t *current_vclk_did) | ||
1934 | { | ||
1935 | struct pp_atomfwctrl_clock_dividers_soc15 dividers; | ||
1936 | |||
1937 | PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr, | ||
1938 | COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, | ||
1939 | vclock, ÷rs), | ||
1940 | "Failed to get VCLK clock settings from VBIOS!", | ||
1941 | return -EINVAL); | ||
1942 | |||
1943 | *current_vclk_did = (uint8_t)dividers.ulDid; | ||
1944 | |||
1945 | return 0; | ||
1946 | } | ||
1947 | |||
1948 | static int vega10_populate_single_dclock_level(struct pp_hwmgr *hwmgr, | ||
1949 | uint32_t dclock, uint8_t *current_dclk_did) | ||
1950 | { | ||
1951 | struct pp_atomfwctrl_clock_dividers_soc15 dividers; | ||
1952 | |||
1953 | PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr, | ||
1954 | COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, | ||
1955 | dclock, ÷rs), | ||
1956 | "Failed to get DCLK clock settings from VBIOS!", | ||
1957 | return -EINVAL); | ||
1958 | |||
1959 | *current_dclk_did = (uint8_t)dividers.ulDid; | ||
1960 | |||
1961 | return 0; | ||
1962 | } | ||
1963 | |||
1964 | static int vega10_populate_smc_uvd_levels(struct pp_hwmgr *hwmgr) | ||
1965 | { | ||
1966 | struct vega10_hwmgr *data = | ||
1967 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
1968 | PPTable_t *pp_table = &(data->smc_state_table.pp_table); | ||
1969 | struct vega10_single_dpm_table *vclk_dpm_table = | ||
1970 | &(data->dpm_table.vclk_table); | ||
1971 | struct vega10_single_dpm_table *dclk_dpm_table = | ||
1972 | &(data->dpm_table.dclk_table); | ||
1973 | struct phm_ppt_v2_information *table_info = | ||
1974 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
1975 | struct phm_ppt_v1_mm_clock_voltage_dependency_table *dep_table = | ||
1976 | table_info->mm_dep_table; | ||
1977 | int result = -EINVAL; | ||
1978 | uint32_t i, j; | ||
1979 | |||
1980 | for (i = 0; i < vclk_dpm_table->count; i++) { | ||
1981 | result = vega10_populate_single_vclock_level(hwmgr, | ||
1982 | vclk_dpm_table->dpm_levels[i].value, | ||
1983 | &(pp_table->VclkDid[i])); | ||
1984 | if (result) | ||
1985 | return result; | ||
1986 | } | ||
1987 | |||
1988 | j = i - 1; | ||
1989 | while (i < NUM_UVD_DPM_LEVELS) { | ||
1990 | result = vega10_populate_single_vclock_level(hwmgr, | ||
1991 | vclk_dpm_table->dpm_levels[j].value, | ||
1992 | &(pp_table->VclkDid[i])); | ||
1993 | if (result) | ||
1994 | return result; | ||
1995 | i++; | ||
1996 | } | ||
1997 | |||
1998 | for (i = 0; i < dclk_dpm_table->count; i++) { | ||
1999 | result = vega10_populate_single_dclock_level(hwmgr, | ||
2000 | dclk_dpm_table->dpm_levels[i].value, | ||
2001 | &(pp_table->DclkDid[i])); | ||
2002 | if (result) | ||
2003 | return result; | ||
2004 | } | ||
2005 | |||
2006 | j = i - 1; | ||
2007 | while (i < NUM_UVD_DPM_LEVELS) { | ||
2008 | result = vega10_populate_single_dclock_level(hwmgr, | ||
2009 | dclk_dpm_table->dpm_levels[j].value, | ||
2010 | &(pp_table->DclkDid[i])); | ||
2011 | if (result) | ||
2012 | return result; | ||
2013 | i++; | ||
2014 | } | ||
2015 | |||
2016 | for (i = 0; i < dep_table->count; i++) { | ||
2017 | if (dep_table->entries[i].vclk == | ||
2018 | vclk_dpm_table->dpm_levels[i].value && | ||
2019 | dep_table->entries[i].dclk == | ||
2020 | dclk_dpm_table->dpm_levels[i].value) | ||
2021 | pp_table->UvdDpmVoltageIndex[i] = | ||
2022 | dep_table->entries[i].vddcInd; | ||
2023 | else | ||
2024 | return -1; | ||
2025 | } | ||
2026 | |||
2027 | j = i - 1; | ||
2028 | while (i < NUM_UVD_DPM_LEVELS) { | ||
2029 | pp_table->UvdDpmVoltageIndex[i] = dep_table->entries[j].vddcInd; | ||
2030 | i++; | ||
2031 | } | ||
2032 | |||
2033 | return 0; | ||
2034 | } | ||
2035 | |||
2036 | static int vega10_populate_clock_stretcher_table(struct pp_hwmgr *hwmgr) | ||
2037 | { | ||
2038 | struct vega10_hwmgr *data = | ||
2039 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
2040 | PPTable_t *pp_table = &(data->smc_state_table.pp_table); | ||
2041 | struct phm_ppt_v2_information *table_info = | ||
2042 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
2043 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_table = | ||
2044 | table_info->vdd_dep_on_sclk; | ||
2045 | uint32_t i; | ||
2046 | |||
2047 | for (i = 0; dep_table->count; i++) { | ||
2048 | pp_table->CksEnable[i] = dep_table->entries[i].cks_enable; | ||
2049 | pp_table->CksVidOffset[i] = convert_to_vid( | ||
2050 | dep_table->entries[i].cks_voffset); | ||
2051 | } | ||
2052 | |||
2053 | return 0; | ||
2054 | } | ||
2055 | |||
2056 | static int vega10_populate_avfs_parameters(struct pp_hwmgr *hwmgr) | ||
2057 | { | ||
2058 | struct vega10_hwmgr *data = | ||
2059 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
2060 | PPTable_t *pp_table = &(data->smc_state_table.pp_table); | ||
2061 | struct phm_ppt_v2_information *table_info = | ||
2062 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
2063 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_table = | ||
2064 | table_info->vdd_dep_on_sclk; | ||
2065 | struct pp_atomfwctrl_avfs_parameters avfs_params = {0}; | ||
2066 | int result = 0; | ||
2067 | uint32_t i; | ||
2068 | |||
2069 | pp_table->MinVoltageVid = (uint8_t)0xff; | ||
2070 | pp_table->MaxVoltageVid = (uint8_t)0; | ||
2071 | |||
2072 | if (data->smu_features[GNLD_AVFS].supported) { | ||
2073 | result = pp_atomfwctrl_get_avfs_information(hwmgr, &avfs_params); | ||
2074 | if (!result) { | ||
2075 | pp_table->MinVoltageVid = (uint8_t) | ||
2076 | convert_to_vid((uint16_t)(avfs_params.ulMaxVddc)); | ||
2077 | pp_table->MaxVoltageVid = (uint8_t) | ||
2078 | convert_to_vid((uint16_t)(avfs_params.ulMinVddc)); | ||
2079 | pp_table->BtcGbVdroopTableCksOn.a0 = | ||
2080 | cpu_to_le32(avfs_params.ulGbVdroopTableCksonA0); | ||
2081 | pp_table->BtcGbVdroopTableCksOn.a1 = | ||
2082 | cpu_to_le32(avfs_params.ulGbVdroopTableCksonA1); | ||
2083 | pp_table->BtcGbVdroopTableCksOn.a2 = | ||
2084 | cpu_to_le32(avfs_params.ulGbVdroopTableCksonA2); | ||
2085 | |||
2086 | pp_table->BtcGbVdroopTableCksOff.a0 = | ||
2087 | cpu_to_le32(avfs_params.ulGbVdroopTableCksoffA0); | ||
2088 | pp_table->BtcGbVdroopTableCksOff.a1 = | ||
2089 | cpu_to_le32(avfs_params.ulGbVdroopTableCksoffA1); | ||
2090 | pp_table->BtcGbVdroopTableCksOff.a2 = | ||
2091 | cpu_to_le32(avfs_params.ulGbVdroopTableCksoffA2); | ||
2092 | |||
2093 | pp_table->AvfsGbCksOn.m1 = | ||
2094 | cpu_to_le32(avfs_params.ulGbFuseTableCksonM1); | ||
2095 | pp_table->AvfsGbCksOn.m2 = | ||
2096 | cpu_to_le16(avfs_params.usGbFuseTableCksonM2); | ||
2097 | pp_table->AvfsGbCksOn.b = | ||
2098 | cpu_to_le32(avfs_params.ulGbFuseTableCksonB); | ||
2099 | pp_table->AvfsGbCksOn.m1_shift = 24; | ||
2100 | pp_table->AvfsGbCksOn.m2_shift = 12; | ||
2101 | |||
2102 | pp_table->AvfsGbCksOff.m1 = | ||
2103 | cpu_to_le32(avfs_params.ulGbFuseTableCksoffM1); | ||
2104 | pp_table->AvfsGbCksOff.m2 = | ||
2105 | cpu_to_le16(avfs_params.usGbFuseTableCksoffM2); | ||
2106 | pp_table->AvfsGbCksOff.b = | ||
2107 | cpu_to_le32(avfs_params.ulGbFuseTableCksoffB); | ||
2108 | pp_table->AvfsGbCksOff.m1_shift = 24; | ||
2109 | pp_table->AvfsGbCksOff.m2_shift = 12; | ||
2110 | |||
2111 | pp_table->AConstant[0] = | ||
2112 | cpu_to_le32(avfs_params.ulMeanNsigmaAcontant0); | ||
2113 | pp_table->AConstant[1] = | ||
2114 | cpu_to_le32(avfs_params.ulMeanNsigmaAcontant1); | ||
2115 | pp_table->AConstant[2] = | ||
2116 | cpu_to_le32(avfs_params.ulMeanNsigmaAcontant2); | ||
2117 | pp_table->DC_tol_sigma = | ||
2118 | cpu_to_le16(avfs_params.usMeanNsigmaDcTolSigma); | ||
2119 | pp_table->Platform_mean = | ||
2120 | cpu_to_le16(avfs_params.usMeanNsigmaPlatformMean); | ||
2121 | pp_table->PSM_Age_CompFactor = | ||
2122 | cpu_to_le16(avfs_params.usPsmAgeComfactor); | ||
2123 | pp_table->Platform_sigma = | ||
2124 | cpu_to_le16(avfs_params.usMeanNsigmaDcTolSigma); | ||
2125 | |||
2126 | for (i = 0; i < dep_table->count; i++) | ||
2127 | pp_table->StaticVoltageOffsetVid[i] = (uint8_t) | ||
2128 | (dep_table->entries[i].sclk_offset * | ||
2129 | VOLTAGE_VID_OFFSET_SCALE2 / | ||
2130 | VOLTAGE_VID_OFFSET_SCALE1); | ||
2131 | |||
2132 | pp_table->OverrideBtcGbCksOn = | ||
2133 | avfs_params.ucEnableGbVdroopTableCkson; | ||
2134 | pp_table->OverrideAvfsGbCksOn = | ||
2135 | avfs_params.ucEnableGbFuseTableCkson; | ||
2136 | |||
2137 | if ((PPREGKEY_VEGA10QUADRATICEQUATION_DFLT != | ||
2138 | data->disp_clk_quad_eqn_a) && | ||
2139 | (PPREGKEY_VEGA10QUADRATICEQUATION_DFLT != | ||
2140 | data->disp_clk_quad_eqn_b)) { | ||
2141 | pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m1 = | ||
2142 | (int32_t)data->disp_clk_quad_eqn_a; | ||
2143 | pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m2 = | ||
2144 | (int16_t)data->disp_clk_quad_eqn_b; | ||
2145 | pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].b = | ||
2146 | (int32_t)data->disp_clk_quad_eqn_c; | ||
2147 | } else { | ||
2148 | pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m1 = | ||
2149 | (int32_t)avfs_params.ulDispclk2GfxclkM1; | ||
2150 | pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m2 = | ||
2151 | (int16_t)avfs_params.usDispclk2GfxclkM2; | ||
2152 | pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].b = | ||
2153 | (int32_t)avfs_params.ulDispclk2GfxclkB; | ||
2154 | } | ||
2155 | |||
2156 | pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m1_shift = 24; | ||
2157 | pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m2_shift = 12; | ||
2158 | |||
2159 | if ((PPREGKEY_VEGA10QUADRATICEQUATION_DFLT != | ||
2160 | data->dcef_clk_quad_eqn_a) && | ||
2161 | (PPREGKEY_VEGA10QUADRATICEQUATION_DFLT != | ||
2162 | data->dcef_clk_quad_eqn_b)) { | ||
2163 | pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m1 = | ||
2164 | (int32_t)data->dcef_clk_quad_eqn_a; | ||
2165 | pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m2 = | ||
2166 | (int16_t)data->dcef_clk_quad_eqn_b; | ||
2167 | pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].b = | ||
2168 | (int32_t)data->dcef_clk_quad_eqn_c; | ||
2169 | } else { | ||
2170 | pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m1 = | ||
2171 | (int32_t)avfs_params.ulDcefclk2GfxclkM1; | ||
2172 | pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m2 = | ||
2173 | (int16_t)avfs_params.usDcefclk2GfxclkM2; | ||
2174 | pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].b = | ||
2175 | (int32_t)avfs_params.ulDcefclk2GfxclkB; | ||
2176 | } | ||
2177 | |||
2178 | pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m1_shift = 24; | ||
2179 | pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m2_shift = 12; | ||
2180 | |||
2181 | if ((PPREGKEY_VEGA10QUADRATICEQUATION_DFLT != | ||
2182 | data->pixel_clk_quad_eqn_a) && | ||
2183 | (PPREGKEY_VEGA10QUADRATICEQUATION_DFLT != | ||
2184 | data->pixel_clk_quad_eqn_b)) { | ||
2185 | pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m1 = | ||
2186 | (int32_t)data->pixel_clk_quad_eqn_a; | ||
2187 | pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m2 = | ||
2188 | (int16_t)data->pixel_clk_quad_eqn_b; | ||
2189 | pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].b = | ||
2190 | (int32_t)data->pixel_clk_quad_eqn_c; | ||
2191 | } else { | ||
2192 | pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m1 = | ||
2193 | (int32_t)avfs_params.ulPixelclk2GfxclkM1; | ||
2194 | pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m2 = | ||
2195 | (int16_t)avfs_params.usPixelclk2GfxclkM2; | ||
2196 | pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].b = | ||
2197 | (int32_t)avfs_params.ulPixelclk2GfxclkB; | ||
2198 | } | ||
2199 | |||
2200 | pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m1_shift = 24; | ||
2201 | pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m2_shift = 12; | ||
2202 | |||
2203 | if ((PPREGKEY_VEGA10QUADRATICEQUATION_DFLT != | ||
2204 | data->phy_clk_quad_eqn_a) && | ||
2205 | (PPREGKEY_VEGA10QUADRATICEQUATION_DFLT != | ||
2206 | data->phy_clk_quad_eqn_b)) { | ||
2207 | pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m1 = | ||
2208 | (int32_t)data->phy_clk_quad_eqn_a; | ||
2209 | pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m2 = | ||
2210 | (int16_t)data->phy_clk_quad_eqn_b; | ||
2211 | pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].b = | ||
2212 | (int32_t)data->phy_clk_quad_eqn_c; | ||
2213 | } else { | ||
2214 | pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m1 = | ||
2215 | (int32_t)avfs_params.ulPhyclk2GfxclkM1; | ||
2216 | pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m2 = | ||
2217 | (int16_t)avfs_params.usPhyclk2GfxclkM2; | ||
2218 | pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].b = | ||
2219 | (int32_t)avfs_params.ulPhyclk2GfxclkB; | ||
2220 | } | ||
2221 | |||
2222 | pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m1_shift = 24; | ||
2223 | pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m2_shift = 12; | ||
2224 | } else { | ||
2225 | data->smu_features[GNLD_AVFS].supported = false; | ||
2226 | } | ||
2227 | } | ||
2228 | |||
2229 | return 0; | ||
2230 | } | ||
2231 | |||
2232 | static int vega10_populate_gpio_parameters(struct pp_hwmgr *hwmgr) | ||
2233 | { | ||
2234 | struct vega10_hwmgr *data = | ||
2235 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
2236 | PPTable_t *pp_table = &(data->smc_state_table.pp_table); | ||
2237 | struct pp_atomfwctrl_gpio_parameters gpio_params = {0}; | ||
2238 | int result; | ||
2239 | |||
2240 | result = pp_atomfwctrl_get_gpio_information(hwmgr, &gpio_params); | ||
2241 | if (!result) { | ||
2242 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2243 | PHM_PlatformCaps_RegulatorHot) && | ||
2244 | (data->registry_data.regulator_hot_gpio_support)) { | ||
2245 | pp_table->VR0HotGpio = gpio_params.ucVR0HotGpio; | ||
2246 | pp_table->VR0HotPolarity = gpio_params.ucVR0HotPolarity; | ||
2247 | pp_table->VR1HotGpio = gpio_params.ucVR1HotGpio; | ||
2248 | pp_table->VR1HotPolarity = gpio_params.ucVR1HotPolarity; | ||
2249 | } else { | ||
2250 | pp_table->VR0HotGpio = 0; | ||
2251 | pp_table->VR0HotPolarity = 0; | ||
2252 | pp_table->VR1HotGpio = 0; | ||
2253 | pp_table->VR1HotPolarity = 0; | ||
2254 | } | ||
2255 | |||
2256 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2257 | PHM_PlatformCaps_AutomaticDCTransition) && | ||
2258 | (data->registry_data.ac_dc_switch_gpio_support)) { | ||
2259 | pp_table->AcDcGpio = gpio_params.ucAcDcGpio; | ||
2260 | pp_table->AcDcPolarity = gpio_params.ucAcDcPolarity; | ||
2261 | } else { | ||
2262 | pp_table->AcDcGpio = 0; | ||
2263 | pp_table->AcDcPolarity = 0; | ||
2264 | } | ||
2265 | } | ||
2266 | |||
2267 | return result; | ||
2268 | } | ||
2269 | |||
2270 | static int vega10_avfs_enable(struct pp_hwmgr *hwmgr, bool enable) | ||
2271 | { | ||
2272 | struct vega10_hwmgr *data = | ||
2273 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
2274 | |||
2275 | if (data->smu_features[GNLD_AVFS].supported) { | ||
2276 | if (enable) { | ||
2277 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
2278 | true, | ||
2279 | data->smu_features[GNLD_AVFS].smu_feature_bitmap), | ||
2280 | "[avfs_control] Attempt to Enable AVFS feature Failed!", | ||
2281 | return -1); | ||
2282 | data->smu_features[GNLD_AVFS].enabled = true; | ||
2283 | } else { | ||
2284 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
2285 | false, | ||
2286 | data->smu_features[GNLD_AVFS].smu_feature_id), | ||
2287 | "[avfs_control] Attempt to Disable AVFS feature Failed!", | ||
2288 | return -1); | ||
2289 | data->smu_features[GNLD_AVFS].enabled = false; | ||
2290 | } | ||
2291 | } | ||
2292 | |||
2293 | return 0; | ||
2294 | } | ||
2295 | |||
2296 | /** | ||
2297 | * Initializes the SMC table and uploads it | ||
2298 | * | ||
2299 | * @param hwmgr the address of the powerplay hardware manager. | ||
2300 | * @param pInput the pointer to input data (PowerState) | ||
2301 | * @return always 0 | ||
2302 | */ | ||
2303 | static int vega10_init_smc_table(struct pp_hwmgr *hwmgr) | ||
2304 | { | ||
2305 | int result; | ||
2306 | struct vega10_hwmgr *data = | ||
2307 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
2308 | struct phm_ppt_v2_information *table_info = | ||
2309 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
2310 | PPTable_t *pp_table = &(data->smc_state_table.pp_table); | ||
2311 | struct pp_atomfwctrl_voltage_table voltage_table; | ||
2312 | |||
2313 | result = vega10_setup_default_dpm_tables(hwmgr); | ||
2314 | PP_ASSERT_WITH_CODE(!result, | ||
2315 | "Failed to setup default DPM tables!", | ||
2316 | return result); | ||
2317 | |||
2318 | pp_atomfwctrl_get_voltage_table_v4(hwmgr, VOLTAGE_TYPE_VDDC, | ||
2319 | VOLTAGE_OBJ_SVID2, &voltage_table); | ||
2320 | pp_table->MaxVidStep = voltage_table.max_vid_step; | ||
2321 | |||
2322 | pp_table->GfxDpmVoltageMode = | ||
2323 | (uint8_t)(table_info->uc_gfx_dpm_voltage_mode); | ||
2324 | pp_table->SocDpmVoltageMode = | ||
2325 | (uint8_t)(table_info->uc_soc_dpm_voltage_mode); | ||
2326 | pp_table->UclkDpmVoltageMode = | ||
2327 | (uint8_t)(table_info->uc_uclk_dpm_voltage_mode); | ||
2328 | pp_table->UvdDpmVoltageMode = | ||
2329 | (uint8_t)(table_info->uc_uvd_dpm_voltage_mode); | ||
2330 | pp_table->VceDpmVoltageMode = | ||
2331 | (uint8_t)(table_info->uc_vce_dpm_voltage_mode); | ||
2332 | pp_table->Mp0DpmVoltageMode = | ||
2333 | (uint8_t)(table_info->uc_mp0_dpm_voltage_mode); | ||
2334 | pp_table->DisplayDpmVoltageMode = | ||
2335 | (uint8_t)(table_info->uc_dcef_dpm_voltage_mode); | ||
2336 | |||
2337 | if (data->registry_data.ulv_support && | ||
2338 | table_info->us_ulv_voltage_offset) { | ||
2339 | result = vega10_populate_ulv_state(hwmgr); | ||
2340 | PP_ASSERT_WITH_CODE(!result, | ||
2341 | "Failed to initialize ULV state!", | ||
2342 | return result); | ||
2343 | } | ||
2344 | |||
2345 | result = vega10_populate_smc_link_levels(hwmgr); | ||
2346 | PP_ASSERT_WITH_CODE(!result, | ||
2347 | "Failed to initialize Link Level!", | ||
2348 | return result); | ||
2349 | |||
2350 | result = vega10_populate_all_graphic_levels(hwmgr); | ||
2351 | PP_ASSERT_WITH_CODE(!result, | ||
2352 | "Failed to initialize Graphics Level!", | ||
2353 | return result); | ||
2354 | |||
2355 | result = vega10_populate_all_memory_levels(hwmgr); | ||
2356 | PP_ASSERT_WITH_CODE(!result, | ||
2357 | "Failed to initialize Memory Level!", | ||
2358 | return result); | ||
2359 | |||
2360 | result = vega10_populate_all_display_clock_levels(hwmgr); | ||
2361 | PP_ASSERT_WITH_CODE(!result, | ||
2362 | "Failed to initialize Display Level!", | ||
2363 | return result); | ||
2364 | |||
2365 | result = vega10_populate_smc_vce_levels(hwmgr); | ||
2366 | PP_ASSERT_WITH_CODE(!result, | ||
2367 | "Failed to initialize VCE Level!", | ||
2368 | return result); | ||
2369 | |||
2370 | result = vega10_populate_smc_uvd_levels(hwmgr); | ||
2371 | PP_ASSERT_WITH_CODE(!result, | ||
2372 | "Failed to initialize UVD Level!", | ||
2373 | return result); | ||
2374 | |||
2375 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2376 | PHM_PlatformCaps_ClockStretcher)) { | ||
2377 | result = vega10_populate_clock_stretcher_table(hwmgr); | ||
2378 | PP_ASSERT_WITH_CODE(!result, | ||
2379 | "Failed to populate Clock Stretcher Table!", | ||
2380 | return result); | ||
2381 | } | ||
2382 | |||
2383 | result = vega10_populate_avfs_parameters(hwmgr); | ||
2384 | PP_ASSERT_WITH_CODE(!result, | ||
2385 | "Failed to initialize AVFS Parameters!", | ||
2386 | return result); | ||
2387 | |||
2388 | result = vega10_populate_gpio_parameters(hwmgr); | ||
2389 | PP_ASSERT_WITH_CODE(!result, | ||
2390 | "Failed to initialize GPIO Parameters!", | ||
2391 | return result); | ||
2392 | |||
2393 | pp_table->GfxclkAverageAlpha = (uint8_t) | ||
2394 | (data->gfxclk_average_alpha); | ||
2395 | pp_table->SocclkAverageAlpha = (uint8_t) | ||
2396 | (data->socclk_average_alpha); | ||
2397 | pp_table->UclkAverageAlpha = (uint8_t) | ||
2398 | (data->uclk_average_alpha); | ||
2399 | pp_table->GfxActivityAverageAlpha = (uint8_t) | ||
2400 | (data->gfx_activity_average_alpha); | ||
2401 | |||
2402 | result = vega10_copy_table_to_smc(hwmgr->smumgr, | ||
2403 | (uint8_t *)pp_table, PPTABLE); | ||
2404 | PP_ASSERT_WITH_CODE(!result, | ||
2405 | "Failed to upload PPtable!", return result); | ||
2406 | |||
2407 | if (data->smu_features[GNLD_AVFS].supported) { | ||
2408 | uint32_t features_enabled; | ||
2409 | result = vega10_get_smc_features(hwmgr->smumgr, &features_enabled); | ||
2410 | PP_ASSERT_WITH_CODE(!result, | ||
2411 | "Failed to Retrieve Enabled Features!", | ||
2412 | return result); | ||
2413 | if (!(features_enabled & (1 << FEATURE_AVFS_BIT))) { | ||
2414 | result = vega10_perform_btc(hwmgr->smumgr); | ||
2415 | PP_ASSERT_WITH_CODE(!result, | ||
2416 | "Failed to Perform BTC!", | ||
2417 | return result); | ||
2418 | result = vega10_avfs_enable(hwmgr, true); | ||
2419 | PP_ASSERT_WITH_CODE(!result, | ||
2420 | "Attempt to enable AVFS feature Failed!", | ||
2421 | return result); | ||
2422 | result = vega10_save_vft_table(hwmgr->smumgr, | ||
2423 | (uint8_t *)&(data->smc_state_table.avfs_table)); | ||
2424 | PP_ASSERT_WITH_CODE(!result, | ||
2425 | "Attempt to save VFT table Failed!", | ||
2426 | return result); | ||
2427 | } else { | ||
2428 | data->smu_features[GNLD_AVFS].enabled = true; | ||
2429 | result = vega10_restore_vft_table(hwmgr->smumgr, | ||
2430 | (uint8_t *)&(data->smc_state_table.avfs_table)); | ||
2431 | PP_ASSERT_WITH_CODE(!result, | ||
2432 | "Attempt to restore VFT table Failed!", | ||
2433 | return result;); | ||
2434 | } | ||
2435 | } | ||
2436 | |||
2437 | return 0; | ||
2438 | } | ||
2439 | |||
2440 | static int vega10_enable_thermal_protection(struct pp_hwmgr *hwmgr) | ||
2441 | { | ||
2442 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
2443 | |||
2444 | if (data->smu_features[GNLD_THERMAL].supported) { | ||
2445 | if (data->smu_features[GNLD_THERMAL].enabled) | ||
2446 | pr_info("THERMAL Feature Already enabled!"); | ||
2447 | |||
2448 | PP_ASSERT_WITH_CODE( | ||
2449 | !vega10_enable_smc_features(hwmgr->smumgr, | ||
2450 | true, | ||
2451 | data->smu_features[GNLD_THERMAL].smu_feature_bitmap), | ||
2452 | "Enable THERMAL Feature Failed!", | ||
2453 | return -1); | ||
2454 | data->smu_features[GNLD_THERMAL].enabled = true; | ||
2455 | } | ||
2456 | |||
2457 | return 0; | ||
2458 | } | ||
2459 | |||
2460 | static int vega10_enable_vrhot_feature(struct pp_hwmgr *hwmgr) | ||
2461 | { | ||
2462 | struct vega10_hwmgr *data = | ||
2463 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
2464 | |||
2465 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2466 | PHM_PlatformCaps_RegulatorHot)) { | ||
2467 | if (data->smu_features[GNLD_VR0HOT].supported) { | ||
2468 | PP_ASSERT_WITH_CODE( | ||
2469 | !vega10_enable_smc_features(hwmgr->smumgr, | ||
2470 | true, | ||
2471 | data->smu_features[GNLD_VR0HOT].smu_feature_bitmap), | ||
2472 | "Attempt to Enable VR0 Hot feature Failed!", | ||
2473 | return -1); | ||
2474 | data->smu_features[GNLD_VR0HOT].enabled = true; | ||
2475 | } else { | ||
2476 | if (data->smu_features[GNLD_VR1HOT].supported) { | ||
2477 | PP_ASSERT_WITH_CODE( | ||
2478 | !vega10_enable_smc_features(hwmgr->smumgr, | ||
2479 | true, | ||
2480 | data->smu_features[GNLD_VR1HOT].smu_feature_bitmap), | ||
2481 | "Attempt to Enable VR0 Hot feature Failed!", | ||
2482 | return -1); | ||
2483 | data->smu_features[GNLD_VR1HOT].enabled = true; | ||
2484 | } | ||
2485 | } | ||
2486 | } | ||
2487 | return 0; | ||
2488 | } | ||
2489 | |||
2490 | static int vega10_enable_ulv(struct pp_hwmgr *hwmgr) | ||
2491 | { | ||
2492 | struct vega10_hwmgr *data = | ||
2493 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
2494 | |||
2495 | if (data->registry_data.ulv_support) { | ||
2496 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
2497 | true, data->smu_features[GNLD_ULV].smu_feature_bitmap), | ||
2498 | "Enable ULV Feature Failed!", | ||
2499 | return -1); | ||
2500 | data->smu_features[GNLD_ULV].enabled = true; | ||
2501 | } | ||
2502 | |||
2503 | return 0; | ||
2504 | } | ||
2505 | |||
2506 | static int vega10_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr) | ||
2507 | { | ||
2508 | struct vega10_hwmgr *data = | ||
2509 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
2510 | |||
2511 | if (data->smu_features[GNLD_DS_GFXCLK].supported) { | ||
2512 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
2513 | true, data->smu_features[GNLD_DS_GFXCLK].smu_feature_bitmap), | ||
2514 | "Attempt to Enable DS_GFXCLK Feature Failed!", | ||
2515 | return -1); | ||
2516 | data->smu_features[GNLD_DS_GFXCLK].enabled = true; | ||
2517 | } | ||
2518 | |||
2519 | if (data->smu_features[GNLD_DS_SOCCLK].supported) { | ||
2520 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
2521 | true, data->smu_features[GNLD_DS_SOCCLK].smu_feature_bitmap), | ||
2522 | "Attempt to Enable DS_GFXCLK Feature Failed!", | ||
2523 | return -1); | ||
2524 | data->smu_features[GNLD_DS_SOCCLK].enabled = true; | ||
2525 | } | ||
2526 | |||
2527 | if (data->smu_features[GNLD_DS_LCLK].supported) { | ||
2528 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
2529 | true, data->smu_features[GNLD_DS_LCLK].smu_feature_bitmap), | ||
2530 | "Attempt to Enable DS_GFXCLK Feature Failed!", | ||
2531 | return -1); | ||
2532 | data->smu_features[GNLD_DS_LCLK].enabled = true; | ||
2533 | } | ||
2534 | |||
2535 | return 0; | ||
2536 | } | ||
2537 | |||
2538 | /** | ||
2539 | * @brief Tell SMC to enabled the supported DPMs. | ||
2540 | * | ||
2541 | * @param hwmgr - the address of the powerplay hardware manager. | ||
2542 | * @Param bitmap - bitmap for the features to enabled. | ||
2543 | * @return 0 on at least one DPM is successfully enabled. | ||
2544 | */ | ||
2545 | static int vega10_start_dpm(struct pp_hwmgr *hwmgr, uint32_t bitmap) | ||
2546 | { | ||
2547 | struct vega10_hwmgr *data = | ||
2548 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
2549 | uint32_t i, feature_mask = 0; | ||
2550 | |||
2551 | for (i = 0; i < GNLD_DPM_MAX; i++) { | ||
2552 | if (data->smu_features[i].smu_feature_bitmap & bitmap) { | ||
2553 | if (data->smu_features[i].supported) { | ||
2554 | if (!data->smu_features[i].enabled) { | ||
2555 | feature_mask |= data->smu_features[i]. | ||
2556 | smu_feature_bitmap; | ||
2557 | data->smu_features[i].enabled = true; | ||
2558 | } | ||
2559 | } | ||
2560 | } | ||
2561 | } | ||
2562 | |||
2563 | if (vega10_enable_smc_features(hwmgr->smumgr, | ||
2564 | true, feature_mask)) { | ||
2565 | for (i = 0; i < GNLD_DPM_MAX; i++) { | ||
2566 | if (data->smu_features[i].smu_feature_bitmap & | ||
2567 | feature_mask) | ||
2568 | data->smu_features[i].enabled = false; | ||
2569 | } | ||
2570 | } | ||
2571 | |||
2572 | if(data->smu_features[GNLD_LED_DISPLAY].supported == true){ | ||
2573 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
2574 | true, data->smu_features[GNLD_LED_DISPLAY].smu_feature_bitmap), | ||
2575 | "Attempt to Enable LED DPM feature Failed!", return -EINVAL); | ||
2576 | data->smu_features[GNLD_LED_DISPLAY].enabled = true; | ||
2577 | } | ||
2578 | |||
2579 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2580 | PHM_PlatformCaps_Falcon_QuickTransition)) { | ||
2581 | if (data->smu_features[GNLD_ACDC].supported) { | ||
2582 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
2583 | true, data->smu_features[GNLD_ACDC].smu_feature_bitmap), | ||
2584 | "Attempt to Enable DS_GFXCLK Feature Failed!", | ||
2585 | return -1); | ||
2586 | data->smu_features[GNLD_ACDC].enabled = true; | ||
2587 | } | ||
2588 | } | ||
2589 | |||
2590 | return 0; | ||
2591 | } | ||
2592 | |||
2593 | static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) | ||
2594 | { | ||
2595 | struct vega10_hwmgr *data = | ||
2596 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
2597 | int tmp_result, result = 0; | ||
2598 | |||
2599 | tmp_result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
2600 | PPSMC_MSG_ConfigureTelemetry, data->config_telemetry); | ||
2601 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
2602 | "Failed to configure telemetry!", | ||
2603 | return tmp_result); | ||
2604 | |||
2605 | vega10_set_tools_address(hwmgr->smumgr); | ||
2606 | |||
2607 | smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
2608 | PPSMC_MSG_NumOfDisplays, 0); | ||
2609 | |||
2610 | tmp_result = (!vega10_is_dpm_running(hwmgr)) ? 0 : -1; | ||
2611 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
2612 | "DPM is already running right , skipping re-enablement!", | ||
2613 | return 0); | ||
2614 | |||
2615 | tmp_result = vega10_construct_voltage_tables(hwmgr); | ||
2616 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
2617 | "Failed to contruct voltage tables!", | ||
2618 | result = tmp_result); | ||
2619 | |||
2620 | tmp_result = vega10_init_smc_table(hwmgr); | ||
2621 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
2622 | "Failed to initialize SMC table!", | ||
2623 | result = tmp_result); | ||
2624 | |||
2625 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2626 | PHM_PlatformCaps_ThermalController)) { | ||
2627 | tmp_result = vega10_enable_thermal_protection(hwmgr); | ||
2628 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
2629 | "Failed to enable thermal protection!", | ||
2630 | result = tmp_result); | ||
2631 | } | ||
2632 | |||
2633 | tmp_result = vega10_enable_vrhot_feature(hwmgr); | ||
2634 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
2635 | "Failed to enable VR hot feature!", | ||
2636 | result = tmp_result); | ||
2637 | |||
2638 | tmp_result = vega10_enable_ulv(hwmgr); | ||
2639 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
2640 | "Failed to enable ULV!", | ||
2641 | result = tmp_result); | ||
2642 | |||
2643 | tmp_result = vega10_enable_deep_sleep_master_switch(hwmgr); | ||
2644 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
2645 | "Failed to enable deep sleep master switch!", | ||
2646 | result = tmp_result); | ||
2647 | |||
2648 | tmp_result = vega10_start_dpm(hwmgr, SMC_DPM_FEATURES); | ||
2649 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
2650 | "Failed to start DPM!", result = tmp_result); | ||
2651 | |||
2652 | tmp_result = vega10_enable_power_containment(hwmgr); | ||
2653 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
2654 | "Failed to enable power containment!", | ||
2655 | result = tmp_result); | ||
2656 | |||
2657 | tmp_result = vega10_power_control_set_level(hwmgr); | ||
2658 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
2659 | "Failed to power control set level!", | ||
2660 | result = tmp_result); | ||
2661 | |||
2662 | return result; | ||
2663 | } | ||
2664 | |||
2665 | static int vega10_get_power_state_size(struct pp_hwmgr *hwmgr) | ||
2666 | { | ||
2667 | return sizeof(struct vega10_power_state); | ||
2668 | } | ||
2669 | |||
2670 | static int vega10_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr, | ||
2671 | void *state, struct pp_power_state *power_state, | ||
2672 | void *pp_table, uint32_t classification_flag) | ||
2673 | { | ||
2674 | struct vega10_power_state *vega10_power_state = | ||
2675 | cast_phw_vega10_power_state(&(power_state->hardware)); | ||
2676 | struct vega10_performance_level *performance_level; | ||
2677 | ATOM_Vega10_State *state_entry = (ATOM_Vega10_State *)state; | ||
2678 | ATOM_Vega10_POWERPLAYTABLE *powerplay_table = | ||
2679 | (ATOM_Vega10_POWERPLAYTABLE *)pp_table; | ||
2680 | ATOM_Vega10_SOCCLK_Dependency_Table *socclk_dep_table = | ||
2681 | (ATOM_Vega10_SOCCLK_Dependency_Table *) | ||
2682 | (((unsigned long)powerplay_table) + | ||
2683 | le16_to_cpu(powerplay_table->usSocclkDependencyTableOffset)); | ||
2684 | ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table = | ||
2685 | (ATOM_Vega10_GFXCLK_Dependency_Table *) | ||
2686 | (((unsigned long)powerplay_table) + | ||
2687 | le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset)); | ||
2688 | ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table = | ||
2689 | (ATOM_Vega10_MCLK_Dependency_Table *) | ||
2690 | (((unsigned long)powerplay_table) + | ||
2691 | le16_to_cpu(powerplay_table->usMclkDependencyTableOffset)); | ||
2692 | |||
2693 | |||
2694 | /* The following fields are not initialized here: | ||
2695 | * id orderedList allStatesList | ||
2696 | */ | ||
2697 | power_state->classification.ui_label = | ||
2698 | (le16_to_cpu(state_entry->usClassification) & | ||
2699 | ATOM_PPLIB_CLASSIFICATION_UI_MASK) >> | ||
2700 | ATOM_PPLIB_CLASSIFICATION_UI_SHIFT; | ||
2701 | power_state->classification.flags = classification_flag; | ||
2702 | /* NOTE: There is a classification2 flag in BIOS | ||
2703 | * that is not being used right now | ||
2704 | */ | ||
2705 | power_state->classification.temporary_state = false; | ||
2706 | power_state->classification.to_be_deleted = false; | ||
2707 | |||
2708 | power_state->validation.disallowOnDC = | ||
2709 | ((le32_to_cpu(state_entry->ulCapsAndSettings) & | ||
2710 | ATOM_Vega10_DISALLOW_ON_DC) != 0); | ||
2711 | |||
2712 | power_state->display.disableFrameModulation = false; | ||
2713 | power_state->display.limitRefreshrate = false; | ||
2714 | power_state->display.enableVariBright = | ||
2715 | ((le32_to_cpu(state_entry->ulCapsAndSettings) & | ||
2716 | ATOM_Vega10_ENABLE_VARIBRIGHT) != 0); | ||
2717 | |||
2718 | power_state->validation.supportedPowerLevels = 0; | ||
2719 | power_state->uvd_clocks.VCLK = 0; | ||
2720 | power_state->uvd_clocks.DCLK = 0; | ||
2721 | power_state->temperatures.min = 0; | ||
2722 | power_state->temperatures.max = 0; | ||
2723 | |||
2724 | performance_level = &(vega10_power_state->performance_levels | ||
2725 | [vega10_power_state->performance_level_count++]); | ||
2726 | |||
2727 | PP_ASSERT_WITH_CODE( | ||
2728 | (vega10_power_state->performance_level_count < | ||
2729 | NUM_GFXCLK_DPM_LEVELS), | ||
2730 | "Performance levels exceeds SMC limit!", | ||
2731 | return -1); | ||
2732 | |||
2733 | PP_ASSERT_WITH_CODE( | ||
2734 | (vega10_power_state->performance_level_count <= | ||
2735 | hwmgr->platform_descriptor. | ||
2736 | hardwareActivityPerformanceLevels), | ||
2737 | "Performance levels exceeds Driver limit!", | ||
2738 | return -1); | ||
2739 | |||
2740 | /* Performance levels are arranged from low to high. */ | ||
2741 | performance_level->soc_clock = socclk_dep_table->entries | ||
2742 | [state_entry->ucSocClockIndexLow].ulClk; | ||
2743 | performance_level->gfx_clock = gfxclk_dep_table->entries | ||
2744 | [state_entry->ucGfxClockIndexLow].ulClk; | ||
2745 | performance_level->mem_clock = mclk_dep_table->entries | ||
2746 | [state_entry->ucMemClockIndexLow].ulMemClk; | ||
2747 | |||
2748 | performance_level = &(vega10_power_state->performance_levels | ||
2749 | [vega10_power_state->performance_level_count++]); | ||
2750 | |||
2751 | performance_level->soc_clock = socclk_dep_table->entries | ||
2752 | [state_entry->ucSocClockIndexHigh].ulClk; | ||
2753 | performance_level->gfx_clock = gfxclk_dep_table->entries | ||
2754 | [state_entry->ucGfxClockIndexHigh].ulClk; | ||
2755 | performance_level->mem_clock = mclk_dep_table->entries | ||
2756 | [state_entry->ucMemClockIndexHigh].ulMemClk; | ||
2757 | return 0; | ||
2758 | } | ||
2759 | |||
2760 | static int vega10_get_pp_table_entry(struct pp_hwmgr *hwmgr, | ||
2761 | unsigned long entry_index, struct pp_power_state *state) | ||
2762 | { | ||
2763 | int result; | ||
2764 | struct vega10_power_state *ps; | ||
2765 | |||
2766 | state->hardware.magic = PhwVega10_Magic; | ||
2767 | |||
2768 | ps = cast_phw_vega10_power_state(&state->hardware); | ||
2769 | |||
2770 | result = vega10_get_powerplay_table_entry(hwmgr, entry_index, state, | ||
2771 | vega10_get_pp_table_entry_callback_func); | ||
2772 | |||
2773 | /* | ||
2774 | * This is the earliest time we have all the dependency table | ||
2775 | * and the VBIOS boot state | ||
2776 | */ | ||
2777 | /* set DC compatible flag if this state supports DC */ | ||
2778 | if (!state->validation.disallowOnDC) | ||
2779 | ps->dc_compatible = true; | ||
2780 | |||
2781 | ps->uvd_clks.vclk = state->uvd_clocks.VCLK; | ||
2782 | ps->uvd_clks.dclk = state->uvd_clocks.DCLK; | ||
2783 | |||
2784 | return 0; | ||
2785 | } | ||
2786 | |||
2787 | static int vega10_patch_boot_state(struct pp_hwmgr *hwmgr, | ||
2788 | struct pp_hw_power_state *hw_ps) | ||
2789 | { | ||
2790 | return 0; | ||
2791 | } | ||
2792 | |||
2793 | static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, | ||
2794 | struct pp_power_state *request_ps, | ||
2795 | const struct pp_power_state *current_ps) | ||
2796 | { | ||
2797 | struct vega10_power_state *vega10_ps = | ||
2798 | cast_phw_vega10_power_state(&request_ps->hardware); | ||
2799 | uint32_t sclk; | ||
2800 | uint32_t mclk; | ||
2801 | struct PP_Clocks minimum_clocks = {0}; | ||
2802 | bool disable_mclk_switching; | ||
2803 | bool disable_mclk_switching_for_frame_lock; | ||
2804 | bool disable_mclk_switching_for_vr; | ||
2805 | bool force_mclk_high; | ||
2806 | struct cgs_display_info info = {0}; | ||
2807 | const struct phm_clock_and_voltage_limits *max_limits; | ||
2808 | uint32_t i; | ||
2809 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
2810 | struct phm_ppt_v2_information *table_info = | ||
2811 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
2812 | int32_t count; | ||
2813 | uint32_t stable_pstate_sclk_dpm_percentage; | ||
2814 | uint32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0; | ||
2815 | uint32_t latency; | ||
2816 | |||
2817 | data->battery_state = (PP_StateUILabel_Battery == | ||
2818 | request_ps->classification.ui_label); | ||
2819 | |||
2820 | if (vega10_ps->performance_level_count != 2) | ||
2821 | pr_info("VI should always have 2 performance levels"); | ||
2822 | |||
2823 | max_limits = (PP_PowerSource_AC == hwmgr->power_source) ? | ||
2824 | &(hwmgr->dyn_state.max_clock_voltage_on_ac) : | ||
2825 | &(hwmgr->dyn_state.max_clock_voltage_on_dc); | ||
2826 | |||
2827 | /* Cap clock DPM tables at DC MAX if it is in DC. */ | ||
2828 | if (PP_PowerSource_DC == hwmgr->power_source) { | ||
2829 | for (i = 0; i < vega10_ps->performance_level_count; i++) { | ||
2830 | if (vega10_ps->performance_levels[i].mem_clock > | ||
2831 | max_limits->mclk) | ||
2832 | vega10_ps->performance_levels[i].mem_clock = | ||
2833 | max_limits->mclk; | ||
2834 | if (vega10_ps->performance_levels[i].gfx_clock > | ||
2835 | max_limits->sclk) | ||
2836 | vega10_ps->performance_levels[i].gfx_clock = | ||
2837 | max_limits->sclk; | ||
2838 | } | ||
2839 | } | ||
2840 | |||
2841 | vega10_ps->vce_clks.evclk = hwmgr->vce_arbiter.evclk; | ||
2842 | vega10_ps->vce_clks.ecclk = hwmgr->vce_arbiter.ecclk; | ||
2843 | |||
2844 | cgs_get_active_displays_info(hwmgr->device, &info); | ||
2845 | |||
2846 | /* result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/ | ||
2847 | minimum_clocks.engineClock = hwmgr->display_config.min_core_set_clock; | ||
2848 | /* minimum_clocks.memoryClock = hwmgr->display_config.min_mem_set_clock; */ | ||
2849 | |||
2850 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2851 | PHM_PlatformCaps_StablePState)) { | ||
2852 | PP_ASSERT_WITH_CODE( | ||
2853 | data->registry_data.stable_pstate_sclk_dpm_percentage >= 1 && | ||
2854 | data->registry_data.stable_pstate_sclk_dpm_percentage <= 100, | ||
2855 | "percent sclk value must range from 1% to 100%, setting default value", | ||
2856 | stable_pstate_sclk_dpm_percentage = 75); | ||
2857 | |||
2858 | max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac); | ||
2859 | stable_pstate_sclk = (max_limits->sclk * | ||
2860 | stable_pstate_sclk_dpm_percentage) / 100; | ||
2861 | |||
2862 | for (count = table_info->vdd_dep_on_sclk->count - 1; | ||
2863 | count >= 0; count--) { | ||
2864 | if (stable_pstate_sclk >= | ||
2865 | table_info->vdd_dep_on_sclk->entries[count].clk) { | ||
2866 | stable_pstate_sclk = | ||
2867 | table_info->vdd_dep_on_sclk->entries[count].clk; | ||
2868 | break; | ||
2869 | } | ||
2870 | } | ||
2871 | |||
2872 | if (count < 0) | ||
2873 | stable_pstate_sclk = table_info->vdd_dep_on_sclk->entries[0].clk; | ||
2874 | |||
2875 | stable_pstate_mclk = max_limits->mclk; | ||
2876 | |||
2877 | minimum_clocks.engineClock = stable_pstate_sclk; | ||
2878 | minimum_clocks.memoryClock = stable_pstate_mclk; | ||
2879 | } | ||
2880 | |||
2881 | if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk) | ||
2882 | minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk; | ||
2883 | |||
2884 | if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk) | ||
2885 | minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk; | ||
2886 | |||
2887 | vega10_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold; | ||
2888 | |||
2889 | if (hwmgr->gfx_arbiter.sclk_over_drive) { | ||
2890 | PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <= | ||
2891 | hwmgr->platform_descriptor.overdriveLimit.engineClock), | ||
2892 | "Overdrive sclk exceeds limit", | ||
2893 | hwmgr->gfx_arbiter.sclk_over_drive = | ||
2894 | hwmgr->platform_descriptor.overdriveLimit.engineClock); | ||
2895 | |||
2896 | if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk) | ||
2897 | vega10_ps->performance_levels[1].gfx_clock = | ||
2898 | hwmgr->gfx_arbiter.sclk_over_drive; | ||
2899 | } | ||
2900 | |||
2901 | if (hwmgr->gfx_arbiter.mclk_over_drive) { | ||
2902 | PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <= | ||
2903 | hwmgr->platform_descriptor.overdriveLimit.memoryClock), | ||
2904 | "Overdrive mclk exceeds limit", | ||
2905 | hwmgr->gfx_arbiter.mclk_over_drive = | ||
2906 | hwmgr->platform_descriptor.overdriveLimit.memoryClock); | ||
2907 | |||
2908 | if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk) | ||
2909 | vega10_ps->performance_levels[1].mem_clock = | ||
2910 | hwmgr->gfx_arbiter.mclk_over_drive; | ||
2911 | } | ||
2912 | |||
2913 | disable_mclk_switching_for_frame_lock = phm_cap_enabled( | ||
2914 | hwmgr->platform_descriptor.platformCaps, | ||
2915 | PHM_PlatformCaps_DisableMclkSwitchingForFrameLock); | ||
2916 | disable_mclk_switching_for_vr = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2917 | PHM_PlatformCaps_DisableMclkSwitchForVR); | ||
2918 | force_mclk_high = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2919 | PHM_PlatformCaps_ForceMclkHigh); | ||
2920 | |||
2921 | disable_mclk_switching = (info.display_count > 1) || | ||
2922 | disable_mclk_switching_for_frame_lock || | ||
2923 | disable_mclk_switching_for_vr || | ||
2924 | force_mclk_high; | ||
2925 | |||
2926 | sclk = vega10_ps->performance_levels[0].gfx_clock; | ||
2927 | mclk = vega10_ps->performance_levels[0].mem_clock; | ||
2928 | |||
2929 | if (sclk < minimum_clocks.engineClock) | ||
2930 | sclk = (minimum_clocks.engineClock > max_limits->sclk) ? | ||
2931 | max_limits->sclk : minimum_clocks.engineClock; | ||
2932 | |||
2933 | if (mclk < minimum_clocks.memoryClock) | ||
2934 | mclk = (minimum_clocks.memoryClock > max_limits->mclk) ? | ||
2935 | max_limits->mclk : minimum_clocks.memoryClock; | ||
2936 | |||
2937 | vega10_ps->performance_levels[0].gfx_clock = sclk; | ||
2938 | vega10_ps->performance_levels[0].mem_clock = mclk; | ||
2939 | |||
2940 | vega10_ps->performance_levels[1].gfx_clock = | ||
2941 | (vega10_ps->performance_levels[1].gfx_clock >= | ||
2942 | vega10_ps->performance_levels[0].gfx_clock) ? | ||
2943 | vega10_ps->performance_levels[1].gfx_clock : | ||
2944 | vega10_ps->performance_levels[0].gfx_clock; | ||
2945 | |||
2946 | if (disable_mclk_switching) { | ||
2947 | /* Set Mclk the max of level 0 and level 1 */ | ||
2948 | if (mclk < vega10_ps->performance_levels[1].mem_clock) | ||
2949 | mclk = vega10_ps->performance_levels[1].mem_clock; | ||
2950 | |||
2951 | /* Find the lowest MCLK frequency that is within | ||
2952 | * the tolerable latency defined in DAL | ||
2953 | */ | ||
2954 | latency = 0; | ||
2955 | for (i = 0; i < data->mclk_latency_table.count; i++) { | ||
2956 | if ((data->mclk_latency_table.entries[i].latency <= latency) && | ||
2957 | (data->mclk_latency_table.entries[i].frequency >= | ||
2958 | vega10_ps->performance_levels[0].mem_clock) && | ||
2959 | (data->mclk_latency_table.entries[i].frequency <= | ||
2960 | vega10_ps->performance_levels[1].mem_clock)) | ||
2961 | mclk = data->mclk_latency_table.entries[i].frequency; | ||
2962 | } | ||
2963 | vega10_ps->performance_levels[0].mem_clock = mclk; | ||
2964 | } else { | ||
2965 | if (vega10_ps->performance_levels[1].mem_clock < | ||
2966 | vega10_ps->performance_levels[0].mem_clock) | ||
2967 | vega10_ps->performance_levels[1].mem_clock = | ||
2968 | vega10_ps->performance_levels[0].mem_clock; | ||
2969 | } | ||
2970 | |||
2971 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2972 | PHM_PlatformCaps_StablePState)) { | ||
2973 | for (i = 0; i < vega10_ps->performance_level_count; i++) { | ||
2974 | vega10_ps->performance_levels[i].gfx_clock = stable_pstate_sclk; | ||
2975 | vega10_ps->performance_levels[i].mem_clock = stable_pstate_mclk; | ||
2976 | } | ||
2977 | } | ||
2978 | |||
2979 | return 0; | ||
2980 | } | ||
2981 | |||
2982 | static int vega10_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input) | ||
2983 | { | ||
2984 | const struct phm_set_power_state_input *states = | ||
2985 | (const struct phm_set_power_state_input *)input; | ||
2986 | const struct vega10_power_state *vega10_ps = | ||
2987 | cast_const_phw_vega10_power_state(states->pnew_state); | ||
2988 | struct vega10_hwmgr *data = | ||
2989 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
2990 | struct vega10_single_dpm_table *sclk_table = | ||
2991 | &(data->dpm_table.gfx_table); | ||
2992 | uint32_t sclk = vega10_ps->performance_levels | ||
2993 | [vega10_ps->performance_level_count - 1].gfx_clock; | ||
2994 | struct vega10_single_dpm_table *mclk_table = | ||
2995 | &(data->dpm_table.mem_table); | ||
2996 | uint32_t mclk = vega10_ps->performance_levels | ||
2997 | [vega10_ps->performance_level_count - 1].mem_clock; | ||
2998 | struct PP_Clocks min_clocks = {0}; | ||
2999 | uint32_t i; | ||
3000 | struct cgs_display_info info = {0}; | ||
3001 | |||
3002 | data->need_update_dpm_table = 0; | ||
3003 | |||
3004 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3005 | PHM_PlatformCaps_ODNinACSupport) || | ||
3006 | phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3007 | PHM_PlatformCaps_ODNinDCSupport)) { | ||
3008 | for (i = 0; i < sclk_table->count; i++) { | ||
3009 | if (sclk == sclk_table->dpm_levels[i].value) | ||
3010 | break; | ||
3011 | } | ||
3012 | |||
3013 | if (!(data->apply_overdrive_next_settings_mask & | ||
3014 | DPMTABLE_OD_UPDATE_SCLK) && i >= sclk_table->count) { | ||
3015 | /* Check SCLK in DAL's minimum clocks | ||
3016 | * in case DeepSleep divider update is required. | ||
3017 | */ | ||
3018 | if (data->display_timing.min_clock_in_sr != | ||
3019 | min_clocks.engineClockInSR && | ||
3020 | (min_clocks.engineClockInSR >= | ||
3021 | VEGA10_MINIMUM_ENGINE_CLOCK || | ||
3022 | data->display_timing.min_clock_in_sr >= | ||
3023 | VEGA10_MINIMUM_ENGINE_CLOCK)) | ||
3024 | data->need_update_dpm_table |= DPMTABLE_UPDATE_SCLK; | ||
3025 | } | ||
3026 | |||
3027 | cgs_get_active_displays_info(hwmgr->device, &info); | ||
3028 | |||
3029 | if (data->display_timing.num_existing_displays != | ||
3030 | info.display_count) | ||
3031 | data->need_update_dpm_table |= DPMTABLE_UPDATE_MCLK; | ||
3032 | } else { | ||
3033 | for (i = 0; i < sclk_table->count; i++) { | ||
3034 | if (sclk == sclk_table->dpm_levels[i].value) | ||
3035 | break; | ||
3036 | } | ||
3037 | |||
3038 | if (i >= sclk_table->count) | ||
3039 | data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK; | ||
3040 | else { | ||
3041 | /* Check SCLK in DAL's minimum clocks | ||
3042 | * in case DeepSleep divider update is required. | ||
3043 | */ | ||
3044 | if (data->display_timing.min_clock_in_sr != | ||
3045 | min_clocks.engineClockInSR && | ||
3046 | (min_clocks.engineClockInSR >= | ||
3047 | VEGA10_MINIMUM_ENGINE_CLOCK || | ||
3048 | data->display_timing.min_clock_in_sr >= | ||
3049 | VEGA10_MINIMUM_ENGINE_CLOCK)) | ||
3050 | data->need_update_dpm_table |= DPMTABLE_UPDATE_SCLK; | ||
3051 | } | ||
3052 | |||
3053 | for (i = 0; i < mclk_table->count; i++) { | ||
3054 | if (mclk == mclk_table->dpm_levels[i].value) | ||
3055 | break; | ||
3056 | } | ||
3057 | |||
3058 | cgs_get_active_displays_info(hwmgr->device, &info); | ||
3059 | |||
3060 | if (i >= mclk_table->count) | ||
3061 | data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_MCLK; | ||
3062 | |||
3063 | if (data->display_timing.num_existing_displays != | ||
3064 | info.display_count || | ||
3065 | i >= mclk_table->count) | ||
3066 | data->need_update_dpm_table |= DPMTABLE_UPDATE_MCLK; | ||
3067 | } | ||
3068 | return 0; | ||
3069 | } | ||
3070 | |||
3071 | static int vega10_populate_and_upload_sclk_mclk_dpm_levels( | ||
3072 | struct pp_hwmgr *hwmgr, const void *input) | ||
3073 | { | ||
3074 | int result = 0; | ||
3075 | const struct phm_set_power_state_input *states = | ||
3076 | (const struct phm_set_power_state_input *)input; | ||
3077 | const struct vega10_power_state *vega10_ps = | ||
3078 | cast_const_phw_vega10_power_state(states->pnew_state); | ||
3079 | struct vega10_hwmgr *data = | ||
3080 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
3081 | uint32_t sclk = vega10_ps->performance_levels | ||
3082 | [vega10_ps->performance_level_count - 1].gfx_clock; | ||
3083 | uint32_t mclk = vega10_ps->performance_levels | ||
3084 | [vega10_ps->performance_level_count - 1].mem_clock; | ||
3085 | struct vega10_dpm_table *dpm_table = &data->dpm_table; | ||
3086 | struct vega10_dpm_table *golden_dpm_table = | ||
3087 | &data->golden_dpm_table; | ||
3088 | uint32_t dpm_count, clock_percent; | ||
3089 | uint32_t i; | ||
3090 | |||
3091 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3092 | PHM_PlatformCaps_ODNinACSupport) || | ||
3093 | phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3094 | PHM_PlatformCaps_ODNinDCSupport)) { | ||
3095 | |||
3096 | if (!data->need_update_dpm_table && | ||
3097 | !data->apply_optimized_settings && | ||
3098 | !data->apply_overdrive_next_settings_mask) | ||
3099 | return 0; | ||
3100 | |||
3101 | if (data->apply_overdrive_next_settings_mask & | ||
3102 | DPMTABLE_OD_UPDATE_SCLK) { | ||
3103 | for (dpm_count = 0; | ||
3104 | dpm_count < dpm_table->gfx_table.count; | ||
3105 | dpm_count++) { | ||
3106 | dpm_table->gfx_table.dpm_levels[dpm_count].enabled = | ||
3107 | data->odn_dpm_table.odn_core_clock_dpm_levels. | ||
3108 | performance_level_entries[dpm_count].enabled; | ||
3109 | dpm_table->gfx_table.dpm_levels[dpm_count].value = | ||
3110 | data->odn_dpm_table.odn_core_clock_dpm_levels. | ||
3111 | performance_level_entries[dpm_count].clock; | ||
3112 | } | ||
3113 | } | ||
3114 | |||
3115 | if (data->apply_overdrive_next_settings_mask & | ||
3116 | DPMTABLE_OD_UPDATE_MCLK) { | ||
3117 | for (dpm_count = 0; | ||
3118 | dpm_count < dpm_table->mem_table.count; | ||
3119 | dpm_count++) { | ||
3120 | dpm_table->mem_table.dpm_levels[dpm_count].enabled = | ||
3121 | data->odn_dpm_table.odn_memory_clock_dpm_levels. | ||
3122 | performance_level_entries[dpm_count].enabled; | ||
3123 | dpm_table->mem_table.dpm_levels[dpm_count].value = | ||
3124 | data->odn_dpm_table.odn_memory_clock_dpm_levels. | ||
3125 | performance_level_entries[dpm_count].clock; | ||
3126 | } | ||
3127 | } | ||
3128 | |||
3129 | if ((data->need_update_dpm_table & DPMTABLE_UPDATE_SCLK) || | ||
3130 | data->apply_optimized_settings || | ||
3131 | (data->apply_overdrive_next_settings_mask & | ||
3132 | DPMTABLE_OD_UPDATE_SCLK)) { | ||
3133 | result = vega10_populate_all_graphic_levels(hwmgr); | ||
3134 | PP_ASSERT_WITH_CODE(!result, | ||
3135 | "Failed to populate SCLK during \ | ||
3136 | PopulateNewDPMClocksStates Function!", | ||
3137 | return result); | ||
3138 | } | ||
3139 | |||
3140 | if ((data->need_update_dpm_table & DPMTABLE_UPDATE_MCLK) || | ||
3141 | (data->apply_overdrive_next_settings_mask & | ||
3142 | DPMTABLE_OD_UPDATE_MCLK)){ | ||
3143 | result = vega10_populate_all_memory_levels(hwmgr); | ||
3144 | PP_ASSERT_WITH_CODE(!result, | ||
3145 | "Failed to populate MCLK during \ | ||
3146 | PopulateNewDPMClocksStates Function!", | ||
3147 | return result); | ||
3148 | } | ||
3149 | } else { | ||
3150 | if (!data->need_update_dpm_table && | ||
3151 | !data->apply_optimized_settings) | ||
3152 | return 0; | ||
3153 | |||
3154 | if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_SCLK && | ||
3155 | data->smu_features[GNLD_DPM_GFXCLK].supported) { | ||
3156 | dpm_table-> | ||
3157 | gfx_table.dpm_levels[dpm_table->gfx_table.count - 1]. | ||
3158 | value = sclk; | ||
3159 | |||
3160 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3161 | PHM_PlatformCaps_OD6PlusinACSupport) || | ||
3162 | phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3163 | PHM_PlatformCaps_OD6PlusinDCSupport)) { | ||
3164 | /* Need to do calculation based on the golden DPM table | ||
3165 | * as the Heatmap GPU Clock axis is also based on | ||
3166 | * the default values | ||
3167 | */ | ||
3168 | PP_ASSERT_WITH_CODE( | ||
3169 | golden_dpm_table->gfx_table.dpm_levels | ||
3170 | [golden_dpm_table->gfx_table.count - 1].value, | ||
3171 | "Divide by 0!", | ||
3172 | return -1); | ||
3173 | |||
3174 | dpm_count = dpm_table->gfx_table.count < 2 ? | ||
3175 | 0 : dpm_table->gfx_table.count - 2; | ||
3176 | for (i = dpm_count; i > 1; i--) { | ||
3177 | if (sclk > golden_dpm_table->gfx_table.dpm_levels | ||
3178 | [golden_dpm_table->gfx_table.count - 1].value) { | ||
3179 | clock_percent = | ||
3180 | ((sclk - golden_dpm_table->gfx_table.dpm_levels | ||
3181 | [golden_dpm_table->gfx_table.count - 1].value) * | ||
3182 | 100) / | ||
3183 | golden_dpm_table->gfx_table.dpm_levels | ||
3184 | [golden_dpm_table->gfx_table.count - 1].value; | ||
3185 | |||
3186 | dpm_table->gfx_table.dpm_levels[i].value = | ||
3187 | golden_dpm_table->gfx_table.dpm_levels[i].value + | ||
3188 | (golden_dpm_table->gfx_table.dpm_levels[i].value * | ||
3189 | clock_percent) / 100; | ||
3190 | } else if (golden_dpm_table-> | ||
3191 | gfx_table.dpm_levels[dpm_table->gfx_table.count-1].value > | ||
3192 | sclk) { | ||
3193 | clock_percent = | ||
3194 | ((golden_dpm_table->gfx_table.dpm_levels | ||
3195 | [golden_dpm_table->gfx_table.count - 1].value - | ||
3196 | sclk) * 100) / | ||
3197 | golden_dpm_table->gfx_table.dpm_levels | ||
3198 | [golden_dpm_table->gfx_table.count-1].value; | ||
3199 | |||
3200 | dpm_table->gfx_table.dpm_levels[i].value = | ||
3201 | golden_dpm_table->gfx_table.dpm_levels[i].value - | ||
3202 | (golden_dpm_table->gfx_table.dpm_levels[i].value * | ||
3203 | clock_percent) / 100; | ||
3204 | } else | ||
3205 | dpm_table->gfx_table.dpm_levels[i].value = | ||
3206 | golden_dpm_table->gfx_table.dpm_levels[i].value; | ||
3207 | } | ||
3208 | } | ||
3209 | } | ||
3210 | |||
3211 | if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_MCLK && | ||
3212 | data->smu_features[GNLD_DPM_UCLK].supported) { | ||
3213 | dpm_table-> | ||
3214 | mem_table.dpm_levels[dpm_table->mem_table.count - 1]. | ||
3215 | value = mclk; | ||
3216 | |||
3217 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3218 | PHM_PlatformCaps_OD6PlusinACSupport) || | ||
3219 | phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3220 | PHM_PlatformCaps_OD6PlusinDCSupport)) { | ||
3221 | |||
3222 | PP_ASSERT_WITH_CODE( | ||
3223 | golden_dpm_table->mem_table.dpm_levels | ||
3224 | [golden_dpm_table->mem_table.count - 1].value, | ||
3225 | "Divide by 0!", | ||
3226 | return -1); | ||
3227 | |||
3228 | dpm_count = dpm_table->mem_table.count < 2 ? | ||
3229 | 0 : dpm_table->mem_table.count - 2; | ||
3230 | for (i = dpm_count; i > 1; i--) { | ||
3231 | if (mclk > golden_dpm_table->mem_table.dpm_levels | ||
3232 | [golden_dpm_table->mem_table.count-1].value) { | ||
3233 | clock_percent = ((mclk - | ||
3234 | golden_dpm_table->mem_table.dpm_levels | ||
3235 | [golden_dpm_table->mem_table.count-1].value) * | ||
3236 | 100) / | ||
3237 | golden_dpm_table->mem_table.dpm_levels | ||
3238 | [golden_dpm_table->mem_table.count-1].value; | ||
3239 | |||
3240 | dpm_table->mem_table.dpm_levels[i].value = | ||
3241 | golden_dpm_table->mem_table.dpm_levels[i].value + | ||
3242 | (golden_dpm_table->mem_table.dpm_levels[i].value * | ||
3243 | clock_percent) / 100; | ||
3244 | } else if (golden_dpm_table->mem_table.dpm_levels | ||
3245 | [dpm_table->mem_table.count-1].value > mclk) { | ||
3246 | clock_percent = ((golden_dpm_table->mem_table.dpm_levels | ||
3247 | [golden_dpm_table->mem_table.count-1].value - mclk) * | ||
3248 | 100) / | ||
3249 | golden_dpm_table->mem_table.dpm_levels | ||
3250 | [golden_dpm_table->mem_table.count-1].value; | ||
3251 | |||
3252 | dpm_table->mem_table.dpm_levels[i].value = | ||
3253 | golden_dpm_table->mem_table.dpm_levels[i].value - | ||
3254 | (golden_dpm_table->mem_table.dpm_levels[i].value * | ||
3255 | clock_percent) / 100; | ||
3256 | } else | ||
3257 | dpm_table->mem_table.dpm_levels[i].value = | ||
3258 | golden_dpm_table->mem_table.dpm_levels[i].value; | ||
3259 | } | ||
3260 | } | ||
3261 | } | ||
3262 | |||
3263 | if ((data->need_update_dpm_table & | ||
3264 | (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) || | ||
3265 | data->apply_optimized_settings) { | ||
3266 | result = vega10_populate_all_graphic_levels(hwmgr); | ||
3267 | PP_ASSERT_WITH_CODE(!result, | ||
3268 | "Failed to populate SCLK during \ | ||
3269 | PopulateNewDPMClocksStates Function!", | ||
3270 | return result); | ||
3271 | } | ||
3272 | |||
3273 | if (data->need_update_dpm_table & | ||
3274 | (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) { | ||
3275 | result = vega10_populate_all_memory_levels(hwmgr); | ||
3276 | PP_ASSERT_WITH_CODE(!result, | ||
3277 | "Failed to populate MCLK during \ | ||
3278 | PopulateNewDPMClocksStates Function!", | ||
3279 | return result); | ||
3280 | } | ||
3281 | } | ||
3282 | |||
3283 | return result; | ||
3284 | } | ||
3285 | |||
3286 | static int vega10_trim_single_dpm_states(struct pp_hwmgr *hwmgr, | ||
3287 | struct vega10_single_dpm_table *dpm_table, | ||
3288 | uint32_t low_limit, uint32_t high_limit) | ||
3289 | { | ||
3290 | uint32_t i; | ||
3291 | |||
3292 | for (i = 0; i < dpm_table->count; i++) { | ||
3293 | if ((dpm_table->dpm_levels[i].value < low_limit) || | ||
3294 | (dpm_table->dpm_levels[i].value > high_limit)) | ||
3295 | dpm_table->dpm_levels[i].enabled = false; | ||
3296 | else | ||
3297 | dpm_table->dpm_levels[i].enabled = true; | ||
3298 | } | ||
3299 | return 0; | ||
3300 | } | ||
3301 | |||
3302 | static int vega10_trim_single_dpm_states_with_mask(struct pp_hwmgr *hwmgr, | ||
3303 | struct vega10_single_dpm_table *dpm_table, | ||
3304 | uint32_t low_limit, uint32_t high_limit, | ||
3305 | uint32_t disable_dpm_mask) | ||
3306 | { | ||
3307 | uint32_t i; | ||
3308 | |||
3309 | for (i = 0; i < dpm_table->count; i++) { | ||
3310 | if ((dpm_table->dpm_levels[i].value < low_limit) || | ||
3311 | (dpm_table->dpm_levels[i].value > high_limit)) | ||
3312 | dpm_table->dpm_levels[i].enabled = false; | ||
3313 | else if (!((1 << i) & disable_dpm_mask)) | ||
3314 | dpm_table->dpm_levels[i].enabled = false; | ||
3315 | else | ||
3316 | dpm_table->dpm_levels[i].enabled = true; | ||
3317 | } | ||
3318 | return 0; | ||
3319 | } | ||
3320 | |||
3321 | static int vega10_trim_dpm_states(struct pp_hwmgr *hwmgr, | ||
3322 | const struct vega10_power_state *vega10_ps) | ||
3323 | { | ||
3324 | struct vega10_hwmgr *data = | ||
3325 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
3326 | uint32_t high_limit_count; | ||
3327 | |||
3328 | PP_ASSERT_WITH_CODE((vega10_ps->performance_level_count >= 1), | ||
3329 | "power state did not have any performance level", | ||
3330 | return -1); | ||
3331 | |||
3332 | high_limit_count = (vega10_ps->performance_level_count == 1) ? 0 : 1; | ||
3333 | |||
3334 | vega10_trim_single_dpm_states(hwmgr, | ||
3335 | &(data->dpm_table.soc_table), | ||
3336 | vega10_ps->performance_levels[0].soc_clock, | ||
3337 | vega10_ps->performance_levels[high_limit_count].soc_clock); | ||
3338 | |||
3339 | vega10_trim_single_dpm_states_with_mask(hwmgr, | ||
3340 | &(data->dpm_table.gfx_table), | ||
3341 | vega10_ps->performance_levels[0].gfx_clock, | ||
3342 | vega10_ps->performance_levels[high_limit_count].gfx_clock, | ||
3343 | data->disable_dpm_mask); | ||
3344 | |||
3345 | vega10_trim_single_dpm_states(hwmgr, | ||
3346 | &(data->dpm_table.mem_table), | ||
3347 | vega10_ps->performance_levels[0].mem_clock, | ||
3348 | vega10_ps->performance_levels[high_limit_count].mem_clock); | ||
3349 | |||
3350 | return 0; | ||
3351 | } | ||
3352 | |||
3353 | static uint32_t vega10_find_lowest_dpm_level( | ||
3354 | struct vega10_single_dpm_table *table) | ||
3355 | { | ||
3356 | uint32_t i; | ||
3357 | |||
3358 | for (i = 0; i < table->count; i++) { | ||
3359 | if (table->dpm_levels[i].enabled) | ||
3360 | break; | ||
3361 | } | ||
3362 | |||
3363 | return i; | ||
3364 | } | ||
3365 | |||
3366 | static uint32_t vega10_find_highest_dpm_level( | ||
3367 | struct vega10_single_dpm_table *table) | ||
3368 | { | ||
3369 | uint32_t i = 0; | ||
3370 | |||
3371 | if (table->count <= MAX_REGULAR_DPM_NUMBER) { | ||
3372 | for (i = table->count; i > 0; i--) { | ||
3373 | if (table->dpm_levels[i - 1].enabled) | ||
3374 | return i - 1; | ||
3375 | } | ||
3376 | } else { | ||
3377 | pr_info("DPM Table Has Too Many Entries!"); | ||
3378 | return MAX_REGULAR_DPM_NUMBER - 1; | ||
3379 | } | ||
3380 | |||
3381 | return i; | ||
3382 | } | ||
3383 | |||
3384 | static void vega10_apply_dal_minimum_voltage_request( | ||
3385 | struct pp_hwmgr *hwmgr) | ||
3386 | { | ||
3387 | return; | ||
3388 | } | ||
3389 | |||
3390 | static int vega10_upload_dpm_bootup_level(struct pp_hwmgr *hwmgr) | ||
3391 | { | ||
3392 | struct vega10_hwmgr *data = | ||
3393 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
3394 | |||
3395 | vega10_apply_dal_minimum_voltage_request(hwmgr); | ||
3396 | |||
3397 | if (!data->registry_data.sclk_dpm_key_disabled) { | ||
3398 | if (data->smc_state_table.gfx_boot_level != | ||
3399 | data->dpm_table.gfx_table.dpm_state.soft_min_level) { | ||
3400 | PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( | ||
3401 | hwmgr->smumgr, | ||
3402 | PPSMC_MSG_SetSoftMinGfxclkByIndex, | ||
3403 | data->smc_state_table.gfx_boot_level), | ||
3404 | "Failed to set soft min sclk index!", | ||
3405 | return -EINVAL); | ||
3406 | data->dpm_table.gfx_table.dpm_state.soft_min_level = | ||
3407 | data->smc_state_table.gfx_boot_level; | ||
3408 | } | ||
3409 | } | ||
3410 | |||
3411 | if (!data->registry_data.mclk_dpm_key_disabled) { | ||
3412 | if (data->smc_state_table.mem_boot_level != | ||
3413 | data->dpm_table.mem_table.dpm_state.soft_min_level) { | ||
3414 | PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( | ||
3415 | hwmgr->smumgr, | ||
3416 | PPSMC_MSG_SetSoftMinUclkByIndex, | ||
3417 | data->smc_state_table.mem_boot_level), | ||
3418 | "Failed to set soft min mclk index!", | ||
3419 | return -EINVAL); | ||
3420 | |||
3421 | data->dpm_table.mem_table.dpm_state.soft_min_level = | ||
3422 | data->smc_state_table.mem_boot_level; | ||
3423 | } | ||
3424 | } | ||
3425 | |||
3426 | return 0; | ||
3427 | } | ||
3428 | |||
3429 | static int vega10_upload_dpm_max_level(struct pp_hwmgr *hwmgr) | ||
3430 | { | ||
3431 | struct vega10_hwmgr *data = | ||
3432 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
3433 | |||
3434 | vega10_apply_dal_minimum_voltage_request(hwmgr); | ||
3435 | |||
3436 | if (!data->registry_data.sclk_dpm_key_disabled) { | ||
3437 | if (data->smc_state_table.gfx_max_level != | ||
3438 | data->dpm_table.gfx_table.dpm_state.soft_max_level) { | ||
3439 | PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( | ||
3440 | hwmgr->smumgr, | ||
3441 | PPSMC_MSG_SetSoftMaxGfxclkByIndex, | ||
3442 | data->smc_state_table.gfx_max_level), | ||
3443 | "Failed to set soft max sclk index!", | ||
3444 | return -EINVAL); | ||
3445 | data->dpm_table.gfx_table.dpm_state.soft_max_level = | ||
3446 | data->smc_state_table.gfx_max_level; | ||
3447 | } | ||
3448 | } | ||
3449 | |||
3450 | if (!data->registry_data.mclk_dpm_key_disabled) { | ||
3451 | if (data->smc_state_table.mem_max_level != | ||
3452 | data->dpm_table.mem_table.dpm_state.soft_max_level) { | ||
3453 | PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( | ||
3454 | hwmgr->smumgr, | ||
3455 | PPSMC_MSG_SetSoftMaxUclkByIndex, | ||
3456 | data->smc_state_table.mem_max_level), | ||
3457 | "Failed to set soft max mclk index!", | ||
3458 | return -EINVAL); | ||
3459 | data->dpm_table.mem_table.dpm_state.soft_max_level = | ||
3460 | data->smc_state_table.mem_max_level; | ||
3461 | } | ||
3462 | } | ||
3463 | |||
3464 | return 0; | ||
3465 | } | ||
3466 | |||
3467 | static int vega10_generate_dpm_level_enable_mask( | ||
3468 | struct pp_hwmgr *hwmgr, const void *input) | ||
3469 | { | ||
3470 | struct vega10_hwmgr *data = | ||
3471 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
3472 | const struct phm_set_power_state_input *states = | ||
3473 | (const struct phm_set_power_state_input *)input; | ||
3474 | const struct vega10_power_state *vega10_ps = | ||
3475 | cast_const_phw_vega10_power_state(states->pnew_state); | ||
3476 | int i; | ||
3477 | |||
3478 | PP_ASSERT_WITH_CODE(!vega10_trim_dpm_states(hwmgr, vega10_ps), | ||
3479 | "Attempt to Trim DPM States Failed!", | ||
3480 | return -1); | ||
3481 | |||
3482 | data->smc_state_table.gfx_boot_level = | ||
3483 | vega10_find_lowest_dpm_level(&(data->dpm_table.gfx_table)); | ||
3484 | data->smc_state_table.gfx_max_level = | ||
3485 | vega10_find_highest_dpm_level(&(data->dpm_table.gfx_table)); | ||
3486 | data->smc_state_table.mem_boot_level = | ||
3487 | vega10_find_lowest_dpm_level(&(data->dpm_table.mem_table)); | ||
3488 | data->smc_state_table.mem_max_level = | ||
3489 | vega10_find_highest_dpm_level(&(data->dpm_table.mem_table)); | ||
3490 | |||
3491 | PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr), | ||
3492 | "Attempt to upload DPM Bootup Levels Failed!", | ||
3493 | return -1); | ||
3494 | PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr), | ||
3495 | "Attempt to upload DPM Max Levels Failed!", | ||
3496 | return -1); | ||
3497 | for(i = data->smc_state_table.gfx_boot_level; i < data->smc_state_table.gfx_max_level; i++) | ||
3498 | data->dpm_table.gfx_table.dpm_levels[i].enabled = true; | ||
3499 | |||
3500 | |||
3501 | for(i = data->smc_state_table.mem_boot_level; i < data->smc_state_table.mem_max_level; i++) | ||
3502 | data->dpm_table.mem_table.dpm_levels[i].enabled = true; | ||
3503 | |||
3504 | return 0; | ||
3505 | } | ||
3506 | |||
3507 | int vega10_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable) | ||
3508 | { | ||
3509 | struct vega10_hwmgr *data = | ||
3510 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
3511 | |||
3512 | if (data->smu_features[GNLD_DPM_VCE].supported) { | ||
3513 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
3514 | enable, | ||
3515 | data->smu_features[GNLD_DPM_VCE].smu_feature_bitmap), | ||
3516 | "Attempt to Enable/Disable DPM VCE Failed!", | ||
3517 | return -1); | ||
3518 | data->smu_features[GNLD_DPM_VCE].enabled = enable; | ||
3519 | } | ||
3520 | |||
3521 | return 0; | ||
3522 | } | ||
3523 | |||
3524 | static int vega10_update_sclk_threshold(struct pp_hwmgr *hwmgr) | ||
3525 | { | ||
3526 | struct vega10_hwmgr *data = | ||
3527 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
3528 | int result = 0; | ||
3529 | uint32_t low_sclk_interrupt_threshold = 0; | ||
3530 | |||
3531 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3532 | PHM_PlatformCaps_SclkThrottleLowNotification) | ||
3533 | && (hwmgr->gfx_arbiter.sclk_threshold != | ||
3534 | data->low_sclk_interrupt_threshold)) { | ||
3535 | data->low_sclk_interrupt_threshold = | ||
3536 | hwmgr->gfx_arbiter.sclk_threshold; | ||
3537 | low_sclk_interrupt_threshold = | ||
3538 | data->low_sclk_interrupt_threshold; | ||
3539 | |||
3540 | data->smc_state_table.pp_table.LowGfxclkInterruptThreshold = | ||
3541 | cpu_to_le32(low_sclk_interrupt_threshold); | ||
3542 | |||
3543 | /* This message will also enable SmcToHost Interrupt */ | ||
3544 | result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
3545 | PPSMC_MSG_SetLowGfxclkInterruptThreshold, | ||
3546 | (uint32_t)low_sclk_interrupt_threshold); | ||
3547 | } | ||
3548 | |||
3549 | return result; | ||
3550 | } | ||
3551 | |||
3552 | static int vega10_set_power_state_tasks(struct pp_hwmgr *hwmgr, | ||
3553 | const void *input) | ||
3554 | { | ||
3555 | int tmp_result, result = 0; | ||
3556 | struct vega10_hwmgr *data = | ||
3557 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
3558 | PPTable_t *pp_table = &(data->smc_state_table.pp_table); | ||
3559 | |||
3560 | tmp_result = vega10_find_dpm_states_clocks_in_dpm_table(hwmgr, input); | ||
3561 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
3562 | "Failed to find DPM states clocks in DPM table!", | ||
3563 | result = tmp_result); | ||
3564 | |||
3565 | tmp_result = vega10_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input); | ||
3566 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
3567 | "Failed to populate and upload SCLK MCLK DPM levels!", | ||
3568 | result = tmp_result); | ||
3569 | |||
3570 | tmp_result = vega10_generate_dpm_level_enable_mask(hwmgr, input); | ||
3571 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
3572 | "Failed to generate DPM level enabled mask!", | ||
3573 | result = tmp_result); | ||
3574 | |||
3575 | tmp_result = vega10_update_sclk_threshold(hwmgr); | ||
3576 | PP_ASSERT_WITH_CODE(!tmp_result, | ||
3577 | "Failed to update SCLK threshold!", | ||
3578 | result = tmp_result); | ||
3579 | |||
3580 | result = vega10_copy_table_to_smc(hwmgr->smumgr, | ||
3581 | (uint8_t *)pp_table, PPTABLE); | ||
3582 | PP_ASSERT_WITH_CODE(!result, | ||
3583 | "Failed to upload PPtable!", return result); | ||
3584 | |||
3585 | data->apply_optimized_settings = false; | ||
3586 | data->apply_overdrive_next_settings_mask = 0; | ||
3587 | |||
3588 | return 0; | ||
3589 | } | ||
3590 | |||
3591 | static int vega10_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low) | ||
3592 | { | ||
3593 | struct pp_power_state *ps; | ||
3594 | struct vega10_power_state *vega10_ps; | ||
3595 | |||
3596 | if (hwmgr == NULL) | ||
3597 | return -EINVAL; | ||
3598 | |||
3599 | ps = hwmgr->request_ps; | ||
3600 | |||
3601 | if (ps == NULL) | ||
3602 | return -EINVAL; | ||
3603 | |||
3604 | vega10_ps = cast_phw_vega10_power_state(&ps->hardware); | ||
3605 | |||
3606 | if (low) | ||
3607 | return vega10_ps->performance_levels[0].gfx_clock; | ||
3608 | else | ||
3609 | return vega10_ps->performance_levels | ||
3610 | [vega10_ps->performance_level_count - 1].gfx_clock; | ||
3611 | } | ||
3612 | |||
3613 | static int vega10_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low) | ||
3614 | { | ||
3615 | struct pp_power_state *ps; | ||
3616 | struct vega10_power_state *vega10_ps; | ||
3617 | |||
3618 | if (hwmgr == NULL) | ||
3619 | return -EINVAL; | ||
3620 | |||
3621 | ps = hwmgr->request_ps; | ||
3622 | |||
3623 | if (ps == NULL) | ||
3624 | return -EINVAL; | ||
3625 | |||
3626 | vega10_ps = cast_phw_vega10_power_state(&ps->hardware); | ||
3627 | |||
3628 | if (low) | ||
3629 | return vega10_ps->performance_levels[0].mem_clock; | ||
3630 | else | ||
3631 | return vega10_ps->performance_levels | ||
3632 | [vega10_ps->performance_level_count-1].mem_clock; | ||
3633 | } | ||
3634 | |||
3635 | static int vega10_read_sensor(struct pp_hwmgr *hwmgr, int idx, | ||
3636 | void *value, int *size) | ||
3637 | { | ||
3638 | uint32_t sclk_idx, mclk_idx, activity_percent = 0; | ||
3639 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
3640 | struct vega10_dpm_table *dpm_table = &data->dpm_table; | ||
3641 | int ret = 0; | ||
3642 | |||
3643 | switch (idx) { | ||
3644 | case AMDGPU_PP_SENSOR_GFX_SCLK: | ||
3645 | ret = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetCurrentGfxclkIndex); | ||
3646 | if (!ret) { | ||
3647 | vega10_read_arg_from_smc(hwmgr->smumgr, &sclk_idx); | ||
3648 | *((uint32_t *)value) = dpm_table->gfx_table.dpm_levels[sclk_idx].value; | ||
3649 | *size = 4; | ||
3650 | } | ||
3651 | break; | ||
3652 | case AMDGPU_PP_SENSOR_GFX_MCLK: | ||
3653 | ret = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetCurrentUclkIndex); | ||
3654 | if (!ret) { | ||
3655 | vega10_read_arg_from_smc(hwmgr->smumgr, &mclk_idx); | ||
3656 | *((uint32_t *)value) = dpm_table->mem_table.dpm_levels[mclk_idx].value; | ||
3657 | *size = 4; | ||
3658 | } | ||
3659 | break; | ||
3660 | case AMDGPU_PP_SENSOR_GPU_LOAD: | ||
3661 | ret = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_GetAverageGfxActivity, 0); | ||
3662 | if (!ret) { | ||
3663 | vega10_read_arg_from_smc(hwmgr->smumgr, &activity_percent); | ||
3664 | *((uint32_t *)value) = activity_percent > 100 ? 100 : activity_percent; | ||
3665 | *size = 4; | ||
3666 | } | ||
3667 | break; | ||
3668 | case AMDGPU_PP_SENSOR_GPU_TEMP: | ||
3669 | *((uint32_t *)value) = vega10_thermal_get_temperature(hwmgr); | ||
3670 | *size = 4; | ||
3671 | break; | ||
3672 | case AMDGPU_PP_SENSOR_UVD_POWER: | ||
3673 | *((uint32_t *)value) = data->uvd_power_gated ? 0 : 1; | ||
3674 | *size = 4; | ||
3675 | break; | ||
3676 | case AMDGPU_PP_SENSOR_VCE_POWER: | ||
3677 | *((uint32_t *)value) = data->vce_power_gated ? 0 : 1; | ||
3678 | *size = 4; | ||
3679 | break; | ||
3680 | default: | ||
3681 | ret = -EINVAL; | ||
3682 | break; | ||
3683 | } | ||
3684 | return ret; | ||
3685 | } | ||
3686 | |||
3687 | static int vega10_notify_smc_display_change(struct pp_hwmgr *hwmgr, | ||
3688 | bool has_disp) | ||
3689 | { | ||
3690 | return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
3691 | PPSMC_MSG_SetUclkFastSwitch, | ||
3692 | has_disp ? 0 : 1); | ||
3693 | } | ||
3694 | |||
3695 | int vega10_display_clock_voltage_request(struct pp_hwmgr *hwmgr, | ||
3696 | struct pp_display_clock_request *clock_req) | ||
3697 | { | ||
3698 | int result = 0; | ||
3699 | enum amd_pp_clock_type clk_type = clock_req->clock_type; | ||
3700 | uint32_t clk_freq = clock_req->clock_freq_in_khz / 100; | ||
3701 | DSPCLK_e clk_select = 0; | ||
3702 | uint32_t clk_request = 0; | ||
3703 | |||
3704 | switch (clk_type) { | ||
3705 | case amd_pp_dcef_clock: | ||
3706 | clk_select = DSPCLK_DCEFCLK; | ||
3707 | break; | ||
3708 | case amd_pp_disp_clock: | ||
3709 | clk_select = DSPCLK_DISPCLK; | ||
3710 | break; | ||
3711 | case amd_pp_pixel_clock: | ||
3712 | clk_select = DSPCLK_PIXCLK; | ||
3713 | break; | ||
3714 | case amd_pp_phy_clock: | ||
3715 | clk_select = DSPCLK_PHYCLK; | ||
3716 | break; | ||
3717 | default: | ||
3718 | pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!"); | ||
3719 | result = -1; | ||
3720 | break; | ||
3721 | } | ||
3722 | |||
3723 | if (!result) { | ||
3724 | clk_request = (clk_freq << 16) | clk_select; | ||
3725 | result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
3726 | PPSMC_MSG_RequestDisplayClockByFreq, | ||
3727 | clk_request); | ||
3728 | } | ||
3729 | |||
3730 | return result; | ||
3731 | } | ||
3732 | |||
3733 | static int vega10_notify_smc_display_config_after_ps_adjustment( | ||
3734 | struct pp_hwmgr *hwmgr) | ||
3735 | { | ||
3736 | struct vega10_hwmgr *data = | ||
3737 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
3738 | struct vega10_single_dpm_table *dpm_table = | ||
3739 | &data->dpm_table.dcef_table; | ||
3740 | uint32_t num_active_disps = 0; | ||
3741 | struct cgs_display_info info = {0}; | ||
3742 | struct PP_Clocks min_clocks = {0}; | ||
3743 | uint32_t i; | ||
3744 | struct pp_display_clock_request clock_req; | ||
3745 | |||
3746 | info.mode_info = NULL; | ||
3747 | |||
3748 | cgs_get_active_displays_info(hwmgr->device, &info); | ||
3749 | |||
3750 | num_active_disps = info.display_count; | ||
3751 | |||
3752 | if (num_active_disps > 1) | ||
3753 | vega10_notify_smc_display_change(hwmgr, false); | ||
3754 | else | ||
3755 | vega10_notify_smc_display_change(hwmgr, true); | ||
3756 | |||
3757 | min_clocks.dcefClock = hwmgr->display_config.min_dcef_set_clk; | ||
3758 | min_clocks.dcefClockInSR = hwmgr->display_config.min_dcef_deep_sleep_set_clk; | ||
3759 | |||
3760 | for (i = 0; i < dpm_table->count; i++) { | ||
3761 | if (dpm_table->dpm_levels[i].value == min_clocks.dcefClock) | ||
3762 | break; | ||
3763 | } | ||
3764 | |||
3765 | if (i < dpm_table->count) { | ||
3766 | clock_req.clock_type = amd_pp_dcef_clock; | ||
3767 | clock_req.clock_freq_in_khz = dpm_table->dpm_levels[i].value; | ||
3768 | if (!vega10_display_clock_voltage_request(hwmgr, &clock_req)) { | ||
3769 | PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( | ||
3770 | hwmgr->smumgr, PPSMC_MSG_SetMinDeepSleepDcefclk, | ||
3771 | min_clocks.dcefClockInSR), | ||
3772 | "Attempt to set divider for DCEFCLK Failed!",); | ||
3773 | } else | ||
3774 | pr_info("Attempt to set Hard Min for DCEFCLK Failed!"); | ||
3775 | } else | ||
3776 | pr_info("Cannot find requested DCEFCLK!"); | ||
3777 | |||
3778 | return 0; | ||
3779 | } | ||
3780 | |||
3781 | static int vega10_force_dpm_highest(struct pp_hwmgr *hwmgr) | ||
3782 | { | ||
3783 | struct vega10_hwmgr *data = | ||
3784 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
3785 | |||
3786 | data->smc_state_table.gfx_boot_level = | ||
3787 | data->smc_state_table.gfx_max_level = | ||
3788 | vega10_find_highest_dpm_level(&(data->dpm_table.gfx_table)); | ||
3789 | data->smc_state_table.mem_boot_level = | ||
3790 | data->smc_state_table.mem_max_level = | ||
3791 | vega10_find_highest_dpm_level(&(data->dpm_table.mem_table)); | ||
3792 | |||
3793 | PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr), | ||
3794 | "Failed to upload boot level to highest!", | ||
3795 | return -1); | ||
3796 | |||
3797 | PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr), | ||
3798 | "Failed to upload dpm max level to highest!", | ||
3799 | return -1); | ||
3800 | |||
3801 | return 0; | ||
3802 | } | ||
3803 | |||
3804 | static int vega10_force_dpm_lowest(struct pp_hwmgr *hwmgr) | ||
3805 | { | ||
3806 | struct vega10_hwmgr *data = | ||
3807 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
3808 | |||
3809 | data->smc_state_table.gfx_boot_level = | ||
3810 | data->smc_state_table.gfx_max_level = | ||
3811 | vega10_find_lowest_dpm_level(&(data->dpm_table.gfx_table)); | ||
3812 | data->smc_state_table.mem_boot_level = | ||
3813 | data->smc_state_table.mem_max_level = | ||
3814 | vega10_find_lowest_dpm_level(&(data->dpm_table.mem_table)); | ||
3815 | |||
3816 | PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr), | ||
3817 | "Failed to upload boot level to highest!", | ||
3818 | return -1); | ||
3819 | |||
3820 | PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr), | ||
3821 | "Failed to upload dpm max level to highest!", | ||
3822 | return -1); | ||
3823 | |||
3824 | return 0; | ||
3825 | |||
3826 | } | ||
3827 | |||
3828 | static int vega10_unforce_dpm_levels(struct pp_hwmgr *hwmgr) | ||
3829 | { | ||
3830 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
3831 | |||
3832 | data->smc_state_table.gfx_boot_level = | ||
3833 | vega10_find_lowest_dpm_level(&(data->dpm_table.gfx_table)); | ||
3834 | data->smc_state_table.gfx_max_level = | ||
3835 | vega10_find_highest_dpm_level(&(data->dpm_table.gfx_table)); | ||
3836 | data->smc_state_table.mem_boot_level = | ||
3837 | vega10_find_lowest_dpm_level(&(data->dpm_table.mem_table)); | ||
3838 | data->smc_state_table.mem_max_level = | ||
3839 | vega10_find_highest_dpm_level(&(data->dpm_table.mem_table)); | ||
3840 | |||
3841 | PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr), | ||
3842 | "Failed to upload DPM Bootup Levels!", | ||
3843 | return -1); | ||
3844 | |||
3845 | PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr), | ||
3846 | "Failed to upload DPM Max Levels!", | ||
3847 | return -1); | ||
3848 | return 0; | ||
3849 | } | ||
3850 | |||
3851 | static int vega10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, | ||
3852 | enum amd_dpm_forced_level level) | ||
3853 | { | ||
3854 | int ret = 0; | ||
3855 | |||
3856 | switch (level) { | ||
3857 | case AMD_DPM_FORCED_LEVEL_HIGH: | ||
3858 | ret = vega10_force_dpm_highest(hwmgr); | ||
3859 | if (ret) | ||
3860 | return ret; | ||
3861 | break; | ||
3862 | case AMD_DPM_FORCED_LEVEL_LOW: | ||
3863 | ret = vega10_force_dpm_lowest(hwmgr); | ||
3864 | if (ret) | ||
3865 | return ret; | ||
3866 | break; | ||
3867 | case AMD_DPM_FORCED_LEVEL_AUTO: | ||
3868 | ret = vega10_unforce_dpm_levels(hwmgr); | ||
3869 | if (ret) | ||
3870 | return ret; | ||
3871 | break; | ||
3872 | default: | ||
3873 | break; | ||
3874 | } | ||
3875 | |||
3876 | hwmgr->dpm_level = level; | ||
3877 | |||
3878 | return ret; | ||
3879 | } | ||
3880 | |||
3881 | static int vega10_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode) | ||
3882 | { | ||
3883 | if (mode) { | ||
3884 | /* stop auto-manage */ | ||
3885 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3886 | PHM_PlatformCaps_MicrocodeFanControl)) | ||
3887 | vega10_fan_ctrl_stop_smc_fan_control(hwmgr); | ||
3888 | vega10_fan_ctrl_set_static_mode(hwmgr, mode); | ||
3889 | } else | ||
3890 | /* restart auto-manage */ | ||
3891 | vega10_fan_ctrl_reset_fan_speed_to_default(hwmgr); | ||
3892 | |||
3893 | return 0; | ||
3894 | } | ||
3895 | |||
3896 | static int vega10_get_fan_control_mode(struct pp_hwmgr *hwmgr) | ||
3897 | { | ||
3898 | uint32_t reg; | ||
3899 | |||
3900 | if (hwmgr->fan_ctrl_is_in_default_mode) { | ||
3901 | return hwmgr->fan_ctrl_default_mode; | ||
3902 | } else { | ||
3903 | reg = soc15_get_register_offset(THM_HWID, 0, | ||
3904 | mmCG_FDO_CTRL2_BASE_IDX, mmCG_FDO_CTRL2); | ||
3905 | return (cgs_read_register(hwmgr->device, reg) & | ||
3906 | CG_FDO_CTRL2__FDO_PWM_MODE_MASK) >> | ||
3907 | CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT; | ||
3908 | } | ||
3909 | } | ||
3910 | |||
3911 | static int vega10_get_dal_power_level(struct pp_hwmgr *hwmgr, | ||
3912 | struct amd_pp_simple_clock_info *info) | ||
3913 | { | ||
3914 | struct phm_ppt_v2_information *table_info = | ||
3915 | (struct phm_ppt_v2_information *)hwmgr->pptable; | ||
3916 | struct phm_clock_and_voltage_limits *max_limits = | ||
3917 | &table_info->max_clock_voltage_on_ac; | ||
3918 | |||
3919 | info->engine_max_clock = max_limits->sclk; | ||
3920 | info->memory_max_clock = max_limits->mclk; | ||
3921 | |||
3922 | return 0; | ||
3923 | } | ||
3924 | |||
3925 | static void vega10_get_sclks(struct pp_hwmgr *hwmgr, | ||
3926 | struct pp_clock_levels_with_latency *clocks) | ||
3927 | { | ||
3928 | struct phm_ppt_v2_information *table_info = | ||
3929 | (struct phm_ppt_v2_information *)hwmgr->pptable; | ||
3930 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_table = | ||
3931 | table_info->vdd_dep_on_sclk; | ||
3932 | uint32_t i; | ||
3933 | |||
3934 | for (i = 0; i < dep_table->count; i++) { | ||
3935 | if (dep_table->entries[i].clk) { | ||
3936 | clocks->data[clocks->num_levels].clocks_in_khz = | ||
3937 | dep_table->entries[i].clk; | ||
3938 | clocks->num_levels++; | ||
3939 | } | ||
3940 | } | ||
3941 | |||
3942 | } | ||
3943 | |||
3944 | static uint32_t vega10_get_mem_latency(struct pp_hwmgr *hwmgr, | ||
3945 | uint32_t clock) | ||
3946 | { | ||
3947 | if (clock >= MEM_FREQ_LOW_LATENCY && | ||
3948 | clock < MEM_FREQ_HIGH_LATENCY) | ||
3949 | return MEM_LATENCY_HIGH; | ||
3950 | else if (clock >= MEM_FREQ_HIGH_LATENCY) | ||
3951 | return MEM_LATENCY_LOW; | ||
3952 | else | ||
3953 | return MEM_LATENCY_ERR; | ||
3954 | } | ||
3955 | |||
3956 | static void vega10_get_memclocks(struct pp_hwmgr *hwmgr, | ||
3957 | struct pp_clock_levels_with_latency *clocks) | ||
3958 | { | ||
3959 | struct phm_ppt_v2_information *table_info = | ||
3960 | (struct phm_ppt_v2_information *)hwmgr->pptable; | ||
3961 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_table = | ||
3962 | table_info->vdd_dep_on_mclk; | ||
3963 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
3964 | uint32_t i; | ||
3965 | |||
3966 | clocks->num_levels = 0; | ||
3967 | data->mclk_latency_table.count = 0; | ||
3968 | |||
3969 | for (i = 0; i < dep_table->count; i++) { | ||
3970 | if (dep_table->entries[i].clk) { | ||
3971 | clocks->data[clocks->num_levels].clocks_in_khz = | ||
3972 | data->mclk_latency_table.entries | ||
3973 | [data->mclk_latency_table.count].frequency = | ||
3974 | dep_table->entries[i].clk; | ||
3975 | clocks->data[clocks->num_levels].latency_in_us = | ||
3976 | data->mclk_latency_table.entries | ||
3977 | [data->mclk_latency_table.count].latency = | ||
3978 | vega10_get_mem_latency(hwmgr, | ||
3979 | dep_table->entries[i].clk); | ||
3980 | clocks->num_levels++; | ||
3981 | data->mclk_latency_table.count++; | ||
3982 | } | ||
3983 | } | ||
3984 | } | ||
3985 | |||
3986 | static void vega10_get_dcefclocks(struct pp_hwmgr *hwmgr, | ||
3987 | struct pp_clock_levels_with_latency *clocks) | ||
3988 | { | ||
3989 | struct phm_ppt_v2_information *table_info = | ||
3990 | (struct phm_ppt_v2_information *)hwmgr->pptable; | ||
3991 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_table = | ||
3992 | table_info->vdd_dep_on_dcefclk; | ||
3993 | uint32_t i; | ||
3994 | |||
3995 | for (i = 0; i < dep_table->count; i++) { | ||
3996 | clocks->data[i].clocks_in_khz = dep_table->entries[i].clk; | ||
3997 | clocks->data[i].latency_in_us = 0; | ||
3998 | clocks->num_levels++; | ||
3999 | } | ||
4000 | } | ||
4001 | |||
4002 | static void vega10_get_socclocks(struct pp_hwmgr *hwmgr, | ||
4003 | struct pp_clock_levels_with_latency *clocks) | ||
4004 | { | ||
4005 | struct phm_ppt_v2_information *table_info = | ||
4006 | (struct phm_ppt_v2_information *)hwmgr->pptable; | ||
4007 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_table = | ||
4008 | table_info->vdd_dep_on_socclk; | ||
4009 | uint32_t i; | ||
4010 | |||
4011 | for (i = 0; i < dep_table->count; i++) { | ||
4012 | clocks->data[i].clocks_in_khz = dep_table->entries[i].clk; | ||
4013 | clocks->data[i].latency_in_us = 0; | ||
4014 | clocks->num_levels++; | ||
4015 | } | ||
4016 | } | ||
4017 | |||
4018 | static int vega10_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr, | ||
4019 | enum amd_pp_clock_type type, | ||
4020 | struct pp_clock_levels_with_latency *clocks) | ||
4021 | { | ||
4022 | switch (type) { | ||
4023 | case amd_pp_sys_clock: | ||
4024 | vega10_get_sclks(hwmgr, clocks); | ||
4025 | break; | ||
4026 | case amd_pp_mem_clock: | ||
4027 | vega10_get_memclocks(hwmgr, clocks); | ||
4028 | break; | ||
4029 | case amd_pp_dcef_clock: | ||
4030 | vega10_get_dcefclocks(hwmgr, clocks); | ||
4031 | break; | ||
4032 | case amd_pp_soc_clock: | ||
4033 | vega10_get_socclocks(hwmgr, clocks); | ||
4034 | break; | ||
4035 | default: | ||
4036 | return -1; | ||
4037 | } | ||
4038 | |||
4039 | return 0; | ||
4040 | } | ||
4041 | |||
4042 | static int vega10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, | ||
4043 | enum amd_pp_clock_type type, | ||
4044 | struct pp_clock_levels_with_voltage *clocks) | ||
4045 | { | ||
4046 | struct phm_ppt_v2_information *table_info = | ||
4047 | (struct phm_ppt_v2_information *)hwmgr->pptable; | ||
4048 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_table; | ||
4049 | uint32_t i; | ||
4050 | |||
4051 | switch (type) { | ||
4052 | case amd_pp_mem_clock: | ||
4053 | dep_table = table_info->vdd_dep_on_mclk; | ||
4054 | break; | ||
4055 | case amd_pp_dcef_clock: | ||
4056 | dep_table = table_info->vdd_dep_on_dcefclk; | ||
4057 | break; | ||
4058 | case amd_pp_disp_clock: | ||
4059 | dep_table = table_info->vdd_dep_on_dispclk; | ||
4060 | break; | ||
4061 | case amd_pp_pixel_clock: | ||
4062 | dep_table = table_info->vdd_dep_on_pixclk; | ||
4063 | break; | ||
4064 | case amd_pp_phy_clock: | ||
4065 | dep_table = table_info->vdd_dep_on_phyclk; | ||
4066 | break; | ||
4067 | default: | ||
4068 | return -1; | ||
4069 | } | ||
4070 | |||
4071 | for (i = 0; i < dep_table->count; i++) { | ||
4072 | clocks->data[i].clocks_in_khz = dep_table->entries[i].clk; | ||
4073 | clocks->data[i].voltage_in_mv = (uint32_t)(table_info->vddc_lookup_table-> | ||
4074 | entries[dep_table->entries[i].vddInd].us_vdd); | ||
4075 | clocks->num_levels++; | ||
4076 | } | ||
4077 | |||
4078 | if (i < dep_table->count) | ||
4079 | return -1; | ||
4080 | |||
4081 | return 0; | ||
4082 | } | ||
4083 | |||
4084 | static int vega10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, | ||
4085 | struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) | ||
4086 | { | ||
4087 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
4088 | Watermarks_t *table = &(data->smc_state_table.water_marks_table); | ||
4089 | int result = 0; | ||
4090 | uint32_t i; | ||
4091 | |||
4092 | if (!data->registry_data.disable_water_mark) { | ||
4093 | for (i = 0; i < wm_with_clock_ranges->num_wm_sets_dmif; i++) { | ||
4094 | table->WatermarkRow[WM_DCEFCLK][i].MinClock = | ||
4095 | cpu_to_le16((uint16_t) | ||
4096 | (wm_with_clock_ranges->wm_sets_dmif[i].wm_min_dcefclk_in_khz) / | ||
4097 | 100); | ||
4098 | table->WatermarkRow[WM_DCEFCLK][i].MaxClock = | ||
4099 | cpu_to_le16((uint16_t) | ||
4100 | (wm_with_clock_ranges->wm_sets_dmif[i].wm_max_dcefclk_in_khz) / | ||
4101 | 100); | ||
4102 | table->WatermarkRow[WM_DCEFCLK][i].MinUclk = | ||
4103 | cpu_to_le16((uint16_t) | ||
4104 | (wm_with_clock_ranges->wm_sets_dmif[i].wm_min_memclk_in_khz) / | ||
4105 | 100); | ||
4106 | table->WatermarkRow[WM_DCEFCLK][i].MaxUclk = | ||
4107 | cpu_to_le16((uint16_t) | ||
4108 | (wm_with_clock_ranges->wm_sets_dmif[i].wm_max_memclk_in_khz) / | ||
4109 | 100); | ||
4110 | table->WatermarkRow[WM_DCEFCLK][i].WmSetting = (uint8_t) | ||
4111 | wm_with_clock_ranges->wm_sets_dmif[i].wm_set_id; | ||
4112 | } | ||
4113 | |||
4114 | for (i = 0; i < wm_with_clock_ranges->num_wm_sets_mcif; i++) { | ||
4115 | table->WatermarkRow[WM_SOCCLK][i].MinClock = | ||
4116 | cpu_to_le16((uint16_t) | ||
4117 | (wm_with_clock_ranges->wm_sets_mcif[i].wm_min_socclk_in_khz) / | ||
4118 | 100); | ||
4119 | table->WatermarkRow[WM_SOCCLK][i].MaxClock = | ||
4120 | cpu_to_le16((uint16_t) | ||
4121 | (wm_with_clock_ranges->wm_sets_mcif[i].wm_max_socclk_in_khz) / | ||
4122 | 100); | ||
4123 | table->WatermarkRow[WM_SOCCLK][i].MinUclk = | ||
4124 | cpu_to_le16((uint16_t) | ||
4125 | (wm_with_clock_ranges->wm_sets_mcif[i].wm_min_memclk_in_khz) / | ||
4126 | 100); | ||
4127 | table->WatermarkRow[WM_SOCCLK][i].MaxUclk = | ||
4128 | cpu_to_le16((uint16_t) | ||
4129 | (wm_with_clock_ranges->wm_sets_mcif[i].wm_max_memclk_in_khz) / | ||
4130 | 100); | ||
4131 | table->WatermarkRow[WM_SOCCLK][i].WmSetting = (uint8_t) | ||
4132 | wm_with_clock_ranges->wm_sets_mcif[i].wm_set_id; | ||
4133 | } | ||
4134 | data->water_marks_bitmap = WaterMarksExist; | ||
4135 | } | ||
4136 | |||
4137 | return result; | ||
4138 | } | ||
4139 | |||
4140 | static int vega10_force_clock_level(struct pp_hwmgr *hwmgr, | ||
4141 | enum pp_clock_type type, uint32_t mask) | ||
4142 | { | ||
4143 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
4144 | uint32_t i; | ||
4145 | |||
4146 | if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) | ||
4147 | return -EINVAL; | ||
4148 | |||
4149 | switch (type) { | ||
4150 | case PP_SCLK: | ||
4151 | if (data->registry_data.sclk_dpm_key_disabled) | ||
4152 | break; | ||
4153 | |||
4154 | for (i = 0; i < 32; i++) { | ||
4155 | if (mask & (1 << i)) | ||
4156 | break; | ||
4157 | } | ||
4158 | |||
4159 | PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( | ||
4160 | hwmgr->smumgr, | ||
4161 | PPSMC_MSG_SetSoftMinGfxclkByIndex, | ||
4162 | i), | ||
4163 | "Failed to set soft min sclk index!", | ||
4164 | return -1); | ||
4165 | break; | ||
4166 | |||
4167 | case PP_MCLK: | ||
4168 | if (data->registry_data.mclk_dpm_key_disabled) | ||
4169 | break; | ||
4170 | |||
4171 | for (i = 0; i < 32; i++) { | ||
4172 | if (mask & (1 << i)) | ||
4173 | break; | ||
4174 | } | ||
4175 | |||
4176 | PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( | ||
4177 | hwmgr->smumgr, | ||
4178 | PPSMC_MSG_SetSoftMinUclkByIndex, | ||
4179 | i), | ||
4180 | "Failed to set soft min mclk index!", | ||
4181 | return -1); | ||
4182 | break; | ||
4183 | |||
4184 | case PP_PCIE: | ||
4185 | if (data->registry_data.pcie_dpm_key_disabled) | ||
4186 | break; | ||
4187 | |||
4188 | for (i = 0; i < 32; i++) { | ||
4189 | if (mask & (1 << i)) | ||
4190 | break; | ||
4191 | } | ||
4192 | |||
4193 | PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( | ||
4194 | hwmgr->smumgr, | ||
4195 | PPSMC_MSG_SetMinLinkDpmByIndex, | ||
4196 | i), | ||
4197 | "Failed to set min pcie index!", | ||
4198 | return -1); | ||
4199 | break; | ||
4200 | default: | ||
4201 | break; | ||
4202 | } | ||
4203 | |||
4204 | return 0; | ||
4205 | } | ||
4206 | |||
4207 | static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr, | ||
4208 | enum pp_clock_type type, char *buf) | ||
4209 | { | ||
4210 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
4211 | struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table); | ||
4212 | struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table); | ||
4213 | struct vega10_pcie_table *pcie_table = &(data->dpm_table.pcie_table); | ||
4214 | int i, now, size = 0; | ||
4215 | |||
4216 | switch (type) { | ||
4217 | case PP_SCLK: | ||
4218 | if (data->registry_data.sclk_dpm_key_disabled) | ||
4219 | break; | ||
4220 | |||
4221 | PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr->smumgr, | ||
4222 | PPSMC_MSG_GetCurrentGfxclkIndex), | ||
4223 | "Attempt to get current sclk index Failed!", | ||
4224 | return -1); | ||
4225 | PP_ASSERT_WITH_CODE(!vega10_read_arg_from_smc(hwmgr->smumgr, | ||
4226 | &now), | ||
4227 | "Attempt to read sclk index Failed!", | ||
4228 | return -1); | ||
4229 | |||
4230 | for (i = 0; i < sclk_table->count; i++) | ||
4231 | size += sprintf(buf + size, "%d: %uMhz %s\n", | ||
4232 | i, sclk_table->dpm_levels[i].value / 100, | ||
4233 | (i == now) ? "*" : ""); | ||
4234 | break; | ||
4235 | case PP_MCLK: | ||
4236 | if (data->registry_data.mclk_dpm_key_disabled) | ||
4237 | break; | ||
4238 | |||
4239 | PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr->smumgr, | ||
4240 | PPSMC_MSG_GetCurrentUclkIndex), | ||
4241 | "Attempt to get current mclk index Failed!", | ||
4242 | return -1); | ||
4243 | PP_ASSERT_WITH_CODE(!vega10_read_arg_from_smc(hwmgr->smumgr, | ||
4244 | &now), | ||
4245 | "Attempt to read mclk index Failed!", | ||
4246 | return -1); | ||
4247 | |||
4248 | for (i = 0; i < mclk_table->count; i++) | ||
4249 | size += sprintf(buf + size, "%d: %uMhz %s\n", | ||
4250 | i, mclk_table->dpm_levels[i].value / 100, | ||
4251 | (i == now) ? "*" : ""); | ||
4252 | break; | ||
4253 | case PP_PCIE: | ||
4254 | PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr->smumgr, | ||
4255 | PPSMC_MSG_GetCurrentLinkIndex), | ||
4256 | "Attempt to get current mclk index Failed!", | ||
4257 | return -1); | ||
4258 | PP_ASSERT_WITH_CODE(!vega10_read_arg_from_smc(hwmgr->smumgr, | ||
4259 | &now), | ||
4260 | "Attempt to read mclk index Failed!", | ||
4261 | return -1); | ||
4262 | |||
4263 | for (i = 0; i < pcie_table->count; i++) | ||
4264 | size += sprintf(buf + size, "%d: %s %s\n", i, | ||
4265 | (pcie_table->pcie_gen[i] == 0) ? "2.5GB, x1" : | ||
4266 | (pcie_table->pcie_gen[i] == 1) ? "5.0GB, x16" : | ||
4267 | (pcie_table->pcie_gen[i] == 2) ? "8.0GB, x16" : "", | ||
4268 | (i == now) ? "*" : ""); | ||
4269 | break; | ||
4270 | default: | ||
4271 | break; | ||
4272 | } | ||
4273 | return size; | ||
4274 | } | ||
4275 | |||
4276 | static int vega10_display_configuration_changed_task(struct pp_hwmgr *hwmgr) | ||
4277 | { | ||
4278 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
4279 | int result = 0; | ||
4280 | uint32_t num_turned_on_displays = 1; | ||
4281 | Watermarks_t *wm_table = &(data->smc_state_table.water_marks_table); | ||
4282 | struct cgs_display_info info = {0}; | ||
4283 | |||
4284 | if ((data->water_marks_bitmap & WaterMarksExist) && | ||
4285 | !(data->water_marks_bitmap & WaterMarksLoaded)) { | ||
4286 | result = vega10_copy_table_to_smc(hwmgr->smumgr, | ||
4287 | (uint8_t *)wm_table, WMTABLE); | ||
4288 | PP_ASSERT_WITH_CODE(result, "Failed to update WMTABLE!", return EINVAL); | ||
4289 | data->water_marks_bitmap |= WaterMarksLoaded; | ||
4290 | } | ||
4291 | |||
4292 | if (data->water_marks_bitmap & WaterMarksLoaded) { | ||
4293 | cgs_get_active_displays_info(hwmgr->device, &info); | ||
4294 | num_turned_on_displays = info.display_count; | ||
4295 | smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
4296 | PPSMC_MSG_NumOfDisplays, num_turned_on_displays); | ||
4297 | } | ||
4298 | |||
4299 | return result; | ||
4300 | } | ||
4301 | |||
4302 | int vega10_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable) | ||
4303 | { | ||
4304 | struct vega10_hwmgr *data = | ||
4305 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
4306 | |||
4307 | if (data->smu_features[GNLD_DPM_UVD].supported) { | ||
4308 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
4309 | enable, | ||
4310 | data->smu_features[GNLD_DPM_UVD].smu_feature_bitmap), | ||
4311 | "Attempt to Enable/Disable DPM UVD Failed!", | ||
4312 | return -1); | ||
4313 | data->smu_features[GNLD_DPM_UVD].enabled = enable; | ||
4314 | } | ||
4315 | return 0; | ||
4316 | } | ||
4317 | |||
4318 | static int vega10_power_gate_vce(struct pp_hwmgr *hwmgr, bool bgate) | ||
4319 | { | ||
4320 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
4321 | |||
4322 | data->vce_power_gated = bgate; | ||
4323 | return vega10_enable_disable_vce_dpm(hwmgr, !bgate); | ||
4324 | } | ||
4325 | |||
4326 | static int vega10_power_gate_uvd(struct pp_hwmgr *hwmgr, bool bgate) | ||
4327 | { | ||
4328 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
4329 | |||
4330 | data->uvd_power_gated = bgate; | ||
4331 | return vega10_enable_disable_uvd_dpm(hwmgr, !bgate); | ||
4332 | } | ||
4333 | |||
4334 | static inline bool vega10_are_power_levels_equal( | ||
4335 | const struct vega10_performance_level *pl1, | ||
4336 | const struct vega10_performance_level *pl2) | ||
4337 | { | ||
4338 | return ((pl1->soc_clock == pl2->soc_clock) && | ||
4339 | (pl1->gfx_clock == pl2->gfx_clock) && | ||
4340 | (pl1->mem_clock == pl2->mem_clock)); | ||
4341 | } | ||
4342 | |||
4343 | static int vega10_check_states_equal(struct pp_hwmgr *hwmgr, | ||
4344 | const struct pp_hw_power_state *pstate1, | ||
4345 | const struct pp_hw_power_state *pstate2, bool *equal) | ||
4346 | { | ||
4347 | const struct vega10_power_state *psa; | ||
4348 | const struct vega10_power_state *psb; | ||
4349 | int i; | ||
4350 | |||
4351 | if (pstate1 == NULL || pstate2 == NULL || equal == NULL) | ||
4352 | return -EINVAL; | ||
4353 | |||
4354 | psa = cast_const_phw_vega10_power_state(pstate1); | ||
4355 | psb = cast_const_phw_vega10_power_state(pstate2); | ||
4356 | /* If the two states don't even have the same number of performance levels they cannot be the same state. */ | ||
4357 | if (psa->performance_level_count != psb->performance_level_count) { | ||
4358 | *equal = false; | ||
4359 | return 0; | ||
4360 | } | ||
4361 | |||
4362 | for (i = 0; i < psa->performance_level_count; i++) { | ||
4363 | if (!vega10_are_power_levels_equal(&(psa->performance_levels[i]), &(psb->performance_levels[i]))) { | ||
4364 | /* If we have found even one performance level pair that is different the states are different. */ | ||
4365 | *equal = false; | ||
4366 | return 0; | ||
4367 | } | ||
4368 | } | ||
4369 | |||
4370 | /* If all performance levels are the same try to use the UVD clocks to break the tie.*/ | ||
4371 | *equal = ((psa->uvd_clks.vclk == psb->uvd_clks.vclk) && (psa->uvd_clks.dclk == psb->uvd_clks.dclk)); | ||
4372 | *equal &= ((psa->vce_clks.evclk == psb->vce_clks.evclk) && (psa->vce_clks.ecclk == psb->vce_clks.ecclk)); | ||
4373 | *equal &= (psa->sclk_threshold == psb->sclk_threshold); | ||
4374 | |||
4375 | return 0; | ||
4376 | } | ||
4377 | |||
4378 | static bool | ||
4379 | vega10_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr) | ||
4380 | { | ||
4381 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
4382 | bool is_update_required = false; | ||
4383 | struct cgs_display_info info = {0, 0, NULL}; | ||
4384 | |||
4385 | cgs_get_active_displays_info(hwmgr->device, &info); | ||
4386 | |||
4387 | if (data->display_timing.num_existing_displays != info.display_count) | ||
4388 | is_update_required = true; | ||
4389 | |||
4390 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) { | ||
4391 | if (data->display_timing.min_clock_in_sr != hwmgr->display_config.min_core_set_clock_in_sr) | ||
4392 | is_update_required = true; | ||
4393 | } | ||
4394 | |||
4395 | return is_update_required; | ||
4396 | } | ||
4397 | |||
4398 | static const struct pp_hwmgr_func vega10_hwmgr_funcs = { | ||
4399 | .backend_init = vega10_hwmgr_backend_init, | ||
4400 | .backend_fini = vega10_hwmgr_backend_fini, | ||
4401 | .asic_setup = vega10_setup_asic_task, | ||
4402 | .dynamic_state_management_enable = vega10_enable_dpm_tasks, | ||
4403 | .get_num_of_pp_table_entries = | ||
4404 | vega10_get_number_of_powerplay_table_entries, | ||
4405 | .get_power_state_size = vega10_get_power_state_size, | ||
4406 | .get_pp_table_entry = vega10_get_pp_table_entry, | ||
4407 | .patch_boot_state = vega10_patch_boot_state, | ||
4408 | .apply_state_adjust_rules = vega10_apply_state_adjust_rules, | ||
4409 | .power_state_set = vega10_set_power_state_tasks, | ||
4410 | .get_sclk = vega10_dpm_get_sclk, | ||
4411 | .get_mclk = vega10_dpm_get_mclk, | ||
4412 | .notify_smc_display_config_after_ps_adjustment = | ||
4413 | vega10_notify_smc_display_config_after_ps_adjustment, | ||
4414 | .force_dpm_level = vega10_dpm_force_dpm_level, | ||
4415 | .get_temperature = vega10_thermal_get_temperature, | ||
4416 | .stop_thermal_controller = vega10_thermal_stop_thermal_controller, | ||
4417 | .get_fan_speed_info = vega10_fan_ctrl_get_fan_speed_info, | ||
4418 | .get_fan_speed_percent = vega10_fan_ctrl_get_fan_speed_percent, | ||
4419 | .set_fan_speed_percent = vega10_fan_ctrl_set_fan_speed_percent, | ||
4420 | .reset_fan_speed_to_default = | ||
4421 | vega10_fan_ctrl_reset_fan_speed_to_default, | ||
4422 | .get_fan_speed_rpm = vega10_fan_ctrl_get_fan_speed_rpm, | ||
4423 | .set_fan_speed_rpm = vega10_fan_ctrl_set_fan_speed_rpm, | ||
4424 | .uninitialize_thermal_controller = | ||
4425 | vega10_thermal_ctrl_uninitialize_thermal_controller, | ||
4426 | .set_fan_control_mode = vega10_set_fan_control_mode, | ||
4427 | .get_fan_control_mode = vega10_get_fan_control_mode, | ||
4428 | .read_sensor = vega10_read_sensor, | ||
4429 | .get_dal_power_level = vega10_get_dal_power_level, | ||
4430 | .get_clock_by_type_with_latency = vega10_get_clock_by_type_with_latency, | ||
4431 | .get_clock_by_type_with_voltage = vega10_get_clock_by_type_with_voltage, | ||
4432 | .set_watermarks_for_clocks_ranges = vega10_set_watermarks_for_clocks_ranges, | ||
4433 | .display_clock_voltage_request = vega10_display_clock_voltage_request, | ||
4434 | .force_clock_level = vega10_force_clock_level, | ||
4435 | .print_clock_levels = vega10_print_clock_levels, | ||
4436 | .display_config_changed = vega10_display_configuration_changed_task, | ||
4437 | .powergate_uvd = vega10_power_gate_uvd, | ||
4438 | .powergate_vce = vega10_power_gate_vce, | ||
4439 | .check_states_equal = vega10_check_states_equal, | ||
4440 | .check_smc_update_required_for_display_configuration = | ||
4441 | vega10_check_smc_update_required_for_display_configuration, | ||
4442 | }; | ||
4443 | |||
4444 | int vega10_hwmgr_init(struct pp_hwmgr *hwmgr) | ||
4445 | { | ||
4446 | hwmgr->hwmgr_func = &vega10_hwmgr_funcs; | ||
4447 | hwmgr->pptable_func = &vega10_pptable_funcs; | ||
4448 | pp_vega10_thermal_initialize(hwmgr); | ||
4449 | return 0; | ||
4450 | } | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h new file mode 100644 index 000000000000..83c67b9262ff --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h | |||
@@ -0,0 +1,434 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef _VEGA10_HWMGR_H_ | ||
25 | #define _VEGA10_HWMGR_H_ | ||
26 | |||
27 | #include "hwmgr.h" | ||
28 | #include "smu9_driver_if.h" | ||
29 | #include "ppatomctrl.h" | ||
30 | #include "ppatomfwctrl.h" | ||
31 | #include "vega10_ppsmc.h" | ||
32 | #include "vega10_powertune.h" | ||
33 | |||
34 | extern const uint32_t PhwVega10_Magic; | ||
35 | #define VEGA10_MAX_HARDWARE_POWERLEVELS 2 | ||
36 | |||
37 | #define WaterMarksExist 1 | ||
38 | #define WaterMarksLoaded 2 | ||
39 | |||
40 | enum { | ||
41 | GNLD_DPM_PREFETCHER = 0, | ||
42 | GNLD_DPM_GFXCLK, | ||
43 | GNLD_DPM_UCLK, | ||
44 | GNLD_DPM_SOCCLK, | ||
45 | GNLD_DPM_UVD, | ||
46 | GNLD_DPM_VCE, | ||
47 | GNLD_ULV, | ||
48 | GNLD_DPM_MP0CLK, | ||
49 | GNLD_DPM_LINK, | ||
50 | GNLD_DPM_DCEFCLK, | ||
51 | GNLD_AVFS, | ||
52 | GNLD_DS_GFXCLK, | ||
53 | GNLD_DS_SOCCLK, | ||
54 | GNLD_DS_LCLK, | ||
55 | GNLD_PPT, | ||
56 | GNLD_TDC, | ||
57 | GNLD_THERMAL, | ||
58 | GNLD_GFX_PER_CU_CG, | ||
59 | GNLD_RM, | ||
60 | GNLD_DS_DCEFCLK, | ||
61 | GNLD_ACDC, | ||
62 | GNLD_VR0HOT, | ||
63 | GNLD_VR1HOT, | ||
64 | GNLD_FW_CTF, | ||
65 | GNLD_LED_DISPLAY, | ||
66 | GNLD_FAN_CONTROL, | ||
67 | GNLD_VOLTAGE_CONTROLLER, | ||
68 | GNLD_FEATURES_MAX | ||
69 | }; | ||
70 | |||
71 | #define GNLD_DPM_MAX (GNLD_DPM_DCEFCLK + 1) | ||
72 | |||
73 | #define SMC_DPM_FEATURES 0x30F | ||
74 | |||
75 | struct smu_features { | ||
76 | bool supported; | ||
77 | bool enabled; | ||
78 | uint32_t smu_feature_id; | ||
79 | uint32_t smu_feature_bitmap; | ||
80 | }; | ||
81 | |||
82 | struct vega10_performance_level { | ||
83 | uint32_t soc_clock; | ||
84 | uint32_t gfx_clock; | ||
85 | uint32_t mem_clock; | ||
86 | }; | ||
87 | |||
88 | struct vega10_bacos { | ||
89 | uint32_t baco_flags; | ||
90 | /* struct vega10_performance_level performance_level; */ | ||
91 | }; | ||
92 | |||
93 | struct vega10_uvd_clocks { | ||
94 | uint32_t vclk; | ||
95 | uint32_t dclk; | ||
96 | }; | ||
97 | |||
98 | struct vega10_vce_clocks { | ||
99 | uint32_t evclk; | ||
100 | uint32_t ecclk; | ||
101 | }; | ||
102 | |||
103 | struct vega10_power_state { | ||
104 | uint32_t magic; | ||
105 | struct vega10_uvd_clocks uvd_clks; | ||
106 | struct vega10_vce_clocks vce_clks; | ||
107 | uint16_t performance_level_count; | ||
108 | bool dc_compatible; | ||
109 | uint32_t sclk_threshold; | ||
110 | struct vega10_performance_level performance_levels[VEGA10_MAX_HARDWARE_POWERLEVELS]; | ||
111 | }; | ||
112 | |||
113 | struct vega10_dpm_level { | ||
114 | bool enabled; | ||
115 | uint32_t value; | ||
116 | uint32_t param1; | ||
117 | }; | ||
118 | |||
119 | #define VEGA10_MAX_DEEPSLEEP_DIVIDER_ID 5 | ||
120 | #define MAX_REGULAR_DPM_NUMBER 8 | ||
121 | #define MAX_PCIE_CONF 2 | ||
122 | #define VEGA10_MINIMUM_ENGINE_CLOCK 2500 | ||
123 | |||
124 | struct vega10_dpm_state { | ||
125 | uint32_t soft_min_level; | ||
126 | uint32_t soft_max_level; | ||
127 | uint32_t hard_min_level; | ||
128 | uint32_t hard_max_level; | ||
129 | }; | ||
130 | |||
131 | struct vega10_single_dpm_table { | ||
132 | uint32_t count; | ||
133 | struct vega10_dpm_state dpm_state; | ||
134 | struct vega10_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER]; | ||
135 | }; | ||
136 | |||
137 | struct vega10_pcie_table { | ||
138 | uint16_t count; | ||
139 | uint8_t pcie_gen[MAX_PCIE_CONF]; | ||
140 | uint8_t pcie_lane[MAX_PCIE_CONF]; | ||
141 | uint32_t lclk[MAX_PCIE_CONF]; | ||
142 | }; | ||
143 | |||
144 | struct vega10_dpm_table { | ||
145 | struct vega10_single_dpm_table soc_table; | ||
146 | struct vega10_single_dpm_table gfx_table; | ||
147 | struct vega10_single_dpm_table mem_table; | ||
148 | struct vega10_single_dpm_table eclk_table; | ||
149 | struct vega10_single_dpm_table vclk_table; | ||
150 | struct vega10_single_dpm_table dclk_table; | ||
151 | struct vega10_single_dpm_table dcef_table; | ||
152 | struct vega10_single_dpm_table pixel_table; | ||
153 | struct vega10_single_dpm_table display_table; | ||
154 | struct vega10_single_dpm_table phy_table; | ||
155 | struct vega10_pcie_table pcie_table; | ||
156 | }; | ||
157 | |||
158 | #define VEGA10_MAX_LEAKAGE_COUNT 8 | ||
159 | struct vega10_leakage_voltage { | ||
160 | uint16_t count; | ||
161 | uint16_t leakage_id[VEGA10_MAX_LEAKAGE_COUNT]; | ||
162 | uint16_t actual_voltage[VEGA10_MAX_LEAKAGE_COUNT]; | ||
163 | }; | ||
164 | |||
165 | struct vega10_display_timing { | ||
166 | uint32_t min_clock_in_sr; | ||
167 | uint32_t num_existing_displays; | ||
168 | }; | ||
169 | |||
170 | struct vega10_dpmlevel_enable_mask { | ||
171 | uint32_t uvd_dpm_enable_mask; | ||
172 | uint32_t vce_dpm_enable_mask; | ||
173 | uint32_t acp_dpm_enable_mask; | ||
174 | uint32_t samu_dpm_enable_mask; | ||
175 | uint32_t sclk_dpm_enable_mask; | ||
176 | uint32_t mclk_dpm_enable_mask; | ||
177 | }; | ||
178 | |||
179 | struct vega10_vbios_boot_state { | ||
180 | uint16_t vddc; | ||
181 | uint16_t vddci; | ||
182 | uint32_t gfx_clock; | ||
183 | uint32_t mem_clock; | ||
184 | uint32_t soc_clock; | ||
185 | }; | ||
186 | |||
187 | #define DPMTABLE_OD_UPDATE_SCLK 0x00000001 | ||
188 | #define DPMTABLE_OD_UPDATE_MCLK 0x00000002 | ||
189 | #define DPMTABLE_UPDATE_SCLK 0x00000004 | ||
190 | #define DPMTABLE_UPDATE_MCLK 0x00000008 | ||
191 | #define DPMTABLE_OD_UPDATE_VDDC 0x00000010 | ||
192 | |||
193 | struct vega10_smc_state_table { | ||
194 | uint32_t soc_boot_level; | ||
195 | uint32_t gfx_boot_level; | ||
196 | uint32_t dcef_boot_level; | ||
197 | uint32_t mem_boot_level; | ||
198 | uint32_t uvd_boot_level; | ||
199 | uint32_t vce_boot_level; | ||
200 | uint32_t gfx_max_level; | ||
201 | uint32_t mem_max_level; | ||
202 | uint8_t vr_hot_gpio; | ||
203 | uint8_t ac_dc_gpio; | ||
204 | uint8_t therm_out_gpio; | ||
205 | uint8_t therm_out_polarity; | ||
206 | uint8_t therm_out_mode; | ||
207 | PPTable_t pp_table; | ||
208 | Watermarks_t water_marks_table; | ||
209 | AvfsTable_t avfs_table; | ||
210 | }; | ||
211 | |||
212 | struct vega10_mclk_latency_entries { | ||
213 | uint32_t frequency; | ||
214 | uint32_t latency; | ||
215 | }; | ||
216 | |||
217 | struct vega10_mclk_latency_table { | ||
218 | uint32_t count; | ||
219 | struct vega10_mclk_latency_entries entries[MAX_REGULAR_DPM_NUMBER]; | ||
220 | }; | ||
221 | |||
222 | struct vega10_registry_data { | ||
223 | uint8_t ac_dc_switch_gpio_support; | ||
224 | uint8_t avfs_support; | ||
225 | uint8_t cac_support; | ||
226 | uint8_t clock_stretcher_support; | ||
227 | uint8_t db_ramping_support; | ||
228 | uint8_t didt_support; | ||
229 | uint8_t dynamic_state_patching_support; | ||
230 | uint8_t enable_pkg_pwr_tracking_feature; | ||
231 | uint8_t enable_tdc_limit_feature; | ||
232 | uint32_t fast_watermark_threshold; | ||
233 | uint8_t force_dpm_high; | ||
234 | uint8_t fuzzy_fan_control_support; | ||
235 | uint8_t long_idle_baco_support; | ||
236 | uint8_t mclk_dpm_key_disabled; | ||
237 | uint8_t od_state_in_dc_support; | ||
238 | uint8_t pcieLaneOverride; | ||
239 | uint8_t pcieSpeedOverride; | ||
240 | uint32_t pcieClockOverride; | ||
241 | uint8_t pcie_dpm_key_disabled; | ||
242 | uint8_t dcefclk_dpm_key_disabled; | ||
243 | uint8_t power_containment_support; | ||
244 | uint8_t ppt_support; | ||
245 | uint8_t prefetcher_dpm_key_disabled; | ||
246 | uint8_t quick_transition_support; | ||
247 | uint8_t regulator_hot_gpio_support; | ||
248 | uint8_t sclk_deep_sleep_support; | ||
249 | uint8_t sclk_dpm_key_disabled; | ||
250 | uint8_t sclk_from_vbios; | ||
251 | uint8_t sclk_throttle_low_notification; | ||
252 | uint8_t show_baco_dbg_info; | ||
253 | uint8_t skip_baco_hardware; | ||
254 | uint8_t socclk_dpm_key_disabled; | ||
255 | uint8_t spll_shutdown_support; | ||
256 | uint8_t sq_ramping_support; | ||
257 | uint32_t stable_pstate_sclk_dpm_percentage; | ||
258 | uint8_t tcp_ramping_support; | ||
259 | uint8_t tdc_support; | ||
260 | uint8_t td_ramping_support; | ||
261 | uint8_t thermal_out_gpio_support; | ||
262 | uint8_t thermal_support; | ||
263 | uint8_t fw_ctf_enabled; | ||
264 | uint8_t fan_control_support; | ||
265 | uint8_t ulps_support; | ||
266 | uint8_t ulv_support; | ||
267 | uint32_t vddc_vddci_delta; | ||
268 | uint8_t odn_feature_enable; | ||
269 | uint8_t disable_water_mark; | ||
270 | uint8_t zrpm_stop_temp; | ||
271 | uint8_t zrpm_start_temp; | ||
272 | uint8_t led_dpm_enabled; | ||
273 | uint8_t vr0hot_enabled; | ||
274 | uint8_t vr1hot_enabled; | ||
275 | }; | ||
276 | |||
277 | struct vega10_odn_clock_voltage_dependency_table { | ||
278 | uint32_t count; | ||
279 | struct phm_ppt_v1_clock_voltage_dependency_record | ||
280 | entries[MAX_REGULAR_DPM_NUMBER]; | ||
281 | }; | ||
282 | |||
283 | struct vega10_odn_dpm_table { | ||
284 | struct phm_odn_clock_levels odn_core_clock_dpm_levels; | ||
285 | struct phm_odn_clock_levels odn_memory_clock_dpm_levels; | ||
286 | struct vega10_odn_clock_voltage_dependency_table vdd_dependency_on_sclk; | ||
287 | struct vega10_odn_clock_voltage_dependency_table vdd_dependency_on_mclk; | ||
288 | }; | ||
289 | |||
290 | struct vega10_odn_fan_table { | ||
291 | uint32_t target_fan_speed; | ||
292 | uint32_t target_temperature; | ||
293 | uint32_t min_performance_clock; | ||
294 | uint32_t min_fan_limit; | ||
295 | }; | ||
296 | |||
297 | struct vega10_hwmgr { | ||
298 | struct vega10_dpm_table dpm_table; | ||
299 | struct vega10_dpm_table golden_dpm_table; | ||
300 | struct vega10_registry_data registry_data; | ||
301 | struct vega10_vbios_boot_state vbios_boot_state; | ||
302 | struct vega10_mclk_latency_table mclk_latency_table; | ||
303 | |||
304 | struct vega10_leakage_voltage vddc_leakage; | ||
305 | |||
306 | uint32_t vddc_control; | ||
307 | struct pp_atomfwctrl_voltage_table vddc_voltage_table; | ||
308 | uint32_t mvdd_control; | ||
309 | struct pp_atomfwctrl_voltage_table mvdd_voltage_table; | ||
310 | uint32_t vddci_control; | ||
311 | struct pp_atomfwctrl_voltage_table vddci_voltage_table; | ||
312 | |||
313 | uint32_t active_auto_throttle_sources; | ||
314 | uint32_t water_marks_bitmap; | ||
315 | struct vega10_bacos bacos; | ||
316 | |||
317 | struct vega10_odn_dpm_table odn_dpm_table; | ||
318 | struct vega10_odn_fan_table odn_fan_table; | ||
319 | |||
320 | /* ---- General data ---- */ | ||
321 | uint8_t need_update_dpm_table; | ||
322 | |||
323 | bool cac_enabled; | ||
324 | bool battery_state; | ||
325 | bool is_tlu_enabled; | ||
326 | |||
327 | uint32_t low_sclk_interrupt_threshold; | ||
328 | |||
329 | uint32_t total_active_cus; | ||
330 | |||
331 | struct vega10_display_timing display_timing; | ||
332 | |||
333 | /* ---- Vega10 Dyn Register Settings ---- */ | ||
334 | |||
335 | uint32_t debug_settings; | ||
336 | uint32_t lowest_uclk_reserved_for_ulv; | ||
337 | uint32_t gfxclk_average_alpha; | ||
338 | uint32_t socclk_average_alpha; | ||
339 | uint32_t uclk_average_alpha; | ||
340 | uint32_t gfx_activity_average_alpha; | ||
341 | uint32_t display_voltage_mode; | ||
342 | uint32_t dcef_clk_quad_eqn_a; | ||
343 | uint32_t dcef_clk_quad_eqn_b; | ||
344 | uint32_t dcef_clk_quad_eqn_c; | ||
345 | uint32_t disp_clk_quad_eqn_a; | ||
346 | uint32_t disp_clk_quad_eqn_b; | ||
347 | uint32_t disp_clk_quad_eqn_c; | ||
348 | uint32_t pixel_clk_quad_eqn_a; | ||
349 | uint32_t pixel_clk_quad_eqn_b; | ||
350 | uint32_t pixel_clk_quad_eqn_c; | ||
351 | uint32_t phy_clk_quad_eqn_a; | ||
352 | uint32_t phy_clk_quad_eqn_b; | ||
353 | uint32_t phy_clk_quad_eqn_c; | ||
354 | |||
355 | /* ---- Thermal Temperature Setting ---- */ | ||
356 | struct vega10_dpmlevel_enable_mask dpm_level_enable_mask; | ||
357 | |||
358 | /* ---- Power Gating States ---- */ | ||
359 | bool uvd_power_gated; | ||
360 | bool vce_power_gated; | ||
361 | bool samu_power_gated; | ||
362 | bool need_long_memory_training; | ||
363 | |||
364 | /* Internal settings to apply the application power optimization parameters */ | ||
365 | bool apply_optimized_settings; | ||
366 | uint32_t disable_dpm_mask; | ||
367 | |||
368 | /* ---- Overdrive next setting ---- */ | ||
369 | uint32_t apply_overdrive_next_settings_mask; | ||
370 | |||
371 | /* ---- Workload Mask ---- */ | ||
372 | uint32_t workload_mask; | ||
373 | |||
374 | /* ---- SMU9 ---- */ | ||
375 | struct smu_features smu_features[GNLD_FEATURES_MAX]; | ||
376 | struct vega10_smc_state_table smc_state_table; | ||
377 | |||
378 | uint32_t config_telemetry; | ||
379 | }; | ||
380 | |||
381 | #define VEGA10_DPM2_NEAR_TDP_DEC 10 | ||
382 | #define VEGA10_DPM2_ABOVE_SAFE_INC 5 | ||
383 | #define VEGA10_DPM2_BELOW_SAFE_INC 20 | ||
384 | |||
385 | #define VEGA10_DPM2_LTA_WINDOW_SIZE 7 | ||
386 | |||
387 | #define VEGA10_DPM2_LTS_TRUNCATE 0 | ||
388 | |||
389 | #define VEGA10_DPM2_TDP_SAFE_LIMIT_PERCENT 80 | ||
390 | |||
391 | #define VEGA10_DPM2_MAXPS_PERCENT_M 90 | ||
392 | #define VEGA10_DPM2_MAXPS_PERCENT_H 90 | ||
393 | |||
394 | #define VEGA10_DPM2_PWREFFICIENCYRATIO_MARGIN 50 | ||
395 | |||
396 | #define VEGA10_DPM2_SQ_RAMP_MAX_POWER 0x3FFF | ||
397 | #define VEGA10_DPM2_SQ_RAMP_MIN_POWER 0x12 | ||
398 | #define VEGA10_DPM2_SQ_RAMP_MAX_POWER_DELTA 0x15 | ||
399 | #define VEGA10_DPM2_SQ_RAMP_SHORT_TERM_INTERVAL_SIZE 0x1E | ||
400 | #define VEGA10_DPM2_SQ_RAMP_LONG_TERM_INTERVAL_RATIO 0xF | ||
401 | |||
402 | #define VEGA10_VOLTAGE_CONTROL_NONE 0x0 | ||
403 | #define VEGA10_VOLTAGE_CONTROL_BY_GPIO 0x1 | ||
404 | #define VEGA10_VOLTAGE_CONTROL_BY_SVID2 0x2 | ||
405 | #define VEGA10_VOLTAGE_CONTROL_MERGED 0x3 | ||
406 | /* To convert to Q8.8 format for firmware */ | ||
407 | #define VEGA10_Q88_FORMAT_CONVERSION_UNIT 256 | ||
408 | |||
409 | #define VEGA10_UNUSED_GPIO_PIN 0x7F | ||
410 | |||
411 | #define VEGA10_THERM_OUT_MODE_DISABLE 0x0 | ||
412 | #define VEGA10_THERM_OUT_MODE_THERM_ONLY 0x1 | ||
413 | #define VEGA10_THERM_OUT_MODE_THERM_VRHOT 0x2 | ||
414 | |||
415 | #define PPVEGA10_VEGA10DISPLAYVOLTAGEMODE_DFLT 0xffffffff | ||
416 | #define PPREGKEY_VEGA10QUADRATICEQUATION_DFLT 0xffffffff | ||
417 | |||
418 | #define PPVEGA10_VEGA10GFXCLKAVERAGEALPHA_DFLT 25 /* 10% * 255 = 25 */ | ||
419 | #define PPVEGA10_VEGA10SOCCLKAVERAGEALPHA_DFLT 25 /* 10% * 255 = 25 */ | ||
420 | #define PPVEGA10_VEGA10UCLKCLKAVERAGEALPHA_DFLT 25 /* 10% * 255 = 25 */ | ||
421 | #define PPVEGA10_VEGA10GFXACTIVITYAVERAGEALPHA_DFLT 25 /* 10% * 255 = 25 */ | ||
422 | |||
423 | extern int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr); | ||
424 | extern int tonga_hwmgr_backend_fini(struct pp_hwmgr *hwmgr); | ||
425 | extern int tonga_get_mc_microcode_version (struct pp_hwmgr *hwmgr); | ||
426 | extern int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr); | ||
427 | extern int tonga_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display); | ||
428 | int vega10_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input); | ||
429 | int vega10_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate); | ||
430 | int vega10_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate); | ||
431 | int vega10_update_acp_dpm(struct pp_hwmgr *hwmgr, bool bgate); | ||
432 | int vega10_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable); | ||
433 | |||
434 | #endif /* _VEGA10_HWMGR_H_ */ | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_inc.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_inc.h new file mode 100644 index 000000000000..8c55eaa3c32b --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_inc.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef VEGA10_INC_H | ||
25 | #define VEGA10_INC_H | ||
26 | |||
27 | #include "asic_reg/vega10/THM/thm_9_0_default.h" | ||
28 | #include "asic_reg/vega10/THM/thm_9_0_offset.h" | ||
29 | #include "asic_reg/vega10/THM/thm_9_0_sh_mask.h" | ||
30 | |||
31 | #include "asic_reg/vega10/MP/mp_9_0_default.h" | ||
32 | #include "asic_reg/vega10/MP/mp_9_0_offset.h" | ||
33 | #include "asic_reg/vega10/MP/mp_9_0_sh_mask.h" | ||
34 | |||
35 | #include "asic_reg/vega10/GC/gc_9_0_default.h" | ||
36 | #include "asic_reg/vega10/GC/gc_9_0_offset.h" | ||
37 | #include "asic_reg/vega10/GC/gc_9_0_sh_mask.h" | ||
38 | |||
39 | #include "asic_reg/vega10/NBIO/nbio_6_1_default.h" | ||
40 | #include "asic_reg/vega10/NBIO/nbio_6_1_offset.h" | ||
41 | #include "asic_reg/vega10/NBIO/nbio_6_1_sh_mask.h" | ||
42 | |||
43 | |||
44 | #endif | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c new file mode 100644 index 000000000000..f1e244cd2370 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "hwmgr.h" | ||
25 | #include "vega10_hwmgr.h" | ||
26 | #include "vega10_powertune.h" | ||
27 | #include "vega10_smumgr.h" | ||
28 | #include "vega10_ppsmc.h" | ||
29 | #include "pp_debug.h" | ||
30 | |||
31 | void vega10_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) | ||
32 | { | ||
33 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
34 | struct phm_ppt_v2_information *table_info = | ||
35 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
36 | struct phm_tdp_table *tdp_table = table_info->tdp_table; | ||
37 | PPTable_t *table = &(data->smc_state_table.pp_table); | ||
38 | |||
39 | table->SocketPowerLimit = cpu_to_le16( | ||
40 | tdp_table->usMaximumPowerDeliveryLimit); | ||
41 | table->TdcLimit = cpu_to_le16(tdp_table->usTDC); | ||
42 | table->EdcLimit = cpu_to_le16(tdp_table->usEDCLimit); | ||
43 | table->TedgeLimit = cpu_to_le16(tdp_table->usTemperatureLimitTedge); | ||
44 | table->ThotspotLimit = cpu_to_le16(tdp_table->usTemperatureLimitHotspot); | ||
45 | table->ThbmLimit = cpu_to_le16(tdp_table->usTemperatureLimitHBM); | ||
46 | table->Tvr_socLimit = cpu_to_le16(tdp_table->usTemperatureLimitVrVddc); | ||
47 | table->Tvr_memLimit = cpu_to_le16(tdp_table->usTemperatureLimitVrMvdd); | ||
48 | table->Tliquid1Limit = cpu_to_le16(tdp_table->usTemperatureLimitLiquid1); | ||
49 | table->Tliquid2Limit = cpu_to_le16(tdp_table->usTemperatureLimitLiquid2); | ||
50 | table->TplxLimit = cpu_to_le16(tdp_table->usTemperatureLimitPlx); | ||
51 | table->LoadLineResistance = cpu_to_le16( | ||
52 | hwmgr->platform_descriptor.LoadLineSlope); | ||
53 | table->FitLimit = 0; /* Not used for Vega10 */ | ||
54 | |||
55 | table->Liquid1_I2C_address = tdp_table->ucLiquid1_I2C_address; | ||
56 | table->Liquid2_I2C_address = tdp_table->ucLiquid2_I2C_address; | ||
57 | table->Vr_I2C_address = tdp_table->ucVr_I2C_address; | ||
58 | table->Plx_I2C_address = tdp_table->ucPlx_I2C_address; | ||
59 | |||
60 | table->Liquid_I2C_LineSCL = tdp_table->ucLiquid_I2C_Line; | ||
61 | table->Liquid_I2C_LineSDA = tdp_table->ucLiquid_I2C_LineSDA; | ||
62 | |||
63 | table->Vr_I2C_LineSCL = tdp_table->ucVr_I2C_Line; | ||
64 | table->Vr_I2C_LineSDA = tdp_table->ucVr_I2C_LineSDA; | ||
65 | |||
66 | table->Plx_I2C_LineSCL = tdp_table->ucPlx_I2C_Line; | ||
67 | table->Plx_I2C_LineSDA = tdp_table->ucPlx_I2C_LineSDA; | ||
68 | } | ||
69 | |||
70 | int vega10_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n) | ||
71 | { | ||
72 | struct vega10_hwmgr *data = | ||
73 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
74 | |||
75 | if (data->registry_data.enable_pkg_pwr_tracking_feature) | ||
76 | return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
77 | PPSMC_MSG_SetPptLimit, n); | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | int vega10_enable_power_containment(struct pp_hwmgr *hwmgr) | ||
83 | { | ||
84 | struct vega10_hwmgr *data = | ||
85 | (struct vega10_hwmgr *)(hwmgr->backend); | ||
86 | struct phm_ppt_v2_information *table_info = | ||
87 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
88 | struct phm_tdp_table *tdp_table = table_info->tdp_table; | ||
89 | uint32_t default_pwr_limit = | ||
90 | (uint32_t)(tdp_table->usMaximumPowerDeliveryLimit); | ||
91 | int result = 0; | ||
92 | |||
93 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
94 | PHM_PlatformCaps_PowerContainment)) { | ||
95 | if (data->smu_features[GNLD_PPT].supported) | ||
96 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
97 | true, data->smu_features[GNLD_PPT].smu_feature_bitmap), | ||
98 | "Attempt to enable PPT feature Failed!", | ||
99 | data->smu_features[GNLD_PPT].supported = false); | ||
100 | |||
101 | if (data->smu_features[GNLD_TDC].supported) | ||
102 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
103 | true, data->smu_features[GNLD_TDC].smu_feature_bitmap), | ||
104 | "Attempt to enable PPT feature Failed!", | ||
105 | data->smu_features[GNLD_TDC].supported = false); | ||
106 | |||
107 | result = vega10_set_power_limit(hwmgr, default_pwr_limit); | ||
108 | PP_ASSERT_WITH_CODE(!result, | ||
109 | "Failed to set Default Power Limit in SMC!", | ||
110 | return result); | ||
111 | } | ||
112 | |||
113 | return result; | ||
114 | } | ||
115 | |||
116 | static int vega10_set_overdrive_target_percentage(struct pp_hwmgr *hwmgr, | ||
117 | uint32_t adjust_percent) | ||
118 | { | ||
119 | return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
120 | PPSMC_MSG_OverDriveSetPercentage, adjust_percent); | ||
121 | } | ||
122 | |||
123 | int vega10_power_control_set_level(struct pp_hwmgr *hwmgr) | ||
124 | { | ||
125 | int adjust_percent, result = 0; | ||
126 | |||
127 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
128 | PHM_PlatformCaps_PowerContainment)) { | ||
129 | adjust_percent = | ||
130 | hwmgr->platform_descriptor.TDPAdjustmentPolarity ? | ||
131 | hwmgr->platform_descriptor.TDPAdjustment : | ||
132 | (-1 * hwmgr->platform_descriptor.TDPAdjustment); | ||
133 | result = vega10_set_overdrive_target_percentage(hwmgr, | ||
134 | (uint32_t)adjust_percent); | ||
135 | } | ||
136 | return result; | ||
137 | } | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.h new file mode 100644 index 000000000000..d9662bf4a4b4 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.h | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | #ifndef _VEGA10_POWERTUNE_H_ | ||
24 | #define _VEGA10_POWERTUNE_H_ | ||
25 | |||
26 | enum vega10_pt_config_reg_type { | ||
27 | VEGA10_CONFIGREG_MMR = 0, | ||
28 | VEGA10_CONFIGREG_SMC_IND, | ||
29 | VEGA10_CONFIGREG_DIDT_IND, | ||
30 | VEGA10_CONFIGREG_CACHE, | ||
31 | VEGA10_CONFIGREG_MAX | ||
32 | }; | ||
33 | |||
34 | /* PowerContainment Features */ | ||
35 | #define POWERCONTAINMENT_FEATURE_DTE 0x00000001 | ||
36 | #define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002 | ||
37 | #define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004 | ||
38 | |||
39 | struct vega10_pt_config_reg { | ||
40 | uint32_t offset; | ||
41 | uint32_t mask; | ||
42 | uint32_t shift; | ||
43 | uint32_t value; | ||
44 | enum vega10_pt_config_reg_type type; | ||
45 | }; | ||
46 | |||
47 | struct vega10_pt_defaults { | ||
48 | uint8_t SviLoadLineEn; | ||
49 | uint8_t SviLoadLineVddC; | ||
50 | uint8_t TDC_VDDC_ThrottleReleaseLimitPerc; | ||
51 | uint8_t TDC_MAWt; | ||
52 | uint8_t TdcWaterfallCtl; | ||
53 | uint8_t DTEAmbientTempBase; | ||
54 | }; | ||
55 | |||
56 | void vega10_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr); | ||
57 | int vega10_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr); | ||
58 | int vega10_populate_pm_fuses(struct pp_hwmgr *hwmgr); | ||
59 | int vega10_enable_smc_cac(struct pp_hwmgr *hwmgr); | ||
60 | int vega10_enable_power_containment(struct pp_hwmgr *hwmgr); | ||
61 | int vega10_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n); | ||
62 | int vega10_power_control_set_level(struct pp_hwmgr *hwmgr); | ||
63 | |||
64 | #endif /* _VEGA10_POWERTUNE_H_ */ | ||
65 | |||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_pptable.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_pptable.h new file mode 100644 index 000000000000..8e53d3a5e725 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_pptable.h | |||
@@ -0,0 +1,331 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | #ifndef _VEGA10_PPTABLE_H_ | ||
24 | #define _VEGA10_PPTABLE_H_ | ||
25 | |||
26 | #pragma pack(push, 1) | ||
27 | |||
28 | #define ATOM_VEGA10_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK 0x0f | ||
29 | #define ATOM_VEGA10_PP_FANPARAMETERS_NOFAN 0x80 | ||
30 | |||
31 | #define ATOM_VEGA10_PP_THERMALCONTROLLER_NONE 0 | ||
32 | #define ATOM_VEGA10_PP_THERMALCONTROLLER_LM96163 17 | ||
33 | #define ATOM_VEGA10_PP_THERMALCONTROLLER_VEGA10 24 | ||
34 | |||
35 | #define ATOM_VEGA10_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL 0x89 | ||
36 | #define ATOM_VEGA10_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL 0x8D | ||
37 | |||
38 | #define ATOM_VEGA10_PP_PLATFORM_CAP_POWERPLAY 0x1 | ||
39 | #define ATOM_VEGA10_PP_PLATFORM_CAP_SBIOSPOWERSOURCE 0x2 | ||
40 | #define ATOM_VEGA10_PP_PLATFORM_CAP_HARDWAREDC 0x4 | ||
41 | #define ATOM_VEGA10_PP_PLATFORM_CAP_BACO 0x8 | ||
42 | #define ATOM_VEGA10_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL 0x10 | ||
43 | |||
44 | |||
45 | /* ATOM_PPLIB_NONCLOCK_INFO::usClassification */ | ||
46 | #define ATOM_PPLIB_CLASSIFICATION_UI_MASK 0x0007 | ||
47 | #define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT 0 | ||
48 | #define ATOM_PPLIB_CLASSIFICATION_UI_NONE 0 | ||
49 | #define ATOM_PPLIB_CLASSIFICATION_UI_BATTERY 1 | ||
50 | #define ATOM_PPLIB_CLASSIFICATION_UI_BALANCED 3 | ||
51 | #define ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE 5 | ||
52 | /* 2, 4, 6, 7 are reserved */ | ||
53 | |||
54 | #define ATOM_PPLIB_CLASSIFICATION_BOOT 0x0008 | ||
55 | #define ATOM_PPLIB_CLASSIFICATION_THERMAL 0x0010 | ||
56 | #define ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE 0x0020 | ||
57 | #define ATOM_PPLIB_CLASSIFICATION_REST 0x0040 | ||
58 | #define ATOM_PPLIB_CLASSIFICATION_FORCED 0x0080 | ||
59 | #define ATOM_PPLIB_CLASSIFICATION_ACPI 0x1000 | ||
60 | |||
61 | /* ATOM_PPLIB_NONCLOCK_INFO::usClassification2 */ | ||
62 | #define ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2 0x0001 | ||
63 | |||
64 | #define ATOM_Vega10_DISALLOW_ON_DC 0x00004000 | ||
65 | #define ATOM_Vega10_ENABLE_VARIBRIGHT 0x00008000 | ||
66 | |||
67 | #define ATOM_Vega10_TABLE_REVISION_VEGA10 8 | ||
68 | |||
69 | #define ATOM_Vega10_VoltageMode_AVFS_Interpolate 0 | ||
70 | #define ATOM_Vega10_VoltageMode_AVFS_WorstCase 1 | ||
71 | #define ATOM_Vega10_VoltageMode_Static 2 | ||
72 | |||
73 | typedef struct _ATOM_Vega10_POWERPLAYTABLE { | ||
74 | struct atom_common_table_header sHeader; | ||
75 | UCHAR ucTableRevision; | ||
76 | USHORT usTableSize; /* the size of header structure */ | ||
77 | ULONG ulGoldenPPID; /* PPGen use only */ | ||
78 | ULONG ulGoldenRevision; /* PPGen use only */ | ||
79 | USHORT usFormatID; /* PPGen use only */ | ||
80 | ULONG ulPlatformCaps; /* See ATOM_Vega10_CAPS_* */ | ||
81 | ULONG ulMaxODEngineClock; /* For Overdrive. */ | ||
82 | ULONG ulMaxODMemoryClock; /* For Overdrive. */ | ||
83 | USHORT usPowerControlLimit; | ||
84 | USHORT usUlvVoltageOffset; /* in mv units */ | ||
85 | USHORT usUlvSmnclkDid; | ||
86 | USHORT usUlvMp1clkDid; | ||
87 | USHORT usUlvGfxclkBypass; | ||
88 | USHORT usGfxclkSlewRate; | ||
89 | UCHAR ucGfxVoltageMode; | ||
90 | UCHAR ucSocVoltageMode; | ||
91 | UCHAR ucUclkVoltageMode; | ||
92 | UCHAR ucUvdVoltageMode; | ||
93 | UCHAR ucVceVoltageMode; | ||
94 | UCHAR ucMp0VoltageMode; | ||
95 | UCHAR ucDcefVoltageMode; | ||
96 | USHORT usStateArrayOffset; /* points to ATOM_Vega10_State_Array */ | ||
97 | USHORT usFanTableOffset; /* points to ATOM_Vega10_Fan_Table */ | ||
98 | USHORT usThermalControllerOffset; /* points to ATOM_Vega10_Thermal_Controller */ | ||
99 | USHORT usSocclkDependencyTableOffset; /* points to ATOM_Vega10_SOCCLK_Dependency_Table */ | ||
100 | USHORT usMclkDependencyTableOffset; /* points to ATOM_Vega10_MCLK_Dependency_Table */ | ||
101 | USHORT usGfxclkDependencyTableOffset; /* points to ATOM_Vega10_GFXCLK_Dependency_Table */ | ||
102 | USHORT usDcefclkDependencyTableOffset; /* points to ATOM_Vega10_DCEFCLK_Dependency_Table */ | ||
103 | USHORT usVddcLookupTableOffset; /* points to ATOM_Vega10_Voltage_Lookup_Table */ | ||
104 | USHORT usVddmemLookupTableOffset; /* points to ATOM_Vega10_Voltage_Lookup_Table */ | ||
105 | USHORT usMMDependencyTableOffset; /* points to ATOM_Vega10_MM_Dependency_Table */ | ||
106 | USHORT usVCEStateTableOffset; /* points to ATOM_Vega10_VCE_State_Table */ | ||
107 | USHORT usReserve; /* No PPM Support for Vega10 */ | ||
108 | USHORT usPowerTuneTableOffset; /* points to ATOM_Vega10_PowerTune_Table */ | ||
109 | USHORT usHardLimitTableOffset; /* points to ATOM_Vega10_Hard_Limit_Table */ | ||
110 | USHORT usVddciLookupTableOffset; /* points to ATOM_Vega10_Voltage_Lookup_Table */ | ||
111 | USHORT usPCIETableOffset; /* points to ATOM_Vega10_PCIE_Table */ | ||
112 | USHORT usPixclkDependencyTableOffset; /* points to ATOM_Vega10_PIXCLK_Dependency_Table */ | ||
113 | USHORT usDispClkDependencyTableOffset; /* points to ATOM_Vega10_DISPCLK_Dependency_Table */ | ||
114 | USHORT usPhyClkDependencyTableOffset; /* points to ATOM_Vega10_PHYCLK_Dependency_Table */ | ||
115 | } ATOM_Vega10_POWERPLAYTABLE; | ||
116 | |||
117 | typedef struct _ATOM_Vega10_State { | ||
118 | UCHAR ucSocClockIndexHigh; | ||
119 | UCHAR ucSocClockIndexLow; | ||
120 | UCHAR ucGfxClockIndexHigh; | ||
121 | UCHAR ucGfxClockIndexLow; | ||
122 | UCHAR ucMemClockIndexHigh; | ||
123 | UCHAR ucMemClockIndexLow; | ||
124 | USHORT usClassification; | ||
125 | ULONG ulCapsAndSettings; | ||
126 | USHORT usClassification2; | ||
127 | } ATOM_Vega10_State; | ||
128 | |||
129 | typedef struct _ATOM_Vega10_State_Array { | ||
130 | UCHAR ucRevId; | ||
131 | UCHAR ucNumEntries; /* Number of entries. */ | ||
132 | ATOM_Vega10_State states[1]; /* Dynamically allocate entries. */ | ||
133 | } ATOM_Vega10_State_Array; | ||
134 | |||
135 | typedef struct _ATOM_Vega10_CLK_Dependency_Record { | ||
136 | ULONG ulClk; /* Frequency of Clock */ | ||
137 | UCHAR ucVddInd; /* Base voltage */ | ||
138 | } ATOM_Vega10_CLK_Dependency_Record; | ||
139 | |||
140 | typedef struct _ATOM_Vega10_GFXCLK_Dependency_Record { | ||
141 | ULONG ulClk; /* Clock Frequency */ | ||
142 | UCHAR ucVddInd; /* SOC_VDD index */ | ||
143 | USHORT usCKSVOffsetandDisable; /* Bits 0~30: Voltage offset for CKS, Bit 31: Disable/enable for the GFXCLK level. */ | ||
144 | USHORT usAVFSOffset; /* AVFS Voltage offset */ | ||
145 | } ATOM_Vega10_GFXCLK_Dependency_Record; | ||
146 | |||
147 | typedef struct _ATOM_Vega10_MCLK_Dependency_Record { | ||
148 | ULONG ulMemClk; /* Clock Frequency */ | ||
149 | UCHAR ucVddInd; /* SOC_VDD index */ | ||
150 | UCHAR ucVddMemInd; /* MEM_VDD - only non zero for MCLK record */ | ||
151 | UCHAR ucVddciInd; /* VDDCI = only non zero for MCLK record */ | ||
152 | } ATOM_Vega10_MCLK_Dependency_Record; | ||
153 | |||
154 | typedef struct _ATOM_Vega10_GFXCLK_Dependency_Table { | ||
155 | UCHAR ucRevId; | ||
156 | UCHAR ucNumEntries; /* Number of entries. */ | ||
157 | ATOM_Vega10_GFXCLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */ | ||
158 | } ATOM_Vega10_GFXCLK_Dependency_Table; | ||
159 | |||
160 | typedef struct _ATOM_Vega10_MCLK_Dependency_Table { | ||
161 | UCHAR ucRevId; | ||
162 | UCHAR ucNumEntries; /* Number of entries. */ | ||
163 | ATOM_Vega10_MCLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */ | ||
164 | } ATOM_Vega10_MCLK_Dependency_Table; | ||
165 | |||
166 | typedef struct _ATOM_Vega10_SOCCLK_Dependency_Table { | ||
167 | UCHAR ucRevId; | ||
168 | UCHAR ucNumEntries; /* Number of entries. */ | ||
169 | ATOM_Vega10_CLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */ | ||
170 | } ATOM_Vega10_SOCCLK_Dependency_Table; | ||
171 | |||
172 | typedef struct _ATOM_Vega10_DCEFCLK_Dependency_Table { | ||
173 | UCHAR ucRevId; | ||
174 | UCHAR ucNumEntries; /* Number of entries. */ | ||
175 | ATOM_Vega10_CLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */ | ||
176 | } ATOM_Vega10_DCEFCLK_Dependency_Table; | ||
177 | |||
178 | typedef struct _ATOM_Vega10_PIXCLK_Dependency_Table { | ||
179 | UCHAR ucRevId; | ||
180 | UCHAR ucNumEntries; /* Number of entries. */ | ||
181 | ATOM_Vega10_CLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */ | ||
182 | } ATOM_Vega10_PIXCLK_Dependency_Table; | ||
183 | |||
184 | typedef struct _ATOM_Vega10_DISPCLK_Dependency_Table { | ||
185 | UCHAR ucRevId; | ||
186 | UCHAR ucNumEntries; /* Number of entries.*/ | ||
187 | ATOM_Vega10_CLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */ | ||
188 | } ATOM_Vega10_DISPCLK_Dependency_Table; | ||
189 | |||
190 | typedef struct _ATOM_Vega10_PHYCLK_Dependency_Table { | ||
191 | UCHAR ucRevId; | ||
192 | UCHAR ucNumEntries; /* Number of entries. */ | ||
193 | ATOM_Vega10_CLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */ | ||
194 | } ATOM_Vega10_PHYCLK_Dependency_Table; | ||
195 | |||
196 | typedef struct _ATOM_Vega10_MM_Dependency_Record { | ||
197 | UCHAR ucVddcInd; /* SOC_VDD voltage */ | ||
198 | ULONG ulDClk; /* UVD D-clock */ | ||
199 | ULONG ulVClk; /* UVD V-clock */ | ||
200 | ULONG ulEClk; /* VCE clock */ | ||
201 | ULONG ulPSPClk; /* PSP clock */ | ||
202 | } ATOM_Vega10_MM_Dependency_Record; | ||
203 | |||
204 | typedef struct _ATOM_Vega10_MM_Dependency_Table { | ||
205 | UCHAR ucRevId; | ||
206 | UCHAR ucNumEntries; /* Number of entries */ | ||
207 | ATOM_Vega10_MM_Dependency_Record entries[1]; /* Dynamically allocate entries */ | ||
208 | } ATOM_Vega10_MM_Dependency_Table; | ||
209 | |||
210 | typedef struct _ATOM_Vega10_PCIE_Record { | ||
211 | ULONG ulLCLK; /* LClock */ | ||
212 | UCHAR ucPCIEGenSpeed; /* PCIE Speed */ | ||
213 | UCHAR ucPCIELaneWidth; /* PCIE Lane Width */ | ||
214 | } ATOM_Vega10_PCIE_Record; | ||
215 | |||
216 | typedef struct _ATOM_Vega10_PCIE_Table { | ||
217 | UCHAR ucRevId; | ||
218 | UCHAR ucNumEntries; /* Number of entries */ | ||
219 | ATOM_Vega10_PCIE_Record entries[1]; /* Dynamically allocate entries. */ | ||
220 | } ATOM_Vega10_PCIE_Table; | ||
221 | |||
222 | typedef struct _ATOM_Vega10_Voltage_Lookup_Record { | ||
223 | USHORT usVdd; /* Base voltage */ | ||
224 | } ATOM_Vega10_Voltage_Lookup_Record; | ||
225 | |||
226 | typedef struct _ATOM_Vega10_Voltage_Lookup_Table { | ||
227 | UCHAR ucRevId; | ||
228 | UCHAR ucNumEntries; /* Number of entries */ | ||
229 | ATOM_Vega10_Voltage_Lookup_Record entries[1]; /* Dynamically allocate entries */ | ||
230 | } ATOM_Vega10_Voltage_Lookup_Table; | ||
231 | |||
232 | typedef struct _ATOM_Vega10_Fan_Table { | ||
233 | UCHAR ucRevId; /* Change this if the table format changes or version changes so that the other fields are not the same. */ | ||
234 | USHORT usFanOutputSensitivity; /* Sensitivity of fan reaction to temepature changes. */ | ||
235 | USHORT usFanRPMMax; /* The default value in RPM. */ | ||
236 | USHORT usThrottlingRPM; | ||
237 | USHORT usFanAcousticLimit; /* Minimum Fan Controller Frequency Acoustic Limit. */ | ||
238 | USHORT usTargetTemperature; /* The default ideal temperature in Celcius. */ | ||
239 | USHORT usMinimumPWMLimit; /* The minimum PWM that the advanced fan controller can set. */ | ||
240 | USHORT usTargetGfxClk; /* The ideal Fan Controller GFXCLK Frequency Acoustic Limit. */ | ||
241 | USHORT usFanGainEdge; | ||
242 | USHORT usFanGainHotspot; | ||
243 | USHORT usFanGainLiquid; | ||
244 | USHORT usFanGainVrVddc; | ||
245 | USHORT usFanGainVrMvdd; | ||
246 | USHORT usFanGainPlx; | ||
247 | USHORT usFanGainHbm; | ||
248 | UCHAR ucEnableZeroRPM; | ||
249 | USHORT usFanStopTemperature; | ||
250 | USHORT usFanStartTemperature; | ||
251 | } ATOM_Vega10_Fan_Table; | ||
252 | |||
253 | typedef struct _ATOM_Vega10_Thermal_Controller { | ||
254 | UCHAR ucRevId; | ||
255 | UCHAR ucType; /* one of ATOM_VEGA10_PP_THERMALCONTROLLER_*/ | ||
256 | UCHAR ucI2cLine; /* as interpreted by DAL I2C */ | ||
257 | UCHAR ucI2cAddress; | ||
258 | UCHAR ucFanParameters; /* Fan Control Parameters. */ | ||
259 | UCHAR ucFanMinRPM; /* Fan Minimum RPM (hundreds) -- for display purposes only.*/ | ||
260 | UCHAR ucFanMaxRPM; /* Fan Maximum RPM (hundreds) -- for display purposes only.*/ | ||
261 | UCHAR ucFlags; /* to be defined */ | ||
262 | } ATOM_Vega10_Thermal_Controller; | ||
263 | |||
264 | typedef struct _ATOM_Vega10_VCE_State_Record | ||
265 | { | ||
266 | UCHAR ucVCEClockIndex; /*index into usVCEDependencyTableOffset of 'ATOM_Vega10_MM_Dependency_Table' type */ | ||
267 | UCHAR ucFlag; /* 2 bits indicates memory p-states */ | ||
268 | UCHAR ucSCLKIndex; /* index into ATOM_Vega10_SCLK_Dependency_Table */ | ||
269 | UCHAR ucMCLKIndex; /* index into ATOM_Vega10_MCLK_Dependency_Table */ | ||
270 | } ATOM_Vega10_VCE_State_Record; | ||
271 | |||
272 | typedef struct _ATOM_Vega10_VCE_State_Table | ||
273 | { | ||
274 | UCHAR ucRevId; | ||
275 | UCHAR ucNumEntries; | ||
276 | ATOM_Vega10_VCE_State_Record entries[1]; | ||
277 | } ATOM_Vega10_VCE_State_Table; | ||
278 | |||
279 | typedef struct _ATOM_Vega10_PowerTune_Table { | ||
280 | UCHAR ucRevId; | ||
281 | USHORT usSocketPowerLimit; | ||
282 | USHORT usBatteryPowerLimit; | ||
283 | USHORT usSmallPowerLimit; | ||
284 | USHORT usTdcLimit; | ||
285 | USHORT usEdcLimit; | ||
286 | USHORT usSoftwareShutdownTemp; | ||
287 | USHORT usTemperatureLimitHotSpot; | ||
288 | USHORT usTemperatureLimitLiquid1; | ||
289 | USHORT usTemperatureLimitLiquid2; | ||
290 | USHORT usTemperatureLimitHBM; | ||
291 | USHORT usTemperatureLimitVrSoc; | ||
292 | USHORT usTemperatureLimitVrMem; | ||
293 | USHORT usTemperatureLimitPlx; | ||
294 | USHORT usLoadLineResistance; | ||
295 | UCHAR ucLiquid1_I2C_address; | ||
296 | UCHAR ucLiquid2_I2C_address; | ||
297 | UCHAR ucVr_I2C_address; | ||
298 | UCHAR ucPlx_I2C_address; | ||
299 | UCHAR ucLiquid_I2C_LineSCL; | ||
300 | UCHAR ucLiquid_I2C_LineSDA; | ||
301 | UCHAR ucVr_I2C_LineSCL; | ||
302 | UCHAR ucVr_I2C_LineSDA; | ||
303 | UCHAR ucPlx_I2C_LineSCL; | ||
304 | UCHAR ucPlx_I2C_LineSDA; | ||
305 | USHORT usTemperatureLimitTedge; | ||
306 | } ATOM_Vega10_PowerTune_Table; | ||
307 | |||
308 | typedef struct _ATOM_Vega10_Hard_Limit_Record { | ||
309 | ULONG ulSOCCLKLimit; | ||
310 | ULONG ulGFXCLKLimit; | ||
311 | ULONG ulMCLKLimit; | ||
312 | USHORT usVddcLimit; | ||
313 | USHORT usVddciLimit; | ||
314 | USHORT usVddMemLimit; | ||
315 | } ATOM_Vega10_Hard_Limit_Record; | ||
316 | |||
317 | typedef struct _ATOM_Vega10_Hard_Limit_Table | ||
318 | { | ||
319 | UCHAR ucRevId; | ||
320 | UCHAR ucNumEntries; | ||
321 | ATOM_Vega10_Hard_Limit_Record entries[1]; | ||
322 | } ATOM_Vega10_Hard_Limit_Table; | ||
323 | |||
324 | typedef struct _Vega10_PPTable_Generic_SubTable_Header | ||
325 | { | ||
326 | UCHAR ucRevId; | ||
327 | } Vega10_PPTable_Generic_SubTable_Header; | ||
328 | |||
329 | #pragma pack(pop) | ||
330 | |||
331 | #endif | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c new file mode 100644 index 000000000000..518634f995e7 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c | |||
@@ -0,0 +1,1056 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/fb.h> | ||
26 | |||
27 | #include "vega10_processpptables.h" | ||
28 | #include "ppatomfwctrl.h" | ||
29 | #include "atomfirmware.h" | ||
30 | #include "pp_debug.h" | ||
31 | #include "cgs_common.h" | ||
32 | #include "vega10_pptable.h" | ||
33 | |||
34 | static void set_hw_cap(struct pp_hwmgr *hwmgr, bool enable, | ||
35 | enum phm_platform_caps cap) | ||
36 | { | ||
37 | if (enable) | ||
38 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap); | ||
39 | else | ||
40 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap); | ||
41 | } | ||
42 | |||
43 | static const void *get_powerplay_table(struct pp_hwmgr *hwmgr) | ||
44 | { | ||
45 | int index = GetIndexIntoMasterDataTable(powerplayinfo); | ||
46 | |||
47 | u16 size; | ||
48 | u8 frev, crev; | ||
49 | const void *table_address = hwmgr->soft_pp_table; | ||
50 | |||
51 | if (!table_address) { | ||
52 | table_address = (ATOM_Vega10_POWERPLAYTABLE *) | ||
53 | cgs_atom_get_data_table(hwmgr->device, index, | ||
54 | &size, &frev, &crev); | ||
55 | |||
56 | hwmgr->soft_pp_table = table_address; /*Cache the result in RAM.*/ | ||
57 | } | ||
58 | |||
59 | return table_address; | ||
60 | } | ||
61 | |||
62 | static int check_powerplay_tables( | ||
63 | struct pp_hwmgr *hwmgr, | ||
64 | const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) | ||
65 | { | ||
66 | const ATOM_Vega10_State_Array *state_arrays; | ||
67 | |||
68 | state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)powerplay_table) + | ||
69 | le16_to_cpu(powerplay_table->usStateArrayOffset)); | ||
70 | |||
71 | PP_ASSERT_WITH_CODE((powerplay_table->sHeader.format_revision >= | ||
72 | ATOM_Vega10_TABLE_REVISION_VEGA10), | ||
73 | "Unsupported PPTable format!", return -1); | ||
74 | PP_ASSERT_WITH_CODE(powerplay_table->usStateArrayOffset, | ||
75 | "State table is not set!", return -1); | ||
76 | PP_ASSERT_WITH_CODE(powerplay_table->sHeader.structuresize > 0, | ||
77 | "Invalid PowerPlay Table!", return -1); | ||
78 | PP_ASSERT_WITH_CODE(state_arrays->ucNumEntries > 0, | ||
79 | "Invalid PowerPlay Table!", return -1); | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps) | ||
85 | { | ||
86 | set_hw_cap( | ||
87 | hwmgr, | ||
88 | 0 != (powerplay_caps & ATOM_VEGA10_PP_PLATFORM_CAP_POWERPLAY), | ||
89 | PHM_PlatformCaps_PowerPlaySupport); | ||
90 | |||
91 | set_hw_cap( | ||
92 | hwmgr, | ||
93 | 0 != (powerplay_caps & ATOM_VEGA10_PP_PLATFORM_CAP_SBIOSPOWERSOURCE), | ||
94 | PHM_PlatformCaps_BiosPowerSourceControl); | ||
95 | |||
96 | set_hw_cap( | ||
97 | hwmgr, | ||
98 | 0 != (powerplay_caps & ATOM_VEGA10_PP_PLATFORM_CAP_HARDWAREDC), | ||
99 | PHM_PlatformCaps_AutomaticDCTransition); | ||
100 | |||
101 | set_hw_cap( | ||
102 | hwmgr, | ||
103 | 0 != (powerplay_caps & ATOM_VEGA10_PP_PLATFORM_CAP_BACO), | ||
104 | PHM_PlatformCaps_BACO); | ||
105 | |||
106 | set_hw_cap( | ||
107 | hwmgr, | ||
108 | 0 != (powerplay_caps & ATOM_VEGA10_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL), | ||
109 | PHM_PlatformCaps_CombinePCCWithThermalSignal); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int init_thermal_controller( | ||
115 | struct pp_hwmgr *hwmgr, | ||
116 | const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) | ||
117 | { | ||
118 | const ATOM_Vega10_Thermal_Controller *thermal_controller; | ||
119 | const ATOM_Vega10_Fan_Table *fan_table; | ||
120 | |||
121 | thermal_controller = (ATOM_Vega10_Thermal_Controller *) | ||
122 | (((unsigned long)powerplay_table) + | ||
123 | le16_to_cpu(powerplay_table->usThermalControllerOffset)); | ||
124 | |||
125 | PP_ASSERT_WITH_CODE((powerplay_table->usThermalControllerOffset != 0), | ||
126 | "Thermal controller table not set!", return -1); | ||
127 | |||
128 | hwmgr->thermal_controller.ucType = thermal_controller->ucType; | ||
129 | hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine; | ||
130 | hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress; | ||
131 | |||
132 | hwmgr->thermal_controller.fanInfo.bNoFan = | ||
133 | (0 != (thermal_controller->ucFanParameters & | ||
134 | ATOM_VEGA10_PP_FANPARAMETERS_NOFAN)); | ||
135 | |||
136 | hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution = | ||
137 | thermal_controller->ucFanParameters & | ||
138 | ATOM_VEGA10_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK; | ||
139 | |||
140 | hwmgr->thermal_controller.fanInfo.ulMinRPM = | ||
141 | thermal_controller->ucFanMinRPM * 100UL; | ||
142 | hwmgr->thermal_controller.fanInfo.ulMaxRPM = | ||
143 | thermal_controller->ucFanMaxRPM * 100UL; | ||
144 | |||
145 | set_hw_cap( | ||
146 | hwmgr, | ||
147 | ATOM_VEGA10_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType, | ||
148 | PHM_PlatformCaps_ThermalController); | ||
149 | |||
150 | if (!powerplay_table->usFanTableOffset) | ||
151 | return 0; | ||
152 | |||
153 | fan_table = (const ATOM_Vega10_Fan_Table *) | ||
154 | (((unsigned long)powerplay_table) + | ||
155 | le16_to_cpu(powerplay_table->usFanTableOffset)); | ||
156 | |||
157 | PP_ASSERT_WITH_CODE((fan_table->ucRevId >= 8), | ||
158 | "Invalid Input Fan Table!", return -1); | ||
159 | |||
160 | hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay | ||
161 | = 100000; | ||
162 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
163 | PHM_PlatformCaps_MicrocodeFanControl); | ||
164 | |||
165 | hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity = | ||
166 | le16_to_cpu(fan_table->usFanOutputSensitivity); | ||
167 | hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM = | ||
168 | le16_to_cpu(fan_table->usFanRPMMax); | ||
169 | hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMMaxLimit = | ||
170 | le16_to_cpu(fan_table->usThrottlingRPM); | ||
171 | hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit = | ||
172 | le32_to_cpu((uint32_t)(fan_table->usFanAcousticLimit)); | ||
173 | hwmgr->thermal_controller.advanceFanControlParameters.usTMax = | ||
174 | le16_to_cpu(fan_table->usTargetTemperature); | ||
175 | hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin = | ||
176 | le16_to_cpu(fan_table->usMinimumPWMLimit); | ||
177 | hwmgr->thermal_controller.advanceFanControlParameters.ulTargetGfxClk = | ||
178 | le32_to_cpu((uint32_t)(fan_table->usTargetGfxClk)); | ||
179 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainEdge = | ||
180 | le16_to_cpu(fan_table->usFanGainEdge); | ||
181 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHotspot = | ||
182 | le16_to_cpu(fan_table->usFanGainHotspot); | ||
183 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainLiquid = | ||
184 | le16_to_cpu(fan_table->usFanGainLiquid); | ||
185 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrVddc = | ||
186 | le16_to_cpu(fan_table->usFanGainVrVddc); | ||
187 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrMvdd = | ||
188 | le16_to_cpu(fan_table->usFanGainVrMvdd); | ||
189 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainPlx = | ||
190 | le16_to_cpu(fan_table->usFanGainPlx); | ||
191 | hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHbm = | ||
192 | le16_to_cpu(fan_table->usFanGainHbm); | ||
193 | |||
194 | hwmgr->thermal_controller.advanceFanControlParameters.ucEnableZeroRPM = | ||
195 | fan_table->ucEnableZeroRPM; | ||
196 | hwmgr->thermal_controller.advanceFanControlParameters.usZeroRPMStopTemperature = | ||
197 | le16_to_cpu(fan_table->usFanStopTemperature); | ||
198 | hwmgr->thermal_controller.advanceFanControlParameters.usZeroRPMStartTemperature = | ||
199 | le16_to_cpu(fan_table->usFanStartTemperature); | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int init_over_drive_limits( | ||
205 | struct pp_hwmgr *hwmgr, | ||
206 | const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) | ||
207 | { | ||
208 | hwmgr->platform_descriptor.overdriveLimit.engineClock = | ||
209 | le32_to_cpu(powerplay_table->ulMaxODEngineClock); | ||
210 | hwmgr->platform_descriptor.overdriveLimit.memoryClock = | ||
211 | le32_to_cpu(powerplay_table->ulMaxODMemoryClock); | ||
212 | |||
213 | hwmgr->platform_descriptor.minOverdriveVDDC = 0; | ||
214 | hwmgr->platform_descriptor.maxOverdriveVDDC = 0; | ||
215 | hwmgr->platform_descriptor.overdriveVDDCStep = 0; | ||
216 | |||
217 | if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0 && | ||
218 | hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0) { | ||
219 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
220 | PHM_PlatformCaps_ACOverdriveSupport); | ||
221 | } | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int get_mm_clock_voltage_table( | ||
227 | struct pp_hwmgr *hwmgr, | ||
228 | phm_ppt_v1_mm_clock_voltage_dependency_table **vega10_mm_table, | ||
229 | const ATOM_Vega10_MM_Dependency_Table *mm_dependency_table) | ||
230 | { | ||
231 | uint32_t table_size, i; | ||
232 | const ATOM_Vega10_MM_Dependency_Record *mm_dependency_record; | ||
233 | phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table; | ||
234 | |||
235 | PP_ASSERT_WITH_CODE((mm_dependency_table->ucNumEntries != 0), | ||
236 | "Invalid PowerPlay Table!", return -1); | ||
237 | |||
238 | table_size = sizeof(uint32_t) + | ||
239 | sizeof(phm_ppt_v1_mm_clock_voltage_dependency_record) * | ||
240 | mm_dependency_table->ucNumEntries; | ||
241 | mm_table = (phm_ppt_v1_mm_clock_voltage_dependency_table *) | ||
242 | kzalloc(table_size, GFP_KERNEL); | ||
243 | |||
244 | if (!mm_table) | ||
245 | return -ENOMEM; | ||
246 | |||
247 | mm_table->count = mm_dependency_table->ucNumEntries; | ||
248 | |||
249 | for (i = 0; i < mm_dependency_table->ucNumEntries; i++) { | ||
250 | mm_dependency_record = &mm_dependency_table->entries[i]; | ||
251 | mm_table->entries[i].vddcInd = mm_dependency_record->ucVddcInd; | ||
252 | mm_table->entries[i].samclock = | ||
253 | le32_to_cpu(mm_dependency_record->ulPSPClk); | ||
254 | mm_table->entries[i].eclk = le32_to_cpu(mm_dependency_record->ulEClk); | ||
255 | mm_table->entries[i].vclk = le32_to_cpu(mm_dependency_record->ulVClk); | ||
256 | mm_table->entries[i].dclk = le32_to_cpu(mm_dependency_record->ulDClk); | ||
257 | } | ||
258 | |||
259 | *vega10_mm_table = mm_table; | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int get_tdp_table( | ||
265 | struct pp_hwmgr *hwmgr, | ||
266 | struct phm_tdp_table **info_tdp_table, | ||
267 | const Vega10_PPTable_Generic_SubTable_Header *table) | ||
268 | { | ||
269 | uint32_t table_size; | ||
270 | struct phm_tdp_table *tdp_table; | ||
271 | |||
272 | const ATOM_Vega10_PowerTune_Table *power_tune_table = | ||
273 | (ATOM_Vega10_PowerTune_Table *)table; | ||
274 | |||
275 | table_size = sizeof(uint32_t) + sizeof(struct phm_cac_tdp_table); | ||
276 | hwmgr->dyn_state.cac_dtp_table = (struct phm_cac_tdp_table *) | ||
277 | kzalloc(table_size, GFP_KERNEL); | ||
278 | |||
279 | if (!hwmgr->dyn_state.cac_dtp_table) | ||
280 | return -ENOMEM; | ||
281 | |||
282 | table_size = sizeof(uint32_t) + sizeof(struct phm_tdp_table); | ||
283 | tdp_table = kzalloc(table_size, GFP_KERNEL); | ||
284 | |||
285 | if (!tdp_table) { | ||
286 | kfree(hwmgr->dyn_state.cac_dtp_table); | ||
287 | hwmgr->dyn_state.cac_dtp_table = NULL; | ||
288 | return -ENOMEM; | ||
289 | } | ||
290 | |||
291 | tdp_table->usMaximumPowerDeliveryLimit = le16_to_cpu(power_tune_table->usSocketPowerLimit); | ||
292 | tdp_table->usTDC = le16_to_cpu(power_tune_table->usTdcLimit); | ||
293 | tdp_table->usEDCLimit = le16_to_cpu(power_tune_table->usEdcLimit); | ||
294 | tdp_table->usSoftwareShutdownTemp = | ||
295 | le16_to_cpu(power_tune_table->usSoftwareShutdownTemp); | ||
296 | tdp_table->usTemperatureLimitTedge = | ||
297 | le16_to_cpu(power_tune_table->usTemperatureLimitTedge); | ||
298 | tdp_table->usTemperatureLimitHotspot = | ||
299 | le16_to_cpu(power_tune_table->usTemperatureLimitHotSpot); | ||
300 | tdp_table->usTemperatureLimitLiquid1 = | ||
301 | le16_to_cpu(power_tune_table->usTemperatureLimitLiquid1); | ||
302 | tdp_table->usTemperatureLimitLiquid2 = | ||
303 | le16_to_cpu(power_tune_table->usTemperatureLimitLiquid2); | ||
304 | tdp_table->usTemperatureLimitHBM = | ||
305 | le16_to_cpu(power_tune_table->usTemperatureLimitHBM); | ||
306 | tdp_table->usTemperatureLimitVrVddc = | ||
307 | le16_to_cpu(power_tune_table->usTemperatureLimitVrSoc); | ||
308 | tdp_table->usTemperatureLimitVrMvdd = | ||
309 | le16_to_cpu(power_tune_table->usTemperatureLimitVrMem); | ||
310 | tdp_table->usTemperatureLimitPlx = | ||
311 | le16_to_cpu(power_tune_table->usTemperatureLimitPlx); | ||
312 | tdp_table->ucLiquid1_I2C_address = power_tune_table->ucLiquid1_I2C_address; | ||
313 | tdp_table->ucLiquid2_I2C_address = power_tune_table->ucLiquid2_I2C_address; | ||
314 | tdp_table->ucLiquid_I2C_Line = power_tune_table->ucLiquid_I2C_LineSCL; | ||
315 | tdp_table->ucLiquid_I2C_LineSDA = power_tune_table->ucLiquid_I2C_LineSDA; | ||
316 | tdp_table->ucVr_I2C_address = power_tune_table->ucVr_I2C_address; | ||
317 | tdp_table->ucVr_I2C_Line = power_tune_table->ucVr_I2C_LineSCL; | ||
318 | tdp_table->ucVr_I2C_LineSDA = power_tune_table->ucVr_I2C_LineSDA; | ||
319 | tdp_table->ucPlx_I2C_address = power_tune_table->ucPlx_I2C_address; | ||
320 | tdp_table->ucPlx_I2C_Line = power_tune_table->ucPlx_I2C_LineSCL; | ||
321 | tdp_table->ucPlx_I2C_LineSDA = power_tune_table->ucPlx_I2C_LineSDA; | ||
322 | |||
323 | hwmgr->platform_descriptor.LoadLineSlope = power_tune_table->usLoadLineResistance; | ||
324 | |||
325 | *info_tdp_table = tdp_table; | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int get_socclk_voltage_dependency_table( | ||
331 | struct pp_hwmgr *hwmgr, | ||
332 | phm_ppt_v1_clock_voltage_dependency_table **pp_vega10_clk_dep_table, | ||
333 | const ATOM_Vega10_SOCCLK_Dependency_Table *clk_dep_table) | ||
334 | { | ||
335 | uint32_t table_size, i; | ||
336 | phm_ppt_v1_clock_voltage_dependency_table *clk_table; | ||
337 | |||
338 | PP_ASSERT_WITH_CODE(clk_dep_table->ucNumEntries, | ||
339 | "Invalid PowerPlay Table!", return -1); | ||
340 | |||
341 | table_size = sizeof(uint32_t) + | ||
342 | sizeof(phm_ppt_v1_clock_voltage_dependency_record) * | ||
343 | clk_dep_table->ucNumEntries; | ||
344 | |||
345 | clk_table = (phm_ppt_v1_clock_voltage_dependency_table *) | ||
346 | kzalloc(table_size, GFP_KERNEL); | ||
347 | |||
348 | if (!clk_table) | ||
349 | return -ENOMEM; | ||
350 | |||
351 | clk_table->count = (uint32_t)clk_dep_table->ucNumEntries; | ||
352 | |||
353 | for (i = 0; i < clk_dep_table->ucNumEntries; i++) { | ||
354 | clk_table->entries[i].vddInd = | ||
355 | clk_dep_table->entries[i].ucVddInd; | ||
356 | clk_table->entries[i].clk = | ||
357 | le32_to_cpu(clk_dep_table->entries[i].ulClk); | ||
358 | } | ||
359 | |||
360 | *pp_vega10_clk_dep_table = clk_table; | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | static int get_mclk_voltage_dependency_table( | ||
366 | struct pp_hwmgr *hwmgr, | ||
367 | phm_ppt_v1_clock_voltage_dependency_table **pp_vega10_mclk_dep_table, | ||
368 | const ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table) | ||
369 | { | ||
370 | uint32_t table_size, i; | ||
371 | phm_ppt_v1_clock_voltage_dependency_table *mclk_table; | ||
372 | |||
373 | PP_ASSERT_WITH_CODE(mclk_dep_table->ucNumEntries, | ||
374 | "Invalid PowerPlay Table!", return -1); | ||
375 | |||
376 | table_size = sizeof(uint32_t) + | ||
377 | sizeof(phm_ppt_v1_clock_voltage_dependency_record) * | ||
378 | mclk_dep_table->ucNumEntries; | ||
379 | |||
380 | mclk_table = (phm_ppt_v1_clock_voltage_dependency_table *) | ||
381 | kzalloc(table_size, GFP_KERNEL); | ||
382 | |||
383 | if (!mclk_table) | ||
384 | return -ENOMEM; | ||
385 | |||
386 | mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries; | ||
387 | |||
388 | for (i = 0; i < mclk_dep_table->ucNumEntries; i++) { | ||
389 | mclk_table->entries[i].vddInd = | ||
390 | mclk_dep_table->entries[i].ucVddInd; | ||
391 | mclk_table->entries[i].vddciInd = | ||
392 | mclk_dep_table->entries[i].ucVddciInd; | ||
393 | mclk_table->entries[i].mvddInd = | ||
394 | mclk_dep_table->entries[i].ucVddMemInd; | ||
395 | mclk_table->entries[i].clk = | ||
396 | le32_to_cpu(mclk_dep_table->entries[i].ulMemClk); | ||
397 | } | ||
398 | |||
399 | *pp_vega10_mclk_dep_table = mclk_table; | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static int get_gfxclk_voltage_dependency_table( | ||
405 | struct pp_hwmgr *hwmgr, | ||
406 | struct phm_ppt_v1_clock_voltage_dependency_table | ||
407 | **pp_vega10_clk_dep_table, | ||
408 | const ATOM_Vega10_GFXCLK_Dependency_Table *clk_dep_table) | ||
409 | { | ||
410 | uint32_t table_size, i; | ||
411 | struct phm_ppt_v1_clock_voltage_dependency_table | ||
412 | *clk_table; | ||
413 | |||
414 | PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0), | ||
415 | "Invalid PowerPlay Table!", return -1); | ||
416 | |||
417 | table_size = sizeof(uint32_t) + | ||
418 | sizeof(phm_ppt_v1_clock_voltage_dependency_record) * | ||
419 | clk_dep_table->ucNumEntries; | ||
420 | |||
421 | clk_table = (struct phm_ppt_v1_clock_voltage_dependency_table *) | ||
422 | kzalloc(table_size, GFP_KERNEL); | ||
423 | |||
424 | if (!clk_table) | ||
425 | return -ENOMEM; | ||
426 | |||
427 | clk_table->count = clk_dep_table->ucNumEntries; | ||
428 | |||
429 | for (i = 0; i < clk_table->count; i++) { | ||
430 | clk_table->entries[i].vddInd = | ||
431 | clk_dep_table->entries[i].ucVddInd; | ||
432 | clk_table->entries[i].clk = | ||
433 | le32_to_cpu(clk_dep_table->entries[i].ulClk); | ||
434 | clk_table->entries[i].cks_enable = | ||
435 | (((clk_dep_table->entries[i].usCKSVOffsetandDisable & 0x80) | ||
436 | >> 15) == 0) ? 1 : 0; | ||
437 | clk_table->entries[i].cks_voffset = | ||
438 | (clk_dep_table->entries[i].usCKSVOffsetandDisable & 0x7F); | ||
439 | clk_table->entries[i].sclk_offset = | ||
440 | clk_dep_table->entries[i].usAVFSOffset; | ||
441 | } | ||
442 | |||
443 | *pp_vega10_clk_dep_table = clk_table; | ||
444 | |||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int get_dcefclk_voltage_dependency_table( | ||
449 | struct pp_hwmgr *hwmgr, | ||
450 | struct phm_ppt_v1_clock_voltage_dependency_table | ||
451 | **pp_vega10_clk_dep_table, | ||
452 | const ATOM_Vega10_DCEFCLK_Dependency_Table *clk_dep_table) | ||
453 | { | ||
454 | uint32_t table_size, i; | ||
455 | struct phm_ppt_v1_clock_voltage_dependency_table | ||
456 | *clk_table; | ||
457 | |||
458 | PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0), | ||
459 | "Invalid PowerPlay Table!", return -1); | ||
460 | |||
461 | table_size = sizeof(uint32_t) + | ||
462 | sizeof(phm_ppt_v1_clock_voltage_dependency_record) * | ||
463 | clk_dep_table->ucNumEntries; | ||
464 | |||
465 | clk_table = (struct phm_ppt_v1_clock_voltage_dependency_table *) | ||
466 | kzalloc(table_size, GFP_KERNEL); | ||
467 | |||
468 | if (!clk_table) | ||
469 | return -ENOMEM; | ||
470 | |||
471 | clk_table->count = clk_dep_table->ucNumEntries; | ||
472 | |||
473 | for (i = 0; i < clk_table->count; i++) { | ||
474 | clk_table->entries[i].vddInd = | ||
475 | clk_dep_table->entries[i].ucVddInd; | ||
476 | clk_table->entries[i].clk = | ||
477 | le32_to_cpu(clk_dep_table->entries[i].ulClk); | ||
478 | } | ||
479 | |||
480 | *pp_vega10_clk_dep_table = clk_table; | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static int get_pcie_table(struct pp_hwmgr *hwmgr, | ||
486 | struct phm_ppt_v1_pcie_table **vega10_pcie_table, | ||
487 | const Vega10_PPTable_Generic_SubTable_Header *table) | ||
488 | { | ||
489 | uint32_t table_size, i, pcie_count; | ||
490 | struct phm_ppt_v1_pcie_table *pcie_table; | ||
491 | struct phm_ppt_v2_information *table_info = | ||
492 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
493 | const ATOM_Vega10_PCIE_Table *atom_pcie_table = | ||
494 | (ATOM_Vega10_PCIE_Table *)table; | ||
495 | |||
496 | PP_ASSERT_WITH_CODE(atom_pcie_table->ucNumEntries, | ||
497 | "Invalid PowerPlay Table!", | ||
498 | return 0); | ||
499 | |||
500 | table_size = sizeof(uint32_t) + | ||
501 | sizeof(struct phm_ppt_v1_pcie_record) * | ||
502 | atom_pcie_table->ucNumEntries; | ||
503 | |||
504 | pcie_table = (struct phm_ppt_v1_pcie_table *) | ||
505 | kzalloc(table_size, GFP_KERNEL); | ||
506 | |||
507 | if (!pcie_table) | ||
508 | return -ENOMEM; | ||
509 | |||
510 | pcie_count = table_info->vdd_dep_on_sclk->count; | ||
511 | if (atom_pcie_table->ucNumEntries <= pcie_count) | ||
512 | pcie_count = atom_pcie_table->ucNumEntries; | ||
513 | else | ||
514 | pr_info("Number of Pcie Entries exceed the number of" | ||
515 | " GFXCLK Dpm Levels!" | ||
516 | " Disregarding the excess entries...\n"); | ||
517 | |||
518 | pcie_table->count = pcie_count; | ||
519 | |||
520 | for (i = 0; i < pcie_count; i++) { | ||
521 | pcie_table->entries[i].gen_speed = | ||
522 | atom_pcie_table->entries[i].ucPCIEGenSpeed; | ||
523 | pcie_table->entries[i].lane_width = | ||
524 | atom_pcie_table->entries[i].ucPCIELaneWidth; | ||
525 | pcie_table->entries[i].pcie_sclk = | ||
526 | atom_pcie_table->entries[i].ulLCLK; | ||
527 | } | ||
528 | |||
529 | *vega10_pcie_table = pcie_table; | ||
530 | |||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | static int get_hard_limits( | ||
535 | struct pp_hwmgr *hwmgr, | ||
536 | struct phm_clock_and_voltage_limits *limits, | ||
537 | const ATOM_Vega10_Hard_Limit_Table *limit_table) | ||
538 | { | ||
539 | PP_ASSERT_WITH_CODE(limit_table->ucNumEntries, | ||
540 | "Invalid PowerPlay Table!", return -1); | ||
541 | |||
542 | /* currently we always take entries[0] parameters */ | ||
543 | limits->sclk = le32_to_cpu(limit_table->entries[0].ulSOCCLKLimit); | ||
544 | limits->mclk = le32_to_cpu(limit_table->entries[0].ulMCLKLimit); | ||
545 | limits->gfxclk = le32_to_cpu(limit_table->entries[0].ulGFXCLKLimit); | ||
546 | limits->vddc = le16_to_cpu(limit_table->entries[0].usVddcLimit); | ||
547 | limits->vddci = le16_to_cpu(limit_table->entries[0].usVddciLimit); | ||
548 | limits->vddmem = le16_to_cpu(limit_table->entries[0].usVddMemLimit); | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | static int get_valid_clk( | ||
554 | struct pp_hwmgr *hwmgr, | ||
555 | struct phm_clock_array **clk_table, | ||
556 | const phm_ppt_v1_clock_voltage_dependency_table *clk_volt_pp_table) | ||
557 | { | ||
558 | uint32_t table_size, i; | ||
559 | struct phm_clock_array *table; | ||
560 | |||
561 | PP_ASSERT_WITH_CODE(clk_volt_pp_table->count, | ||
562 | "Invalid PowerPlay Table!", return -1); | ||
563 | |||
564 | table_size = sizeof(uint32_t) + | ||
565 | sizeof(uint32_t) * clk_volt_pp_table->count; | ||
566 | |||
567 | table = kzalloc(table_size, GFP_KERNEL); | ||
568 | |||
569 | if (!table) | ||
570 | return -ENOMEM; | ||
571 | |||
572 | table->count = (uint32_t)clk_volt_pp_table->count; | ||
573 | |||
574 | for (i = 0; i < table->count; i++) | ||
575 | table->values[i] = (uint32_t)clk_volt_pp_table->entries[i].clk; | ||
576 | |||
577 | *clk_table = table; | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | static int init_powerplay_extended_tables( | ||
583 | struct pp_hwmgr *hwmgr, | ||
584 | const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) | ||
585 | { | ||
586 | int result = 0; | ||
587 | struct phm_ppt_v2_information *pp_table_info = | ||
588 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
589 | |||
590 | const ATOM_Vega10_MM_Dependency_Table *mm_dependency_table = | ||
591 | (const ATOM_Vega10_MM_Dependency_Table *) | ||
592 | (((unsigned long) powerplay_table) + | ||
593 | le16_to_cpu(powerplay_table->usMMDependencyTableOffset)); | ||
594 | const Vega10_PPTable_Generic_SubTable_Header *power_tune_table = | ||
595 | (const Vega10_PPTable_Generic_SubTable_Header *) | ||
596 | (((unsigned long) powerplay_table) + | ||
597 | le16_to_cpu(powerplay_table->usPowerTuneTableOffset)); | ||
598 | const ATOM_Vega10_SOCCLK_Dependency_Table *socclk_dep_table = | ||
599 | (const ATOM_Vega10_SOCCLK_Dependency_Table *) | ||
600 | (((unsigned long) powerplay_table) + | ||
601 | le16_to_cpu(powerplay_table->usSocclkDependencyTableOffset)); | ||
602 | const ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table = | ||
603 | (const ATOM_Vega10_GFXCLK_Dependency_Table *) | ||
604 | (((unsigned long) powerplay_table) + | ||
605 | le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset)); | ||
606 | const ATOM_Vega10_DCEFCLK_Dependency_Table *dcefclk_dep_table = | ||
607 | (const ATOM_Vega10_DCEFCLK_Dependency_Table *) | ||
608 | (((unsigned long) powerplay_table) + | ||
609 | le16_to_cpu(powerplay_table->usDcefclkDependencyTableOffset)); | ||
610 | const ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table = | ||
611 | (const ATOM_Vega10_MCLK_Dependency_Table *) | ||
612 | (((unsigned long) powerplay_table) + | ||
613 | le16_to_cpu(powerplay_table->usMclkDependencyTableOffset)); | ||
614 | const ATOM_Vega10_Hard_Limit_Table *hard_limits = | ||
615 | (const ATOM_Vega10_Hard_Limit_Table *) | ||
616 | (((unsigned long) powerplay_table) + | ||
617 | le16_to_cpu(powerplay_table->usHardLimitTableOffset)); | ||
618 | const Vega10_PPTable_Generic_SubTable_Header *pcie_table = | ||
619 | (const Vega10_PPTable_Generic_SubTable_Header *) | ||
620 | (((unsigned long) powerplay_table) + | ||
621 | le16_to_cpu(powerplay_table->usPCIETableOffset)); | ||
622 | const ATOM_Vega10_PIXCLK_Dependency_Table *pixclk_dep_table = | ||
623 | (const ATOM_Vega10_PIXCLK_Dependency_Table *) | ||
624 | (((unsigned long) powerplay_table) + | ||
625 | le16_to_cpu(powerplay_table->usPixclkDependencyTableOffset)); | ||
626 | const ATOM_Vega10_PHYCLK_Dependency_Table *phyclk_dep_table = | ||
627 | (const ATOM_Vega10_PHYCLK_Dependency_Table *) | ||
628 | (((unsigned long) powerplay_table) + | ||
629 | le16_to_cpu(powerplay_table->usPhyClkDependencyTableOffset)); | ||
630 | const ATOM_Vega10_DISPCLK_Dependency_Table *dispclk_dep_table = | ||
631 | (const ATOM_Vega10_DISPCLK_Dependency_Table *) | ||
632 | (((unsigned long) powerplay_table) + | ||
633 | le16_to_cpu(powerplay_table->usDispClkDependencyTableOffset)); | ||
634 | |||
635 | pp_table_info->vdd_dep_on_socclk = NULL; | ||
636 | pp_table_info->vdd_dep_on_sclk = NULL; | ||
637 | pp_table_info->vdd_dep_on_mclk = NULL; | ||
638 | pp_table_info->vdd_dep_on_dcefclk = NULL; | ||
639 | pp_table_info->mm_dep_table = NULL; | ||
640 | pp_table_info->tdp_table = NULL; | ||
641 | pp_table_info->vdd_dep_on_pixclk = NULL; | ||
642 | pp_table_info->vdd_dep_on_phyclk = NULL; | ||
643 | pp_table_info->vdd_dep_on_dispclk = NULL; | ||
644 | |||
645 | if (powerplay_table->usMMDependencyTableOffset) | ||
646 | result = get_mm_clock_voltage_table(hwmgr, | ||
647 | &pp_table_info->mm_dep_table, | ||
648 | mm_dependency_table); | ||
649 | |||
650 | if (!result && powerplay_table->usPowerTuneTableOffset) | ||
651 | result = get_tdp_table(hwmgr, | ||
652 | &pp_table_info->tdp_table, | ||
653 | power_tune_table); | ||
654 | |||
655 | if (!result && powerplay_table->usSocclkDependencyTableOffset) | ||
656 | result = get_socclk_voltage_dependency_table(hwmgr, | ||
657 | &pp_table_info->vdd_dep_on_socclk, | ||
658 | socclk_dep_table); | ||
659 | |||
660 | if (!result && powerplay_table->usGfxclkDependencyTableOffset) | ||
661 | result = get_gfxclk_voltage_dependency_table(hwmgr, | ||
662 | &pp_table_info->vdd_dep_on_sclk, | ||
663 | gfxclk_dep_table); | ||
664 | |||
665 | if (!result && powerplay_table->usPixclkDependencyTableOffset) | ||
666 | result = get_dcefclk_voltage_dependency_table(hwmgr, | ||
667 | &pp_table_info->vdd_dep_on_pixclk, | ||
668 | (const ATOM_Vega10_DCEFCLK_Dependency_Table*) | ||
669 | pixclk_dep_table); | ||
670 | |||
671 | if (!result && powerplay_table->usPhyClkDependencyTableOffset) | ||
672 | result = get_dcefclk_voltage_dependency_table(hwmgr, | ||
673 | &pp_table_info->vdd_dep_on_phyclk, | ||
674 | (const ATOM_Vega10_DCEFCLK_Dependency_Table *) | ||
675 | phyclk_dep_table); | ||
676 | |||
677 | if (!result && powerplay_table->usDispClkDependencyTableOffset) | ||
678 | result = get_dcefclk_voltage_dependency_table(hwmgr, | ||
679 | &pp_table_info->vdd_dep_on_dispclk, | ||
680 | (const ATOM_Vega10_DCEFCLK_Dependency_Table *) | ||
681 | dispclk_dep_table); | ||
682 | |||
683 | if (!result && powerplay_table->usDcefclkDependencyTableOffset) | ||
684 | result = get_dcefclk_voltage_dependency_table(hwmgr, | ||
685 | &pp_table_info->vdd_dep_on_dcefclk, | ||
686 | dcefclk_dep_table); | ||
687 | |||
688 | if (!result && powerplay_table->usMclkDependencyTableOffset) | ||
689 | result = get_mclk_voltage_dependency_table(hwmgr, | ||
690 | &pp_table_info->vdd_dep_on_mclk, | ||
691 | mclk_dep_table); | ||
692 | |||
693 | if (!result && powerplay_table->usPCIETableOffset) | ||
694 | result = get_pcie_table(hwmgr, | ||
695 | &pp_table_info->pcie_table, | ||
696 | pcie_table); | ||
697 | |||
698 | if (!result && powerplay_table->usHardLimitTableOffset) | ||
699 | result = get_hard_limits(hwmgr, | ||
700 | &pp_table_info->max_clock_voltage_on_dc, | ||
701 | hard_limits); | ||
702 | |||
703 | hwmgr->dyn_state.max_clock_voltage_on_dc.sclk = | ||
704 | pp_table_info->max_clock_voltage_on_dc.sclk; | ||
705 | hwmgr->dyn_state.max_clock_voltage_on_dc.mclk = | ||
706 | pp_table_info->max_clock_voltage_on_dc.mclk; | ||
707 | hwmgr->dyn_state.max_clock_voltage_on_dc.vddc = | ||
708 | pp_table_info->max_clock_voltage_on_dc.vddc; | ||
709 | hwmgr->dyn_state.max_clock_voltage_on_dc.vddci = | ||
710 | pp_table_info->max_clock_voltage_on_dc.vddci; | ||
711 | |||
712 | if (!result && | ||
713 | pp_table_info->vdd_dep_on_socclk && | ||
714 | pp_table_info->vdd_dep_on_socclk->count) | ||
715 | result = get_valid_clk(hwmgr, | ||
716 | &pp_table_info->valid_socclk_values, | ||
717 | pp_table_info->vdd_dep_on_socclk); | ||
718 | |||
719 | if (!result && | ||
720 | pp_table_info->vdd_dep_on_sclk && | ||
721 | pp_table_info->vdd_dep_on_sclk->count) | ||
722 | result = get_valid_clk(hwmgr, | ||
723 | &pp_table_info->valid_sclk_values, | ||
724 | pp_table_info->vdd_dep_on_sclk); | ||
725 | |||
726 | if (!result && | ||
727 | pp_table_info->vdd_dep_on_dcefclk && | ||
728 | pp_table_info->vdd_dep_on_dcefclk->count) | ||
729 | result = get_valid_clk(hwmgr, | ||
730 | &pp_table_info->valid_dcefclk_values, | ||
731 | pp_table_info->vdd_dep_on_dcefclk); | ||
732 | |||
733 | if (!result && | ||
734 | pp_table_info->vdd_dep_on_mclk && | ||
735 | pp_table_info->vdd_dep_on_mclk->count) | ||
736 | result = get_valid_clk(hwmgr, | ||
737 | &pp_table_info->valid_mclk_values, | ||
738 | pp_table_info->vdd_dep_on_mclk); | ||
739 | |||
740 | return result; | ||
741 | } | ||
742 | |||
743 | static int get_vddc_lookup_table( | ||
744 | struct pp_hwmgr *hwmgr, | ||
745 | phm_ppt_v1_voltage_lookup_table **lookup_table, | ||
746 | const ATOM_Vega10_Voltage_Lookup_Table *vddc_lookup_pp_tables, | ||
747 | uint32_t max_levels) | ||
748 | { | ||
749 | uint32_t table_size, i; | ||
750 | phm_ppt_v1_voltage_lookup_table *table; | ||
751 | |||
752 | PP_ASSERT_WITH_CODE((vddc_lookup_pp_tables->ucNumEntries != 0), | ||
753 | "Invalid SOC_VDDD Lookup Table!", return 1); | ||
754 | |||
755 | table_size = sizeof(uint32_t) + | ||
756 | sizeof(phm_ppt_v1_voltage_lookup_record) * max_levels; | ||
757 | |||
758 | table = (phm_ppt_v1_voltage_lookup_table *) | ||
759 | kzalloc(table_size, GFP_KERNEL); | ||
760 | |||
761 | if (NULL == table) | ||
762 | return -ENOMEM; | ||
763 | |||
764 | table->count = vddc_lookup_pp_tables->ucNumEntries; | ||
765 | |||
766 | for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) | ||
767 | table->entries[i].us_vdd = | ||
768 | le16_to_cpu(vddc_lookup_pp_tables->entries[i].usVdd); | ||
769 | |||
770 | *lookup_table = table; | ||
771 | |||
772 | return 0; | ||
773 | } | ||
774 | |||
775 | static int init_dpm_2_parameters( | ||
776 | struct pp_hwmgr *hwmgr, | ||
777 | const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) | ||
778 | { | ||
779 | int result = 0; | ||
780 | struct phm_ppt_v2_information *pp_table_info = | ||
781 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
782 | uint32_t disable_power_control = 0; | ||
783 | |||
784 | pp_table_info->us_ulv_voltage_offset = | ||
785 | le16_to_cpu(powerplay_table->usUlvVoltageOffset); | ||
786 | |||
787 | pp_table_info->us_ulv_smnclk_did = | ||
788 | le16_to_cpu(powerplay_table->usUlvSmnclkDid); | ||
789 | pp_table_info->us_ulv_mp1clk_did = | ||
790 | le16_to_cpu(powerplay_table->usUlvMp1clkDid); | ||
791 | pp_table_info->us_ulv_gfxclk_bypass = | ||
792 | le16_to_cpu(powerplay_table->usUlvGfxclkBypass); | ||
793 | pp_table_info->us_gfxclk_slew_rate = | ||
794 | le16_to_cpu(powerplay_table->usGfxclkSlewRate); | ||
795 | pp_table_info->uc_gfx_dpm_voltage_mode = | ||
796 | le16_to_cpu(powerplay_table->ucGfxVoltageMode); | ||
797 | pp_table_info->uc_soc_dpm_voltage_mode = | ||
798 | le16_to_cpu(powerplay_table->ucSocVoltageMode); | ||
799 | pp_table_info->uc_uclk_dpm_voltage_mode = | ||
800 | le16_to_cpu(powerplay_table->ucUclkVoltageMode); | ||
801 | pp_table_info->uc_uvd_dpm_voltage_mode = | ||
802 | le16_to_cpu(powerplay_table->ucUvdVoltageMode); | ||
803 | pp_table_info->uc_vce_dpm_voltage_mode = | ||
804 | le16_to_cpu(powerplay_table->ucVceVoltageMode); | ||
805 | pp_table_info->uc_mp0_dpm_voltage_mode = | ||
806 | le16_to_cpu(powerplay_table->ucMp0VoltageMode); | ||
807 | pp_table_info->uc_dcef_dpm_voltage_mode = | ||
808 | le16_to_cpu(powerplay_table->ucDcefVoltageMode); | ||
809 | |||
810 | pp_table_info->ppm_parameter_table = NULL; | ||
811 | pp_table_info->vddc_lookup_table = NULL; | ||
812 | pp_table_info->vddmem_lookup_table = NULL; | ||
813 | pp_table_info->vddci_lookup_table = NULL; | ||
814 | |||
815 | /* TDP limits */ | ||
816 | hwmgr->platform_descriptor.TDPODLimit = | ||
817 | le16_to_cpu(powerplay_table->usPowerControlLimit); | ||
818 | hwmgr->platform_descriptor.TDPAdjustment = 0; | ||
819 | hwmgr->platform_descriptor.VidAdjustment = 0; | ||
820 | hwmgr->platform_descriptor.VidAdjustmentPolarity = 0; | ||
821 | hwmgr->platform_descriptor.VidMinLimit = 0; | ||
822 | hwmgr->platform_descriptor.VidMaxLimit = 1500000; | ||
823 | hwmgr->platform_descriptor.VidStep = 6250; | ||
824 | |||
825 | disable_power_control = 0; | ||
826 | if (!disable_power_control) { | ||
827 | /* enable TDP overdrive (PowerControl) feature as well if supported */ | ||
828 | if (hwmgr->platform_descriptor.TDPODLimit) | ||
829 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
830 | PHM_PlatformCaps_PowerControl); | ||
831 | } | ||
832 | |||
833 | if (powerplay_table->usVddcLookupTableOffset) { | ||
834 | const ATOM_Vega10_Voltage_Lookup_Table *vddc_table = | ||
835 | (ATOM_Vega10_Voltage_Lookup_Table *) | ||
836 | (((unsigned long)powerplay_table) + | ||
837 | le16_to_cpu(powerplay_table->usVddcLookupTableOffset)); | ||
838 | result = get_vddc_lookup_table(hwmgr, | ||
839 | &pp_table_info->vddc_lookup_table, vddc_table, 16); | ||
840 | } | ||
841 | |||
842 | if (powerplay_table->usVddmemLookupTableOffset) { | ||
843 | const ATOM_Vega10_Voltage_Lookup_Table *vdd_mem_table = | ||
844 | (ATOM_Vega10_Voltage_Lookup_Table *) | ||
845 | (((unsigned long)powerplay_table) + | ||
846 | le16_to_cpu(powerplay_table->usVddmemLookupTableOffset)); | ||
847 | result = get_vddc_lookup_table(hwmgr, | ||
848 | &pp_table_info->vddmem_lookup_table, vdd_mem_table, 16); | ||
849 | } | ||
850 | |||
851 | if (powerplay_table->usVddciLookupTableOffset) { | ||
852 | const ATOM_Vega10_Voltage_Lookup_Table *vddci_table = | ||
853 | (ATOM_Vega10_Voltage_Lookup_Table *) | ||
854 | (((unsigned long)powerplay_table) + | ||
855 | le16_to_cpu(powerplay_table->usVddciLookupTableOffset)); | ||
856 | result = get_vddc_lookup_table(hwmgr, | ||
857 | &pp_table_info->vddci_lookup_table, vddci_table, 16); | ||
858 | } | ||
859 | |||
860 | return result; | ||
861 | } | ||
862 | |||
863 | int vega10_pp_tables_initialize(struct pp_hwmgr *hwmgr) | ||
864 | { | ||
865 | int result = 0; | ||
866 | const ATOM_Vega10_POWERPLAYTABLE *powerplay_table; | ||
867 | |||
868 | hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v2_information), GFP_KERNEL); | ||
869 | |||
870 | PP_ASSERT_WITH_CODE((NULL != hwmgr->pptable), | ||
871 | "Failed to allocate hwmgr->pptable!", return -ENOMEM); | ||
872 | |||
873 | powerplay_table = get_powerplay_table(hwmgr); | ||
874 | |||
875 | PP_ASSERT_WITH_CODE((NULL != powerplay_table), | ||
876 | "Missing PowerPlay Table!", return -1); | ||
877 | |||
878 | result = check_powerplay_tables(hwmgr, powerplay_table); | ||
879 | |||
880 | PP_ASSERT_WITH_CODE((result == 0), | ||
881 | "check_powerplay_tables failed", return result); | ||
882 | |||
883 | result = set_platform_caps(hwmgr, | ||
884 | le32_to_cpu(powerplay_table->ulPlatformCaps)); | ||
885 | |||
886 | PP_ASSERT_WITH_CODE((result == 0), | ||
887 | "set_platform_caps failed", return result); | ||
888 | |||
889 | result = init_thermal_controller(hwmgr, powerplay_table); | ||
890 | |||
891 | PP_ASSERT_WITH_CODE((result == 0), | ||
892 | "init_thermal_controller failed", return result); | ||
893 | |||
894 | result = init_over_drive_limits(hwmgr, powerplay_table); | ||
895 | |||
896 | PP_ASSERT_WITH_CODE((result == 0), | ||
897 | "init_over_drive_limits failed", return result); | ||
898 | |||
899 | result = init_powerplay_extended_tables(hwmgr, powerplay_table); | ||
900 | |||
901 | PP_ASSERT_WITH_CODE((result == 0), | ||
902 | "init_powerplay_extended_tables failed", return result); | ||
903 | |||
904 | result = init_dpm_2_parameters(hwmgr, powerplay_table); | ||
905 | |||
906 | PP_ASSERT_WITH_CODE((result == 0), | ||
907 | "init_dpm_2_parameters failed", return result); | ||
908 | |||
909 | return result; | ||
910 | } | ||
911 | |||
912 | static int vega10_pp_tables_uninitialize(struct pp_hwmgr *hwmgr) | ||
913 | { | ||
914 | int result = 0; | ||
915 | struct phm_ppt_v2_information *pp_table_info = | ||
916 | (struct phm_ppt_v2_information *)(hwmgr->pptable); | ||
917 | |||
918 | kfree(pp_table_info->vdd_dep_on_sclk); | ||
919 | pp_table_info->vdd_dep_on_sclk = NULL; | ||
920 | |||
921 | kfree(pp_table_info->vdd_dep_on_mclk); | ||
922 | pp_table_info->vdd_dep_on_mclk = NULL; | ||
923 | |||
924 | kfree(pp_table_info->valid_mclk_values); | ||
925 | pp_table_info->valid_mclk_values = NULL; | ||
926 | |||
927 | kfree(pp_table_info->valid_sclk_values); | ||
928 | pp_table_info->valid_sclk_values = NULL; | ||
929 | |||
930 | kfree(pp_table_info->vddc_lookup_table); | ||
931 | pp_table_info->vddc_lookup_table = NULL; | ||
932 | |||
933 | kfree(pp_table_info->vddmem_lookup_table); | ||
934 | pp_table_info->vddmem_lookup_table = NULL; | ||
935 | |||
936 | kfree(pp_table_info->vddci_lookup_table); | ||
937 | pp_table_info->vddci_lookup_table = NULL; | ||
938 | |||
939 | kfree(pp_table_info->ppm_parameter_table); | ||
940 | pp_table_info->ppm_parameter_table = NULL; | ||
941 | |||
942 | kfree(pp_table_info->mm_dep_table); | ||
943 | pp_table_info->mm_dep_table = NULL; | ||
944 | |||
945 | kfree(pp_table_info->cac_dtp_table); | ||
946 | pp_table_info->cac_dtp_table = NULL; | ||
947 | |||
948 | kfree(hwmgr->dyn_state.cac_dtp_table); | ||
949 | hwmgr->dyn_state.cac_dtp_table = NULL; | ||
950 | |||
951 | kfree(pp_table_info->tdp_table); | ||
952 | pp_table_info->tdp_table = NULL; | ||
953 | |||
954 | kfree(hwmgr->pptable); | ||
955 | hwmgr->pptable = NULL; | ||
956 | |||
957 | return result; | ||
958 | } | ||
959 | |||
960 | const struct pp_table_func vega10_pptable_funcs = { | ||
961 | .pptable_init = vega10_pp_tables_initialize, | ||
962 | .pptable_fini = vega10_pp_tables_uninitialize, | ||
963 | }; | ||
964 | |||
965 | int vega10_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr) | ||
966 | { | ||
967 | const ATOM_Vega10_State_Array *state_arrays; | ||
968 | const ATOM_Vega10_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr); | ||
969 | |||
970 | PP_ASSERT_WITH_CODE((NULL != pp_table), | ||
971 | "Missing PowerPlay Table!", return -1); | ||
972 | PP_ASSERT_WITH_CODE((pp_table->sHeader.format_revision >= | ||
973 | ATOM_Vega10_TABLE_REVISION_VEGA10), | ||
974 | "Incorrect PowerPlay table revision!", return -1); | ||
975 | |||
976 | state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)pp_table) + | ||
977 | le16_to_cpu(pp_table->usStateArrayOffset)); | ||
978 | |||
979 | return (uint32_t)(state_arrays->ucNumEntries); | ||
980 | } | ||
981 | |||
982 | static uint32_t make_classification_flags(struct pp_hwmgr *hwmgr, | ||
983 | uint16_t classification, uint16_t classification2) | ||
984 | { | ||
985 | uint32_t result = 0; | ||
986 | |||
987 | if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT) | ||
988 | result |= PP_StateClassificationFlag_Boot; | ||
989 | |||
990 | if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL) | ||
991 | result |= PP_StateClassificationFlag_Thermal; | ||
992 | |||
993 | if (classification & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE) | ||
994 | result |= PP_StateClassificationFlag_LimitedPowerSource; | ||
995 | |||
996 | if (classification & ATOM_PPLIB_CLASSIFICATION_REST) | ||
997 | result |= PP_StateClassificationFlag_Rest; | ||
998 | |||
999 | if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED) | ||
1000 | result |= PP_StateClassificationFlag_Forced; | ||
1001 | |||
1002 | if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI) | ||
1003 | result |= PP_StateClassificationFlag_ACPI; | ||
1004 | |||
1005 | if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2) | ||
1006 | result |= PP_StateClassificationFlag_LimitedPowerSource_2; | ||
1007 | |||
1008 | return result; | ||
1009 | } | ||
1010 | |||
1011 | int vega10_get_powerplay_table_entry(struct pp_hwmgr *hwmgr, | ||
1012 | uint32_t entry_index, struct pp_power_state *power_state, | ||
1013 | int (*call_back_func)(struct pp_hwmgr *, void *, | ||
1014 | struct pp_power_state *, void *, uint32_t)) | ||
1015 | { | ||
1016 | int result = 0; | ||
1017 | const ATOM_Vega10_State_Array *state_arrays; | ||
1018 | const ATOM_Vega10_State *state_entry; | ||
1019 | const ATOM_Vega10_POWERPLAYTABLE *pp_table = | ||
1020 | get_powerplay_table(hwmgr); | ||
1021 | |||
1022 | PP_ASSERT_WITH_CODE(pp_table, "Missing PowerPlay Table!", | ||
1023 | return -1;); | ||
1024 | power_state->classification.bios_index = entry_index; | ||
1025 | |||
1026 | if (pp_table->sHeader.format_revision >= | ||
1027 | ATOM_Vega10_TABLE_REVISION_VEGA10) { | ||
1028 | state_arrays = (ATOM_Vega10_State_Array *) | ||
1029 | (((unsigned long)pp_table) + | ||
1030 | le16_to_cpu(pp_table->usStateArrayOffset)); | ||
1031 | |||
1032 | PP_ASSERT_WITH_CODE(pp_table->usStateArrayOffset > 0, | ||
1033 | "Invalid PowerPlay Table State Array Offset.", | ||
1034 | return -1); | ||
1035 | PP_ASSERT_WITH_CODE(state_arrays->ucNumEntries > 0, | ||
1036 | "Invalid PowerPlay Table State Array.", | ||
1037 | return -1); | ||
1038 | PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries), | ||
1039 | "Invalid PowerPlay Table State Array Entry.", | ||
1040 | return -1); | ||
1041 | |||
1042 | state_entry = &(state_arrays->states[entry_index]); | ||
1043 | |||
1044 | result = call_back_func(hwmgr, (void *)state_entry, power_state, | ||
1045 | (void *)pp_table, | ||
1046 | make_classification_flags(hwmgr, | ||
1047 | le16_to_cpu(state_entry->usClassification), | ||
1048 | le16_to_cpu(state_entry->usClassification2))); | ||
1049 | } | ||
1050 | |||
1051 | if (!result && (power_state->classification.flags & | ||
1052 | PP_StateClassificationFlag_Boot)) | ||
1053 | result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(power_state->hardware)); | ||
1054 | |||
1055 | return result; | ||
1056 | } | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.h new file mode 100644 index 000000000000..995d133ba6aa --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef VEGA10_PROCESSPPTABLES_H | ||
25 | #define VEGA10_PROCESSPPTABLES_H | ||
26 | |||
27 | #include "hwmgr.h" | ||
28 | |||
29 | extern const struct pp_table_func vega10_pptable_funcs; | ||
30 | extern int vega10_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr); | ||
31 | extern int vega10_get_powerplay_table_entry(struct pp_hwmgr *hwmgr, uint32_t entry_index, | ||
32 | struct pp_power_state *power_state, int (*call_back_func)(struct pp_hwmgr *, void *, | ||
33 | struct pp_power_state *, void *, uint32_t)); | ||
34 | #endif | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c new file mode 100644 index 000000000000..f4d77b62e1ba --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c | |||
@@ -0,0 +1,761 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "vega10_thermal.h" | ||
25 | #include "vega10_hwmgr.h" | ||
26 | #include "vega10_smumgr.h" | ||
27 | #include "vega10_ppsmc.h" | ||
28 | #include "vega10_inc.h" | ||
29 | #include "pp_soc15.h" | ||
30 | #include "pp_debug.h" | ||
31 | |||
32 | static int vega10_get_current_rpm(struct pp_hwmgr *hwmgr, uint32_t *current_rpm) | ||
33 | { | ||
34 | PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr->smumgr, | ||
35 | PPSMC_MSG_GetCurrentRpm), | ||
36 | "Attempt to get current RPM from SMC Failed!", | ||
37 | return -1); | ||
38 | PP_ASSERT_WITH_CODE(!vega10_read_arg_from_smc(hwmgr->smumgr, | ||
39 | current_rpm), | ||
40 | "Attempt to read current RPM from SMC Failed!", | ||
41 | return -1); | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | int vega10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, | ||
46 | struct phm_fan_speed_info *fan_speed_info) | ||
47 | { | ||
48 | |||
49 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | ||
50 | return 0; | ||
51 | |||
52 | fan_speed_info->supports_percent_read = true; | ||
53 | fan_speed_info->supports_percent_write = true; | ||
54 | fan_speed_info->min_percent = 0; | ||
55 | fan_speed_info->max_percent = 100; | ||
56 | |||
57 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
58 | PHM_PlatformCaps_FanSpeedInTableIsRPM) && | ||
59 | hwmgr->thermal_controller.fanInfo. | ||
60 | ucTachometerPulsesPerRevolution) { | ||
61 | fan_speed_info->supports_rpm_read = true; | ||
62 | fan_speed_info->supports_rpm_write = true; | ||
63 | fan_speed_info->min_rpm = | ||
64 | hwmgr->thermal_controller.fanInfo.ulMinRPM; | ||
65 | fan_speed_info->max_rpm = | ||
66 | hwmgr->thermal_controller.fanInfo.ulMaxRPM; | ||
67 | } else { | ||
68 | fan_speed_info->min_rpm = 0; | ||
69 | fan_speed_info->max_rpm = 0; | ||
70 | } | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | int vega10_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, | ||
76 | uint32_t *speed) | ||
77 | { | ||
78 | uint32_t current_rpm; | ||
79 | uint32_t percent = 0; | ||
80 | |||
81 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | ||
82 | return 0; | ||
83 | |||
84 | if (vega10_get_current_rpm(hwmgr, ¤t_rpm)) | ||
85 | return -1; | ||
86 | |||
87 | if (hwmgr->thermal_controller. | ||
88 | advanceFanControlParameters.usMaxFanRPM != 0) | ||
89 | percent = current_rpm * 100 / | ||
90 | hwmgr->thermal_controller. | ||
91 | advanceFanControlParameters.usMaxFanRPM; | ||
92 | |||
93 | *speed = percent > 100 ? 100 : percent; | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | int vega10_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed) | ||
99 | { | ||
100 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
101 | uint32_t tach_period; | ||
102 | uint32_t crystal_clock_freq; | ||
103 | int result = 0; | ||
104 | |||
105 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | ||
106 | return -1; | ||
107 | |||
108 | if (data->smu_features[GNLD_FAN_CONTROL].supported) | ||
109 | result = vega10_get_current_rpm(hwmgr, speed); | ||
110 | else { | ||
111 | uint32_t reg = soc15_get_register_offset(THM_HWID, 0, | ||
112 | mmCG_TACH_STATUS_BASE_IDX, mmCG_TACH_STATUS); | ||
113 | tach_period = (cgs_read_register(hwmgr->device, | ||
114 | reg) & CG_TACH_STATUS__TACH_PERIOD_MASK) >> | ||
115 | CG_TACH_STATUS__TACH_PERIOD__SHIFT; | ||
116 | |||
117 | if (tach_period == 0) | ||
118 | return -EINVAL; | ||
119 | |||
120 | crystal_clock_freq = smu7_get_xclk(hwmgr); | ||
121 | |||
122 | *speed = 60 * crystal_clock_freq * 10000 / tach_period; | ||
123 | } | ||
124 | |||
125 | return result; | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * Set Fan Speed Control to static mode, | ||
130 | * so that the user can decide what speed to use. | ||
131 | * @param hwmgr the address of the powerplay hardware manager. | ||
132 | * mode the fan control mode, 0 default, 1 by percent, 5, by RPM | ||
133 | * @exception Should always succeed. | ||
134 | */ | ||
135 | int vega10_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode) | ||
136 | { | ||
137 | uint32_t reg; | ||
138 | |||
139 | reg = soc15_get_register_offset(THM_HWID, 0, | ||
140 | mmCG_FDO_CTRL2_BASE_IDX, mmCG_FDO_CTRL2); | ||
141 | |||
142 | if (hwmgr->fan_ctrl_is_in_default_mode) { | ||
143 | hwmgr->fan_ctrl_default_mode = | ||
144 | (cgs_read_register(hwmgr->device, reg) & | ||
145 | CG_FDO_CTRL2__FDO_PWM_MODE_MASK) >> | ||
146 | CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT; | ||
147 | hwmgr->tmin = (cgs_read_register(hwmgr->device, reg) & | ||
148 | CG_FDO_CTRL2__TMIN_MASK) >> | ||
149 | CG_FDO_CTRL2__TMIN__SHIFT; | ||
150 | hwmgr->fan_ctrl_is_in_default_mode = false; | ||
151 | } | ||
152 | |||
153 | cgs_write_register(hwmgr->device, reg, | ||
154 | (cgs_read_register(hwmgr->device, reg) & | ||
155 | ~CG_FDO_CTRL2__TMIN_MASK) | | ||
156 | (0 << CG_FDO_CTRL2__TMIN__SHIFT)); | ||
157 | cgs_write_register(hwmgr->device, reg, | ||
158 | (cgs_read_register(hwmgr->device, reg) & | ||
159 | ~CG_FDO_CTRL2__FDO_PWM_MODE_MASK) | | ||
160 | (mode << CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT)); | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * Reset Fan Speed Control to default mode. | ||
167 | * @param hwmgr the address of the powerplay hardware manager. | ||
168 | * @exception Should always succeed. | ||
169 | */ | ||
170 | int vega10_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr) | ||
171 | { | ||
172 | uint32_t reg; | ||
173 | |||
174 | reg = soc15_get_register_offset(THM_HWID, 0, | ||
175 | mmCG_FDO_CTRL2_BASE_IDX, mmCG_FDO_CTRL2); | ||
176 | |||
177 | if (!hwmgr->fan_ctrl_is_in_default_mode) { | ||
178 | cgs_write_register(hwmgr->device, reg, | ||
179 | (cgs_read_register(hwmgr->device, reg) & | ||
180 | ~CG_FDO_CTRL2__FDO_PWM_MODE_MASK) | | ||
181 | (hwmgr->fan_ctrl_default_mode << | ||
182 | CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT)); | ||
183 | cgs_write_register(hwmgr->device, reg, | ||
184 | (cgs_read_register(hwmgr->device, reg) & | ||
185 | ~CG_FDO_CTRL2__TMIN_MASK) | | ||
186 | (hwmgr->tmin << CG_FDO_CTRL2__TMIN__SHIFT)); | ||
187 | hwmgr->fan_ctrl_is_in_default_mode = true; | ||
188 | } | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | /** | ||
194 | * @fn vega10_enable_fan_control_feature | ||
195 | * @brief Enables the SMC Fan Control Feature. | ||
196 | * | ||
197 | * @param hwmgr - the address of the powerplay hardware manager. | ||
198 | * @return 0 on success. -1 otherwise. | ||
199 | */ | ||
200 | static int vega10_enable_fan_control_feature(struct pp_hwmgr *hwmgr) | ||
201 | { | ||
202 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
203 | |||
204 | if (data->smu_features[GNLD_FAN_CONTROL].supported) { | ||
205 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features( | ||
206 | hwmgr->smumgr, true, | ||
207 | data->smu_features[GNLD_FAN_CONTROL]. | ||
208 | smu_feature_bitmap), | ||
209 | "Attempt to Enable FAN CONTROL feature Failed!", | ||
210 | return -1); | ||
211 | data->smu_features[GNLD_FAN_CONTROL].enabled = true; | ||
212 | } | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static int vega10_disable_fan_control_feature(struct pp_hwmgr *hwmgr) | ||
218 | { | ||
219 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
220 | |||
221 | if (data->smu_features[GNLD_FAN_CONTROL].supported) { | ||
222 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features( | ||
223 | hwmgr->smumgr, false, | ||
224 | data->smu_features[GNLD_FAN_CONTROL]. | ||
225 | smu_feature_bitmap), | ||
226 | "Attempt to Enable FAN CONTROL feature Failed!", | ||
227 | return -1); | ||
228 | data->smu_features[GNLD_FAN_CONTROL].enabled = false; | ||
229 | } | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | int vega10_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr) | ||
235 | { | ||
236 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | ||
237 | return -1; | ||
238 | |||
239 | PP_ASSERT_WITH_CODE(!vega10_enable_fan_control_feature(hwmgr), | ||
240 | "Attempt to Enable SMC FAN CONTROL Feature Failed!", | ||
241 | return -1); | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | |||
247 | int vega10_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr) | ||
248 | { | ||
249 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
250 | |||
251 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | ||
252 | return -1; | ||
253 | |||
254 | if (data->smu_features[GNLD_FAN_CONTROL].supported) { | ||
255 | PP_ASSERT_WITH_CODE(!vega10_disable_fan_control_feature(hwmgr), | ||
256 | "Attempt to Disable SMC FAN CONTROL Feature Failed!", | ||
257 | return -1); | ||
258 | } | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | /** | ||
263 | * Set Fan Speed in percent. | ||
264 | * @param hwmgr the address of the powerplay hardware manager. | ||
265 | * @param speed is the percentage value (0% - 100%) to be set. | ||
266 | * @exception Fails is the 100% setting appears to be 0. | ||
267 | */ | ||
268 | int vega10_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, | ||
269 | uint32_t speed) | ||
270 | { | ||
271 | uint32_t duty100; | ||
272 | uint32_t duty; | ||
273 | uint64_t tmp64; | ||
274 | uint32_t reg; | ||
275 | |||
276 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | ||
277 | return 0; | ||
278 | |||
279 | if (speed > 100) | ||
280 | speed = 100; | ||
281 | |||
282 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
283 | PHM_PlatformCaps_MicrocodeFanControl)) | ||
284 | vega10_fan_ctrl_stop_smc_fan_control(hwmgr); | ||
285 | |||
286 | reg = soc15_get_register_offset(THM_HWID, 0, | ||
287 | mmCG_FDO_CTRL1_BASE_IDX, mmCG_FDO_CTRL1); | ||
288 | |||
289 | duty100 = (cgs_read_register(hwmgr->device, reg) & | ||
290 | CG_FDO_CTRL1__FMAX_DUTY100_MASK) >> | ||
291 | CG_FDO_CTRL1__FMAX_DUTY100__SHIFT; | ||
292 | |||
293 | if (duty100 == 0) | ||
294 | return -EINVAL; | ||
295 | |||
296 | tmp64 = (uint64_t)speed * duty100; | ||
297 | do_div(tmp64, 100); | ||
298 | duty = (uint32_t)tmp64; | ||
299 | |||
300 | reg = soc15_get_register_offset(THM_HWID, 0, | ||
301 | mmCG_FDO_CTRL0_BASE_IDX, mmCG_FDO_CTRL0); | ||
302 | cgs_write_register(hwmgr->device, reg, | ||
303 | (cgs_read_register(hwmgr->device, reg) & | ||
304 | ~CG_FDO_CTRL0__FDO_STATIC_DUTY_MASK) | | ||
305 | (duty << CG_FDO_CTRL0__FDO_STATIC_DUTY__SHIFT)); | ||
306 | |||
307 | return vega10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); | ||
308 | } | ||
309 | |||
310 | /** | ||
311 | * Reset Fan Speed to default. | ||
312 | * @param hwmgr the address of the powerplay hardware manager. | ||
313 | * @exception Always succeeds. | ||
314 | */ | ||
315 | int vega10_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr) | ||
316 | { | ||
317 | int result; | ||
318 | |||
319 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | ||
320 | return 0; | ||
321 | |||
322 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
323 | PHM_PlatformCaps_MicrocodeFanControl)) { | ||
324 | result = vega10_fan_ctrl_set_static_mode(hwmgr, | ||
325 | FDO_PWM_MODE_STATIC); | ||
326 | if (!result) | ||
327 | result = vega10_fan_ctrl_start_smc_fan_control(hwmgr); | ||
328 | } else | ||
329 | result = vega10_fan_ctrl_set_default_mode(hwmgr); | ||
330 | |||
331 | return result; | ||
332 | } | ||
333 | |||
334 | /** | ||
335 | * Set Fan Speed in RPM. | ||
336 | * @param hwmgr the address of the powerplay hardware manager. | ||
337 | * @param speed is the percentage value (min - max) to be set. | ||
338 | * @exception Fails is the speed not lie between min and max. | ||
339 | */ | ||
340 | int vega10_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed) | ||
341 | { | ||
342 | uint32_t tach_period; | ||
343 | uint32_t crystal_clock_freq; | ||
344 | int result = 0; | ||
345 | uint32_t reg; | ||
346 | |||
347 | if (hwmgr->thermal_controller.fanInfo.bNoFan || | ||
348 | (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) || | ||
349 | (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM)) | ||
350 | return -1; | ||
351 | |||
352 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
353 | PHM_PlatformCaps_MicrocodeFanControl)) | ||
354 | result = vega10_fan_ctrl_stop_smc_fan_control(hwmgr); | ||
355 | |||
356 | if (!result) { | ||
357 | crystal_clock_freq = smu7_get_xclk(hwmgr); | ||
358 | tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed); | ||
359 | reg = soc15_get_register_offset(THM_HWID, 0, | ||
360 | mmCG_TACH_STATUS_BASE_IDX, mmCG_TACH_STATUS); | ||
361 | cgs_write_register(hwmgr->device, reg, | ||
362 | (cgs_read_register(hwmgr->device, reg) & | ||
363 | ~CG_TACH_STATUS__TACH_PERIOD_MASK) | | ||
364 | (tach_period << CG_TACH_STATUS__TACH_PERIOD__SHIFT)); | ||
365 | } | ||
366 | return vega10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC_RPM); | ||
367 | } | ||
368 | |||
369 | /** | ||
370 | * Reads the remote temperature from the SIslands thermal controller. | ||
371 | * | ||
372 | * @param hwmgr The address of the hardware manager. | ||
373 | */ | ||
374 | int vega10_thermal_get_temperature(struct pp_hwmgr *hwmgr) | ||
375 | { | ||
376 | int temp; | ||
377 | uint32_t reg; | ||
378 | |||
379 | reg = soc15_get_register_offset(THM_HWID, 0, | ||
380 | mmCG_TACH_STATUS_BASE_IDX, mmCG_MULT_THERMAL_STATUS); | ||
381 | |||
382 | temp = cgs_read_register(hwmgr->device, reg); | ||
383 | |||
384 | temp = (temp & CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >> | ||
385 | CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT; | ||
386 | |||
387 | /* Bit 9 means the reading is lower than the lowest usable value. */ | ||
388 | if (temp & 0x200) | ||
389 | temp = VEGA10_THERMAL_MAXIMUM_TEMP_READING; | ||
390 | else | ||
391 | temp = temp & 0x1ff; | ||
392 | |||
393 | temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | ||
394 | |||
395 | return temp; | ||
396 | } | ||
397 | |||
398 | /** | ||
399 | * Set the requested temperature range for high and low alert signals | ||
400 | * | ||
401 | * @param hwmgr The address of the hardware manager. | ||
402 | * @param range Temperature range to be programmed for | ||
403 | * high and low alert signals | ||
404 | * @exception PP_Result_BadInput if the input data is not valid. | ||
405 | */ | ||
406 | static int vega10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, | ||
407 | struct PP_TemperatureRange *range) | ||
408 | { | ||
409 | uint32_t low = VEGA10_THERMAL_MINIMUM_ALERT_TEMP * | ||
410 | PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | ||
411 | uint32_t high = VEGA10_THERMAL_MAXIMUM_ALERT_TEMP * | ||
412 | PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | ||
413 | uint32_t val, reg; | ||
414 | |||
415 | if (low < range->min) | ||
416 | low = range->min; | ||
417 | if (high > range->max) | ||
418 | high = range->max; | ||
419 | |||
420 | if (low > high) | ||
421 | return -EINVAL; | ||
422 | |||
423 | reg = soc15_get_register_offset(THM_HWID, 0, | ||
424 | mmTHM_THERMAL_INT_CTRL_BASE_IDX, mmTHM_THERMAL_INT_CTRL); | ||
425 | |||
426 | val = cgs_read_register(hwmgr->device, reg); | ||
427 | val &= ~(THM_THERMAL_INT_CTRL__DIG_THERM_INTH_MASK); | ||
428 | val |= (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES) << | ||
429 | THM_THERMAL_INT_CTRL__DIG_THERM_INTH__SHIFT; | ||
430 | val &= ~(THM_THERMAL_INT_CTRL__DIG_THERM_INTL_MASK); | ||
431 | val |= (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES) << | ||
432 | THM_THERMAL_INT_CTRL__DIG_THERM_INTL__SHIFT; | ||
433 | cgs_write_register(hwmgr->device, reg, val); | ||
434 | |||
435 | reg = soc15_get_register_offset(THM_HWID, 0, | ||
436 | mmTHM_TCON_HTC_BASE_IDX, mmTHM_TCON_HTC); | ||
437 | |||
438 | val = cgs_read_register(hwmgr->device, reg); | ||
439 | val &= ~(THM_TCON_HTC__HTC_TMP_LMT_MASK); | ||
440 | val |= (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES) << | ||
441 | THM_TCON_HTC__HTC_TMP_LMT__SHIFT; | ||
442 | cgs_write_register(hwmgr->device, reg, val); | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * Programs thermal controller one-time setting registers | ||
449 | * | ||
450 | * @param hwmgr The address of the hardware manager. | ||
451 | */ | ||
452 | static int vega10_thermal_initialize(struct pp_hwmgr *hwmgr) | ||
453 | { | ||
454 | uint32_t reg; | ||
455 | |||
456 | if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) { | ||
457 | reg = soc15_get_register_offset(THM_HWID, 0, | ||
458 | mmCG_TACH_CTRL_BASE_IDX, mmCG_TACH_CTRL); | ||
459 | cgs_write_register(hwmgr->device, reg, | ||
460 | (cgs_read_register(hwmgr->device, reg) & | ||
461 | ~CG_TACH_CTRL__EDGE_PER_REV_MASK) | | ||
462 | ((hwmgr->thermal_controller.fanInfo. | ||
463 | ucTachometerPulsesPerRevolution - 1) << | ||
464 | CG_TACH_CTRL__EDGE_PER_REV__SHIFT)); | ||
465 | } | ||
466 | |||
467 | reg = soc15_get_register_offset(THM_HWID, 0, | ||
468 | mmCG_FDO_CTRL2_BASE_IDX, mmCG_FDO_CTRL2); | ||
469 | cgs_write_register(hwmgr->device, reg, | ||
470 | (cgs_read_register(hwmgr->device, reg) & | ||
471 | ~CG_FDO_CTRL2__TACH_PWM_RESP_RATE_MASK) | | ||
472 | (0x28 << CG_FDO_CTRL2__TACH_PWM_RESP_RATE__SHIFT)); | ||
473 | |||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | /** | ||
478 | * Enable thermal alerts on the RV770 thermal controller. | ||
479 | * | ||
480 | * @param hwmgr The address of the hardware manager. | ||
481 | */ | ||
482 | static int vega10_thermal_enable_alert(struct pp_hwmgr *hwmgr) | ||
483 | { | ||
484 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
485 | |||
486 | if (data->smu_features[GNLD_FW_CTF].supported) { | ||
487 | if (data->smu_features[GNLD_FW_CTF].enabled) | ||
488 | printk("[Thermal_EnableAlert] FW CTF Already Enabled!\n"); | ||
489 | } | ||
490 | |||
491 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
492 | true, | ||
493 | data->smu_features[GNLD_FW_CTF].smu_feature_bitmap), | ||
494 | "Attempt to Enable FW CTF feature Failed!", | ||
495 | return -1); | ||
496 | data->smu_features[GNLD_FW_CTF].enabled = true; | ||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | /** | ||
501 | * Disable thermal alerts on the RV770 thermal controller. | ||
502 | * @param hwmgr The address of the hardware manager. | ||
503 | */ | ||
504 | static int vega10_thermal_disable_alert(struct pp_hwmgr *hwmgr) | ||
505 | { | ||
506 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
507 | |||
508 | if (data->smu_features[GNLD_FW_CTF].supported) { | ||
509 | if (!data->smu_features[GNLD_FW_CTF].enabled) | ||
510 | printk("[Thermal_EnableAlert] FW CTF Already disabled!\n"); | ||
511 | } | ||
512 | |||
513 | PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr, | ||
514 | false, | ||
515 | data->smu_features[GNLD_FW_CTF].smu_feature_bitmap), | ||
516 | "Attempt to disable FW CTF feature Failed!", | ||
517 | return -1); | ||
518 | data->smu_features[GNLD_FW_CTF].enabled = false; | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | /** | ||
523 | * Uninitialize the thermal controller. | ||
524 | * Currently just disables alerts. | ||
525 | * @param hwmgr The address of the hardware manager. | ||
526 | */ | ||
527 | int vega10_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr) | ||
528 | { | ||
529 | int result = vega10_thermal_disable_alert(hwmgr); | ||
530 | |||
531 | if (!hwmgr->thermal_controller.fanInfo.bNoFan) | ||
532 | vega10_fan_ctrl_set_default_mode(hwmgr); | ||
533 | |||
534 | return result; | ||
535 | } | ||
536 | |||
537 | /** | ||
538 | * Set up the fan table to control the fan using the SMC. | ||
539 | * @param hwmgr the address of the powerplay hardware manager. | ||
540 | * @param pInput the pointer to input data | ||
541 | * @param pOutput the pointer to output data | ||
542 | * @param pStorage the pointer to temporary storage | ||
543 | * @param Result the last failure code | ||
544 | * @return result from set temperature range routine | ||
545 | */ | ||
546 | int tf_vega10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr, | ||
547 | void *input, void *output, void *storage, int result) | ||
548 | { | ||
549 | int ret; | ||
550 | struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); | ||
551 | PPTable_t *table = &(data->smc_state_table.pp_table); | ||
552 | |||
553 | if (!data->smu_features[GNLD_FAN_CONTROL].supported) | ||
554 | return 0; | ||
555 | |||
556 | table->FanMaximumRpm = (uint16_t)hwmgr->thermal_controller. | ||
557 | advanceFanControlParameters.usMaxFanRPM; | ||
558 | table->FanThrottlingRpm = hwmgr->thermal_controller. | ||
559 | advanceFanControlParameters.usFanRPMMaxLimit; | ||
560 | table->FanAcousticLimitRpm = (uint16_t)(hwmgr->thermal_controller. | ||
561 | advanceFanControlParameters.ulMinFanSCLKAcousticLimit); | ||
562 | table->FanTargetTemperature = hwmgr->thermal_controller. | ||
563 | advanceFanControlParameters.usTMax; | ||
564 | table->FanPwmMin = hwmgr->thermal_controller. | ||
565 | advanceFanControlParameters.usPWMMin * 255 / 100; | ||
566 | table->FanTargetGfxclk = (uint16_t)(hwmgr->thermal_controller. | ||
567 | advanceFanControlParameters.ulTargetGfxClk); | ||
568 | table->FanGainEdge = hwmgr->thermal_controller. | ||
569 | advanceFanControlParameters.usFanGainEdge; | ||
570 | table->FanGainHotspot = hwmgr->thermal_controller. | ||
571 | advanceFanControlParameters.usFanGainHotspot; | ||
572 | table->FanGainLiquid = hwmgr->thermal_controller. | ||
573 | advanceFanControlParameters.usFanGainLiquid; | ||
574 | table->FanGainVrVddc = hwmgr->thermal_controller. | ||
575 | advanceFanControlParameters.usFanGainVrVddc; | ||
576 | table->FanGainVrMvdd = hwmgr->thermal_controller. | ||
577 | advanceFanControlParameters.usFanGainVrMvdd; | ||
578 | table->FanGainPlx = hwmgr->thermal_controller. | ||
579 | advanceFanControlParameters.usFanGainPlx; | ||
580 | table->FanGainHbm = hwmgr->thermal_controller. | ||
581 | advanceFanControlParameters.usFanGainHbm; | ||
582 | table->FanZeroRpmEnable = hwmgr->thermal_controller. | ||
583 | advanceFanControlParameters.ucEnableZeroRPM; | ||
584 | table->FanStopTemp = hwmgr->thermal_controller. | ||
585 | advanceFanControlParameters.usZeroRPMStopTemperature; | ||
586 | table->FanStartTemp = hwmgr->thermal_controller. | ||
587 | advanceFanControlParameters.usZeroRPMStartTemperature; | ||
588 | |||
589 | ret = vega10_copy_table_to_smc(hwmgr->smumgr, | ||
590 | (uint8_t *)(&(data->smc_state_table.pp_table)), PPTABLE); | ||
591 | if (ret) | ||
592 | pr_info("Failed to update Fan Control Table in PPTable!"); | ||
593 | |||
594 | return ret; | ||
595 | } | ||
596 | |||
597 | /** | ||
598 | * Start the fan control on the SMC. | ||
599 | * @param hwmgr the address of the powerplay hardware manager. | ||
600 | * @param pInput the pointer to input data | ||
601 | * @param pOutput the pointer to output data | ||
602 | * @param pStorage the pointer to temporary storage | ||
603 | * @param Result the last failure code | ||
604 | * @return result from set temperature range routine | ||
605 | */ | ||
606 | int tf_vega10_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr, | ||
607 | void *input, void *output, void *storage, int result) | ||
608 | { | ||
609 | /* If the fantable setup has failed we could have disabled | ||
610 | * PHM_PlatformCaps_MicrocodeFanControl even after | ||
611 | * this function was included in the table. | ||
612 | * Make sure that we still think controlling the fan is OK. | ||
613 | */ | ||
614 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
615 | PHM_PlatformCaps_MicrocodeFanControl)) { | ||
616 | vega10_fan_ctrl_start_smc_fan_control(hwmgr); | ||
617 | vega10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); | ||
618 | } | ||
619 | |||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | /** | ||
624 | * Set temperature range for high and low alerts | ||
625 | * @param hwmgr the address of the powerplay hardware manager. | ||
626 | * @param pInput the pointer to input data | ||
627 | * @param pOutput the pointer to output data | ||
628 | * @param pStorage the pointer to temporary storage | ||
629 | * @param Result the last failure code | ||
630 | * @return result from set temperature range routine | ||
631 | */ | ||
632 | int tf_vega10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, | ||
633 | void *input, void *output, void *storage, int result) | ||
634 | { | ||
635 | struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input; | ||
636 | |||
637 | if (range == NULL) | ||
638 | return -EINVAL; | ||
639 | |||
640 | return vega10_thermal_set_temperature_range(hwmgr, range); | ||
641 | } | ||
642 | |||
643 | /** | ||
644 | * Programs one-time setting registers | ||
645 | * @param hwmgr the address of the powerplay hardware manager. | ||
646 | * @param pInput the pointer to input data | ||
647 | * @param pOutput the pointer to output data | ||
648 | * @param pStorage the pointer to temporary storage | ||
649 | * @param Result the last failure code | ||
650 | * @return result from initialize thermal controller routine | ||
651 | */ | ||
652 | int tf_vega10_thermal_initialize(struct pp_hwmgr *hwmgr, | ||
653 | void *input, void *output, void *storage, int result) | ||
654 | { | ||
655 | return vega10_thermal_initialize(hwmgr); | ||
656 | } | ||
657 | |||
658 | /** | ||
659 | * Enable high and low alerts | ||
660 | * @param hwmgr the address of the powerplay hardware manager. | ||
661 | * @param pInput the pointer to input data | ||
662 | * @param pOutput the pointer to output data | ||
663 | * @param pStorage the pointer to temporary storage | ||
664 | * @param Result the last failure code | ||
665 | * @return result from enable alert routine | ||
666 | */ | ||
667 | int tf_vega10_thermal_enable_alert(struct pp_hwmgr *hwmgr, | ||
668 | void *input, void *output, void *storage, int result) | ||
669 | { | ||
670 | return vega10_thermal_enable_alert(hwmgr); | ||
671 | } | ||
672 | |||
673 | /** | ||
674 | * Disable high and low alerts | ||
675 | * @param hwmgr the address of the powerplay hardware manager. | ||
676 | * @param pInput the pointer to input data | ||
677 | * @param pOutput the pointer to output data | ||
678 | * @param pStorage the pointer to temporary storage | ||
679 | * @param Result the last failure code | ||
680 | * @return result from disable alert routine | ||
681 | */ | ||
682 | static int tf_vega10_thermal_disable_alert(struct pp_hwmgr *hwmgr, | ||
683 | void *input, void *output, void *storage, int result) | ||
684 | { | ||
685 | return vega10_thermal_disable_alert(hwmgr); | ||
686 | } | ||
687 | |||
688 | static struct phm_master_table_item | ||
689 | vega10_thermal_start_thermal_controller_master_list[] = { | ||
690 | {NULL, tf_vega10_thermal_initialize}, | ||
691 | {NULL, tf_vega10_thermal_set_temperature_range}, | ||
692 | {NULL, tf_vega10_thermal_enable_alert}, | ||
693 | /* We should restrict performance levels to low before we halt the SMC. | ||
694 | * On the other hand we are still in boot state when we do this | ||
695 | * so it would be pointless. | ||
696 | * If this assumption changes we have to revisit this table. | ||
697 | */ | ||
698 | {NULL, tf_vega10_thermal_setup_fan_table}, | ||
699 | {NULL, tf_vega10_thermal_start_smc_fan_control}, | ||
700 | {NULL, NULL} | ||
701 | }; | ||
702 | |||
703 | static struct phm_master_table_header | ||
704 | vega10_thermal_start_thermal_controller_master = { | ||
705 | 0, | ||
706 | PHM_MasterTableFlag_None, | ||
707 | vega10_thermal_start_thermal_controller_master_list | ||
708 | }; | ||
709 | |||
710 | static struct phm_master_table_item | ||
711 | vega10_thermal_set_temperature_range_master_list[] = { | ||
712 | {NULL, tf_vega10_thermal_disable_alert}, | ||
713 | {NULL, tf_vega10_thermal_set_temperature_range}, | ||
714 | {NULL, tf_vega10_thermal_enable_alert}, | ||
715 | {NULL, NULL} | ||
716 | }; | ||
717 | |||
718 | struct phm_master_table_header | ||
719 | vega10_thermal_set_temperature_range_master = { | ||
720 | 0, | ||
721 | PHM_MasterTableFlag_None, | ||
722 | vega10_thermal_set_temperature_range_master_list | ||
723 | }; | ||
724 | |||
725 | int vega10_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr) | ||
726 | { | ||
727 | if (!hwmgr->thermal_controller.fanInfo.bNoFan) { | ||
728 | vega10_fan_ctrl_set_default_mode(hwmgr); | ||
729 | vega10_fan_ctrl_stop_smc_fan_control(hwmgr); | ||
730 | } | ||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | /** | ||
735 | * Initializes the thermal controller related functions | ||
736 | * in the Hardware Manager structure. | ||
737 | * @param hwmgr The address of the hardware manager. | ||
738 | * @exception Any error code from the low-level communication. | ||
739 | */ | ||
740 | int pp_vega10_thermal_initialize(struct pp_hwmgr *hwmgr) | ||
741 | { | ||
742 | int result; | ||
743 | |||
744 | result = phm_construct_table(hwmgr, | ||
745 | &vega10_thermal_set_temperature_range_master, | ||
746 | &(hwmgr->set_temperature_range)); | ||
747 | |||
748 | if (!result) { | ||
749 | result = phm_construct_table(hwmgr, | ||
750 | &vega10_thermal_start_thermal_controller_master, | ||
751 | &(hwmgr->start_thermal_controller)); | ||
752 | if (result) | ||
753 | phm_destroy_table(hwmgr, | ||
754 | &(hwmgr->set_temperature_range)); | ||
755 | } | ||
756 | |||
757 | if (!result) | ||
758 | hwmgr->fan_ctrl_is_in_default_mode = true; | ||
759 | return result; | ||
760 | } | ||
761 | |||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h new file mode 100644 index 000000000000..8036808ec421 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef VEGA10_THERMAL_H | ||
25 | #define VEGA10_THERMAL_H | ||
26 | |||
27 | #include "hwmgr.h" | ||
28 | |||
29 | struct vega10_temperature { | ||
30 | uint16_t edge_temp; | ||
31 | uint16_t hot_spot_temp; | ||
32 | uint16_t hbm_temp; | ||
33 | uint16_t vr_soc_temp; | ||
34 | uint16_t vr_mem_temp; | ||
35 | uint16_t liquid1_temp; | ||
36 | uint16_t liquid2_temp; | ||
37 | uint16_t plx_temp; | ||
38 | }; | ||
39 | |||
40 | #define VEGA10_THERMAL_HIGH_ALERT_MASK 0x1 | ||
41 | #define VEGA10_THERMAL_LOW_ALERT_MASK 0x2 | ||
42 | |||
43 | #define VEGA10_THERMAL_MINIMUM_TEMP_READING -256 | ||
44 | #define VEGA10_THERMAL_MAXIMUM_TEMP_READING 255 | ||
45 | |||
46 | #define VEGA10_THERMAL_MINIMUM_ALERT_TEMP 0 | ||
47 | #define VEGA10_THERMAL_MAXIMUM_ALERT_TEMP 255 | ||
48 | |||
49 | #define FDO_PWM_MODE_STATIC 1 | ||
50 | #define FDO_PWM_MODE_STATIC_RPM 5 | ||
51 | |||
52 | |||
53 | extern int tf_vega10_thermal_initialize(struct pp_hwmgr *hwmgr, | ||
54 | void *input, void *output, void *storage, int result); | ||
55 | extern int tf_vega10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, | ||
56 | void *input, void *output, void *storage, int result); | ||
57 | extern int tf_vega10_thermal_enable_alert(struct pp_hwmgr *hwmgr, | ||
58 | void *input, void *output, void *storage, int result); | ||
59 | |||
60 | extern int vega10_thermal_get_temperature(struct pp_hwmgr *hwmgr); | ||
61 | extern int vega10_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr); | ||
62 | extern int vega10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, | ||
63 | struct phm_fan_speed_info *fan_speed_info); | ||
64 | extern int vega10_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, | ||
65 | uint32_t *speed); | ||
66 | extern int vega10_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr); | ||
67 | extern int vega10_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, | ||
68 | uint32_t mode); | ||
69 | extern int vega10_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, | ||
70 | uint32_t speed); | ||
71 | extern int vega10_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr); | ||
72 | extern int pp_vega10_thermal_initialize(struct pp_hwmgr *hwmgr); | ||
73 | extern int vega10_thermal_ctrl_uninitialize_thermal_controller( | ||
74 | struct pp_hwmgr *hwmgr); | ||
75 | extern int vega10_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, | ||
76 | uint32_t speed); | ||
77 | extern int vega10_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, | ||
78 | uint32_t *speed); | ||
79 | extern int vega10_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr); | ||
80 | extern uint32_t smu7_get_xclk(struct pp_hwmgr *hwmgr); | ||
81 | |||
82 | #endif | ||
83 | |||
diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index 7de9beabb35d..320225dd3328 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | |||
@@ -85,6 +85,7 @@ enum PP_FEATURE_MASK { | |||
85 | PP_CLOCK_STRETCH_MASK = 0x400, | 85 | PP_CLOCK_STRETCH_MASK = 0x400, |
86 | PP_OD_FUZZY_FAN_CONTROL_MASK = 0x800, | 86 | PP_OD_FUZZY_FAN_CONTROL_MASK = 0x800, |
87 | PP_SOCCLK_DPM_MASK = 0x1000, | 87 | PP_SOCCLK_DPM_MASK = 0x1000, |
88 | PP_DCEFCLK_DPM_MASK = 0x2000, | ||
88 | }; | 89 | }; |
89 | 90 | ||
90 | enum PHM_BackEnd_Magic { | 91 | enum PHM_BackEnd_Magic { |
@@ -820,6 +821,8 @@ extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t ma | |||
820 | extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr); | 821 | extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr); |
821 | 822 | ||
822 | extern int smu7_init_function_pointers(struct pp_hwmgr *hwmgr); | 823 | extern int smu7_init_function_pointers(struct pp_hwmgr *hwmgr); |
824 | extern int vega10_hwmgr_init(struct pp_hwmgr *hwmgr); | ||
825 | |||
823 | extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, | 826 | extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, |
824 | uint32_t sclk, uint16_t id, uint16_t *voltage); | 827 | uint32_t sclk, uint16_t id, uint16_t *voltage); |
825 | 828 | ||
diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_soc15.h b/drivers/gpu/drm/amd/powerplay/inc/pp_soc15.h new file mode 100644 index 000000000000..227d999b6bd1 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/pp_soc15.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | #ifndef PP_SOC15_H | ||
24 | #define PP_SOC15_H | ||
25 | |||
26 | #include "vega10/soc15ip.h" | ||
27 | |||
28 | inline static uint32_t soc15_get_register_offset( | ||
29 | uint32_t hw_id, | ||
30 | uint32_t inst, | ||
31 | uint32_t segment, | ||
32 | uint32_t offset) | ||
33 | { | ||
34 | uint32_t reg = 0; | ||
35 | |||
36 | if (hw_id == THM_HWID) | ||
37 | reg = THM_BASE.instance[inst].segment[segment] + offset; | ||
38 | else if (hw_id == NBIF_HWID) | ||
39 | reg = NBIF_BASE.instance[inst].segment[segment] + offset; | ||
40 | else if (hw_id == MP1_HWID) | ||
41 | reg = MP1_BASE.instance[inst].segment[segment] + offset; | ||
42 | else if (hw_id == DF_HWID) | ||
43 | reg = DF_BASE.instance[inst].segment[segment] + offset; | ||
44 | |||
45 | return reg; | ||
46 | } | ||
47 | |||
48 | #endif | ||
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h index 52f56f40bc54..37f41217b8a0 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h | |||
@@ -38,6 +38,7 @@ extern const struct pp_smumgr_func iceland_smu_funcs; | |||
38 | extern const struct pp_smumgr_func tonga_smu_funcs; | 38 | extern const struct pp_smumgr_func tonga_smu_funcs; |
39 | extern const struct pp_smumgr_func fiji_smu_funcs; | 39 | extern const struct pp_smumgr_func fiji_smu_funcs; |
40 | extern const struct pp_smumgr_func polaris10_smu_funcs; | 40 | extern const struct pp_smumgr_func polaris10_smu_funcs; |
41 | extern const struct pp_smumgr_func vega10_smu_funcs; | ||
41 | 42 | ||
42 | enum AVFS_BTC_STATUS { | 43 | enum AVFS_BTC_STATUS { |
43 | AVFS_BTC_BOOT = 0, | 44 | AVFS_BTC_BOOT = 0, |
@@ -177,6 +178,8 @@ extern int smu_allocate_memory(void *device, uint32_t size, | |||
177 | void **kptr, void *handle); | 178 | void **kptr, void *handle); |
178 | 179 | ||
179 | extern int smu_free_memory(void *device, void *handle); | 180 | extern int smu_free_memory(void *device, void *handle); |
181 | extern int vega10_smum_init(struct pp_smumgr *smumgr); | ||
182 | |||
180 | extern int smum_update_sclk_threshold(struct pp_hwmgr *hwmgr); | 183 | extern int smum_update_sclk_threshold(struct pp_hwmgr *hwmgr); |
181 | 184 | ||
182 | extern int smum_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type); | 185 | extern int smum_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type); |
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile index 51ff08301651..68b01b594e11 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o fiji_smc.o \ | 5 | SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o fiji_smc.o \ |
6 | polaris10_smumgr.o iceland_smumgr.o polaris10_smc.o tonga_smc.o \ | 6 | polaris10_smumgr.o iceland_smumgr.o polaris10_smc.o tonga_smc.o \ |
7 | smu7_smumgr.o iceland_smc.o | 7 | smu7_smumgr.o iceland_smc.o vega10_smumgr.o |
8 | 8 | ||
9 | AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR)) | 9 | AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR)) |
10 | 10 | ||
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c index 454f4459131f..c0d75766bbc8 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c | |||
@@ -86,6 +86,15 @@ int smum_early_init(struct pp_instance *handle) | |||
86 | return -EINVAL; | 86 | return -EINVAL; |
87 | } | 87 | } |
88 | break; | 88 | break; |
89 | case AMDGPU_FAMILY_AI: | ||
90 | switch (smumgr->chip_id) { | ||
91 | case CHIP_VEGA10: | ||
92 | smumgr->smumgr_funcs = &vega10_smu_funcs; | ||
93 | break; | ||
94 | default: | ||
95 | return -EINVAL; | ||
96 | } | ||
97 | break; | ||
89 | default: | 98 | default: |
90 | kfree(smumgr); | 99 | kfree(smumgr); |
91 | return -EINVAL; | 100 | return -EINVAL; |
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c new file mode 100644 index 000000000000..2685f02ab551 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c | |||
@@ -0,0 +1,564 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "smumgr.h" | ||
25 | #include "vega10_inc.h" | ||
26 | #include "pp_soc15.h" | ||
27 | #include "vega10_smumgr.h" | ||
28 | #include "vega10_ppsmc.h" | ||
29 | #include "smu9_driver_if.h" | ||
30 | |||
31 | #include "ppatomctrl.h" | ||
32 | #include "pp_debug.h" | ||
33 | #include "smu_ucode_xfer_vi.h" | ||
34 | #include "smu7_smumgr.h" | ||
35 | |||
36 | #define AVFS_EN_MSB 1568 | ||
37 | #define AVFS_EN_LSB 1568 | ||
38 | |||
39 | #define VOLTAGE_SCALE 4 | ||
40 | |||
41 | /* Microcode file is stored in this buffer */ | ||
42 | #define BUFFER_SIZE 80000 | ||
43 | #define MAX_STRING_SIZE 15 | ||
44 | #define BUFFER_SIZETWO 131072 /* 128 *1024 */ | ||
45 | |||
46 | /* MP Apertures */ | ||
47 | #define MP0_Public 0x03800000 | ||
48 | #define MP0_SRAM 0x03900000 | ||
49 | #define MP1_Public 0x03b00000 | ||
50 | #define MP1_SRAM 0x03c00004 | ||
51 | |||
52 | #define smnMP1_FIRMWARE_FLAGS 0x3010028 | ||
53 | #define smnMP0_FW_INTF 0x3010104 | ||
54 | #define smnMP1_PUB_CTRL 0x3010b14 | ||
55 | |||
56 | static bool vega10_is_smc_ram_running(struct pp_smumgr *smumgr) | ||
57 | { | ||
58 | uint32_t mp1_fw_flags, reg; | ||
59 | |||
60 | reg = soc15_get_register_offset(NBIF_HWID, 0, | ||
61 | mmPCIE_INDEX2_BASE_IDX, mmPCIE_INDEX2); | ||
62 | |||
63 | cgs_write_register(smumgr->device, reg, | ||
64 | (MP1_Public | (smnMP1_FIRMWARE_FLAGS & 0xffffffff))); | ||
65 | |||
66 | reg = soc15_get_register_offset(NBIF_HWID, 0, | ||
67 | mmPCIE_DATA2_BASE_IDX, mmPCIE_DATA2); | ||
68 | |||
69 | mp1_fw_flags = cgs_read_register(smumgr->device, reg); | ||
70 | |||
71 | if (mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) | ||
72 | return true; | ||
73 | |||
74 | return false; | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * Check if SMC has responded to previous message. | ||
79 | * | ||
80 | * @param smumgr the address of the powerplay hardware manager. | ||
81 | * @return TRUE SMC has responded, FALSE otherwise. | ||
82 | */ | ||
83 | static uint32_t vega10_wait_for_response(struct pp_smumgr *smumgr) | ||
84 | { | ||
85 | uint32_t reg; | ||
86 | |||
87 | if (!vega10_is_smc_ram_running(smumgr)) | ||
88 | return -1; | ||
89 | |||
90 | reg = soc15_get_register_offset(MP1_HWID, 0, | ||
91 | mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); | ||
92 | |||
93 | smum_wait_for_register_unequal(smumgr, reg, | ||
94 | 0, MP1_C2PMSG_90__CONTENT_MASK); | ||
95 | |||
96 | return cgs_read_register(smumgr->device, reg); | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * Send a message to the SMC, and do not wait for its response. | ||
101 | * | ||
102 | * @param smumgr the address of the powerplay hardware manager. | ||
103 | * @param msg the message to send. | ||
104 | * @return Always return 0. | ||
105 | */ | ||
106 | int vega10_send_msg_to_smc_without_waiting(struct pp_smumgr *smumgr, | ||
107 | uint16_t msg) | ||
108 | { | ||
109 | uint32_t reg; | ||
110 | |||
111 | if (!vega10_is_smc_ram_running(smumgr)) | ||
112 | return -1; | ||
113 | |||
114 | reg = soc15_get_register_offset(MP1_HWID, 0, | ||
115 | mmMP1_SMN_C2PMSG_66_BASE_IDX, mmMP1_SMN_C2PMSG_66); | ||
116 | cgs_write_register(smumgr->device, reg, msg); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | /** | ||
122 | * Send a message to the SMC, and wait for its response. | ||
123 | * | ||
124 | * @param smumgr the address of the powerplay hardware manager. | ||
125 | * @param msg the message to send. | ||
126 | * @return The response that came from the SMC. | ||
127 | */ | ||
128 | int vega10_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg) | ||
129 | { | ||
130 | uint32_t reg; | ||
131 | |||
132 | if (!vega10_is_smc_ram_running(smumgr)) | ||
133 | return -1; | ||
134 | |||
135 | vega10_wait_for_response(smumgr); | ||
136 | |||
137 | reg = soc15_get_register_offset(MP1_HWID, 0, | ||
138 | mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); | ||
139 | cgs_write_register(smumgr->device, reg, 0); | ||
140 | |||
141 | vega10_send_msg_to_smc_without_waiting(smumgr, msg); | ||
142 | |||
143 | PP_ASSERT_WITH_CODE(vega10_wait_for_response(smumgr) == 1, | ||
144 | "Failed to send Message.", | ||
145 | return -1); | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * Send a message to the SMC with parameter | ||
152 | * @param smumgr: the address of the powerplay hardware manager. | ||
153 | * @param msg: the message to send. | ||
154 | * @param parameter: the parameter to send | ||
155 | * @return The response that came from the SMC. | ||
156 | */ | ||
157 | int vega10_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr, | ||
158 | uint16_t msg, uint32_t parameter) | ||
159 | { | ||
160 | uint32_t reg; | ||
161 | |||
162 | if (!vega10_is_smc_ram_running(smumgr)) | ||
163 | return -1; | ||
164 | |||
165 | vega10_wait_for_response(smumgr); | ||
166 | |||
167 | reg = soc15_get_register_offset(MP1_HWID, 0, | ||
168 | mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); | ||
169 | cgs_write_register(smumgr->device, reg, 0); | ||
170 | |||
171 | reg = soc15_get_register_offset(MP1_HWID, 0, | ||
172 | mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); | ||
173 | cgs_write_register(smumgr->device, reg, parameter); | ||
174 | |||
175 | vega10_send_msg_to_smc_without_waiting(smumgr, msg); | ||
176 | |||
177 | PP_ASSERT_WITH_CODE(vega10_wait_for_response(smumgr) == 1, | ||
178 | "Failed to send Message.", | ||
179 | return -1); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | |||
185 | /** | ||
186 | * Send a message to the SMC with parameter, do not wait for response | ||
187 | * | ||
188 | * @param smumgr: the address of the powerplay hardware manager. | ||
189 | * @param msg: the message to send. | ||
190 | * @param parameter: the parameter to send | ||
191 | * @return The response that came from the SMC. | ||
192 | */ | ||
193 | int vega10_send_msg_to_smc_with_parameter_without_waiting( | ||
194 | struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter) | ||
195 | { | ||
196 | uint32_t reg; | ||
197 | |||
198 | reg = soc15_get_register_offset(MP1_HWID, 0, | ||
199 | mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); | ||
200 | cgs_write_register(smumgr->device, reg, parameter); | ||
201 | |||
202 | return vega10_send_msg_to_smc_without_waiting(smumgr, msg); | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * Retrieve an argument from SMC. | ||
207 | * | ||
208 | * @param smumgr the address of the powerplay hardware manager. | ||
209 | * @param arg pointer to store the argument from SMC. | ||
210 | * @return Always return 0. | ||
211 | */ | ||
212 | int vega10_read_arg_from_smc(struct pp_smumgr *smumgr, uint32_t *arg) | ||
213 | { | ||
214 | uint32_t reg; | ||
215 | |||
216 | reg = soc15_get_register_offset(MP1_HWID, 0, | ||
217 | mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); | ||
218 | |||
219 | *arg = cgs_read_register(smumgr->device, reg); | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | /** | ||
225 | * Copy table from SMC into driver FB | ||
226 | * @param smumgr the address of the SMC manager | ||
227 | * @param table_id the driver's table ID to copy from | ||
228 | */ | ||
229 | int vega10_copy_table_from_smc(struct pp_smumgr *smumgr, | ||
230 | uint8_t *table, int16_t table_id) | ||
231 | { | ||
232 | struct vega10_smumgr *priv = | ||
233 | (struct vega10_smumgr *)(smumgr->backend); | ||
234 | |||
235 | PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, | ||
236 | "Invalid SMU Table ID!", return -1;); | ||
237 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, | ||
238 | "Invalid SMU Table version!", return -1;); | ||
239 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, | ||
240 | "Invalid SMU Table Length!", return -1;); | ||
241 | PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(smumgr, | ||
242 | PPSMC_MSG_SetDriverDramAddrHigh, | ||
243 | priv->smu_tables.entry[table_id].table_addr_high) == 0, | ||
244 | "[CopyTableFromSMC] Attempt to Set Dram Addr High Failed!", return -1;); | ||
245 | PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(smumgr, | ||
246 | PPSMC_MSG_SetDriverDramAddrLow, | ||
247 | priv->smu_tables.entry[table_id].table_addr_low) == 0, | ||
248 | "[CopyTableFromSMC] Attempt to Set Dram Addr Low Failed!", | ||
249 | return -1;); | ||
250 | PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(smumgr, | ||
251 | PPSMC_MSG_TransferTableSmu2Dram, | ||
252 | priv->smu_tables.entry[table_id].table_id) == 0, | ||
253 | "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!", | ||
254 | return -1;); | ||
255 | |||
256 | memcpy(table, priv->smu_tables.entry[table_id].table, | ||
257 | priv->smu_tables.entry[table_id].size); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | /** | ||
263 | * Copy table from Driver FB into SMC | ||
264 | * @param smumgr the address of the SMC manager | ||
265 | * @param table_id the table to copy from | ||
266 | */ | ||
267 | int vega10_copy_table_to_smc(struct pp_smumgr *smumgr, | ||
268 | uint8_t *table, int16_t table_id) | ||
269 | { | ||
270 | struct vega10_smumgr *priv = | ||
271 | (struct vega10_smumgr *)(smumgr->backend); | ||
272 | |||
273 | PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, | ||
274 | "Invalid SMU Table ID!", return -1;); | ||
275 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, | ||
276 | "Invalid SMU Table version!", return -1;); | ||
277 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, | ||
278 | "Invalid SMU Table Length!", return -1;); | ||
279 | |||
280 | memcpy(priv->smu_tables.entry[table_id].table, table, | ||
281 | priv->smu_tables.entry[table_id].size); | ||
282 | |||
283 | PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(smumgr, | ||
284 | PPSMC_MSG_SetDriverDramAddrHigh, | ||
285 | priv->smu_tables.entry[table_id].table_addr_high) == 0, | ||
286 | "[CopyTableToSMC] Attempt to Set Dram Addr High Failed!", | ||
287 | return -1;); | ||
288 | PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(smumgr, | ||
289 | PPSMC_MSG_SetDriverDramAddrLow, | ||
290 | priv->smu_tables.entry[table_id].table_addr_low) == 0, | ||
291 | "[CopyTableToSMC] Attempt to Set Dram Addr Low Failed!", | ||
292 | return -1;); | ||
293 | PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(smumgr, | ||
294 | PPSMC_MSG_TransferTableDram2Smu, | ||
295 | priv->smu_tables.entry[table_id].table_id) == 0, | ||
296 | "[CopyTableToSMC] Attempt to Transfer Table To SMU Failed!", | ||
297 | return -1;); | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | int vega10_perform_btc(struct pp_smumgr *smumgr) | ||
303 | { | ||
304 | PP_ASSERT_WITH_CODE(!vega10_send_msg_to_smc_with_parameter( | ||
305 | smumgr, PPSMC_MSG_RunBtc, 0), | ||
306 | "Attempt to run DC BTC Failed!", | ||
307 | return -1); | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | int vega10_save_vft_table(struct pp_smumgr *smumgr, uint8_t *avfs_table) | ||
312 | { | ||
313 | PP_ASSERT_WITH_CODE(avfs_table, | ||
314 | "No access to SMC AVFS Table", | ||
315 | return -1); | ||
316 | |||
317 | return vega10_copy_table_from_smc(smumgr, avfs_table, AVFSTABLE); | ||
318 | } | ||
319 | |||
320 | int vega10_restore_vft_table(struct pp_smumgr *smumgr, uint8_t *avfs_table) | ||
321 | { | ||
322 | PP_ASSERT_WITH_CODE(avfs_table, | ||
323 | "No access to SMC AVFS Table", | ||
324 | return -1); | ||
325 | |||
326 | return vega10_copy_table_to_smc(smumgr, avfs_table, AVFSTABLE); | ||
327 | } | ||
328 | |||
329 | int vega10_enable_smc_features(struct pp_smumgr *smumgr, | ||
330 | bool enable, uint32_t feature_mask) | ||
331 | { | ||
332 | int msg = enable ? PPSMC_MSG_EnableSmuFeatures : | ||
333 | PPSMC_MSG_DisableSmuFeatures; | ||
334 | |||
335 | return vega10_send_msg_to_smc_with_parameter(smumgr, | ||
336 | msg, feature_mask); | ||
337 | } | ||
338 | |||
339 | int vega10_get_smc_features(struct pp_smumgr *smumgr, | ||
340 | uint32_t *features_enabled) | ||
341 | { | ||
342 | if (!vega10_send_msg_to_smc(smumgr, | ||
343 | PPSMC_MSG_GetEnabledSmuFeatures)) { | ||
344 | if (!vega10_read_arg_from_smc(smumgr, features_enabled)) | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | return -1; | ||
349 | } | ||
350 | |||
351 | int vega10_set_tools_address(struct pp_smumgr *smumgr) | ||
352 | { | ||
353 | struct vega10_smumgr *priv = | ||
354 | (struct vega10_smumgr *)(smumgr->backend); | ||
355 | |||
356 | if (priv->smu_tables.entry[TOOLSTABLE].table_addr_high || | ||
357 | priv->smu_tables.entry[TOOLSTABLE].table_addr_low) { | ||
358 | if (!vega10_send_msg_to_smc_with_parameter(smumgr, | ||
359 | PPSMC_MSG_SetToolsDramAddrHigh, | ||
360 | priv->smu_tables.entry[TOOLSTABLE].table_addr_high)) | ||
361 | vega10_send_msg_to_smc_with_parameter(smumgr, | ||
362 | PPSMC_MSG_SetToolsDramAddrLow, | ||
363 | priv->smu_tables.entry[TOOLSTABLE].table_addr_low); | ||
364 | } | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static int vega10_verify_smc_interface(struct pp_smumgr *smumgr) | ||
369 | { | ||
370 | uint32_t smc_driver_if_version; | ||
371 | |||
372 | PP_ASSERT_WITH_CODE(!vega10_send_msg_to_smc(smumgr, | ||
373 | PPSMC_MSG_GetDriverIfVersion), | ||
374 | "Attempt to get SMC IF Version Number Failed!", | ||
375 | return -1); | ||
376 | PP_ASSERT_WITH_CODE(!vega10_read_arg_from_smc(smumgr, | ||
377 | &smc_driver_if_version), | ||
378 | "Attempt to read SMC IF Version Number Failed!", | ||
379 | return -1); | ||
380 | |||
381 | if (smc_driver_if_version != SMU9_DRIVER_IF_VERSION) | ||
382 | return -1; | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | /** | ||
388 | * Write a 32bit value to the SMC SRAM space. | ||
389 | * ALL PARAMETERS ARE IN HOST BYTE ORDER. | ||
390 | * @param smumgr the address of the powerplay hardware manager. | ||
391 | * @param smc_addr the address in the SMC RAM to access. | ||
392 | * @param value to write to the SMC SRAM. | ||
393 | */ | ||
394 | static int vega10_smu_init(struct pp_smumgr *smumgr) | ||
395 | { | ||
396 | struct vega10_smumgr *priv; | ||
397 | uint64_t mc_addr; | ||
398 | void *kaddr = NULL; | ||
399 | unsigned long handle, tools_size; | ||
400 | int ret; | ||
401 | struct cgs_firmware_info info = {0}; | ||
402 | |||
403 | ret = cgs_get_firmware_info(smumgr->device, | ||
404 | smu7_convert_fw_type_to_cgs(UCODE_ID_SMU), | ||
405 | &info); | ||
406 | if (ret || !info.kptr) | ||
407 | return -EINVAL; | ||
408 | |||
409 | priv = kzalloc(sizeof(struct vega10_smumgr), GFP_KERNEL); | ||
410 | |||
411 | if (!priv) | ||
412 | return -ENOMEM; | ||
413 | |||
414 | smumgr->backend = priv; | ||
415 | |||
416 | /* allocate space for pptable */ | ||
417 | smu_allocate_memory(smumgr->device, | ||
418 | sizeof(PPTable_t), | ||
419 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | ||
420 | PAGE_SIZE, | ||
421 | &mc_addr, | ||
422 | &kaddr, | ||
423 | &handle); | ||
424 | |||
425 | PP_ASSERT_WITH_CODE(kaddr, | ||
426 | "[vega10_smu_init] Out of memory for pptable.", | ||
427 | kfree(smumgr->backend); | ||
428 | cgs_free_gpu_mem(smumgr->device, | ||
429 | (cgs_handle_t)handle); | ||
430 | return -1); | ||
431 | |||
432 | priv->smu_tables.entry[PPTABLE].version = 0x01; | ||
433 | priv->smu_tables.entry[PPTABLE].size = sizeof(PPTable_t); | ||
434 | priv->smu_tables.entry[PPTABLE].table_id = TABLE_PPTABLE; | ||
435 | priv->smu_tables.entry[PPTABLE].table_addr_high = | ||
436 | smu_upper_32_bits(mc_addr); | ||
437 | priv->smu_tables.entry[PPTABLE].table_addr_low = | ||
438 | smu_lower_32_bits(mc_addr); | ||
439 | priv->smu_tables.entry[PPTABLE].table = kaddr; | ||
440 | priv->smu_tables.entry[PPTABLE].handle = handle; | ||
441 | |||
442 | /* allocate space for watermarks table */ | ||
443 | smu_allocate_memory(smumgr->device, | ||
444 | sizeof(Watermarks_t), | ||
445 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | ||
446 | PAGE_SIZE, | ||
447 | &mc_addr, | ||
448 | &kaddr, | ||
449 | &handle); | ||
450 | |||
451 | PP_ASSERT_WITH_CODE(kaddr, | ||
452 | "[vega10_smu_init] Out of memory for wmtable.", | ||
453 | kfree(smumgr->backend); | ||
454 | cgs_free_gpu_mem(smumgr->device, | ||
455 | (cgs_handle_t)priv->smu_tables.entry[PPTABLE].handle); | ||
456 | cgs_free_gpu_mem(smumgr->device, | ||
457 | (cgs_handle_t)handle); | ||
458 | return -1); | ||
459 | |||
460 | priv->smu_tables.entry[WMTABLE].version = 0x01; | ||
461 | priv->smu_tables.entry[WMTABLE].size = sizeof(Watermarks_t); | ||
462 | priv->smu_tables.entry[WMTABLE].table_id = TABLE_WATERMARKS; | ||
463 | priv->smu_tables.entry[WMTABLE].table_addr_high = | ||
464 | smu_upper_32_bits(mc_addr); | ||
465 | priv->smu_tables.entry[WMTABLE].table_addr_low = | ||
466 | smu_lower_32_bits(mc_addr); | ||
467 | priv->smu_tables.entry[WMTABLE].table = kaddr; | ||
468 | priv->smu_tables.entry[WMTABLE].handle = handle; | ||
469 | |||
470 | /* allocate space for AVFS table */ | ||
471 | smu_allocate_memory(smumgr->device, | ||
472 | sizeof(AvfsTable_t), | ||
473 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | ||
474 | PAGE_SIZE, | ||
475 | &mc_addr, | ||
476 | &kaddr, | ||
477 | &handle); | ||
478 | |||
479 | PP_ASSERT_WITH_CODE(kaddr, | ||
480 | "[vega10_smu_init] Out of memory for avfs table.", | ||
481 | kfree(smumgr->backend); | ||
482 | cgs_free_gpu_mem(smumgr->device, | ||
483 | (cgs_handle_t)priv->smu_tables.entry[PPTABLE].handle); | ||
484 | cgs_free_gpu_mem(smumgr->device, | ||
485 | (cgs_handle_t)priv->smu_tables.entry[WMTABLE].handle); | ||
486 | cgs_free_gpu_mem(smumgr->device, | ||
487 | (cgs_handle_t)handle); | ||
488 | return -1); | ||
489 | |||
490 | priv->smu_tables.entry[AVFSTABLE].version = 0x01; | ||
491 | priv->smu_tables.entry[AVFSTABLE].size = sizeof(AvfsTable_t); | ||
492 | priv->smu_tables.entry[AVFSTABLE].table_id = TABLE_AVFS; | ||
493 | priv->smu_tables.entry[AVFSTABLE].table_addr_high = | ||
494 | smu_upper_32_bits(mc_addr); | ||
495 | priv->smu_tables.entry[AVFSTABLE].table_addr_low = | ||
496 | smu_lower_32_bits(mc_addr); | ||
497 | priv->smu_tables.entry[AVFSTABLE].table = kaddr; | ||
498 | priv->smu_tables.entry[AVFSTABLE].handle = handle; | ||
499 | |||
500 | tools_size = 0; | ||
501 | if (tools_size) { | ||
502 | smu_allocate_memory(smumgr->device, | ||
503 | tools_size, | ||
504 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | ||
505 | PAGE_SIZE, | ||
506 | &mc_addr, | ||
507 | &kaddr, | ||
508 | &handle); | ||
509 | |||
510 | if (kaddr) { | ||
511 | priv->smu_tables.entry[TOOLSTABLE].version = 0x01; | ||
512 | priv->smu_tables.entry[TOOLSTABLE].size = tools_size; | ||
513 | priv->smu_tables.entry[TOOLSTABLE].table_id = TABLE_PMSTATUSLOG; | ||
514 | priv->smu_tables.entry[TOOLSTABLE].table_addr_high = | ||
515 | smu_upper_32_bits(mc_addr); | ||
516 | priv->smu_tables.entry[TOOLSTABLE].table_addr_low = | ||
517 | smu_lower_32_bits(mc_addr); | ||
518 | priv->smu_tables.entry[TOOLSTABLE].table = kaddr; | ||
519 | priv->smu_tables.entry[TOOLSTABLE].handle = handle; | ||
520 | } | ||
521 | } | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | static int vega10_smu_fini(struct pp_smumgr *smumgr) | ||
527 | { | ||
528 | struct vega10_smumgr *priv = | ||
529 | (struct vega10_smumgr *)(smumgr->backend); | ||
530 | |||
531 | if (priv) { | ||
532 | cgs_free_gpu_mem(smumgr->device, | ||
533 | (cgs_handle_t)priv->smu_tables.entry[PPTABLE].handle); | ||
534 | cgs_free_gpu_mem(smumgr->device, | ||
535 | (cgs_handle_t)priv->smu_tables.entry[WMTABLE].handle); | ||
536 | cgs_free_gpu_mem(smumgr->device, | ||
537 | (cgs_handle_t)priv->smu_tables.entry[AVFSTABLE].handle); | ||
538 | if (priv->smu_tables.entry[TOOLSTABLE].table) | ||
539 | cgs_free_gpu_mem(smumgr->device, | ||
540 | (cgs_handle_t)priv->smu_tables.entry[TOOLSTABLE].handle); | ||
541 | kfree(smumgr->backend); | ||
542 | smumgr->backend = NULL; | ||
543 | } | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static int vega10_start_smu(struct pp_smumgr *smumgr) | ||
548 | { | ||
549 | PP_ASSERT_WITH_CODE(!vega10_verify_smc_interface(smumgr), | ||
550 | "Failed to verify SMC interface!", | ||
551 | return -1); | ||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | const struct pp_smumgr_func vega10_smu_funcs = { | ||
556 | .smu_init = &vega10_smu_init, | ||
557 | .smu_fini = &vega10_smu_fini, | ||
558 | .start_smu = &vega10_start_smu, | ||
559 | .request_smu_load_specific_fw = NULL, | ||
560 | .send_msg_to_smc = &vega10_send_msg_to_smc, | ||
561 | .send_msg_to_smc_with_parameter = &vega10_send_msg_to_smc_with_parameter, | ||
562 | .download_pptable_settings = NULL, | ||
563 | .upload_pptable_settings = NULL, | ||
564 | }; | ||
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.h new file mode 100644 index 000000000000..ad050212426d --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.h | |||
@@ -0,0 +1,70 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | #ifndef _VEGA10_SMUMANAGER_H_ | ||
24 | #define _VEGA10_SMUMANAGER_H_ | ||
25 | |||
26 | #include "vega10_hwmgr.h" | ||
27 | |||
28 | enum smu_table_id { | ||
29 | PPTABLE = 0, | ||
30 | WMTABLE, | ||
31 | AVFSTABLE, | ||
32 | TOOLSTABLE, | ||
33 | MAX_SMU_TABLE, | ||
34 | }; | ||
35 | |||
36 | struct smu_table_entry { | ||
37 | uint32_t version; | ||
38 | uint32_t size; | ||
39 | uint32_t table_id; | ||
40 | uint32_t table_addr_high; | ||
41 | uint32_t table_addr_low; | ||
42 | uint8_t *table; | ||
43 | unsigned long handle; | ||
44 | }; | ||
45 | |||
46 | struct smu_table_array { | ||
47 | struct smu_table_entry entry[MAX_SMU_TABLE]; | ||
48 | }; | ||
49 | |||
50 | struct vega10_smumgr { | ||
51 | struct smu_table_array smu_tables; | ||
52 | }; | ||
53 | |||
54 | int vega10_read_arg_from_smc(struct pp_smumgr *smumgr, uint32_t *arg); | ||
55 | int vega10_copy_table_from_smc(struct pp_smumgr *smumgr, | ||
56 | uint8_t *table, int16_t table_id); | ||
57 | int vega10_copy_table_to_smc(struct pp_smumgr *smumgr, | ||
58 | uint8_t *table, int16_t table_id); | ||
59 | int vega10_enable_smc_features(struct pp_smumgr *smumgr, | ||
60 | bool enable, uint32_t feature_mask); | ||
61 | int vega10_get_smc_features(struct pp_smumgr *smumgr, | ||
62 | uint32_t *features_enabled); | ||
63 | int vega10_save_vft_table(struct pp_smumgr *smumgr, uint8_t *avfs_table); | ||
64 | int vega10_restore_vft_table(struct pp_smumgr *smumgr, uint8_t *avfs_table); | ||
65 | int vega10_perform_btc(struct pp_smumgr *smumgr); | ||
66 | |||
67 | int vega10_set_tools_address(struct pp_smumgr *smumgr); | ||
68 | |||
69 | #endif | ||
70 | |||