aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c1
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/Makefile4
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c9
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c4450
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h434
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_inc.h44
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c137
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.h65
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_pptable.h331
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c1056
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.h34
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c761
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h83
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/hwmgr.h3
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/pp_soc15.h48
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smumgr.h3
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/Makefile2
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c9
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c564
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.h70
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
13AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR)) 15AMD_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
58uint32_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
81const ULONG PhwVega10_Magic = (ULONG)(PHM_VIslands_Magic);
82
83struct 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
93const 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
103static 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
158static 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
247static 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
380static 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*/
416static 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 */
474static 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*/
502static 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
515static 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
525static 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
607static 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
633static 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
664static 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
708static 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
719static 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
836static 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
846static 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
879static 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
892static 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
911static 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
955static 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
982static 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
1008static 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 */
1035static 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*/
1059static 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 */
1121static 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
1129static 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}
1145static 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 */
1216static 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 */
1427static 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
1453static 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, &dividers),
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
1470static 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
1517static 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, &dividers),
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 */
1574static 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, &dividers),
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
1607uint16_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*/
1627static 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 */
1698static 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, &dividers),
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 */
1754static 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
1803static 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
1860static 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
1873static 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, &dividers),
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
1900static 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
1932static 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, &dividers),
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
1948static 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, &dividers),
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
1964static 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
2036static 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
2056static 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
2232static 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
2270static 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*/
2303static 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
2440static 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
2460static 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
2490static 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
2506static 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 */
2545static 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
2593static 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
2665static int vega10_get_power_state_size(struct pp_hwmgr *hwmgr)
2666{
2667 return sizeof(struct vega10_power_state);
2668}
2669
2670static 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
2760static 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
2787static int vega10_patch_boot_state(struct pp_hwmgr *hwmgr,
2788 struct pp_hw_power_state *hw_ps)
2789{
2790 return 0;
2791}
2792
2793static 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
2982static 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
3071static 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
3286static 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
3302static 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
3321static 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
3353static 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
3366static 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
3384static void vega10_apply_dal_minimum_voltage_request(
3385 struct pp_hwmgr *hwmgr)
3386{
3387 return;
3388}
3389
3390static 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
3429static 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
3467static 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
3507int 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
3524static 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
3552static 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
3591static 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
3613static 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
3635static 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
3687static 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
3695int 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
3733static 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
3781static 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
3804static 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
3828static 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
3851static 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
3881static 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
3896static 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
3911static 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
3925static 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
3944static 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
3956static 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
3986static 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
4002static 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
4018static 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
4042static 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
4084static 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
4140static 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
4207static 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
4276static 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
4302int 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
4318static 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
4326static 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
4334static 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
4343static 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
4378static bool
4379vega10_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
4398static 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
4444int 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
34extern const uint32_t PhwVega10_Magic;
35#define VEGA10_MAX_HARDWARE_POWERLEVELS 2
36
37#define WaterMarksExist 1
38#define WaterMarksLoaded 2
39
40enum {
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
75struct smu_features {
76 bool supported;
77 bool enabled;
78 uint32_t smu_feature_id;
79 uint32_t smu_feature_bitmap;
80};
81
82struct vega10_performance_level {
83 uint32_t soc_clock;
84 uint32_t gfx_clock;
85 uint32_t mem_clock;
86};
87
88struct vega10_bacos {
89 uint32_t baco_flags;
90 /* struct vega10_performance_level performance_level; */
91};
92
93struct vega10_uvd_clocks {
94 uint32_t vclk;
95 uint32_t dclk;
96};
97
98struct vega10_vce_clocks {
99 uint32_t evclk;
100 uint32_t ecclk;
101};
102
103struct 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
113struct 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
124struct 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
131struct 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
137struct 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
144struct 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
159struct 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
165struct vega10_display_timing {
166 uint32_t min_clock_in_sr;
167 uint32_t num_existing_displays;
168};
169
170struct 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
179struct 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
193struct 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
212struct vega10_mclk_latency_entries {
213 uint32_t frequency;
214 uint32_t latency;
215};
216
217struct vega10_mclk_latency_table {
218 uint32_t count;
219 struct vega10_mclk_latency_entries entries[MAX_REGULAR_DPM_NUMBER];
220};
221
222struct 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
277struct 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
283struct 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
290struct 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
297struct 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
423extern int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr);
424extern int tonga_hwmgr_backend_fini(struct pp_hwmgr *hwmgr);
425extern int tonga_get_mc_microcode_version (struct pp_hwmgr *hwmgr);
426extern int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr);
427extern int tonga_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display);
428int vega10_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input);
429int vega10_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
430int vega10_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate);
431int vega10_update_acp_dpm(struct pp_hwmgr *hwmgr, bool bgate);
432int 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
31void 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
70int 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
82int 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
116static 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
123int 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
26enum 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
39struct 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
47struct 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
56void vega10_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr);
57int vega10_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr);
58int vega10_populate_pm_fuses(struct pp_hwmgr *hwmgr);
59int vega10_enable_smc_cac(struct pp_hwmgr *hwmgr);
60int vega10_enable_power_containment(struct pp_hwmgr *hwmgr);
61int vega10_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n);
62int 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
73typedef 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
117typedef 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
129typedef 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
135typedef struct _ATOM_Vega10_CLK_Dependency_Record {
136 ULONG ulClk; /* Frequency of Clock */
137 UCHAR ucVddInd; /* Base voltage */
138} ATOM_Vega10_CLK_Dependency_Record;
139
140typedef 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
147typedef 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
154typedef 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
160typedef 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
166typedef 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
172typedef 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
178typedef 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
184typedef 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
190typedef 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
196typedef 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
204typedef 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
210typedef 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
216typedef 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
222typedef struct _ATOM_Vega10_Voltage_Lookup_Record {
223 USHORT usVdd; /* Base voltage */
224} ATOM_Vega10_Voltage_Lookup_Record;
225
226typedef 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
232typedef 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
253typedef 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
264typedef 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
272typedef 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
279typedef 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
308typedef 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
317typedef 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
324typedef 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
34static 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
43static 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
62static 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
84static 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
114static 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
204static 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
226static 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
264static 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
330static 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
365static 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
404static 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
448static 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
485static 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
534static 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
553static 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
582static 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
743static 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
775static 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
863int 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
912static 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
960const struct pp_table_func vega10_pptable_funcs = {
961 .pptable_init = vega10_pp_tables_initialize,
962 .pptable_fini = vega10_pp_tables_uninitialize,
963};
964
965int 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
982static 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
1011int 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
29extern const struct pp_table_func vega10_pptable_funcs;
30extern int vega10_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr);
31extern 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
32static 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
45int 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
75int 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, &current_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
98int 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*/
135int 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*/
170int 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 */
200static 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
217static 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
234int 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
247int 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*/
268int 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*/
315int 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*/
340int 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*/
374int 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*/
406static 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*/
452static 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*/
482static 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*/
504static 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*/
527int 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*/
546int 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*/
606int 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*/
632int 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*/
652int 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*/
667int 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*/
682static 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
688static struct phm_master_table_item
689vega10_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
703static struct phm_master_table_header
704vega10_thermal_start_thermal_controller_master = {
705 0,
706 PHM_MasterTableFlag_None,
707 vega10_thermal_start_thermal_controller_master_list
708};
709
710static struct phm_master_table_item
711vega10_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
718struct phm_master_table_header
719vega10_thermal_set_temperature_range_master = {
720 0,
721 PHM_MasterTableFlag_None,
722 vega10_thermal_set_temperature_range_master_list
723};
724
725int 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*/
740int 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
29struct 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
53extern int tf_vega10_thermal_initialize(struct pp_hwmgr *hwmgr,
54 void *input, void *output, void *storage, int result);
55extern int tf_vega10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
56 void *input, void *output, void *storage, int result);
57extern int tf_vega10_thermal_enable_alert(struct pp_hwmgr *hwmgr,
58 void *input, void *output, void *storage, int result);
59
60extern int vega10_thermal_get_temperature(struct pp_hwmgr *hwmgr);
61extern int vega10_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
62extern int vega10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
63 struct phm_fan_speed_info *fan_speed_info);
64extern int vega10_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
65 uint32_t *speed);
66extern int vega10_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
67extern int vega10_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr,
68 uint32_t mode);
69extern int vega10_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
70 uint32_t speed);
71extern int vega10_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
72extern int pp_vega10_thermal_initialize(struct pp_hwmgr *hwmgr);
73extern int vega10_thermal_ctrl_uninitialize_thermal_controller(
74 struct pp_hwmgr *hwmgr);
75extern int vega10_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr,
76 uint32_t speed);
77extern int vega10_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr,
78 uint32_t *speed);
79extern int vega10_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
80extern 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
90enum PHM_BackEnd_Magic { 91enum PHM_BackEnd_Magic {
@@ -820,6 +821,8 @@ extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t ma
820extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr); 821extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr);
821 822
822extern int smu7_init_function_pointers(struct pp_hwmgr *hwmgr); 823extern int smu7_init_function_pointers(struct pp_hwmgr *hwmgr);
824extern int vega10_hwmgr_init(struct pp_hwmgr *hwmgr);
825
823extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, 826extern 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
28inline 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;
38extern const struct pp_smumgr_func tonga_smu_funcs; 38extern const struct pp_smumgr_func tonga_smu_funcs;
39extern const struct pp_smumgr_func fiji_smu_funcs; 39extern const struct pp_smumgr_func fiji_smu_funcs;
40extern const struct pp_smumgr_func polaris10_smu_funcs; 40extern const struct pp_smumgr_func polaris10_smu_funcs;
41extern const struct pp_smumgr_func vega10_smu_funcs;
41 42
42enum AVFS_BTC_STATUS { 43enum 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
179extern int smu_free_memory(void *device, void *handle); 180extern int smu_free_memory(void *device, void *handle);
181extern int vega10_smum_init(struct pp_smumgr *smumgr);
182
180extern int smum_update_sclk_threshold(struct pp_hwmgr *hwmgr); 183extern int smum_update_sclk_threshold(struct pp_hwmgr *hwmgr);
181 184
182extern int smum_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type); 185extern 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
5SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o fiji_smc.o \ 5SMU_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
9AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR)) 9AMD_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
56static 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*/
83static 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*/
106int 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*/
128int 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 */
157int 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*/
193int 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*/
212int 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*/
229int 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*/
267int 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
302int 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
311int 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
320int 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
329int 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
339int 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
351int 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
368static 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*/
394static 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
526static 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
547static 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
555const 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
28enum smu_table_id {
29 PPTABLE = 0,
30 WMTABLE,
31 AVFSTABLE,
32 TOOLSTABLE,
33 MAX_SMU_TABLE,
34};
35
36struct 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
46struct smu_table_array {
47 struct smu_table_entry entry[MAX_SMU_TABLE];
48};
49
50struct vega10_smumgr {
51 struct smu_table_array smu_tables;
52};
53
54int vega10_read_arg_from_smc(struct pp_smumgr *smumgr, uint32_t *arg);
55int vega10_copy_table_from_smc(struct pp_smumgr *smumgr,
56 uint8_t *table, int16_t table_id);
57int vega10_copy_table_to_smc(struct pp_smumgr *smumgr,
58 uint8_t *table, int16_t table_id);
59int vega10_enable_smc_features(struct pp_smumgr *smumgr,
60 bool enable, uint32_t feature_mask);
61int vega10_get_smc_features(struct pp_smumgr *smumgr,
62 uint32_t *features_enabled);
63int vega10_save_vft_table(struct pp_smumgr *smumgr, uint8_t *avfs_table);
64int vega10_restore_vft_table(struct pp_smumgr *smumgr, uint8_t *avfs_table);
65int vega10_perform_btc(struct pp_smumgr *smumgr);
66
67int vega10_set_tools_address(struct pp_smumgr *smumgr);
68
69#endif
70