1f46a221bSXiaojian Du /*
2f46a221bSXiaojian Du  * Copyright 2020 Advanced Micro Devices, Inc.
3f46a221bSXiaojian Du  *
4f46a221bSXiaojian Du  * Permission is hereby granted, free of charge, to any person obtaining a
5f46a221bSXiaojian Du  * copy of this software and associated documentation files (the "Software"),
6f46a221bSXiaojian Du  * to deal in the Software without restriction, including without limitation
7f46a221bSXiaojian Du  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8f46a221bSXiaojian Du  * and/or sell copies of the Software, and to permit persons to whom the
9f46a221bSXiaojian Du  * Software is furnished to do so, subject to the following conditions:
10f46a221bSXiaojian Du  *
11f46a221bSXiaojian Du  * The above copyright notice and this permission notice shall be included in
12f46a221bSXiaojian Du  * all copies or substantial portions of the Software.
13f46a221bSXiaojian Du  *
14f46a221bSXiaojian Du  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15f46a221bSXiaojian Du  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16f46a221bSXiaojian Du  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17f46a221bSXiaojian Du  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18f46a221bSXiaojian Du  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19f46a221bSXiaojian Du  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20f46a221bSXiaojian Du  * OTHER DEALINGS IN THE SOFTWARE.
21f46a221bSXiaojian Du  *
22f46a221bSXiaojian Du  */
23f46a221bSXiaojian Du 
24f46a221bSXiaojian Du #define SWSMU_CODE_LAYER_L2
25f46a221bSXiaojian Du 
26f46a221bSXiaojian Du #include "amdgpu.h"
27f46a221bSXiaojian Du #include "amdgpu_smu.h"
28f46a221bSXiaojian Du #include "smu_v11_0.h"
29f46a221bSXiaojian Du #include "smu11_driver_if_vangogh.h"
30f46a221bSXiaojian Du #include "vangogh_ppt.h"
31f46a221bSXiaojian Du #include "smu_v11_5_ppsmc.h"
32f46a221bSXiaojian Du #include "smu_v11_5_pmfw.h"
33f46a221bSXiaojian Du #include "smu_cmn.h"
34eefdf047SJinzhou Su #include "soc15_common.h"
35eefdf047SJinzhou Su #include "asic_reg/gc/gc_10_3_0_offset.h"
36eefdf047SJinzhou Su #include "asic_reg/gc/gc_10_3_0_sh_mask.h"
37517cb957SHuang Rui #include <asm/processor.h>
38f46a221bSXiaojian Du 
39f46a221bSXiaojian Du /*
40f46a221bSXiaojian Du  * DO NOT use these for err/warn/info/debug messages.
41f46a221bSXiaojian Du  * Use dev_err, dev_warn, dev_info and dev_dbg instead.
42f46a221bSXiaojian Du  * They are more MGPU friendly.
43f46a221bSXiaojian Du  */
44f46a221bSXiaojian Du #undef pr_err
45f46a221bSXiaojian Du #undef pr_warn
46f46a221bSXiaojian Du #undef pr_info
47f46a221bSXiaojian Du #undef pr_debug
48f46a221bSXiaojian Du 
49f46a221bSXiaojian Du #define FEATURE_MASK(feature) (1ULL << feature)
50f46a221bSXiaojian Du #define SMC_DPM_FEATURE ( \
51f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \
52f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_VCN_DPM_BIT)	 | \
53f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_FCLK_DPM_BIT)	 | \
54f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT)	 | \
55f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT)	 | \
56f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_LCLK_DPM_BIT)	 | \
57f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT)	 | \
58f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \
59271ab489SXiaojian Du 	FEATURE_MASK(FEATURE_GFX_DPM_BIT))
60f46a221bSXiaojian Du 
61f46a221bSXiaojian Du static struct cmn2asic_msg_mapping vangogh_message_map[SMU_MSG_MAX_COUNT] = {
62271ab489SXiaojian Du 	MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,			0),
63271ab489SXiaojian Du 	MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion,		0),
64271ab489SXiaojian Du 	MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion,	0),
65271ab489SXiaojian Du 	MSG_MAP(EnableGfxOff,                   PPSMC_MSG_EnableGfxOff,			0),
66b58ce1feSJinzhou Su 	MSG_MAP(AllowGfxOff,                    PPSMC_MSG_AllowGfxOff,          0),
67b58ce1feSJinzhou Su 	MSG_MAP(DisallowGfxOff,                 PPSMC_MSG_DisallowGfxOff,		0),
68271ab489SXiaojian Du 	MSG_MAP(PowerDownIspByTile,             PPSMC_MSG_PowerDownIspByTile,	0),
69271ab489SXiaojian Du 	MSG_MAP(PowerUpIspByTile,               PPSMC_MSG_PowerUpIspByTile,		0),
70271ab489SXiaojian Du 	MSG_MAP(PowerDownVcn,                   PPSMC_MSG_PowerDownVcn,			0),
71271ab489SXiaojian Du 	MSG_MAP(PowerUpVcn,                     PPSMC_MSG_PowerUpVcn,			0),
72a0f55287SXiaomeng Hou 	MSG_MAP(RlcPowerNotify,                 PPSMC_MSG_RlcPowerNotify,		0),
73271ab489SXiaojian Du 	MSG_MAP(SetHardMinVcn,                  PPSMC_MSG_SetHardMinVcn,		0),
74271ab489SXiaojian Du 	MSG_MAP(SetSoftMinGfxclk,               PPSMC_MSG_SetSoftMinGfxclk,		0),
75271ab489SXiaojian Du 	MSG_MAP(ActiveProcessNotify,            PPSMC_MSG_ActiveProcessNotify,		0),
76271ab489SXiaojian Du 	MSG_MAP(SetHardMinIspiclkByFreq,        PPSMC_MSG_SetHardMinIspiclkByFreq,	0),
77271ab489SXiaojian Du 	MSG_MAP(SetHardMinIspxclkByFreq,        PPSMC_MSG_SetHardMinIspxclkByFreq,	0),
78271ab489SXiaojian Du 	MSG_MAP(SetDriverDramAddrHigh,          PPSMC_MSG_SetDriverDramAddrHigh,	0),
79271ab489SXiaojian Du 	MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverDramAddrLow,		0),
80271ab489SXiaojian Du 	MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram,	0),
81271ab489SXiaojian Du 	MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu,	0),
82271ab489SXiaojian Du 	MSG_MAP(GfxDeviceDriverReset,           PPSMC_MSG_GfxDeviceDriverReset,		0),
83271ab489SXiaojian Du 	MSG_MAP(GetEnabledSmuFeatures,          PPSMC_MSG_GetEnabledSmuFeatures,	0),
84271ab489SXiaojian Du 	MSG_MAP(Spare1,                         PPSMC_MSG_spare1,					0),
85271ab489SXiaojian Du 	MSG_MAP(SetHardMinSocclkByFreq,         PPSMC_MSG_SetHardMinSocclkByFreq,	0),
86271ab489SXiaojian Du 	MSG_MAP(SetSoftMinFclk,                 PPSMC_MSG_SetSoftMinFclk,		0),
87271ab489SXiaojian Du 	MSG_MAP(SetSoftMinVcn,                  PPSMC_MSG_SetSoftMinVcn,		0),
88271ab489SXiaojian Du 	MSG_MAP(EnablePostCode,                 PPSMC_MSG_EnablePostCode,		0),
89271ab489SXiaojian Du 	MSG_MAP(GetGfxclkFrequency,             PPSMC_MSG_GetGfxclkFrequency,	0),
90271ab489SXiaojian Du 	MSG_MAP(GetFclkFrequency,               PPSMC_MSG_GetFclkFrequency,		0),
91271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxGfxClk,               PPSMC_MSG_SetSoftMaxGfxClk,		0),
92271ab489SXiaojian Du 	MSG_MAP(SetHardMinGfxClk,               PPSMC_MSG_SetHardMinGfxClk,		0),
93271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxSocclkByFreq,         PPSMC_MSG_SetSoftMaxSocclkByFreq,	0),
94271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxFclkByFreq,           PPSMC_MSG_SetSoftMaxFclkByFreq,		0),
95271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxVcn,                  PPSMC_MSG_SetSoftMaxVcn,			0),
96271ab489SXiaojian Du 	MSG_MAP(Spare2,                         PPSMC_MSG_spare2,					0),
97271ab489SXiaojian Du 	MSG_MAP(SetPowerLimitPercentage,        PPSMC_MSG_SetPowerLimitPercentage,	0),
98271ab489SXiaojian Du 	MSG_MAP(PowerDownJpeg,                  PPSMC_MSG_PowerDownJpeg,			0),
99271ab489SXiaojian Du 	MSG_MAP(PowerUpJpeg,                    PPSMC_MSG_PowerUpJpeg,				0),
100271ab489SXiaojian Du 	MSG_MAP(SetHardMinFclkByFreq,           PPSMC_MSG_SetHardMinFclkByFreq,		0),
101271ab489SXiaojian Du 	MSG_MAP(SetSoftMinSocclkByFreq,         PPSMC_MSG_SetSoftMinSocclkByFreq,	0),
102271ab489SXiaojian Du 	MSG_MAP(PowerUpCvip,                    PPSMC_MSG_PowerUpCvip,				0),
103271ab489SXiaojian Du 	MSG_MAP(PowerDownCvip,                  PPSMC_MSG_PowerDownCvip,			0),
104271ab489SXiaojian Du 	MSG_MAP(GetPptLimit,                        PPSMC_MSG_GetPptLimit,			0),
105271ab489SXiaojian Du 	MSG_MAP(GetThermalLimit,                    PPSMC_MSG_GetThermalLimit,		0),
106271ab489SXiaojian Du 	MSG_MAP(GetCurrentTemperature,              PPSMC_MSG_GetCurrentTemperature, 0),
107271ab489SXiaojian Du 	MSG_MAP(GetCurrentPower,                    PPSMC_MSG_GetCurrentPower,		 0),
108271ab489SXiaojian Du 	MSG_MAP(GetCurrentVoltage,                  PPSMC_MSG_GetCurrentVoltage,	 0),
109271ab489SXiaojian Du 	MSG_MAP(GetCurrentCurrent,                  PPSMC_MSG_GetCurrentCurrent,	 0),
110271ab489SXiaojian Du 	MSG_MAP(GetAverageCpuActivity,              PPSMC_MSG_GetAverageCpuActivity, 0),
111271ab489SXiaojian Du 	MSG_MAP(GetAverageGfxActivity,              PPSMC_MSG_GetAverageGfxActivity, 0),
112271ab489SXiaojian Du 	MSG_MAP(GetAveragePower,                    PPSMC_MSG_GetAveragePower,		 0),
113271ab489SXiaojian Du 	MSG_MAP(GetAverageTemperature,              PPSMC_MSG_GetAverageTemperature, 0),
114271ab489SXiaojian Du 	MSG_MAP(SetAveragePowerTimeConstant,        PPSMC_MSG_SetAveragePowerTimeConstant,			0),
115271ab489SXiaojian Du 	MSG_MAP(SetAverageActivityTimeConstant,     PPSMC_MSG_SetAverageActivityTimeConstant,		0),
116271ab489SXiaojian Du 	MSG_MAP(SetAverageTemperatureTimeConstant,  PPSMC_MSG_SetAverageTemperatureTimeConstant,	0),
117271ab489SXiaojian Du 	MSG_MAP(SetMitigationEndHysteresis,         PPSMC_MSG_SetMitigationEndHysteresis,			0),
118271ab489SXiaojian Du 	MSG_MAP(GetCurrentFreq,                     PPSMC_MSG_GetCurrentFreq,						0),
119271ab489SXiaojian Du 	MSG_MAP(SetReducedPptLimit,                 PPSMC_MSG_SetReducedPptLimit,					0),
120271ab489SXiaojian Du 	MSG_MAP(SetReducedThermalLimit,             PPSMC_MSG_SetReducedThermalLimit,				0),
121271ab489SXiaojian Du 	MSG_MAP(DramLogSetDramAddr,                 PPSMC_MSG_DramLogSetDramAddr,					0),
122271ab489SXiaojian Du 	MSG_MAP(StartDramLogging,                   PPSMC_MSG_StartDramLogging,						0),
123271ab489SXiaojian Du 	MSG_MAP(StopDramLogging,                    PPSMC_MSG_StopDramLogging,						0),
124271ab489SXiaojian Du 	MSG_MAP(SetSoftMinCclk,                     PPSMC_MSG_SetSoftMinCclk,						0),
125271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxCclk,                     PPSMC_MSG_SetSoftMaxCclk,						0),
126eefdf047SJinzhou Su 	MSG_MAP(RequestActiveWgp,                   PPSMC_MSG_RequestActiveWgp,                     0),
127f46a221bSXiaojian Du };
128f46a221bSXiaojian Du 
129f46a221bSXiaojian Du static struct cmn2asic_mapping vangogh_feature_mask_map[SMU_FEATURE_COUNT] = {
130f46a221bSXiaojian Du 	FEA_MAP(PPT),
131f46a221bSXiaojian Du 	FEA_MAP(TDC),
132f46a221bSXiaojian Du 	FEA_MAP(THERMAL),
133f46a221bSXiaojian Du 	FEA_MAP(DS_GFXCLK),
134f46a221bSXiaojian Du 	FEA_MAP(DS_SOCCLK),
135f46a221bSXiaojian Du 	FEA_MAP(DS_LCLK),
136f46a221bSXiaojian Du 	FEA_MAP(DS_FCLK),
137f46a221bSXiaojian Du 	FEA_MAP(DS_MP1CLK),
138f46a221bSXiaojian Du 	FEA_MAP(DS_MP0CLK),
139f46a221bSXiaojian Du 	FEA_MAP(ATHUB_PG),
140f46a221bSXiaojian Du 	FEA_MAP(CCLK_DPM),
141f46a221bSXiaojian Du 	FEA_MAP(FAN_CONTROLLER),
142f46a221bSXiaojian Du 	FEA_MAP(ULV),
143f46a221bSXiaojian Du 	FEA_MAP(VCN_DPM),
144f46a221bSXiaojian Du 	FEA_MAP(LCLK_DPM),
145f46a221bSXiaojian Du 	FEA_MAP(SHUBCLK_DPM),
146f46a221bSXiaojian Du 	FEA_MAP(DCFCLK_DPM),
147f46a221bSXiaojian Du 	FEA_MAP(DS_DCFCLK),
148f46a221bSXiaojian Du 	FEA_MAP(S0I2),
149f46a221bSXiaojian Du 	FEA_MAP(SMU_LOW_POWER),
150f46a221bSXiaojian Du 	FEA_MAP(GFX_DEM),
151f46a221bSXiaojian Du 	FEA_MAP(PSI),
152f46a221bSXiaojian Du 	FEA_MAP(PROCHOT),
153f46a221bSXiaojian Du 	FEA_MAP(CPUOFF),
154f46a221bSXiaojian Du 	FEA_MAP(STAPM),
155f46a221bSXiaojian Du 	FEA_MAP(S0I3),
156f46a221bSXiaojian Du 	FEA_MAP(DF_CSTATES),
157f46a221bSXiaojian Du 	FEA_MAP(PERF_LIMIT),
158f46a221bSXiaojian Du 	FEA_MAP(CORE_DLDO),
159f46a221bSXiaojian Du 	FEA_MAP(RSMU_LOW_POWER),
160f46a221bSXiaojian Du 	FEA_MAP(SMN_LOW_POWER),
161f46a221bSXiaojian Du 	FEA_MAP(THM_LOW_POWER),
162f46a221bSXiaojian Du 	FEA_MAP(SMUIO_LOW_POWER),
163f46a221bSXiaojian Du 	FEA_MAP(MP1_LOW_POWER),
164f46a221bSXiaojian Du 	FEA_MAP(DS_VCN),
165f46a221bSXiaojian Du 	FEA_MAP(CPPC),
166f46a221bSXiaojian Du 	FEA_MAP(OS_CSTATES),
167f46a221bSXiaojian Du 	FEA_MAP(ISP_DPM),
168f46a221bSXiaojian Du 	FEA_MAP(A55_DPM),
169f46a221bSXiaojian Du 	FEA_MAP(CVIP_DSP_DPM),
170f46a221bSXiaojian Du 	FEA_MAP(MSMU_LOW_POWER),
17154800b58SXiaojian Du 	FEA_MAP_REVERSE(SOCCLK),
17254800b58SXiaojian Du 	FEA_MAP_REVERSE(FCLK),
17354800b58SXiaojian Du 	FEA_MAP_HALF_REVERSE(GFX),
174f46a221bSXiaojian Du };
175f46a221bSXiaojian Du 
176f46a221bSXiaojian Du static struct cmn2asic_mapping vangogh_table_map[SMU_TABLE_COUNT] = {
177f46a221bSXiaojian Du 	TAB_MAP_VALID(WATERMARKS),
178f46a221bSXiaojian Du 	TAB_MAP_VALID(SMU_METRICS),
179f46a221bSXiaojian Du 	TAB_MAP_VALID(CUSTOM_DPM),
180f46a221bSXiaojian Du 	TAB_MAP_VALID(DPMCLOCKS),
181f46a221bSXiaojian Du };
182f46a221bSXiaojian Du 
183f727ebebSXiaojian Du static struct cmn2asic_mapping vangogh_workload_map[PP_SMC_POWER_PROFILE_COUNT] = {
184f727ebebSXiaojian Du 	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D,		WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT),
185f727ebebSXiaojian Du 	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO,		WORKLOAD_PPLIB_VIDEO_BIT),
186f727ebebSXiaojian Du 	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR,			WORKLOAD_PPLIB_VR_BIT),
187f727ebebSXiaojian Du 	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE,		WORKLOAD_PPLIB_COMPUTE_BIT),
188f727ebebSXiaojian Du 	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM,		WORKLOAD_PPLIB_CUSTOM_BIT),
189f727ebebSXiaojian Du };
190f727ebebSXiaojian Du 
191f46a221bSXiaojian Du static int vangogh_tables_init(struct smu_context *smu)
192f46a221bSXiaojian Du {
193f46a221bSXiaojian Du 	struct smu_table_context *smu_table = &smu->smu_table;
194f46a221bSXiaojian Du 	struct smu_table *tables = smu_table->tables;
195f46a221bSXiaojian Du 
196f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
197f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
198f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
199f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
200f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
201f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
202f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE,
203f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
204f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF, sizeof(DpmActivityMonitorCoeffExt_t),
205f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
206f46a221bSXiaojian Du 	smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
207f46a221bSXiaojian Du 	if (!smu_table->metrics_table)
208f46a221bSXiaojian Du 		goto err0_out;
209f46a221bSXiaojian Du 	smu_table->metrics_time = 0;
210f46a221bSXiaojian Du 
211f46a221bSXiaojian Du 	smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_0);
212f46a221bSXiaojian Du 	smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
213f46a221bSXiaojian Du 	if (!smu_table->gpu_metrics_table)
214f46a221bSXiaojian Du 		goto err1_out;
215f46a221bSXiaojian Du 
216f46a221bSXiaojian Du 	smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
217f46a221bSXiaojian Du 	if (!smu_table->watermarks_table)
218f46a221bSXiaojian Du 		goto err2_out;
219f46a221bSXiaojian Du 
220c98ee897SXiaojian Du 	smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
221c98ee897SXiaojian Du 	if (!smu_table->clocks_table)
222c98ee897SXiaojian Du 		goto err3_out;
223c98ee897SXiaojian Du 
224f46a221bSXiaojian Du 	return 0;
225f46a221bSXiaojian Du 
226c98ee897SXiaojian Du err3_out:
227c98ee897SXiaojian Du 	kfree(smu_table->clocks_table);
228f46a221bSXiaojian Du err2_out:
229f46a221bSXiaojian Du 	kfree(smu_table->gpu_metrics_table);
230f46a221bSXiaojian Du err1_out:
231f46a221bSXiaojian Du 	kfree(smu_table->metrics_table);
232f46a221bSXiaojian Du err0_out:
233f46a221bSXiaojian Du 	return -ENOMEM;
234f46a221bSXiaojian Du }
235f46a221bSXiaojian Du 
236271ab489SXiaojian Du static int vangogh_get_smu_metrics_data(struct smu_context *smu,
237271ab489SXiaojian Du 				       MetricsMember_t member,
238271ab489SXiaojian Du 				       uint32_t *value)
239271ab489SXiaojian Du {
240271ab489SXiaojian Du 	struct smu_table_context *smu_table = &smu->smu_table;
241271ab489SXiaojian Du 
242271ab489SXiaojian Du 	SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
243271ab489SXiaojian Du 	int ret = 0;
244271ab489SXiaojian Du 
245271ab489SXiaojian Du 	mutex_lock(&smu->metrics_lock);
246271ab489SXiaojian Du 
247271ab489SXiaojian Du 	ret = smu_cmn_get_metrics_table_locked(smu,
248271ab489SXiaojian Du 					       NULL,
249271ab489SXiaojian Du 					       false);
250271ab489SXiaojian Du 	if (ret) {
251271ab489SXiaojian Du 		mutex_unlock(&smu->metrics_lock);
252271ab489SXiaojian Du 		return ret;
253271ab489SXiaojian Du 	}
254271ab489SXiaojian Du 
255271ab489SXiaojian Du 	switch (member) {
256271ab489SXiaojian Du 	case METRICS_AVERAGE_GFXCLK:
257271ab489SXiaojian Du 		*value = metrics->GfxclkFrequency;
258271ab489SXiaojian Du 		break;
259271ab489SXiaojian Du 	case METRICS_AVERAGE_SOCCLK:
260271ab489SXiaojian Du 		*value = metrics->SocclkFrequency;
261271ab489SXiaojian Du 		break;
262f02c7336SXiaojian Du 	case METRICS_AVERAGE_VCLK:
263f02c7336SXiaojian Du 		*value = metrics->VclkFrequency;
264f02c7336SXiaojian Du 		break;
265f02c7336SXiaojian Du 	case METRICS_AVERAGE_DCLK:
266f02c7336SXiaojian Du 		*value = metrics->DclkFrequency;
267f02c7336SXiaojian Du 		break;
268271ab489SXiaojian Du 	case METRICS_AVERAGE_UCLK:
269271ab489SXiaojian Du 		*value = metrics->MemclkFrequency;
270271ab489SXiaojian Du 		break;
271271ab489SXiaojian Du 	case METRICS_AVERAGE_GFXACTIVITY:
272271ab489SXiaojian Du 		*value = metrics->GfxActivity / 100;
273271ab489SXiaojian Du 		break;
274271ab489SXiaojian Du 	case METRICS_AVERAGE_VCNACTIVITY:
275271ab489SXiaojian Du 		*value = metrics->UvdActivity;
276271ab489SXiaojian Du 		break;
277271ab489SXiaojian Du 	case METRICS_AVERAGE_SOCKETPOWER:
27823289a22SXiaojian Du 		*value = (metrics->CurrentSocketPower << 8) /
27923289a22SXiaojian Du 		1000 ;
280271ab489SXiaojian Du 		break;
281271ab489SXiaojian Du 	case METRICS_TEMPERATURE_EDGE:
282271ab489SXiaojian Du 		*value = metrics->GfxTemperature / 100 *
283271ab489SXiaojian Du 		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
284271ab489SXiaojian Du 		break;
285271ab489SXiaojian Du 	case METRICS_TEMPERATURE_HOTSPOT:
286271ab489SXiaojian Du 		*value = metrics->SocTemperature / 100 *
287271ab489SXiaojian Du 		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
288271ab489SXiaojian Du 		break;
289271ab489SXiaojian Du 	case METRICS_THROTTLER_STATUS:
290271ab489SXiaojian Du 		*value = metrics->ThrottlerStatus;
291271ab489SXiaojian Du 		break;
2922139d12bSAlex Deucher 	case METRICS_VOLTAGE_VDDGFX:
2932139d12bSAlex Deucher 		*value = metrics->Voltage[2];
2942139d12bSAlex Deucher 		break;
2952139d12bSAlex Deucher 	case METRICS_VOLTAGE_VDDSOC:
2962139d12bSAlex Deucher 		*value = metrics->Voltage[1];
2972139d12bSAlex Deucher 		break;
298517cb957SHuang Rui 	case METRICS_AVERAGE_CPUCLK:
299517cb957SHuang Rui 		memcpy(value, &metrics->CoreFrequency[0],
300517cb957SHuang Rui 		       boot_cpu_data.x86_max_cores * sizeof(uint16_t));
301517cb957SHuang Rui 		break;
302271ab489SXiaojian Du 	default:
303271ab489SXiaojian Du 		*value = UINT_MAX;
304271ab489SXiaojian Du 		break;
305271ab489SXiaojian Du 	}
306271ab489SXiaojian Du 
307271ab489SXiaojian Du 	mutex_unlock(&smu->metrics_lock);
308271ab489SXiaojian Du 
309271ab489SXiaojian Du 	return ret;
310271ab489SXiaojian Du }
311271ab489SXiaojian Du 
312f46a221bSXiaojian Du static int vangogh_allocate_dpm_context(struct smu_context *smu)
313f46a221bSXiaojian Du {
314f46a221bSXiaojian Du 	struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
315f46a221bSXiaojian Du 
316f46a221bSXiaojian Du 	smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context),
317f46a221bSXiaojian Du 				       GFP_KERNEL);
318f46a221bSXiaojian Du 	if (!smu_dpm->dpm_context)
319f46a221bSXiaojian Du 		return -ENOMEM;
320f46a221bSXiaojian Du 
321f46a221bSXiaojian Du 	smu_dpm->dpm_context_size = sizeof(struct smu_11_0_dpm_context);
322f46a221bSXiaojian Du 
323f46a221bSXiaojian Du 	return 0;
324f46a221bSXiaojian Du }
325f46a221bSXiaojian Du 
326f46a221bSXiaojian Du static int vangogh_init_smc_tables(struct smu_context *smu)
327f46a221bSXiaojian Du {
328f46a221bSXiaojian Du 	int ret = 0;
329f46a221bSXiaojian Du 
330f46a221bSXiaojian Du 	ret = vangogh_tables_init(smu);
331f46a221bSXiaojian Du 	if (ret)
332f46a221bSXiaojian Du 		return ret;
333f46a221bSXiaojian Du 
334f46a221bSXiaojian Du 	ret = vangogh_allocate_dpm_context(smu);
335f46a221bSXiaojian Du 	if (ret)
336f46a221bSXiaojian Du 		return ret;
337f46a221bSXiaojian Du 
338f46a221bSXiaojian Du 	return smu_v11_0_init_smc_tables(smu);
339f46a221bSXiaojian Du }
340f46a221bSXiaojian Du 
341f46a221bSXiaojian Du static int vangogh_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
342f46a221bSXiaojian Du {
343f46a221bSXiaojian Du 	int ret = 0;
344f46a221bSXiaojian Du 
345f46a221bSXiaojian Du 	if (enable) {
346f46a221bSXiaojian Du 		/* vcn dpm on is a prerequisite for vcn power gate messages */
347f46a221bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 0, NULL);
348f46a221bSXiaojian Du 		if (ret)
349f46a221bSXiaojian Du 			return ret;
350f46a221bSXiaojian Du 	} else {
351f46a221bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn, 0, NULL);
352f46a221bSXiaojian Du 		if (ret)
353f46a221bSXiaojian Du 			return ret;
354f46a221bSXiaojian Du 	}
355f46a221bSXiaojian Du 
356f46a221bSXiaojian Du 	return ret;
357f46a221bSXiaojian Du }
358f46a221bSXiaojian Du 
359f46a221bSXiaojian Du static int vangogh_dpm_set_jpeg_enable(struct smu_context *smu, bool enable)
360f46a221bSXiaojian Du {
361f46a221bSXiaojian Du 	int ret = 0;
362f46a221bSXiaojian Du 
363f46a221bSXiaojian Du 	if (enable) {
364f46a221bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0, NULL);
365f46a221bSXiaojian Du 		if (ret)
366f46a221bSXiaojian Du 			return ret;
367f46a221bSXiaojian Du 	} else {
368f46a221bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0, NULL);
369f46a221bSXiaojian Du 		if (ret)
370f46a221bSXiaojian Du 			return ret;
371f46a221bSXiaojian Du 	}
372f46a221bSXiaojian Du 
373f46a221bSXiaojian Du 	return ret;
374f46a221bSXiaojian Du }
375f46a221bSXiaojian Du 
376f46a221bSXiaojian Du static bool vangogh_is_dpm_running(struct smu_context *smu)
377f46a221bSXiaojian Du {
378271ab489SXiaojian Du 	int ret = 0;
379271ab489SXiaojian Du 	uint32_t feature_mask[2];
380271ab489SXiaojian Du 	uint64_t feature_enabled;
381f46a221bSXiaojian Du 
382271ab489SXiaojian Du 	ret = smu_cmn_get_enabled_32_bits_mask(smu, feature_mask, 2);
383271ab489SXiaojian Du 
384271ab489SXiaojian Du 	if (ret)
385f46a221bSXiaojian Du 		return false;
386f46a221bSXiaojian Du 
387271ab489SXiaojian Du 	feature_enabled = (unsigned long)((uint64_t)feature_mask[0] |
388271ab489SXiaojian Du 				((uint64_t)feature_mask[1] << 32));
389271ab489SXiaojian Du 
390271ab489SXiaojian Du 	return !!(feature_enabled & SMC_DPM_FEATURE);
391271ab489SXiaojian Du }
392271ab489SXiaojian Du 
393ae7b32e7SXiaojian Du static int vangogh_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type clk_type,
394ae7b32e7SXiaojian Du 						uint32_t dpm_level, uint32_t *freq)
395ae7b32e7SXiaojian Du {
396ae7b32e7SXiaojian Du 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
397ae7b32e7SXiaojian Du 
398ae7b32e7SXiaojian Du 	if (!clk_table || clk_type >= SMU_CLK_COUNT)
399ae7b32e7SXiaojian Du 		return -EINVAL;
400ae7b32e7SXiaojian Du 
401ae7b32e7SXiaojian Du 	switch (clk_type) {
402ae7b32e7SXiaojian Du 	case SMU_SOCCLK:
403ae7b32e7SXiaojian Du 		if (dpm_level >= clk_table->NumSocClkLevelsEnabled)
404ae7b32e7SXiaojian Du 			return -EINVAL;
405ae7b32e7SXiaojian Du 		*freq = clk_table->SocClocks[dpm_level];
406ae7b32e7SXiaojian Du 		break;
407f02c7336SXiaojian Du 	case SMU_VCLK:
408f02c7336SXiaojian Du 		if (dpm_level >= clk_table->VcnClkLevelsEnabled)
409f02c7336SXiaojian Du 			return -EINVAL;
410f02c7336SXiaojian Du 		*freq = clk_table->VcnClocks[dpm_level].vclk;
411f02c7336SXiaojian Du 		break;
412f02c7336SXiaojian Du 	case SMU_DCLK:
413f02c7336SXiaojian Du 		if (dpm_level >= clk_table->VcnClkLevelsEnabled)
414f02c7336SXiaojian Du 			return -EINVAL;
415f02c7336SXiaojian Du 		*freq = clk_table->VcnClocks[dpm_level].dclk;
416f02c7336SXiaojian Du 		break;
417ae7b32e7SXiaojian Du 	case SMU_UCLK:
418ae7b32e7SXiaojian Du 	case SMU_MCLK:
419ae7b32e7SXiaojian Du 		if (dpm_level >= clk_table->NumDfPstatesEnabled)
420ae7b32e7SXiaojian Du 			return -EINVAL;
421ae7b32e7SXiaojian Du 		*freq = clk_table->DfPstateTable[dpm_level].memclk;
422ae7b32e7SXiaojian Du 
423ae7b32e7SXiaojian Du 		break;
424ae7b32e7SXiaojian Du 	case SMU_FCLK:
425ae7b32e7SXiaojian Du 		if (dpm_level >= clk_table->NumDfPstatesEnabled)
426ae7b32e7SXiaojian Du 			return -EINVAL;
427ae7b32e7SXiaojian Du 		*freq = clk_table->DfPstateTable[dpm_level].fclk;
428ae7b32e7SXiaojian Du 		break;
429ae7b32e7SXiaojian Du 	default:
430ae7b32e7SXiaojian Du 		return -EINVAL;
431ae7b32e7SXiaojian Du 	}
432ae7b32e7SXiaojian Du 
433ae7b32e7SXiaojian Du 	return 0;
434ae7b32e7SXiaojian Du }
435ae7b32e7SXiaojian Du 
436c98ee897SXiaojian Du static int vangogh_print_fine_grain_clk(struct smu_context *smu,
437c98ee897SXiaojian Du 			enum smu_clk_type clk_type, char *buf)
438c98ee897SXiaojian Du {
439ae7b32e7SXiaojian Du 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
440ae7b32e7SXiaojian Du 	SmuMetrics_t metrics;
441ae7b32e7SXiaojian Du 	int i, size = 0, ret = 0;
442ae7b32e7SXiaojian Du 	uint32_t cur_value = 0, value = 0, count = 0;
443ae7b32e7SXiaojian Du 	bool cur_value_match_level = false;
444ae7b32e7SXiaojian Du 
445ae7b32e7SXiaojian Du 	memset(&metrics, 0, sizeof(metrics));
446ae7b32e7SXiaojian Du 
447ae7b32e7SXiaojian Du 	ret = smu_cmn_get_metrics_table(smu, &metrics, false);
448ae7b32e7SXiaojian Du 	if (ret)
449ae7b32e7SXiaojian Du 		return ret;
450c98ee897SXiaojian Du 
451c98ee897SXiaojian Du 	switch (clk_type) {
452c98ee897SXiaojian Du 	case SMU_OD_SCLK:
453c98ee897SXiaojian Du 		if (smu->od_enabled) {
454c98ee897SXiaojian Du 			size = sprintf(buf, "%s:\n", "OD_SCLK");
455c98ee897SXiaojian Du 			size += sprintf(buf + size, "0: %10uMhz\n",
456c98ee897SXiaojian Du 			(smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);
457c98ee897SXiaojian Du 			size += sprintf(buf + size, "1: %10uMhz\n",
458c98ee897SXiaojian Du 			(smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq);
459c98ee897SXiaojian Du 		}
460c98ee897SXiaojian Du 		break;
461*0d90d0ddSHuang Rui 	case SMU_OD_CCLK:
462*0d90d0ddSHuang Rui 		if (smu->od_enabled) {
463*0d90d0ddSHuang Rui 			size = sprintf(buf, "CCLK_RANGE in Core%d:\n",  smu->cpu_core_id_select);
464*0d90d0ddSHuang Rui 			size += sprintf(buf + size, "0: %10uMhz\n",
465*0d90d0ddSHuang Rui 			(smu->cpu_actual_soft_min_freq > 0) ? smu->cpu_actual_soft_min_freq : smu->cpu_default_soft_min_freq);
466*0d90d0ddSHuang Rui 			size += sprintf(buf + size, "1: %10uMhz\n",
467*0d90d0ddSHuang Rui 			(smu->cpu_actual_soft_max_freq > 0) ? smu->cpu_actual_soft_max_freq : smu->cpu_default_soft_max_freq);
468*0d90d0ddSHuang Rui 		}
469*0d90d0ddSHuang Rui 		break;
470c98ee897SXiaojian Du 	case SMU_OD_RANGE:
471c98ee897SXiaojian Du 		if (smu->od_enabled) {
472c98ee897SXiaojian Du 			size = sprintf(buf, "%s:\n", "OD_RANGE");
473c98ee897SXiaojian Du 			size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
474c98ee897SXiaojian Du 				smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);
475*0d90d0ddSHuang Rui 			size += sprintf(buf + size, "CCLK: %7uMhz %10uMhz\n",
476*0d90d0ddSHuang Rui 				smu->cpu_default_soft_min_freq, smu->cpu_default_soft_max_freq);
477c98ee897SXiaojian Du 		}
478c98ee897SXiaojian Du 		break;
479ae7b32e7SXiaojian Du 	case SMU_SOCCLK:
480ae7b32e7SXiaojian Du 		/* the level 3 ~ 6 of socclk use the same frequency for vangogh */
481ae7b32e7SXiaojian Du 		count = clk_table->NumSocClkLevelsEnabled;
482ae7b32e7SXiaojian Du 		cur_value = metrics.SocclkFrequency;
483ae7b32e7SXiaojian Du 		break;
484f02c7336SXiaojian Du 	case SMU_VCLK:
485f02c7336SXiaojian Du 		count = clk_table->VcnClkLevelsEnabled;
486f02c7336SXiaojian Du 		cur_value = metrics.VclkFrequency;
487f02c7336SXiaojian Du 		break;
488f02c7336SXiaojian Du 	case SMU_DCLK:
489f02c7336SXiaojian Du 		count = clk_table->VcnClkLevelsEnabled;
490f02c7336SXiaojian Du 		cur_value = metrics.DclkFrequency;
491f02c7336SXiaojian Du 		break;
492ae7b32e7SXiaojian Du 	case SMU_MCLK:
493ae7b32e7SXiaojian Du 		count = clk_table->NumDfPstatesEnabled;
494ae7b32e7SXiaojian Du 		cur_value = metrics.MemclkFrequency;
495ae7b32e7SXiaojian Du 		break;
496ae7b32e7SXiaojian Du 	case SMU_FCLK:
497ae7b32e7SXiaojian Du 		count = clk_table->NumDfPstatesEnabled;
498ae7b32e7SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetFclkFrequency, 0, &cur_value);
499ae7b32e7SXiaojian Du 		if (ret)
500ae7b32e7SXiaojian Du 			return ret;
501ae7b32e7SXiaojian Du 		break;
502ae7b32e7SXiaojian Du 	default:
503ae7b32e7SXiaojian Du 		break;
504ae7b32e7SXiaojian Du 	}
505ae7b32e7SXiaojian Du 
506ae7b32e7SXiaojian Du 	switch (clk_type) {
507ae7b32e7SXiaojian Du 	case SMU_SOCCLK:
508f02c7336SXiaojian Du 	case SMU_VCLK:
509f02c7336SXiaojian Du 	case SMU_DCLK:
510ae7b32e7SXiaojian Du 	case SMU_MCLK:
511ae7b32e7SXiaojian Du 	case SMU_FCLK:
512ae7b32e7SXiaojian Du 		for (i = 0; i < count; i++) {
513ae7b32e7SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, i, &value);
514ae7b32e7SXiaojian Du 			if (ret)
515ae7b32e7SXiaojian Du 				return ret;
516ae7b32e7SXiaojian Du 			if (!value)
517ae7b32e7SXiaojian Du 				continue;
518ae7b32e7SXiaojian Du 			size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
519ae7b32e7SXiaojian Du 					cur_value == value ? "*" : "");
520ae7b32e7SXiaojian Du 			if (cur_value == value)
521ae7b32e7SXiaojian Du 				cur_value_match_level = true;
522ae7b32e7SXiaojian Du 		}
523ae7b32e7SXiaojian Du 
524ae7b32e7SXiaojian Du 		if (!cur_value_match_level)
525ae7b32e7SXiaojian Du 			size += sprintf(buf + size, "   %uMhz *\n", cur_value);
526ae7b32e7SXiaojian Du 		break;
527c98ee897SXiaojian Du 	default:
528c98ee897SXiaojian Du 		break;
529c98ee897SXiaojian Du 	}
530c98ee897SXiaojian Du 
531c98ee897SXiaojian Du 	return size;
532c98ee897SXiaojian Du }
533c98ee897SXiaojian Du 
534d0e4e112SXiaojian Du static int vangogh_get_profiling_clk_mask(struct smu_context *smu,
535d0e4e112SXiaojian Du 					 enum amd_dpm_forced_level level,
536d0e4e112SXiaojian Du 					 uint32_t *vclk_mask,
537d0e4e112SXiaojian Du 					 uint32_t *dclk_mask,
538d0e4e112SXiaojian Du 					 uint32_t *mclk_mask,
539d0e4e112SXiaojian Du 					 uint32_t *fclk_mask,
540d0e4e112SXiaojian Du 					 uint32_t *soc_mask)
541d0e4e112SXiaojian Du {
542d0e4e112SXiaojian Du 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
543d0e4e112SXiaojian Du 
544307f049bSXiaojian Du 	if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
545d0e4e112SXiaojian Du 		if (mclk_mask)
546d0e4e112SXiaojian Du 			*mclk_mask = clk_table->NumDfPstatesEnabled - 1;
547307f049bSXiaojian Du 
548d0e4e112SXiaojian Du 		if (fclk_mask)
549d0e4e112SXiaojian Du 			*fclk_mask = clk_table->NumDfPstatesEnabled - 1;
550307f049bSXiaojian Du 
551307f049bSXiaojian Du 		if (soc_mask)
552307f049bSXiaojian Du 			*soc_mask = 0;
553d0e4e112SXiaojian Du 	} else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
554d0e4e112SXiaojian Du 		if (mclk_mask)
555d0e4e112SXiaojian Du 			*mclk_mask = 0;
556307f049bSXiaojian Du 
557d0e4e112SXiaojian Du 		if (fclk_mask)
558d0e4e112SXiaojian Du 			*fclk_mask = 0;
559d0e4e112SXiaojian Du 
560d0e4e112SXiaojian Du 		if (soc_mask)
561307f049bSXiaojian Du 			*soc_mask = 1;
562307f049bSXiaojian Du 
563307f049bSXiaojian Du 		if (vclk_mask)
564307f049bSXiaojian Du 			*vclk_mask = 1;
565307f049bSXiaojian Du 
566307f049bSXiaojian Du 		if (dclk_mask)
567307f049bSXiaojian Du 			*dclk_mask = 1;
568307f049bSXiaojian Du 	} else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD) {
569307f049bSXiaojian Du 		if (mclk_mask)
570307f049bSXiaojian Du 			*mclk_mask = 0;
571307f049bSXiaojian Du 
572307f049bSXiaojian Du 		if (fclk_mask)
573307f049bSXiaojian Du 			*fclk_mask = 0;
574307f049bSXiaojian Du 
575307f049bSXiaojian Du 		if (soc_mask)
576307f049bSXiaojian Du 			*soc_mask = 1;
577307f049bSXiaojian Du 
578307f049bSXiaojian Du 		if (vclk_mask)
579307f049bSXiaojian Du 			*vclk_mask = 1;
580307f049bSXiaojian Du 
581307f049bSXiaojian Du 		if (dclk_mask)
582307f049bSXiaojian Du 			*dclk_mask = 1;
583d0e4e112SXiaojian Du 	}
584d0e4e112SXiaojian Du 
585d0e4e112SXiaojian Du 	return 0;
586d0e4e112SXiaojian Du }
587d0e4e112SXiaojian Du 
588d0e4e112SXiaojian Du bool vangogh_clk_dpm_is_enabled(struct smu_context *smu,
589d0e4e112SXiaojian Du 				enum smu_clk_type clk_type)
590d0e4e112SXiaojian Du {
591d0e4e112SXiaojian Du 	enum smu_feature_mask feature_id = 0;
592d0e4e112SXiaojian Du 
593d0e4e112SXiaojian Du 	switch (clk_type) {
594d0e4e112SXiaojian Du 	case SMU_MCLK:
595d0e4e112SXiaojian Du 	case SMU_UCLK:
596d0e4e112SXiaojian Du 	case SMU_FCLK:
597d0e4e112SXiaojian Du 		feature_id = SMU_FEATURE_DPM_FCLK_BIT;
598d0e4e112SXiaojian Du 		break;
599d0e4e112SXiaojian Du 	case SMU_GFXCLK:
600d0e4e112SXiaojian Du 	case SMU_SCLK:
601d0e4e112SXiaojian Du 		feature_id = SMU_FEATURE_DPM_GFXCLK_BIT;
602d0e4e112SXiaojian Du 		break;
603d0e4e112SXiaojian Du 	case SMU_SOCCLK:
604d0e4e112SXiaojian Du 		feature_id = SMU_FEATURE_DPM_SOCCLK_BIT;
605d0e4e112SXiaojian Du 		break;
606d0e4e112SXiaojian Du 	case SMU_VCLK:
607d0e4e112SXiaojian Du 	case SMU_DCLK:
608d0e4e112SXiaojian Du 		feature_id = SMU_FEATURE_VCN_DPM_BIT;
609d0e4e112SXiaojian Du 		break;
610d0e4e112SXiaojian Du 	default:
611d0e4e112SXiaojian Du 		return true;
612d0e4e112SXiaojian Du 	}
613d0e4e112SXiaojian Du 
614d0e4e112SXiaojian Du 	if (!smu_cmn_feature_is_enabled(smu, feature_id))
615d0e4e112SXiaojian Du 		return false;
616d0e4e112SXiaojian Du 
617d0e4e112SXiaojian Du 	return true;
618d0e4e112SXiaojian Du }
619d0e4e112SXiaojian Du 
620d0e4e112SXiaojian Du static int vangogh_get_dpm_ultimate_freq(struct smu_context *smu,
621d0e4e112SXiaojian Du 					enum smu_clk_type clk_type,
622d0e4e112SXiaojian Du 					uint32_t *min,
623d0e4e112SXiaojian Du 					uint32_t *max)
624d0e4e112SXiaojian Du {
625d0e4e112SXiaojian Du 	int ret = 0;
626d0e4e112SXiaojian Du 	uint32_t soc_mask;
627d0e4e112SXiaojian Du 	uint32_t vclk_mask;
628d0e4e112SXiaojian Du 	uint32_t dclk_mask;
629d0e4e112SXiaojian Du 	uint32_t mclk_mask;
630d0e4e112SXiaojian Du 	uint32_t fclk_mask;
631d0e4e112SXiaojian Du 	uint32_t clock_limit;
632d0e4e112SXiaojian Du 
633d0e4e112SXiaojian Du 	if (!vangogh_clk_dpm_is_enabled(smu, clk_type)) {
634d0e4e112SXiaojian Du 		switch (clk_type) {
635d0e4e112SXiaojian Du 		case SMU_MCLK:
636d0e4e112SXiaojian Du 		case SMU_UCLK:
637d0e4e112SXiaojian Du 			clock_limit = smu->smu_table.boot_values.uclk;
638d0e4e112SXiaojian Du 			break;
639d0e4e112SXiaojian Du 		case SMU_FCLK:
640d0e4e112SXiaojian Du 			clock_limit = smu->smu_table.boot_values.fclk;
641d0e4e112SXiaojian Du 			break;
642d0e4e112SXiaojian Du 		case SMU_GFXCLK:
643d0e4e112SXiaojian Du 		case SMU_SCLK:
644d0e4e112SXiaojian Du 			clock_limit = smu->smu_table.boot_values.gfxclk;
645d0e4e112SXiaojian Du 			break;
646d0e4e112SXiaojian Du 		case SMU_SOCCLK:
647d0e4e112SXiaojian Du 			clock_limit = smu->smu_table.boot_values.socclk;
648d0e4e112SXiaojian Du 			break;
649d0e4e112SXiaojian Du 		case SMU_VCLK:
650d0e4e112SXiaojian Du 			clock_limit = smu->smu_table.boot_values.vclk;
651d0e4e112SXiaojian Du 			break;
652d0e4e112SXiaojian Du 		case SMU_DCLK:
653d0e4e112SXiaojian Du 			clock_limit = smu->smu_table.boot_values.dclk;
654d0e4e112SXiaojian Du 			break;
655d0e4e112SXiaojian Du 		default:
656d0e4e112SXiaojian Du 			clock_limit = 0;
657d0e4e112SXiaojian Du 			break;
658d0e4e112SXiaojian Du 		}
659d0e4e112SXiaojian Du 
660d0e4e112SXiaojian Du 		/* clock in Mhz unit */
661d0e4e112SXiaojian Du 		if (min)
662d0e4e112SXiaojian Du 			*min = clock_limit / 100;
663d0e4e112SXiaojian Du 		if (max)
664d0e4e112SXiaojian Du 			*max = clock_limit / 100;
665d0e4e112SXiaojian Du 
666d0e4e112SXiaojian Du 		return 0;
667d0e4e112SXiaojian Du 	}
668d0e4e112SXiaojian Du 	if (max) {
669d0e4e112SXiaojian Du 		ret = vangogh_get_profiling_clk_mask(smu,
670d0e4e112SXiaojian Du 							AMD_DPM_FORCED_LEVEL_PROFILE_PEAK,
671d0e4e112SXiaojian Du 							&vclk_mask,
672d0e4e112SXiaojian Du 							&dclk_mask,
673d0e4e112SXiaojian Du 							&mclk_mask,
674d0e4e112SXiaojian Du 							&fclk_mask,
675d0e4e112SXiaojian Du 							&soc_mask);
676d0e4e112SXiaojian Du 		if (ret)
677d0e4e112SXiaojian Du 			goto failed;
678d0e4e112SXiaojian Du 
679d0e4e112SXiaojian Du 		switch (clk_type) {
680d0e4e112SXiaojian Du 		case SMU_UCLK:
681d0e4e112SXiaojian Du 		case SMU_MCLK:
682d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, mclk_mask, max);
683d0e4e112SXiaojian Du 			if (ret)
684d0e4e112SXiaojian Du 				goto failed;
685d0e4e112SXiaojian Du 			break;
686d0e4e112SXiaojian Du 		case SMU_SOCCLK:
687d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, soc_mask, max);
688d0e4e112SXiaojian Du 			if (ret)
689d0e4e112SXiaojian Du 				goto failed;
690d0e4e112SXiaojian Du 			break;
691d0e4e112SXiaojian Du 		case SMU_FCLK:
692d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, fclk_mask, max);
693d0e4e112SXiaojian Du 			if (ret)
694d0e4e112SXiaojian Du 				goto failed;
695d0e4e112SXiaojian Du 			break;
696d0e4e112SXiaojian Du 		case SMU_VCLK:
697d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, vclk_mask, max);
698d0e4e112SXiaojian Du 			if (ret)
699d0e4e112SXiaojian Du 				goto failed;
700d0e4e112SXiaojian Du 			break;
701d0e4e112SXiaojian Du 		case SMU_DCLK:
702d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, dclk_mask, max);
703d0e4e112SXiaojian Du 			if (ret)
704d0e4e112SXiaojian Du 				goto failed;
705d0e4e112SXiaojian Du 			break;
706d0e4e112SXiaojian Du 		default:
707d0e4e112SXiaojian Du 			ret = -EINVAL;
708d0e4e112SXiaojian Du 			goto failed;
709d0e4e112SXiaojian Du 		}
710d0e4e112SXiaojian Du 	}
711d0e4e112SXiaojian Du 	if (min) {
712d0e4e112SXiaojian Du 		switch (clk_type) {
713d0e4e112SXiaojian Du 		case SMU_UCLK:
714d0e4e112SXiaojian Du 		case SMU_MCLK:
715d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, mclk_mask, min);
716d0e4e112SXiaojian Du 			if (ret)
717d0e4e112SXiaojian Du 				goto failed;
718d0e4e112SXiaojian Du 			break;
719d0e4e112SXiaojian Du 		case SMU_SOCCLK:
720d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, soc_mask, min);
721d0e4e112SXiaojian Du 			if (ret)
722d0e4e112SXiaojian Du 				goto failed;
723d0e4e112SXiaojian Du 			break;
724d0e4e112SXiaojian Du 		case SMU_FCLK:
725d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, fclk_mask, min);
726d0e4e112SXiaojian Du 			if (ret)
727d0e4e112SXiaojian Du 				goto failed;
728d0e4e112SXiaojian Du 			break;
729d0e4e112SXiaojian Du 		case SMU_VCLK:
730d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, vclk_mask, min);
731d0e4e112SXiaojian Du 			if (ret)
732d0e4e112SXiaojian Du 				goto failed;
733d0e4e112SXiaojian Du 			break;
734d0e4e112SXiaojian Du 		case SMU_DCLK:
735d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, dclk_mask, min);
736d0e4e112SXiaojian Du 			if (ret)
737d0e4e112SXiaojian Du 				goto failed;
738d0e4e112SXiaojian Du 			break;
739d0e4e112SXiaojian Du 		default:
740d0e4e112SXiaojian Du 			ret = -EINVAL;
741d0e4e112SXiaojian Du 			goto failed;
742d0e4e112SXiaojian Du 		}
743d0e4e112SXiaojian Du 	}
744d0e4e112SXiaojian Du failed:
745d0e4e112SXiaojian Du 	return ret;
746d0e4e112SXiaojian Du }
747d0e4e112SXiaojian Du 
748307f049bSXiaojian Du static int vangogh_get_power_profile_mode(struct smu_context *smu,
749307f049bSXiaojian Du 					   char *buf)
750307f049bSXiaojian Du {
751307f049bSXiaojian Du 	static const char *profile_name[] = {
7522a38ca99SColin Ian King 					"BOOTUP_DEFAULT",
753f727ebebSXiaojian Du 					"3D_FULL_SCREEN",
754f727ebebSXiaojian Du 					"POWER_SAVING",
755307f049bSXiaojian Du 					"VIDEO",
756307f049bSXiaojian Du 					"VR",
757307f049bSXiaojian Du 					"COMPUTE",
758307f049bSXiaojian Du 					"CUSTOM"};
759307f049bSXiaojian Du 	uint32_t i, size = 0;
760307f049bSXiaojian Du 	int16_t workload_type = 0;
761307f049bSXiaojian Du 
762307f049bSXiaojian Du 	if (!buf)
763307f049bSXiaojian Du 		return -EINVAL;
764307f049bSXiaojian Du 
765307f049bSXiaojian Du 	for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
766307f049bSXiaojian Du 		/*
767307f049bSXiaojian Du 		 * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
768307f049bSXiaojian Du 		 * Not all profile modes are supported on vangogh.
769307f049bSXiaojian Du 		 */
770307f049bSXiaojian Du 		workload_type = smu_cmn_to_asic_specific_index(smu,
771307f049bSXiaojian Du 							       CMN2ASIC_MAPPING_WORKLOAD,
772307f049bSXiaojian Du 							       i);
773307f049bSXiaojian Du 
774307f049bSXiaojian Du 		if (workload_type < 0)
775307f049bSXiaojian Du 			continue;
776307f049bSXiaojian Du 
777307f049bSXiaojian Du 		size += sprintf(buf + size, "%2d %14s%s\n",
778307f049bSXiaojian Du 			i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");
779307f049bSXiaojian Du 	}
780307f049bSXiaojian Du 
781307f049bSXiaojian Du 	return size;
782307f049bSXiaojian Du }
783307f049bSXiaojian Du 
784d0e4e112SXiaojian Du static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
785d0e4e112SXiaojian Du {
786d0e4e112SXiaojian Du 	int workload_type, ret;
787d0e4e112SXiaojian Du 	uint32_t profile_mode = input[size];
788d0e4e112SXiaojian Du 
789d0e4e112SXiaojian Du 	if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
790d0e4e112SXiaojian Du 		dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
791d0e4e112SXiaojian Du 		return -EINVAL;
792d0e4e112SXiaojian Du 	}
793d0e4e112SXiaojian Du 
794f727ebebSXiaojian Du 	if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
795f727ebebSXiaojian Du 			profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
796f727ebebSXiaojian Du 		return 0;
797f727ebebSXiaojian Du 
798d0e4e112SXiaojian Du 	/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
799d0e4e112SXiaojian Du 	workload_type = smu_cmn_to_asic_specific_index(smu,
800d0e4e112SXiaojian Du 						       CMN2ASIC_MAPPING_WORKLOAD,
801d0e4e112SXiaojian Du 						       profile_mode);
802d0e4e112SXiaojian Du 	if (workload_type < 0) {
803d0e4e112SXiaojian Du 		dev_err_once(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
804d0e4e112SXiaojian Du 					profile_mode);
805d0e4e112SXiaojian Du 		return -EINVAL;
806d0e4e112SXiaojian Du 	}
807d0e4e112SXiaojian Du 
808d0e4e112SXiaojian Du 	ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
809d0e4e112SXiaojian Du 				    1 << workload_type,
810d0e4e112SXiaojian Du 				    NULL);
811d0e4e112SXiaojian Du 	if (ret) {
812d0e4e112SXiaojian Du 		dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
813d0e4e112SXiaojian Du 					workload_type);
814d0e4e112SXiaojian Du 		return ret;
815d0e4e112SXiaojian Du 	}
816d0e4e112SXiaojian Du 
817d0e4e112SXiaojian Du 	smu->power_profile_mode = profile_mode;
818d0e4e112SXiaojian Du 
819d0e4e112SXiaojian Du 	return 0;
820d0e4e112SXiaojian Du }
821d0e4e112SXiaojian Du 
822dd9e0b21SXiaojian Du static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
823dd9e0b21SXiaojian Du 					  enum smu_clk_type clk_type,
824dd9e0b21SXiaojian Du 					  uint32_t min,
825dd9e0b21SXiaojian Du 					  uint32_t max)
826dd9e0b21SXiaojian Du {
827dd9e0b21SXiaojian Du 	int ret = 0;
828dd9e0b21SXiaojian Du 
829dd9e0b21SXiaojian Du 	if (!vangogh_clk_dpm_is_enabled(smu, clk_type))
830dd9e0b21SXiaojian Du 		return 0;
831dd9e0b21SXiaojian Du 
832dd9e0b21SXiaojian Du 	switch (clk_type) {
833dd9e0b21SXiaojian Du 	case SMU_GFXCLK:
834dd9e0b21SXiaojian Du 	case SMU_SCLK:
835dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
836dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinGfxClk,
837dd9e0b21SXiaojian Du 							min, NULL);
838dd9e0b21SXiaojian Du 		if (ret)
839dd9e0b21SXiaojian Du 			return ret;
840dd9e0b21SXiaojian Du 
841dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
842dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxGfxClk,
843dd9e0b21SXiaojian Du 							max, NULL);
844dd9e0b21SXiaojian Du 		if (ret)
845dd9e0b21SXiaojian Du 			return ret;
846dd9e0b21SXiaojian Du 		break;
847dd9e0b21SXiaojian Du 	case SMU_FCLK:
848dd9e0b21SXiaojian Du 	case SMU_MCLK:
849dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
850dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinFclkByFreq,
851dd9e0b21SXiaojian Du 							min, NULL);
852dd9e0b21SXiaojian Du 		if (ret)
853dd9e0b21SXiaojian Du 			return ret;
854dd9e0b21SXiaojian Du 
855dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
856dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxFclkByFreq,
857dd9e0b21SXiaojian Du 							max, NULL);
858dd9e0b21SXiaojian Du 		if (ret)
859dd9e0b21SXiaojian Du 			return ret;
860dd9e0b21SXiaojian Du 		break;
861dd9e0b21SXiaojian Du 	case SMU_SOCCLK:
862dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
863dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinSocclkByFreq,
864dd9e0b21SXiaojian Du 							min, NULL);
865dd9e0b21SXiaojian Du 		if (ret)
866dd9e0b21SXiaojian Du 			return ret;
867dd9e0b21SXiaojian Du 
868dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
869dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxSocclkByFreq,
870dd9e0b21SXiaojian Du 							max, NULL);
871dd9e0b21SXiaojian Du 		if (ret)
872dd9e0b21SXiaojian Du 			return ret;
873dd9e0b21SXiaojian Du 		break;
874dd9e0b21SXiaojian Du 	case SMU_VCLK:
875dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
876dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinVcn,
877dd9e0b21SXiaojian Du 							min << 16, NULL);
878dd9e0b21SXiaojian Du 		if (ret)
879dd9e0b21SXiaojian Du 			return ret;
880dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
881dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxVcn,
882dd9e0b21SXiaojian Du 							max << 16, NULL);
883dd9e0b21SXiaojian Du 		if (ret)
884dd9e0b21SXiaojian Du 			return ret;
885dd9e0b21SXiaojian Du 		break;
886dd9e0b21SXiaojian Du 	case SMU_DCLK:
887dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
888dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinVcn,
889dd9e0b21SXiaojian Du 							min, NULL);
890dd9e0b21SXiaojian Du 		if (ret)
891dd9e0b21SXiaojian Du 			return ret;
892dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
893dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxVcn,
894dd9e0b21SXiaojian Du 							max, NULL);
895dd9e0b21SXiaojian Du 		if (ret)
896dd9e0b21SXiaojian Du 			return ret;
897dd9e0b21SXiaojian Du 		break;
898dd9e0b21SXiaojian Du 	default:
899dd9e0b21SXiaojian Du 		return -EINVAL;
900dd9e0b21SXiaojian Du 	}
901dd9e0b21SXiaojian Du 
902dd9e0b21SXiaojian Du 	return ret;
903dd9e0b21SXiaojian Du }
904dd9e0b21SXiaojian Du 
905dd9e0b21SXiaojian Du static int vangogh_force_clk_levels(struct smu_context *smu,
906dd9e0b21SXiaojian Du 				   enum smu_clk_type clk_type, uint32_t mask)
907dd9e0b21SXiaojian Du {
908dd9e0b21SXiaojian Du 	uint32_t soft_min_level = 0, soft_max_level = 0;
909dd9e0b21SXiaojian Du 	uint32_t min_freq = 0, max_freq = 0;
910dd9e0b21SXiaojian Du 	int ret = 0 ;
911dd9e0b21SXiaojian Du 
912dd9e0b21SXiaojian Du 	soft_min_level = mask ? (ffs(mask) - 1) : 0;
913dd9e0b21SXiaojian Du 	soft_max_level = mask ? (fls(mask) - 1) : 0;
914dd9e0b21SXiaojian Du 
915dd9e0b21SXiaojian Du 	switch (clk_type) {
916dd9e0b21SXiaojian Du 	case SMU_SOCCLK:
917dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu, clk_type,
918dd9e0b21SXiaojian Du 						soft_min_level, &min_freq);
919dd9e0b21SXiaojian Du 		if (ret)
920dd9e0b21SXiaojian Du 			return ret;
921dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu, clk_type,
922dd9e0b21SXiaojian Du 						soft_max_level, &max_freq);
923dd9e0b21SXiaojian Du 		if (ret)
924dd9e0b21SXiaojian Du 			return ret;
925dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
926dd9e0b21SXiaojian Du 								SMU_MSG_SetSoftMaxSocclkByFreq,
927dd9e0b21SXiaojian Du 								max_freq, NULL);
928dd9e0b21SXiaojian Du 		if (ret)
929dd9e0b21SXiaojian Du 			return ret;
930dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
931dd9e0b21SXiaojian Du 								SMU_MSG_SetHardMinSocclkByFreq,
932dd9e0b21SXiaojian Du 								min_freq, NULL);
933dd9e0b21SXiaojian Du 		if (ret)
934dd9e0b21SXiaojian Du 			return ret;
935dd9e0b21SXiaojian Du 		break;
936dd9e0b21SXiaojian Du 	case SMU_MCLK:
937dd9e0b21SXiaojian Du 	case SMU_FCLK:
938dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
939dd9e0b21SXiaojian Du 							clk_type, soft_min_level, &min_freq);
940dd9e0b21SXiaojian Du 		if (ret)
941dd9e0b21SXiaojian Du 			return ret;
942dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
943dd9e0b21SXiaojian Du 							clk_type, soft_max_level, &max_freq);
944dd9e0b21SXiaojian Du 		if (ret)
945dd9e0b21SXiaojian Du 			return ret;
946dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
947dd9e0b21SXiaojian Du 								SMU_MSG_SetSoftMaxFclkByFreq,
948dd9e0b21SXiaojian Du 								max_freq, NULL);
949dd9e0b21SXiaojian Du 		if (ret)
950dd9e0b21SXiaojian Du 			return ret;
951dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
952dd9e0b21SXiaojian Du 								SMU_MSG_SetHardMinFclkByFreq,
953dd9e0b21SXiaojian Du 								min_freq, NULL);
954dd9e0b21SXiaojian Du 		if (ret)
955dd9e0b21SXiaojian Du 			return ret;
956dd9e0b21SXiaojian Du 		break;
957dd9e0b21SXiaojian Du 	case SMU_VCLK:
958dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
959dd9e0b21SXiaojian Du 							clk_type, soft_min_level, &min_freq);
960dd9e0b21SXiaojian Du 		if (ret)
961dd9e0b21SXiaojian Du 			return ret;
962307f049bSXiaojian Du 
963dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
964dd9e0b21SXiaojian Du 							clk_type, soft_max_level, &max_freq);
965dd9e0b21SXiaojian Du 		if (ret)
966dd9e0b21SXiaojian Du 			return ret;
967307f049bSXiaojian Du 
968307f049bSXiaojian Du 
969dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
970dd9e0b21SXiaojian Du 								SMU_MSG_SetHardMinVcn,
971dd9e0b21SXiaojian Du 								min_freq << 16, NULL);
972dd9e0b21SXiaojian Du 		if (ret)
973dd9e0b21SXiaojian Du 			return ret;
974307f049bSXiaojian Du 
975307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
976307f049bSXiaojian Du 								SMU_MSG_SetSoftMaxVcn,
977307f049bSXiaojian Du 								max_freq << 16, NULL);
978307f049bSXiaojian Du 		if (ret)
979307f049bSXiaojian Du 			return ret;
980307f049bSXiaojian Du 
981dd9e0b21SXiaojian Du 		break;
982dd9e0b21SXiaojian Du 	case SMU_DCLK:
983dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
984dd9e0b21SXiaojian Du 							clk_type, soft_min_level, &min_freq);
985dd9e0b21SXiaojian Du 		if (ret)
986dd9e0b21SXiaojian Du 			return ret;
987307f049bSXiaojian Du 
988dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
989dd9e0b21SXiaojian Du 							clk_type, soft_max_level, &max_freq);
990dd9e0b21SXiaojian Du 		if (ret)
991dd9e0b21SXiaojian Du 			return ret;
992307f049bSXiaojian Du 
993dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
994dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinVcn,
995dd9e0b21SXiaojian Du 							min_freq, NULL);
996dd9e0b21SXiaojian Du 		if (ret)
997dd9e0b21SXiaojian Du 			return ret;
998307f049bSXiaojian Du 
999307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
1000307f049bSXiaojian Du 							SMU_MSG_SetSoftMaxVcn,
1001307f049bSXiaojian Du 							max_freq, NULL);
1002307f049bSXiaojian Du 		if (ret)
1003307f049bSXiaojian Du 			return ret;
1004307f049bSXiaojian Du 
1005dd9e0b21SXiaojian Du 		break;
1006dd9e0b21SXiaojian Du 	default:
1007dd9e0b21SXiaojian Du 		break;
1008dd9e0b21SXiaojian Du 	}
1009dd9e0b21SXiaojian Du 
1010dd9e0b21SXiaojian Du 	return ret;
1011dd9e0b21SXiaojian Du }
1012dd9e0b21SXiaojian Du 
1013dd9e0b21SXiaojian Du static int vangogh_force_dpm_limit_value(struct smu_context *smu, bool highest)
1014dd9e0b21SXiaojian Du {
1015dd9e0b21SXiaojian Du 	int ret = 0, i = 0;
1016dd9e0b21SXiaojian Du 	uint32_t min_freq, max_freq, force_freq;
1017dd9e0b21SXiaojian Du 	enum smu_clk_type clk_type;
1018dd9e0b21SXiaojian Du 
1019dd9e0b21SXiaojian Du 	enum smu_clk_type clks[] = {
1020dd9e0b21SXiaojian Du 		SMU_SOCCLK,
1021dd9e0b21SXiaojian Du 		SMU_VCLK,
1022dd9e0b21SXiaojian Du 		SMU_DCLK,
1023dd9e0b21SXiaojian Du 		SMU_MCLK,
1024dd9e0b21SXiaojian Du 		SMU_FCLK,
1025dd9e0b21SXiaojian Du 	};
1026dd9e0b21SXiaojian Du 
1027dd9e0b21SXiaojian Du 	for (i = 0; i < ARRAY_SIZE(clks); i++) {
1028dd9e0b21SXiaojian Du 		clk_type = clks[i];
1029dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_ultimate_freq(smu, clk_type, &min_freq, &max_freq);
1030dd9e0b21SXiaojian Du 		if (ret)
1031dd9e0b21SXiaojian Du 			return ret;
1032dd9e0b21SXiaojian Du 
1033dd9e0b21SXiaojian Du 		force_freq = highest ? max_freq : min_freq;
1034dd9e0b21SXiaojian Du 		ret = vangogh_set_soft_freq_limited_range(smu, clk_type, force_freq, force_freq);
1035dd9e0b21SXiaojian Du 		if (ret)
1036dd9e0b21SXiaojian Du 			return ret;
1037dd9e0b21SXiaojian Du 	}
1038dd9e0b21SXiaojian Du 
1039dd9e0b21SXiaojian Du 	return ret;
1040dd9e0b21SXiaojian Du }
1041dd9e0b21SXiaojian Du 
1042dd9e0b21SXiaojian Du static int vangogh_unforce_dpm_levels(struct smu_context *smu)
1043dd9e0b21SXiaojian Du {
1044dd9e0b21SXiaojian Du 	int ret = 0, i = 0;
1045dd9e0b21SXiaojian Du 	uint32_t min_freq, max_freq;
1046dd9e0b21SXiaojian Du 	enum smu_clk_type clk_type;
1047dd9e0b21SXiaojian Du 
1048dd9e0b21SXiaojian Du 	struct clk_feature_map {
1049dd9e0b21SXiaojian Du 		enum smu_clk_type clk_type;
1050dd9e0b21SXiaojian Du 		uint32_t	feature;
1051dd9e0b21SXiaojian Du 	} clk_feature_map[] = {
1052dd9e0b21SXiaojian Du 		{SMU_MCLK,   SMU_FEATURE_DPM_FCLK_BIT},
1053dd9e0b21SXiaojian Du 		{SMU_FCLK, SMU_FEATURE_DPM_FCLK_BIT},
1054dd9e0b21SXiaojian Du 		{SMU_SOCCLK, SMU_FEATURE_DPM_SOCCLK_BIT},
1055b0eec124SXiaojian Du 		{SMU_VCLK, SMU_FEATURE_VCN_DPM_BIT},
1056b0eec124SXiaojian Du 		{SMU_DCLK, SMU_FEATURE_VCN_DPM_BIT},
1057dd9e0b21SXiaojian Du 	};
1058dd9e0b21SXiaojian Du 
1059dd9e0b21SXiaojian Du 	for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) {
1060dd9e0b21SXiaojian Du 
1061dd9e0b21SXiaojian Du 		if (!smu_cmn_feature_is_enabled(smu, clk_feature_map[i].feature))
1062dd9e0b21SXiaojian Du 		    continue;
1063dd9e0b21SXiaojian Du 
1064dd9e0b21SXiaojian Du 		clk_type = clk_feature_map[i].clk_type;
1065dd9e0b21SXiaojian Du 
1066dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_ultimate_freq(smu, clk_type, &min_freq, &max_freq);
1067dd9e0b21SXiaojian Du 
1068dd9e0b21SXiaojian Du 		if (ret)
1069dd9e0b21SXiaojian Du 			return ret;
1070dd9e0b21SXiaojian Du 
1071dd9e0b21SXiaojian Du 		ret = vangogh_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq);
1072dd9e0b21SXiaojian Du 
1073dd9e0b21SXiaojian Du 		if (ret)
1074dd9e0b21SXiaojian Du 			return ret;
1075dd9e0b21SXiaojian Du 	}
1076dd9e0b21SXiaojian Du 
1077dd9e0b21SXiaojian Du 	return ret;
1078dd9e0b21SXiaojian Du }
1079dd9e0b21SXiaojian Du 
1080dd9e0b21SXiaojian Du static int vangogh_set_peak_clock_by_device(struct smu_context *smu)
1081dd9e0b21SXiaojian Du {
1082dd9e0b21SXiaojian Du 	int ret = 0;
1083dd9e0b21SXiaojian Du 	uint32_t socclk_freq = 0, fclk_freq = 0;
1084307f049bSXiaojian Du 	uint32_t vclk_freq = 0, dclk_freq = 0;
1085dd9e0b21SXiaojian Du 
1086dd9e0b21SXiaojian Du 	ret = vangogh_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_freq);
1087dd9e0b21SXiaojian Du 	if (ret)
1088dd9e0b21SXiaojian Du 		return ret;
1089dd9e0b21SXiaojian Du 
1090dd9e0b21SXiaojian Du 	ret = vangogh_set_soft_freq_limited_range(smu, SMU_FCLK, fclk_freq, fclk_freq);
1091dd9e0b21SXiaojian Du 	if (ret)
1092dd9e0b21SXiaojian Du 		return ret;
1093dd9e0b21SXiaojian Du 
1094dd9e0b21SXiaojian Du 	ret = vangogh_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_freq);
1095dd9e0b21SXiaojian Du 	if (ret)
1096dd9e0b21SXiaojian Du 		return ret;
1097dd9e0b21SXiaojian Du 
1098dd9e0b21SXiaojian Du 	ret = vangogh_set_soft_freq_limited_range(smu, SMU_SOCCLK, socclk_freq, socclk_freq);
1099dd9e0b21SXiaojian Du 	if (ret)
1100dd9e0b21SXiaojian Du 		return ret;
1101dd9e0b21SXiaojian Du 
1102307f049bSXiaojian Du 	ret = vangogh_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &vclk_freq);
1103307f049bSXiaojian Du 	if (ret)
1104307f049bSXiaojian Du 		return ret;
1105307f049bSXiaojian Du 
1106307f049bSXiaojian Du 	ret = vangogh_set_soft_freq_limited_range(smu, SMU_VCLK, vclk_freq, vclk_freq);
1107307f049bSXiaojian Du 	if (ret)
1108307f049bSXiaojian Du 		return ret;
1109307f049bSXiaojian Du 
1110307f049bSXiaojian Du 	ret = vangogh_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &dclk_freq);
1111307f049bSXiaojian Du 	if (ret)
1112307f049bSXiaojian Du 		return ret;
1113307f049bSXiaojian Du 
1114307f049bSXiaojian Du 	ret = vangogh_set_soft_freq_limited_range(smu, SMU_DCLK, dclk_freq, dclk_freq);
1115307f049bSXiaojian Du 	if (ret)
1116307f049bSXiaojian Du 		return ret;
1117307f049bSXiaojian Du 
1118dd9e0b21SXiaojian Du 	return ret;
1119dd9e0b21SXiaojian Du }
1120dd9e0b21SXiaojian Du 
1121ea173d15SXiaojian Du static int vangogh_set_performance_level(struct smu_context *smu,
1122ea173d15SXiaojian Du 					enum amd_dpm_forced_level level)
1123ea173d15SXiaojian Du {
1124ea173d15SXiaojian Du 	int ret = 0;
1125ea173d15SXiaojian Du 	uint32_t soc_mask, mclk_mask, fclk_mask;
1126307f049bSXiaojian Du 	uint32_t vclk_mask = 0, dclk_mask = 0;
1127ea173d15SXiaojian Du 
1128ea173d15SXiaojian Du 	switch (level) {
1129ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_HIGH:
1130ea173d15SXiaojian Du 		ret = vangogh_force_dpm_limit_value(smu, true);
1131ea173d15SXiaojian Du 		break;
1132ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_LOW:
1133ea173d15SXiaojian Du 		ret = vangogh_force_dpm_limit_value(smu, false);
1134ea173d15SXiaojian Du 		break;
1135ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_AUTO:
1136ea173d15SXiaojian Du 		ret = vangogh_unforce_dpm_levels(smu);
1137ea173d15SXiaojian Du 		break;
1138ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
1139307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
1140307f049bSXiaojian Du 					SMU_MSG_SetHardMinGfxClk,
1141307f049bSXiaojian Du 					VANGOGH_UMD_PSTATE_STANDARD_GFXCLK, NULL);
1142307f049bSXiaojian Du 		if (ret)
1143307f049bSXiaojian Du 			return ret;
1144307f049bSXiaojian Du 
1145307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
1146307f049bSXiaojian Du 					SMU_MSG_SetSoftMaxGfxClk,
1147307f049bSXiaojian Du 					VANGOGH_UMD_PSTATE_STANDARD_GFXCLK, NULL);
1148307f049bSXiaojian Du 		if (ret)
1149307f049bSXiaojian Du 			return ret;
1150307f049bSXiaojian Du 
1151307f049bSXiaojian Du 		ret = vangogh_get_profiling_clk_mask(smu, level,
1152307f049bSXiaojian Du 							&vclk_mask,
1153307f049bSXiaojian Du 							&dclk_mask,
1154307f049bSXiaojian Du 							&mclk_mask,
1155307f049bSXiaojian Du 							&fclk_mask,
1156307f049bSXiaojian Du 							&soc_mask);
1157307f049bSXiaojian Du 		if (ret)
1158307f049bSXiaojian Du 			return ret;
1159307f049bSXiaojian Du 
1160307f049bSXiaojian Du 		vangogh_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask);
1161307f049bSXiaojian Du 		vangogh_force_clk_levels(smu, SMU_FCLK, 1 << fclk_mask);
1162307f049bSXiaojian Du 		vangogh_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask);
1163307f049bSXiaojian Du 		vangogh_force_clk_levels(smu, SMU_VCLK, 1 << vclk_mask);
1164307f049bSXiaojian Du 		vangogh_force_clk_levels(smu, SMU_DCLK, 1 << dclk_mask);
1165307f049bSXiaojian Du 
1166ea173d15SXiaojian Du 		break;
1167ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
1168307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinVcn,
1169307f049bSXiaojian Du 								VANGOGH_UMD_PSTATE_PEAK_DCLK, NULL);
1170307f049bSXiaojian Du 		if (ret)
1171307f049bSXiaojian Du 			return ret;
1172307f049bSXiaojian Du 
1173307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxVcn,
1174307f049bSXiaojian Du 								VANGOGH_UMD_PSTATE_PEAK_DCLK, NULL);
1175307f049bSXiaojian Du 		if (ret)
1176307f049bSXiaojian Du 			return ret;
1177ea173d15SXiaojian Du 		break;
1178ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
1179ea173d15SXiaojian Du 		ret = vangogh_get_profiling_clk_mask(smu, level,
1180ea173d15SXiaojian Du 							NULL,
1181ea173d15SXiaojian Du 							NULL,
1182ea173d15SXiaojian Du 							&mclk_mask,
1183ea173d15SXiaojian Du 							&fclk_mask,
1184307f049bSXiaojian Du 							NULL);
1185ea173d15SXiaojian Du 		if (ret)
1186ea173d15SXiaojian Du 			return ret;
1187307f049bSXiaojian Du 
1188ea173d15SXiaojian Du 		vangogh_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask);
1189ea173d15SXiaojian Du 		vangogh_force_clk_levels(smu, SMU_FCLK, 1 << fclk_mask);
1190ea173d15SXiaojian Du 		break;
1191ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
1192307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
1193307f049bSXiaojian Du 				VANGOGH_UMD_PSTATE_PEAK_GFXCLK, NULL);
1194307f049bSXiaojian Du 		if (ret)
1195307f049bSXiaojian Du 			return ret;
1196307f049bSXiaojian Du 
1197307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
1198307f049bSXiaojian Du 				VANGOGH_UMD_PSTATE_PEAK_GFXCLK, NULL);
1199307f049bSXiaojian Du 		if (ret)
1200307f049bSXiaojian Du 			return ret;
1201307f049bSXiaojian Du 
1202ea173d15SXiaojian Du 		ret = vangogh_set_peak_clock_by_device(smu);
1203ea173d15SXiaojian Du 		break;
1204ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_MANUAL:
1205ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
1206ea173d15SXiaojian Du 	default:
1207ea173d15SXiaojian Du 		break;
1208ea173d15SXiaojian Du 	}
1209ea173d15SXiaojian Du 	return ret;
1210ea173d15SXiaojian Du }
1211ea173d15SXiaojian Du 
1212271ab489SXiaojian Du static int vangogh_read_sensor(struct smu_context *smu,
1213271ab489SXiaojian Du 				 enum amd_pp_sensors sensor,
1214271ab489SXiaojian Du 				 void *data, uint32_t *size)
1215271ab489SXiaojian Du {
1216271ab489SXiaojian Du 	int ret = 0;
1217271ab489SXiaojian Du 
1218271ab489SXiaojian Du 	if (!data || !size)
1219271ab489SXiaojian Du 		return -EINVAL;
1220271ab489SXiaojian Du 
1221271ab489SXiaojian Du 	mutex_lock(&smu->sensor_lock);
1222271ab489SXiaojian Du 	switch (sensor) {
1223271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_GPU_LOAD:
12246cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
12256cc24d8dSAlex Deucher 						   METRICS_AVERAGE_GFXACTIVITY,
12266cc24d8dSAlex Deucher 						   (uint32_t *)data);
1227271ab489SXiaojian Du 		*size = 4;
1228271ab489SXiaojian Du 		break;
1229271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_GPU_POWER:
12306cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
12316cc24d8dSAlex Deucher 						   METRICS_AVERAGE_SOCKETPOWER,
12326cc24d8dSAlex Deucher 						   (uint32_t *)data);
1233271ab489SXiaojian Du 		*size = 4;
1234271ab489SXiaojian Du 		break;
1235271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_EDGE_TEMP:
12366cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
12376cc24d8dSAlex Deucher 						   METRICS_TEMPERATURE_EDGE,
12386cc24d8dSAlex Deucher 						   (uint32_t *)data);
12396cc24d8dSAlex Deucher 		*size = 4;
12406cc24d8dSAlex Deucher 		break;
1241271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
12426cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
12436cc24d8dSAlex Deucher 						   METRICS_TEMPERATURE_HOTSPOT,
12446cc24d8dSAlex Deucher 						   (uint32_t *)data);
1245271ab489SXiaojian Du 		*size = 4;
1246271ab489SXiaojian Du 		break;
1247271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_GFX_MCLK:
12486cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
12496cc24d8dSAlex Deucher 						   METRICS_AVERAGE_UCLK,
12506cc24d8dSAlex Deucher 						   (uint32_t *)data);
1251271ab489SXiaojian Du 		*(uint32_t *)data *= 100;
1252271ab489SXiaojian Du 		*size = 4;
1253271ab489SXiaojian Du 		break;
1254271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_GFX_SCLK:
12556cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
12566cc24d8dSAlex Deucher 						   METRICS_AVERAGE_GFXCLK,
12576cc24d8dSAlex Deucher 						   (uint32_t *)data);
1258271ab489SXiaojian Du 		*(uint32_t *)data *= 100;
1259271ab489SXiaojian Du 		*size = 4;
1260271ab489SXiaojian Du 		break;
1261271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_VDDGFX:
12622139d12bSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
12632139d12bSAlex Deucher 						   METRICS_VOLTAGE_VDDGFX,
12642139d12bSAlex Deucher 						   (uint32_t *)data);
12652139d12bSAlex Deucher 		*size = 4;
12662139d12bSAlex Deucher 		break;
12672139d12bSAlex Deucher 	case AMDGPU_PP_SENSOR_VDDNB:
12682139d12bSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
12692139d12bSAlex Deucher 						   METRICS_VOLTAGE_VDDSOC,
12702139d12bSAlex Deucher 						   (uint32_t *)data);
1271271ab489SXiaojian Du 		*size = 4;
1272271ab489SXiaojian Du 		break;
1273517cb957SHuang Rui 	case AMDGPU_PP_SENSOR_CPU_CLK:
1274517cb957SHuang Rui 		ret = vangogh_get_smu_metrics_data(smu,
1275517cb957SHuang Rui 						   METRICS_AVERAGE_CPUCLK,
1276517cb957SHuang Rui 						   (uint32_t *)data);
1277517cb957SHuang Rui 		*size = boot_cpu_data.x86_max_cores * sizeof(uint16_t);
1278517cb957SHuang Rui 		break;
1279271ab489SXiaojian Du 	default:
1280271ab489SXiaojian Du 		ret = -EOPNOTSUPP;
1281271ab489SXiaojian Du 		break;
1282271ab489SXiaojian Du 	}
1283271ab489SXiaojian Du 	mutex_unlock(&smu->sensor_lock);
1284271ab489SXiaojian Du 
1285271ab489SXiaojian Du 	return ret;
1286271ab489SXiaojian Du }
1287271ab489SXiaojian Du 
1288271ab489SXiaojian Du static int vangogh_set_watermarks_table(struct smu_context *smu,
1289271ab489SXiaojian Du 				       struct pp_smu_wm_range_sets *clock_ranges)
1290271ab489SXiaojian Du {
1291271ab489SXiaojian Du 	int i;
1292271ab489SXiaojian Du 	int ret = 0;
1293271ab489SXiaojian Du 	Watermarks_t *table = smu->smu_table.watermarks_table;
1294271ab489SXiaojian Du 
1295271ab489SXiaojian Du 	if (!table || !clock_ranges)
1296271ab489SXiaojian Du 		return -EINVAL;
1297271ab489SXiaojian Du 
1298271ab489SXiaojian Du 	if (clock_ranges) {
1299271ab489SXiaojian Du 		if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES ||
1300271ab489SXiaojian Du 			clock_ranges->num_writer_wm_sets > NUM_WM_RANGES)
1301271ab489SXiaojian Du 			return -EINVAL;
1302271ab489SXiaojian Du 
1303271ab489SXiaojian Du 		for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) {
1304271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].MinClock =
1305271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].min_drain_clk_mhz;
1306271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].MaxClock =
1307271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].max_drain_clk_mhz;
1308271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].MinMclk =
1309271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].min_fill_clk_mhz;
1310271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].MaxMclk =
1311271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].max_fill_clk_mhz;
1312271ab489SXiaojian Du 
1313271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].WmSetting =
1314271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].wm_inst;
1315271ab489SXiaojian Du 		}
1316271ab489SXiaojian Du 
1317271ab489SXiaojian Du 		for (i = 0; i < clock_ranges->num_writer_wm_sets; i++) {
1318271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].MinClock =
1319271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].min_fill_clk_mhz;
1320271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].MaxClock =
1321271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].max_fill_clk_mhz;
1322271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].MinMclk =
1323271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].min_drain_clk_mhz;
1324271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].MaxMclk =
1325271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].max_drain_clk_mhz;
1326271ab489SXiaojian Du 
1327271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].WmSetting =
1328271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].wm_inst;
1329271ab489SXiaojian Du 		}
1330271ab489SXiaojian Du 
1331271ab489SXiaojian Du 		smu->watermarks_bitmap |= WATERMARKS_EXIST;
1332271ab489SXiaojian Du 	}
1333271ab489SXiaojian Du 
1334271ab489SXiaojian Du 	/* pass data to smu controller */
1335271ab489SXiaojian Du 	if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
1336271ab489SXiaojian Du 	     !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
1337271ab489SXiaojian Du 		ret = smu_cmn_write_watermarks_table(smu);
1338271ab489SXiaojian Du 		if (ret) {
1339271ab489SXiaojian Du 			dev_err(smu->adev->dev, "Failed to update WMTABLE!");
1340271ab489SXiaojian Du 			return ret;
1341271ab489SXiaojian Du 		}
1342271ab489SXiaojian Du 		smu->watermarks_bitmap |= WATERMARKS_LOADED;
1343271ab489SXiaojian Du 	}
1344271ab489SXiaojian Du 
1345271ab489SXiaojian Du 	return 0;
1346f46a221bSXiaojian Du }
1347f46a221bSXiaojian Du 
1348fd253334SXiaojian Du static ssize_t vangogh_get_gpu_metrics(struct smu_context *smu,
1349fd253334SXiaojian Du 				      void **table)
1350fd253334SXiaojian Du {
1351fd253334SXiaojian Du 	struct smu_table_context *smu_table = &smu->smu_table;
1352fd253334SXiaojian Du 	struct gpu_metrics_v2_0 *gpu_metrics =
1353fd253334SXiaojian Du 		(struct gpu_metrics_v2_0 *)smu_table->gpu_metrics_table;
1354fd253334SXiaojian Du 	SmuMetrics_t metrics;
1355fd253334SXiaojian Du 	int ret = 0;
1356fd253334SXiaojian Du 
1357fd253334SXiaojian Du 	ret = smu_cmn_get_metrics_table(smu, &metrics, true);
1358fd253334SXiaojian Du 	if (ret)
1359fd253334SXiaojian Du 		return ret;
1360fd253334SXiaojian Du 
1361fd253334SXiaojian Du 	smu_v11_0_init_gpu_metrics_v2_0(gpu_metrics);
1362fd253334SXiaojian Du 
1363fd253334SXiaojian Du 	gpu_metrics->temperature_gfx = metrics.GfxTemperature;
1364fd253334SXiaojian Du 	gpu_metrics->temperature_soc = metrics.SocTemperature;
1365fd253334SXiaojian Du 	memcpy(&gpu_metrics->temperature_core[0],
1366fd253334SXiaojian Du 		&metrics.CoreTemperature[0],
1367fd253334SXiaojian Du 		sizeof(uint16_t) * 8);
1368fd253334SXiaojian Du 	gpu_metrics->temperature_l3[0] = metrics.L3Temperature[0];
1369fd253334SXiaojian Du 	gpu_metrics->temperature_l3[1] = metrics.L3Temperature[1];
1370fd253334SXiaojian Du 
1371fd253334SXiaojian Du 	gpu_metrics->average_gfx_activity = metrics.GfxActivity;
1372fd253334SXiaojian Du 	gpu_metrics->average_mm_activity = metrics.UvdActivity;
1373fd253334SXiaojian Du 
1374fd253334SXiaojian Du 	gpu_metrics->average_socket_power = metrics.CurrentSocketPower;
1375fd253334SXiaojian Du 	gpu_metrics->average_cpu_power = metrics.Power[0];
1376fd253334SXiaojian Du 	gpu_metrics->average_soc_power = metrics.Power[1];
1377fd253334SXiaojian Du 	memcpy(&gpu_metrics->average_core_power[0],
1378fd253334SXiaojian Du 		&metrics.CorePower[0],
1379fd253334SXiaojian Du 		sizeof(uint16_t) * 8);
1380fd253334SXiaojian Du 
1381fd253334SXiaojian Du 	gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency;
1382fd253334SXiaojian Du 	gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency;
1383fd253334SXiaojian Du 	gpu_metrics->average_fclk_frequency = metrics.MemclkFrequency;
1384fd253334SXiaojian Du 	gpu_metrics->average_vclk_frequency = metrics.VclkFrequency;
1385fd253334SXiaojian Du 
1386fd253334SXiaojian Du 	memcpy(&gpu_metrics->current_coreclk[0],
1387fd253334SXiaojian Du 		&metrics.CoreFrequency[0],
1388fd253334SXiaojian Du 		sizeof(uint16_t) * 8);
1389fd253334SXiaojian Du 	gpu_metrics->current_l3clk[0] = metrics.L3Frequency[0];
1390fd253334SXiaojian Du 	gpu_metrics->current_l3clk[1] = metrics.L3Frequency[1];
1391fd253334SXiaojian Du 
1392fd253334SXiaojian Du 	gpu_metrics->throttle_status = metrics.ThrottlerStatus;
1393fd253334SXiaojian Du 
1394fd253334SXiaojian Du 	*table = (void *)gpu_metrics;
1395fd253334SXiaojian Du 
1396fd253334SXiaojian Du 	return sizeof(struct gpu_metrics_v2_0);
1397fd253334SXiaojian Du }
1398fd253334SXiaojian Du 
1399c98ee897SXiaojian Du static int vangogh_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type,
1400c98ee897SXiaojian Du 					long input[], uint32_t size)
1401c98ee897SXiaojian Du {
1402c98ee897SXiaojian Du 	int ret = 0;
1403*0d90d0ddSHuang Rui 	int i;
1404c98ee897SXiaojian Du 
1405c98ee897SXiaojian Du 	if (!smu->od_enabled) {
1406c98ee897SXiaojian Du 		dev_warn(smu->adev->dev, "Fine grain is not enabled!\n");
1407c98ee897SXiaojian Du 		return -EINVAL;
1408c98ee897SXiaojian Du 	}
1409c98ee897SXiaojian Du 
1410c98ee897SXiaojian Du 	switch (type) {
1411*0d90d0ddSHuang Rui 	case PP_OD_EDIT_CCLK_VDDC_TABLE:
1412*0d90d0ddSHuang Rui 		if (size != 3) {
1413*0d90d0ddSHuang Rui 			dev_err(smu->adev->dev, "Input parameter number not correct (should be 4 for processor)\n");
1414*0d90d0ddSHuang Rui 			return -EINVAL;
1415*0d90d0ddSHuang Rui 		}
1416*0d90d0ddSHuang Rui 		if (input[0] >= boot_cpu_data.x86_max_cores) {
1417*0d90d0ddSHuang Rui 			dev_err(smu->adev->dev, "core index is overflow, should be less than %d\n",
1418*0d90d0ddSHuang Rui 				boot_cpu_data.x86_max_cores);
1419*0d90d0ddSHuang Rui 		}
1420*0d90d0ddSHuang Rui 		smu->cpu_core_id_select = input[0];
1421*0d90d0ddSHuang Rui 		if (input[1] == 0) {
1422*0d90d0ddSHuang Rui 			if (input[2] < smu->cpu_default_soft_min_freq) {
1423*0d90d0ddSHuang Rui 				dev_warn(smu->adev->dev, "Fine grain setting minimum cclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
1424*0d90d0ddSHuang Rui 					input[2], smu->cpu_default_soft_min_freq);
1425*0d90d0ddSHuang Rui 				return -EINVAL;
1426*0d90d0ddSHuang Rui 			}
1427*0d90d0ddSHuang Rui 			smu->cpu_actual_soft_min_freq = input[2];
1428*0d90d0ddSHuang Rui 		} else if (input[1] == 1) {
1429*0d90d0ddSHuang Rui 			if (input[2] > smu->cpu_default_soft_max_freq) {
1430*0d90d0ddSHuang Rui 				dev_warn(smu->adev->dev, "Fine grain setting maximum cclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
1431*0d90d0ddSHuang Rui 					input[2], smu->cpu_default_soft_max_freq);
1432*0d90d0ddSHuang Rui 				return -EINVAL;
1433*0d90d0ddSHuang Rui 			}
1434*0d90d0ddSHuang Rui 			smu->cpu_actual_soft_max_freq = input[2];
1435*0d90d0ddSHuang Rui 		} else {
1436*0d90d0ddSHuang Rui 			return -EINVAL;
1437*0d90d0ddSHuang Rui 		}
1438*0d90d0ddSHuang Rui 		break;
1439c98ee897SXiaojian Du 	case PP_OD_EDIT_SCLK_VDDC_TABLE:
1440c98ee897SXiaojian Du 		if (size != 2) {
1441c98ee897SXiaojian Du 			dev_err(smu->adev->dev, "Input parameter number not correct\n");
1442c98ee897SXiaojian Du 			return -EINVAL;
1443c98ee897SXiaojian Du 		}
1444c98ee897SXiaojian Du 
1445c98ee897SXiaojian Du 		if (input[0] == 0) {
1446c98ee897SXiaojian Du 			if (input[1] < smu->gfx_default_hard_min_freq) {
1447307f049bSXiaojian Du 				dev_warn(smu->adev->dev,
1448307f049bSXiaojian Du 					"Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
1449c98ee897SXiaojian Du 					input[1], smu->gfx_default_hard_min_freq);
1450c98ee897SXiaojian Du 				return -EINVAL;
1451c98ee897SXiaojian Du 			}
1452c98ee897SXiaojian Du 			smu->gfx_actual_hard_min_freq = input[1];
1453c98ee897SXiaojian Du 		} else if (input[0] == 1) {
1454c98ee897SXiaojian Du 			if (input[1] > smu->gfx_default_soft_max_freq) {
1455307f049bSXiaojian Du 				dev_warn(smu->adev->dev,
1456307f049bSXiaojian Du 					"Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
1457c98ee897SXiaojian Du 					input[1], smu->gfx_default_soft_max_freq);
1458c98ee897SXiaojian Du 				return -EINVAL;
1459c98ee897SXiaojian Du 			}
1460c98ee897SXiaojian Du 			smu->gfx_actual_soft_max_freq = input[1];
1461c98ee897SXiaojian Du 		} else {
1462c98ee897SXiaojian Du 			return -EINVAL;
1463c98ee897SXiaojian Du 		}
1464c98ee897SXiaojian Du 		break;
1465c98ee897SXiaojian Du 	case PP_OD_RESTORE_DEFAULT_TABLE:
1466c98ee897SXiaojian Du 		if (size != 0) {
1467c98ee897SXiaojian Du 			dev_err(smu->adev->dev, "Input parameter number not correct\n");
1468c98ee897SXiaojian Du 			return -EINVAL;
1469c98ee897SXiaojian Du 		} else {
1470c98ee897SXiaojian Du 			smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
1471c98ee897SXiaojian Du 			smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
1472*0d90d0ddSHuang Rui 			smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
1473*0d90d0ddSHuang Rui 			smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
1474c98ee897SXiaojian Du 
1475c98ee897SXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
1476c98ee897SXiaojian Du 									smu->gfx_actual_hard_min_freq, NULL);
1477c98ee897SXiaojian Du 			if (ret) {
1478c98ee897SXiaojian Du 				dev_err(smu->adev->dev, "Restore the default hard min sclk failed!");
1479c98ee897SXiaojian Du 				return ret;
1480c98ee897SXiaojian Du 			}
1481c98ee897SXiaojian Du 
1482c98ee897SXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
1483c98ee897SXiaojian Du 									smu->gfx_actual_soft_max_freq, NULL);
1484c98ee897SXiaojian Du 			if (ret) {
1485c98ee897SXiaojian Du 				dev_err(smu->adev->dev, "Restore the default soft max sclk failed!");
1486c98ee897SXiaojian Du 				return ret;
1487c98ee897SXiaojian Du 			}
1488*0d90d0ddSHuang Rui 
1489*0d90d0ddSHuang Rui 			if (smu->adev->pm.fw_version < 0x43f1b00) {
1490*0d90d0ddSHuang Rui 				dev_warn(smu->adev->dev, "CPUSoftMax/CPUSoftMin are not supported, please update SBIOS!\n");
1491*0d90d0ddSHuang Rui 				break;
1492*0d90d0ddSHuang Rui 			}
1493*0d90d0ddSHuang Rui 
1494*0d90d0ddSHuang Rui 			for (i = 0; i < boot_cpu_data.x86_max_cores; i++) {
1495*0d90d0ddSHuang Rui 				ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinCclk,
1496*0d90d0ddSHuang Rui 								      (i << 20) | smu->cpu_actual_soft_min_freq,
1497*0d90d0ddSHuang Rui 								      NULL);
1498*0d90d0ddSHuang Rui 				if (ret) {
1499*0d90d0ddSHuang Rui 					dev_err(smu->adev->dev, "Set hard min cclk failed!");
1500*0d90d0ddSHuang Rui 					return ret;
1501*0d90d0ddSHuang Rui 				}
1502*0d90d0ddSHuang Rui 
1503*0d90d0ddSHuang Rui 				ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxCclk,
1504*0d90d0ddSHuang Rui 								      (i << 20) | smu->cpu_actual_soft_max_freq,
1505*0d90d0ddSHuang Rui 								      NULL);
1506*0d90d0ddSHuang Rui 				if (ret) {
1507*0d90d0ddSHuang Rui 					dev_err(smu->adev->dev, "Set soft max cclk failed!");
1508*0d90d0ddSHuang Rui 					return ret;
1509*0d90d0ddSHuang Rui 				}
1510*0d90d0ddSHuang Rui 			}
1511c98ee897SXiaojian Du 		}
1512c98ee897SXiaojian Du 		break;
1513c98ee897SXiaojian Du 	case PP_OD_COMMIT_DPM_TABLE:
1514c98ee897SXiaojian Du 		if (size != 0) {
1515c98ee897SXiaojian Du 			dev_err(smu->adev->dev, "Input parameter number not correct\n");
1516c98ee897SXiaojian Du 			return -EINVAL;
1517c98ee897SXiaojian Du 		} else {
1518c98ee897SXiaojian Du 			if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) {
1519307f049bSXiaojian Du 				dev_err(smu->adev->dev,
1520307f049bSXiaojian Du 					"The setting minimun sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n",
1521307f049bSXiaojian Du 					smu->gfx_actual_hard_min_freq,
1522307f049bSXiaojian Du 					smu->gfx_actual_soft_max_freq);
1523c98ee897SXiaojian Du 				return -EINVAL;
1524c98ee897SXiaojian Du 			}
1525c98ee897SXiaojian Du 
1526c98ee897SXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
1527c98ee897SXiaojian Du 									smu->gfx_actual_hard_min_freq, NULL);
1528c98ee897SXiaojian Du 			if (ret) {
1529c98ee897SXiaojian Du 				dev_err(smu->adev->dev, "Set hard min sclk failed!");
1530c98ee897SXiaojian Du 				return ret;
1531c98ee897SXiaojian Du 			}
1532c98ee897SXiaojian Du 
1533c98ee897SXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
1534c98ee897SXiaojian Du 									smu->gfx_actual_soft_max_freq, NULL);
1535c98ee897SXiaojian Du 			if (ret) {
1536c98ee897SXiaojian Du 				dev_err(smu->adev->dev, "Set soft max sclk failed!");
1537c98ee897SXiaojian Du 				return ret;
1538c98ee897SXiaojian Du 			}
1539*0d90d0ddSHuang Rui 
1540*0d90d0ddSHuang Rui 			if (smu->adev->pm.fw_version < 0x43f1b00) {
1541*0d90d0ddSHuang Rui 				dev_warn(smu->adev->dev, "CPUSoftMax/CPUSoftMin are not supported, please update SBIOS!\n");
1542*0d90d0ddSHuang Rui 				break;
1543*0d90d0ddSHuang Rui 			}
1544*0d90d0ddSHuang Rui 
1545*0d90d0ddSHuang Rui 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinCclk,
1546*0d90d0ddSHuang Rui 							      ((smu->cpu_core_id_select << 20)
1547*0d90d0ddSHuang Rui 							       | smu->cpu_actual_soft_min_freq),
1548*0d90d0ddSHuang Rui 							      NULL);
1549*0d90d0ddSHuang Rui 			if (ret) {
1550*0d90d0ddSHuang Rui 				dev_err(smu->adev->dev, "Set hard min cclk failed!");
1551*0d90d0ddSHuang Rui 				return ret;
1552*0d90d0ddSHuang Rui 			}
1553*0d90d0ddSHuang Rui 
1554*0d90d0ddSHuang Rui 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxCclk,
1555*0d90d0ddSHuang Rui 							      ((smu->cpu_core_id_select << 20)
1556*0d90d0ddSHuang Rui 							       | smu->cpu_actual_soft_max_freq),
1557*0d90d0ddSHuang Rui 							      NULL);
1558*0d90d0ddSHuang Rui 			if (ret) {
1559*0d90d0ddSHuang Rui 				dev_err(smu->adev->dev, "Set soft max cclk failed!");
1560*0d90d0ddSHuang Rui 				return ret;
1561*0d90d0ddSHuang Rui 			}
1562c98ee897SXiaojian Du 		}
1563c98ee897SXiaojian Du 		break;
1564c98ee897SXiaojian Du 	default:
1565c98ee897SXiaojian Du 		return -ENOSYS;
1566c98ee897SXiaojian Du 	}
1567c98ee897SXiaojian Du 
1568c98ee897SXiaojian Du 	return ret;
1569c98ee897SXiaojian Du }
1570c98ee897SXiaojian Du 
1571fce8a4acSJinzhou Su static int vangogh_set_default_dpm_tables(struct smu_context *smu)
1572c98ee897SXiaojian Du {
1573c98ee897SXiaojian Du 	struct smu_table_context *smu_table = &smu->smu_table;
1574c98ee897SXiaojian Du 
1575c98ee897SXiaojian Du 	return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false);
1576c98ee897SXiaojian Du }
1577c98ee897SXiaojian Du 
1578c98ee897SXiaojian Du static int vangogh_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
1579c98ee897SXiaojian Du {
1580c98ee897SXiaojian Du 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
1581c98ee897SXiaojian Du 
1582c98ee897SXiaojian Du 	smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
1583c98ee897SXiaojian Du 	smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
1584c98ee897SXiaojian Du 	smu->gfx_actual_hard_min_freq = 0;
1585c98ee897SXiaojian Du 	smu->gfx_actual_soft_max_freq = 0;
1586c98ee897SXiaojian Du 
1587*0d90d0ddSHuang Rui 	smu->cpu_default_soft_min_freq = 1400;
1588*0d90d0ddSHuang Rui 	smu->cpu_default_soft_max_freq = 3500;
1589*0d90d0ddSHuang Rui 	smu->cpu_actual_soft_min_freq = 0;
1590*0d90d0ddSHuang Rui 	smu->cpu_actual_soft_max_freq = 0;
1591*0d90d0ddSHuang Rui 
1592c98ee897SXiaojian Du 	return 0;
1593c98ee897SXiaojian Du }
1594c98ee897SXiaojian Du 
1595ae7b32e7SXiaojian Du static int vangogh_get_dpm_clock_table(struct smu_context *smu, struct dpm_clocks *clock_table)
1596ae7b32e7SXiaojian Du {
1597ae7b32e7SXiaojian Du 	DpmClocks_t *table = smu->smu_table.clocks_table;
1598ae7b32e7SXiaojian Du 	int i;
1599ae7b32e7SXiaojian Du 
1600ae7b32e7SXiaojian Du 	if (!clock_table || !table)
1601ae7b32e7SXiaojian Du 		return -EINVAL;
1602ae7b32e7SXiaojian Du 
1603ae7b32e7SXiaojian Du 	for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) {
1604ae7b32e7SXiaojian Du 		clock_table->SocClocks[i].Freq = table->SocClocks[i];
1605ae7b32e7SXiaojian Du 		clock_table->SocClocks[i].Vol = table->SocVoltage[i];
1606ae7b32e7SXiaojian Du 	}
1607ae7b32e7SXiaojian Du 
1608ae7b32e7SXiaojian Du 	for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
1609ae7b32e7SXiaojian Du 		clock_table->FClocks[i].Freq = table->DfPstateTable[i].fclk;
1610ae7b32e7SXiaojian Du 		clock_table->FClocks[i].Vol = table->DfPstateTable[i].voltage;
1611ae7b32e7SXiaojian Du 	}
1612ae7b32e7SXiaojian Du 
1613ae7b32e7SXiaojian Du 	for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
1614ae7b32e7SXiaojian Du 		clock_table->MemClocks[i].Freq = table->DfPstateTable[i].memclk;
1615ae7b32e7SXiaojian Du 		clock_table->MemClocks[i].Vol = table->DfPstateTable[i].voltage;
1616ae7b32e7SXiaojian Du 	}
1617ae7b32e7SXiaojian Du 
1618ae7b32e7SXiaojian Du 	return 0;
1619ae7b32e7SXiaojian Du }
1620ae7b32e7SXiaojian Du 
1621ae7b32e7SXiaojian Du 
1622a0f55287SXiaomeng Hou static int vangogh_system_features_control(struct smu_context *smu, bool en)
1623a0f55287SXiaomeng Hou {
16249e3a6ab7SXiaomeng Hou 	struct amdgpu_device *adev = smu->adev;
1625aedebd40SHuang Rui 	struct smu_feature *feature = &smu->smu_feature;
1626aedebd40SHuang Rui 	uint32_t feature_mask[2];
1627aedebd40SHuang Rui 	int ret = 0;
16289e3a6ab7SXiaomeng Hou 
16299e3a6ab7SXiaomeng Hou 	if (adev->pm.fw_version >= 0x43f1700)
1630aedebd40SHuang Rui 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_RlcPowerNotify,
1631a0f55287SXiaomeng Hou 						      en ? RLC_STATUS_NORMAL : RLC_STATUS_OFF, NULL);
1632aedebd40SHuang Rui 
1633aedebd40SHuang Rui 	bitmap_zero(feature->enabled, feature->feature_num);
1634aedebd40SHuang Rui 	bitmap_zero(feature->supported, feature->feature_num);
1635aedebd40SHuang Rui 
1636aedebd40SHuang Rui 	if (!en)
1637aedebd40SHuang Rui 		return ret;
1638aedebd40SHuang Rui 
1639aedebd40SHuang Rui 	ret = smu_cmn_get_enabled_32_bits_mask(smu, feature_mask, 2);
1640aedebd40SHuang Rui 	if (ret)
1641aedebd40SHuang Rui 		return ret;
1642aedebd40SHuang Rui 
1643aedebd40SHuang Rui 	bitmap_copy(feature->enabled, (unsigned long *)&feature_mask,
1644aedebd40SHuang Rui 		    feature->feature_num);
1645aedebd40SHuang Rui 	bitmap_copy(feature->supported, (unsigned long *)&feature_mask,
1646aedebd40SHuang Rui 		    feature->feature_num);
1647aedebd40SHuang Rui 
16489e3a6ab7SXiaomeng Hou 	return 0;
1649a0f55287SXiaomeng Hou }
1650a0f55287SXiaomeng Hou 
1651eefdf047SJinzhou Su static int vangogh_post_smu_init(struct smu_context *smu)
1652eefdf047SJinzhou Su {
1653eefdf047SJinzhou Su 	struct amdgpu_device *adev = smu->adev;
1654eefdf047SJinzhou Su 	uint32_t tmp;
16553313ef18SJinzhou Su 	int ret = 0;
1656eefdf047SJinzhou Su 	uint8_t aon_bits = 0;
1657eefdf047SJinzhou Su 	/* Two CUs in one WGP */
1658eefdf047SJinzhou Su 	uint32_t req_active_wgps = adev->gfx.cu_info.number/2;
1659eefdf047SJinzhou Su 	uint32_t total_cu = adev->gfx.config.max_cu_per_sh *
1660eefdf047SJinzhou Su 		adev->gfx.config.max_sh_per_se * adev->gfx.config.max_shader_engines;
1661eefdf047SJinzhou Su 
16623313ef18SJinzhou Su 	/* allow message will be sent after enable message on Vangogh*/
16633313ef18SJinzhou Su 	ret = smu_cmn_send_smc_msg(smu, SMU_MSG_EnableGfxOff, NULL);
16643313ef18SJinzhou Su 	if (ret) {
16653313ef18SJinzhou Su 		dev_err(adev->dev, "Failed to Enable GfxOff!\n");
16663313ef18SJinzhou Su 		return ret;
16673313ef18SJinzhou Su 	}
16683313ef18SJinzhou Su 
1669eefdf047SJinzhou Su 	/* if all CUs are active, no need to power off any WGPs */
1670eefdf047SJinzhou Su 	if (total_cu == adev->gfx.cu_info.number)
1671eefdf047SJinzhou Su 		return 0;
1672eefdf047SJinzhou Su 
1673eefdf047SJinzhou Su 	/*
1674eefdf047SJinzhou Su 	 * Calculate the total bits number of always on WGPs for all SA/SEs in
1675eefdf047SJinzhou Su 	 * RLC_PG_ALWAYS_ON_WGP_MASK.
1676eefdf047SJinzhou Su 	 */
1677eefdf047SJinzhou Su 	tmp = RREG32_KIQ(SOC15_REG_OFFSET(GC, 0, mmRLC_PG_ALWAYS_ON_WGP_MASK));
1678eefdf047SJinzhou Su 	tmp &= RLC_PG_ALWAYS_ON_WGP_MASK__AON_WGP_MASK_MASK;
1679eefdf047SJinzhou Su 
1680eefdf047SJinzhou Su 	aon_bits = hweight32(tmp) * adev->gfx.config.max_sh_per_se * adev->gfx.config.max_shader_engines;
1681eefdf047SJinzhou Su 
1682eefdf047SJinzhou Su 	/* Do not request any WGPs less than set in the AON_WGP_MASK */
1683eefdf047SJinzhou Su 	if (aon_bits > req_active_wgps) {
1684eefdf047SJinzhou Su 		dev_info(adev->dev, "Number of always on WGPs greater than active WGPs: WGP power save not requested.\n");
1685eefdf047SJinzhou Su 		return 0;
1686eefdf047SJinzhou Su 	} else {
1687eefdf047SJinzhou Su 		return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_RequestActiveWgp, req_active_wgps, NULL);
1688eefdf047SJinzhou Su 	}
1689eefdf047SJinzhou Su }
1690eefdf047SJinzhou Su 
169174353883SHuang Rui static int vangogh_mode_reset(struct smu_context *smu, int type)
169274353883SHuang Rui {
169374353883SHuang Rui 	int ret = 0, index = 0;
169474353883SHuang Rui 
169574353883SHuang Rui 	index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG,
169674353883SHuang Rui 					       SMU_MSG_GfxDeviceDriverReset);
169774353883SHuang Rui 	if (index < 0)
169874353883SHuang Rui 		return index == -EACCES ? 0 : index;
169974353883SHuang Rui 
170074353883SHuang Rui 	mutex_lock(&smu->message_lock);
170174353883SHuang Rui 
170274353883SHuang Rui 	ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, type);
170374353883SHuang Rui 
170474353883SHuang Rui 	mutex_unlock(&smu->message_lock);
170574353883SHuang Rui 
170674353883SHuang Rui 	mdelay(10);
170774353883SHuang Rui 
170874353883SHuang Rui 	return ret;
170974353883SHuang Rui }
171074353883SHuang Rui 
171120e157c7SAlex Deucher static int vangogh_mode2_reset(struct smu_context *smu)
171220e157c7SAlex Deucher {
171374353883SHuang Rui 	return vangogh_mode_reset(smu, SMU_RESET_MODE_2);
171420e157c7SAlex Deucher }
171520e157c7SAlex Deucher 
1716f46a221bSXiaojian Du static const struct pptable_funcs vangogh_ppt_funcs = {
1717271ab489SXiaojian Du 
1718f46a221bSXiaojian Du 	.check_fw_status = smu_v11_0_check_fw_status,
1719f46a221bSXiaojian Du 	.check_fw_version = smu_v11_0_check_fw_version,
1720f46a221bSXiaojian Du 	.init_smc_tables = vangogh_init_smc_tables,
1721f46a221bSXiaojian Du 	.fini_smc_tables = smu_v11_0_fini_smc_tables,
1722f46a221bSXiaojian Du 	.init_power = smu_v11_0_init_power,
1723f46a221bSXiaojian Du 	.fini_power = smu_v11_0_fini_power,
1724f46a221bSXiaojian Du 	.register_irq_handler = smu_v11_0_register_irq_handler,
1725f46a221bSXiaojian Du 	.notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
1726f46a221bSXiaojian Du 	.send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
1727f46a221bSXiaojian Du 	.send_smc_msg = smu_cmn_send_smc_msg,
1728271ab489SXiaojian Du 	.dpm_set_vcn_enable = vangogh_dpm_set_vcn_enable,
1729271ab489SXiaojian Du 	.dpm_set_jpeg_enable = vangogh_dpm_set_jpeg_enable,
1730f46a221bSXiaojian Du 	.is_dpm_running = vangogh_is_dpm_running,
1731271ab489SXiaojian Du 	.read_sensor = vangogh_read_sensor,
1732271ab489SXiaojian Du 	.get_enabled_mask = smu_cmn_get_enabled_32_bits_mask,
1733f46a221bSXiaojian Du 	.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
1734271ab489SXiaojian Du 	.set_watermarks_table = vangogh_set_watermarks_table,
1735271ab489SXiaojian Du 	.set_driver_table_location = smu_v11_0_set_driver_table_location,
1736f46a221bSXiaojian Du 	.interrupt_work = smu_v11_0_interrupt_work,
1737fd253334SXiaojian Du 	.get_gpu_metrics = vangogh_get_gpu_metrics,
1738c98ee897SXiaojian Du 	.od_edit_dpm_table = vangogh_od_edit_dpm_table,
1739c98ee897SXiaojian Du 	.print_clk_levels = vangogh_print_fine_grain_clk,
1740c98ee897SXiaojian Du 	.set_default_dpm_table = vangogh_set_default_dpm_tables,
1741c98ee897SXiaojian Du 	.set_fine_grain_gfx_freq_parameters = vangogh_set_fine_grain_gfx_freq_parameters,
1742a0f55287SXiaomeng Hou 	.system_features_control = vangogh_system_features_control,
1743d0e4e112SXiaojian Du 	.feature_is_enabled = smu_cmn_feature_is_enabled,
1744d0e4e112SXiaojian Du 	.set_power_profile_mode = vangogh_set_power_profile_mode,
1745307f049bSXiaojian Du 	.get_power_profile_mode = vangogh_get_power_profile_mode,
1746ae7b32e7SXiaojian Du 	.get_dpm_clock_table = vangogh_get_dpm_clock_table,
1747dd9e0b21SXiaojian Du 	.force_clk_levels = vangogh_force_clk_levels,
1748ea173d15SXiaojian Du 	.set_performance_level = vangogh_set_performance_level,
1749eefdf047SJinzhou Su 	.post_init = vangogh_post_smu_init,
175020e157c7SAlex Deucher 	.mode2_reset = vangogh_mode2_reset,
1751b58ce1feSJinzhou Su 	.gfx_off_control = smu_v11_0_gfx_off_control,
1752f46a221bSXiaojian Du };
1753f46a221bSXiaojian Du 
1754f46a221bSXiaojian Du void vangogh_set_ppt_funcs(struct smu_context *smu)
1755f46a221bSXiaojian Du {
1756f46a221bSXiaojian Du 	smu->ppt_funcs = &vangogh_ppt_funcs;
1757f46a221bSXiaojian Du 	smu->message_map = vangogh_message_map;
1758f46a221bSXiaojian Du 	smu->feature_map = vangogh_feature_mask_map;
1759f46a221bSXiaojian Du 	smu->table_map = vangogh_table_map;
1760ec3b35c8SXiaojian Du 	smu->workload_map = vangogh_workload_map;
1761f46a221bSXiaojian Du 	smu->is_apu = true;
1762f46a221bSXiaojian Du }
1763