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(SetHardMinSocclkByFreq,         PPSMC_MSG_SetHardMinSocclkByFreq,	0),
85271ab489SXiaojian Du 	MSG_MAP(SetSoftMinFclk,                 PPSMC_MSG_SetSoftMinFclk,		0),
86271ab489SXiaojian Du 	MSG_MAP(SetSoftMinVcn,                  PPSMC_MSG_SetSoftMinVcn,		0),
87271ab489SXiaojian Du 	MSG_MAP(EnablePostCode,                 PPSMC_MSG_EnablePostCode,		0),
88271ab489SXiaojian Du 	MSG_MAP(GetGfxclkFrequency,             PPSMC_MSG_GetGfxclkFrequency,	0),
89271ab489SXiaojian Du 	MSG_MAP(GetFclkFrequency,               PPSMC_MSG_GetFclkFrequency,		0),
90271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxGfxClk,               PPSMC_MSG_SetSoftMaxGfxClk,		0),
91271ab489SXiaojian Du 	MSG_MAP(SetHardMinGfxClk,               PPSMC_MSG_SetHardMinGfxClk,		0),
92271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxSocclkByFreq,         PPSMC_MSG_SetSoftMaxSocclkByFreq,	0),
93271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxFclkByFreq,           PPSMC_MSG_SetSoftMaxFclkByFreq,		0),
94271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxVcn,                  PPSMC_MSG_SetSoftMaxVcn,			0),
95271ab489SXiaojian Du 	MSG_MAP(SetPowerLimitPercentage,        PPSMC_MSG_SetPowerLimitPercentage,	0),
96271ab489SXiaojian Du 	MSG_MAP(PowerDownJpeg,                  PPSMC_MSG_PowerDownJpeg,			0),
97271ab489SXiaojian Du 	MSG_MAP(PowerUpJpeg,                    PPSMC_MSG_PowerUpJpeg,				0),
98271ab489SXiaojian Du 	MSG_MAP(SetHardMinFclkByFreq,           PPSMC_MSG_SetHardMinFclkByFreq,		0),
99271ab489SXiaojian Du 	MSG_MAP(SetSoftMinSocclkByFreq,         PPSMC_MSG_SetSoftMinSocclkByFreq,	0),
100271ab489SXiaojian Du 	MSG_MAP(PowerUpCvip,                    PPSMC_MSG_PowerUpCvip,				0),
101271ab489SXiaojian Du 	MSG_MAP(PowerDownCvip,                  PPSMC_MSG_PowerDownCvip,			0),
102271ab489SXiaojian Du 	MSG_MAP(GetPptLimit,                        PPSMC_MSG_GetPptLimit,			0),
103271ab489SXiaojian Du 	MSG_MAP(GetThermalLimit,                    PPSMC_MSG_GetThermalLimit,		0),
104271ab489SXiaojian Du 	MSG_MAP(GetCurrentTemperature,              PPSMC_MSG_GetCurrentTemperature, 0),
105271ab489SXiaojian Du 	MSG_MAP(GetCurrentPower,                    PPSMC_MSG_GetCurrentPower,		 0),
106271ab489SXiaojian Du 	MSG_MAP(GetCurrentVoltage,                  PPSMC_MSG_GetCurrentVoltage,	 0),
107271ab489SXiaojian Du 	MSG_MAP(GetCurrentCurrent,                  PPSMC_MSG_GetCurrentCurrent,	 0),
108271ab489SXiaojian Du 	MSG_MAP(GetAverageCpuActivity,              PPSMC_MSG_GetAverageCpuActivity, 0),
109271ab489SXiaojian Du 	MSG_MAP(GetAverageGfxActivity,              PPSMC_MSG_GetAverageGfxActivity, 0),
110271ab489SXiaojian Du 	MSG_MAP(GetAveragePower,                    PPSMC_MSG_GetAveragePower,		 0),
111271ab489SXiaojian Du 	MSG_MAP(GetAverageTemperature,              PPSMC_MSG_GetAverageTemperature, 0),
112271ab489SXiaojian Du 	MSG_MAP(SetAveragePowerTimeConstant,        PPSMC_MSG_SetAveragePowerTimeConstant,			0),
113271ab489SXiaojian Du 	MSG_MAP(SetAverageActivityTimeConstant,     PPSMC_MSG_SetAverageActivityTimeConstant,		0),
114271ab489SXiaojian Du 	MSG_MAP(SetAverageTemperatureTimeConstant,  PPSMC_MSG_SetAverageTemperatureTimeConstant,	0),
115271ab489SXiaojian Du 	MSG_MAP(SetMitigationEndHysteresis,         PPSMC_MSG_SetMitigationEndHysteresis,			0),
116271ab489SXiaojian Du 	MSG_MAP(GetCurrentFreq,                     PPSMC_MSG_GetCurrentFreq,						0),
117271ab489SXiaojian Du 	MSG_MAP(SetReducedPptLimit,                 PPSMC_MSG_SetReducedPptLimit,					0),
118271ab489SXiaojian Du 	MSG_MAP(SetReducedThermalLimit,             PPSMC_MSG_SetReducedThermalLimit,				0),
119271ab489SXiaojian Du 	MSG_MAP(DramLogSetDramAddr,                 PPSMC_MSG_DramLogSetDramAddr,					0),
120271ab489SXiaojian Du 	MSG_MAP(StartDramLogging,                   PPSMC_MSG_StartDramLogging,						0),
121271ab489SXiaojian Du 	MSG_MAP(StopDramLogging,                    PPSMC_MSG_StopDramLogging,						0),
122271ab489SXiaojian Du 	MSG_MAP(SetSoftMinCclk,                     PPSMC_MSG_SetSoftMinCclk,						0),
123271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxCclk,                     PPSMC_MSG_SetSoftMaxCclk,						0),
124eefdf047SJinzhou Su 	MSG_MAP(RequestActiveWgp,                   PPSMC_MSG_RequestActiveWgp,                     0),
125f46a221bSXiaojian Du };
126f46a221bSXiaojian Du 
127f46a221bSXiaojian Du static struct cmn2asic_mapping vangogh_feature_mask_map[SMU_FEATURE_COUNT] = {
128f46a221bSXiaojian Du 	FEA_MAP(PPT),
129f46a221bSXiaojian Du 	FEA_MAP(TDC),
130f46a221bSXiaojian Du 	FEA_MAP(THERMAL),
131f46a221bSXiaojian Du 	FEA_MAP(DS_GFXCLK),
132f46a221bSXiaojian Du 	FEA_MAP(DS_SOCCLK),
133f46a221bSXiaojian Du 	FEA_MAP(DS_LCLK),
134f46a221bSXiaojian Du 	FEA_MAP(DS_FCLK),
135f46a221bSXiaojian Du 	FEA_MAP(DS_MP1CLK),
136f46a221bSXiaojian Du 	FEA_MAP(DS_MP0CLK),
137f46a221bSXiaojian Du 	FEA_MAP(ATHUB_PG),
138f46a221bSXiaojian Du 	FEA_MAP(CCLK_DPM),
139f46a221bSXiaojian Du 	FEA_MAP(FAN_CONTROLLER),
140f46a221bSXiaojian Du 	FEA_MAP(ULV),
141f46a221bSXiaojian Du 	FEA_MAP(VCN_DPM),
142f46a221bSXiaojian Du 	FEA_MAP(LCLK_DPM),
143f46a221bSXiaojian Du 	FEA_MAP(SHUBCLK_DPM),
144f46a221bSXiaojian Du 	FEA_MAP(DCFCLK_DPM),
145f46a221bSXiaojian Du 	FEA_MAP(DS_DCFCLK),
146f46a221bSXiaojian Du 	FEA_MAP(S0I2),
147f46a221bSXiaojian Du 	FEA_MAP(SMU_LOW_POWER),
148f46a221bSXiaojian Du 	FEA_MAP(GFX_DEM),
149f46a221bSXiaojian Du 	FEA_MAP(PSI),
150f46a221bSXiaojian Du 	FEA_MAP(PROCHOT),
151f46a221bSXiaojian Du 	FEA_MAP(CPUOFF),
152f46a221bSXiaojian Du 	FEA_MAP(STAPM),
153f46a221bSXiaojian Du 	FEA_MAP(S0I3),
154f46a221bSXiaojian Du 	FEA_MAP(DF_CSTATES),
155f46a221bSXiaojian Du 	FEA_MAP(PERF_LIMIT),
156f46a221bSXiaojian Du 	FEA_MAP(CORE_DLDO),
157f46a221bSXiaojian Du 	FEA_MAP(RSMU_LOW_POWER),
158f46a221bSXiaojian Du 	FEA_MAP(SMN_LOW_POWER),
159f46a221bSXiaojian Du 	FEA_MAP(THM_LOW_POWER),
160f46a221bSXiaojian Du 	FEA_MAP(SMUIO_LOW_POWER),
161f46a221bSXiaojian Du 	FEA_MAP(MP1_LOW_POWER),
162f46a221bSXiaojian Du 	FEA_MAP(DS_VCN),
163f46a221bSXiaojian Du 	FEA_MAP(CPPC),
164f46a221bSXiaojian Du 	FEA_MAP(OS_CSTATES),
165f46a221bSXiaojian Du 	FEA_MAP(ISP_DPM),
166f46a221bSXiaojian Du 	FEA_MAP(A55_DPM),
167f46a221bSXiaojian Du 	FEA_MAP(CVIP_DSP_DPM),
168f46a221bSXiaojian Du 	FEA_MAP(MSMU_LOW_POWER),
16954800b58SXiaojian Du 	FEA_MAP_REVERSE(SOCCLK),
17054800b58SXiaojian Du 	FEA_MAP_REVERSE(FCLK),
17154800b58SXiaojian Du 	FEA_MAP_HALF_REVERSE(GFX),
172f46a221bSXiaojian Du };
173f46a221bSXiaojian Du 
174f46a221bSXiaojian Du static struct cmn2asic_mapping vangogh_table_map[SMU_TABLE_COUNT] = {
175f46a221bSXiaojian Du 	TAB_MAP_VALID(WATERMARKS),
176f46a221bSXiaojian Du 	TAB_MAP_VALID(SMU_METRICS),
177f46a221bSXiaojian Du 	TAB_MAP_VALID(CUSTOM_DPM),
178f46a221bSXiaojian Du 	TAB_MAP_VALID(DPMCLOCKS),
179f46a221bSXiaojian Du };
180f46a221bSXiaojian Du 
181f727ebebSXiaojian Du static struct cmn2asic_mapping vangogh_workload_map[PP_SMC_POWER_PROFILE_COUNT] = {
182f727ebebSXiaojian Du 	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D,		WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT),
183f727ebebSXiaojian Du 	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO,		WORKLOAD_PPLIB_VIDEO_BIT),
184f727ebebSXiaojian Du 	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR,			WORKLOAD_PPLIB_VR_BIT),
185f727ebebSXiaojian Du 	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE,		WORKLOAD_PPLIB_COMPUTE_BIT),
186f727ebebSXiaojian Du 	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM,		WORKLOAD_PPLIB_CUSTOM_BIT),
187f727ebebSXiaojian Du };
188f727ebebSXiaojian Du 
189f46a221bSXiaojian Du static int vangogh_tables_init(struct smu_context *smu)
190f46a221bSXiaojian Du {
191f46a221bSXiaojian Du 	struct smu_table_context *smu_table = &smu->smu_table;
192f46a221bSXiaojian Du 	struct smu_table *tables = smu_table->tables;
193f46a221bSXiaojian Du 
194f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
195f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
196f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
197f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
198f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
199f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
200f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE,
201f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
202f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF, sizeof(DpmActivityMonitorCoeffExt_t),
203f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
204f46a221bSXiaojian Du 	smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
205f46a221bSXiaojian Du 	if (!smu_table->metrics_table)
206f46a221bSXiaojian Du 		goto err0_out;
207f46a221bSXiaojian Du 	smu_table->metrics_time = 0;
208f46a221bSXiaojian Du 
209f46a221bSXiaojian Du 	smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_0);
210f46a221bSXiaojian Du 	smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
211f46a221bSXiaojian Du 	if (!smu_table->gpu_metrics_table)
212f46a221bSXiaojian Du 		goto err1_out;
213f46a221bSXiaojian Du 
214f46a221bSXiaojian Du 	smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
215f46a221bSXiaojian Du 	if (!smu_table->watermarks_table)
216f46a221bSXiaojian Du 		goto err2_out;
217f46a221bSXiaojian Du 
218c98ee897SXiaojian Du 	smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
219c98ee897SXiaojian Du 	if (!smu_table->clocks_table)
220c98ee897SXiaojian Du 		goto err3_out;
221c98ee897SXiaojian Du 
222f46a221bSXiaojian Du 	return 0;
223f46a221bSXiaojian Du 
224c98ee897SXiaojian Du err3_out:
225c98ee897SXiaojian Du 	kfree(smu_table->clocks_table);
226f46a221bSXiaojian Du err2_out:
227f46a221bSXiaojian Du 	kfree(smu_table->gpu_metrics_table);
228f46a221bSXiaojian Du err1_out:
229f46a221bSXiaojian Du 	kfree(smu_table->metrics_table);
230f46a221bSXiaojian Du err0_out:
231f46a221bSXiaojian Du 	return -ENOMEM;
232f46a221bSXiaojian Du }
233f46a221bSXiaojian Du 
234271ab489SXiaojian Du static int vangogh_get_smu_metrics_data(struct smu_context *smu,
235271ab489SXiaojian Du 				       MetricsMember_t member,
236271ab489SXiaojian Du 				       uint32_t *value)
237271ab489SXiaojian Du {
238271ab489SXiaojian Du 	struct smu_table_context *smu_table = &smu->smu_table;
239271ab489SXiaojian Du 
240271ab489SXiaojian Du 	SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
241271ab489SXiaojian Du 	int ret = 0;
242271ab489SXiaojian Du 
243271ab489SXiaojian Du 	mutex_lock(&smu->metrics_lock);
244271ab489SXiaojian Du 
245271ab489SXiaojian Du 	ret = smu_cmn_get_metrics_table_locked(smu,
246271ab489SXiaojian Du 					       NULL,
247271ab489SXiaojian Du 					       false);
248271ab489SXiaojian Du 	if (ret) {
249271ab489SXiaojian Du 		mutex_unlock(&smu->metrics_lock);
250271ab489SXiaojian Du 		return ret;
251271ab489SXiaojian Du 	}
252271ab489SXiaojian Du 
253271ab489SXiaojian Du 	switch (member) {
254271ab489SXiaojian Du 	case METRICS_AVERAGE_GFXCLK:
255271ab489SXiaojian Du 		*value = metrics->GfxclkFrequency;
256271ab489SXiaojian Du 		break;
257271ab489SXiaojian Du 	case METRICS_AVERAGE_SOCCLK:
258271ab489SXiaojian Du 		*value = metrics->SocclkFrequency;
259271ab489SXiaojian Du 		break;
260f02c7336SXiaojian Du 	case METRICS_AVERAGE_VCLK:
261f02c7336SXiaojian Du 		*value = metrics->VclkFrequency;
262f02c7336SXiaojian Du 		break;
263f02c7336SXiaojian Du 	case METRICS_AVERAGE_DCLK:
264f02c7336SXiaojian Du 		*value = metrics->DclkFrequency;
265f02c7336SXiaojian Du 		break;
266271ab489SXiaojian Du 	case METRICS_AVERAGE_UCLK:
267271ab489SXiaojian Du 		*value = metrics->MemclkFrequency;
268271ab489SXiaojian Du 		break;
269271ab489SXiaojian Du 	case METRICS_AVERAGE_GFXACTIVITY:
270271ab489SXiaojian Du 		*value = metrics->GfxActivity / 100;
271271ab489SXiaojian Du 		break;
272271ab489SXiaojian Du 	case METRICS_AVERAGE_VCNACTIVITY:
273271ab489SXiaojian Du 		*value = metrics->UvdActivity;
274271ab489SXiaojian Du 		break;
275271ab489SXiaojian Du 	case METRICS_AVERAGE_SOCKETPOWER:
27623289a22SXiaojian Du 		*value = (metrics->CurrentSocketPower << 8) /
27723289a22SXiaojian Du 		1000 ;
278271ab489SXiaojian Du 		break;
279271ab489SXiaojian Du 	case METRICS_TEMPERATURE_EDGE:
280271ab489SXiaojian Du 		*value = metrics->GfxTemperature / 100 *
281271ab489SXiaojian Du 		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
282271ab489SXiaojian Du 		break;
283271ab489SXiaojian Du 	case METRICS_TEMPERATURE_HOTSPOT:
284271ab489SXiaojian Du 		*value = metrics->SocTemperature / 100 *
285271ab489SXiaojian Du 		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
286271ab489SXiaojian Du 		break;
287271ab489SXiaojian Du 	case METRICS_THROTTLER_STATUS:
288271ab489SXiaojian Du 		*value = metrics->ThrottlerStatus;
289271ab489SXiaojian Du 		break;
2902139d12bSAlex Deucher 	case METRICS_VOLTAGE_VDDGFX:
2912139d12bSAlex Deucher 		*value = metrics->Voltage[2];
2922139d12bSAlex Deucher 		break;
2932139d12bSAlex Deucher 	case METRICS_VOLTAGE_VDDSOC:
2942139d12bSAlex Deucher 		*value = metrics->Voltage[1];
2952139d12bSAlex Deucher 		break;
296517cb957SHuang Rui 	case METRICS_AVERAGE_CPUCLK:
297517cb957SHuang Rui 		memcpy(value, &metrics->CoreFrequency[0],
2984aef0ebcSHuang Rui 		       smu->cpu_core_num * sizeof(uint16_t));
299517cb957SHuang Rui 		break;
300271ab489SXiaojian Du 	default:
301271ab489SXiaojian Du 		*value = UINT_MAX;
302271ab489SXiaojian Du 		break;
303271ab489SXiaojian Du 	}
304271ab489SXiaojian Du 
305271ab489SXiaojian Du 	mutex_unlock(&smu->metrics_lock);
306271ab489SXiaojian Du 
307271ab489SXiaojian Du 	return ret;
308271ab489SXiaojian Du }
309271ab489SXiaojian Du 
310f46a221bSXiaojian Du static int vangogh_allocate_dpm_context(struct smu_context *smu)
311f46a221bSXiaojian Du {
312f46a221bSXiaojian Du 	struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
313f46a221bSXiaojian Du 
314f46a221bSXiaojian Du 	smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context),
315f46a221bSXiaojian Du 				       GFP_KERNEL);
316f46a221bSXiaojian Du 	if (!smu_dpm->dpm_context)
317f46a221bSXiaojian Du 		return -ENOMEM;
318f46a221bSXiaojian Du 
319f46a221bSXiaojian Du 	smu_dpm->dpm_context_size = sizeof(struct smu_11_0_dpm_context);
320f46a221bSXiaojian Du 
321f46a221bSXiaojian Du 	return 0;
322f46a221bSXiaojian Du }
323f46a221bSXiaojian Du 
324f46a221bSXiaojian Du static int vangogh_init_smc_tables(struct smu_context *smu)
325f46a221bSXiaojian Du {
326f46a221bSXiaojian Du 	int ret = 0;
327f46a221bSXiaojian Du 
328f46a221bSXiaojian Du 	ret = vangogh_tables_init(smu);
329f46a221bSXiaojian Du 	if (ret)
330f46a221bSXiaojian Du 		return ret;
331f46a221bSXiaojian Du 
332f46a221bSXiaojian Du 	ret = vangogh_allocate_dpm_context(smu);
333f46a221bSXiaojian Du 	if (ret)
334f46a221bSXiaojian Du 		return ret;
335f46a221bSXiaojian Du 
3364aef0ebcSHuang Rui #ifdef CONFIG_X86
3374aef0ebcSHuang Rui 	/* AMD x86 APU only */
3384aef0ebcSHuang Rui 	smu->cpu_core_num = boot_cpu_data.x86_max_cores;
3394aef0ebcSHuang Rui #else
3404aef0ebcSHuang Rui 	smu->cpu_core_num = 4;
3414aef0ebcSHuang Rui #endif
3424aef0ebcSHuang Rui 
343f46a221bSXiaojian Du 	return smu_v11_0_init_smc_tables(smu);
344f46a221bSXiaojian Du }
345f46a221bSXiaojian Du 
346f46a221bSXiaojian Du static int vangogh_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
347f46a221bSXiaojian Du {
348f46a221bSXiaojian Du 	int ret = 0;
349f46a221bSXiaojian Du 
350f46a221bSXiaojian Du 	if (enable) {
351f46a221bSXiaojian Du 		/* vcn dpm on is a prerequisite for vcn power gate messages */
352f46a221bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 0, NULL);
353f46a221bSXiaojian Du 		if (ret)
354f46a221bSXiaojian Du 			return ret;
355f46a221bSXiaojian Du 	} else {
356f46a221bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn, 0, NULL);
357f46a221bSXiaojian Du 		if (ret)
358f46a221bSXiaojian Du 			return ret;
359f46a221bSXiaojian Du 	}
360f46a221bSXiaojian Du 
361f46a221bSXiaojian Du 	return ret;
362f46a221bSXiaojian Du }
363f46a221bSXiaojian Du 
364f46a221bSXiaojian Du static int vangogh_dpm_set_jpeg_enable(struct smu_context *smu, bool enable)
365f46a221bSXiaojian Du {
366f46a221bSXiaojian Du 	int ret = 0;
367f46a221bSXiaojian Du 
368f46a221bSXiaojian Du 	if (enable) {
369f46a221bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0, NULL);
370f46a221bSXiaojian Du 		if (ret)
371f46a221bSXiaojian Du 			return ret;
372f46a221bSXiaojian Du 	} else {
373f46a221bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0, NULL);
374f46a221bSXiaojian Du 		if (ret)
375f46a221bSXiaojian Du 			return ret;
376f46a221bSXiaojian Du 	}
377f46a221bSXiaojian Du 
378f46a221bSXiaojian Du 	return ret;
379f46a221bSXiaojian Du }
380f46a221bSXiaojian Du 
381f46a221bSXiaojian Du static bool vangogh_is_dpm_running(struct smu_context *smu)
382f46a221bSXiaojian Du {
383271ab489SXiaojian Du 	int ret = 0;
384271ab489SXiaojian Du 	uint32_t feature_mask[2];
385271ab489SXiaojian Du 	uint64_t feature_enabled;
386f46a221bSXiaojian Du 
387271ab489SXiaojian Du 	ret = smu_cmn_get_enabled_32_bits_mask(smu, feature_mask, 2);
388271ab489SXiaojian Du 
389271ab489SXiaojian Du 	if (ret)
390f46a221bSXiaojian Du 		return false;
391f46a221bSXiaojian Du 
392271ab489SXiaojian Du 	feature_enabled = (unsigned long)((uint64_t)feature_mask[0] |
393271ab489SXiaojian Du 				((uint64_t)feature_mask[1] << 32));
394271ab489SXiaojian Du 
395271ab489SXiaojian Du 	return !!(feature_enabled & SMC_DPM_FEATURE);
396271ab489SXiaojian Du }
397271ab489SXiaojian Du 
398ae7b32e7SXiaojian Du static int vangogh_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type clk_type,
399ae7b32e7SXiaojian Du 						uint32_t dpm_level, uint32_t *freq)
400ae7b32e7SXiaojian Du {
401ae7b32e7SXiaojian Du 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
402ae7b32e7SXiaojian Du 
403ae7b32e7SXiaojian Du 	if (!clk_table || clk_type >= SMU_CLK_COUNT)
404ae7b32e7SXiaojian Du 		return -EINVAL;
405ae7b32e7SXiaojian Du 
406ae7b32e7SXiaojian Du 	switch (clk_type) {
407ae7b32e7SXiaojian Du 	case SMU_SOCCLK:
408ae7b32e7SXiaojian Du 		if (dpm_level >= clk_table->NumSocClkLevelsEnabled)
409ae7b32e7SXiaojian Du 			return -EINVAL;
410ae7b32e7SXiaojian Du 		*freq = clk_table->SocClocks[dpm_level];
411ae7b32e7SXiaojian Du 		break;
412f02c7336SXiaojian Du 	case SMU_VCLK:
413f02c7336SXiaojian Du 		if (dpm_level >= clk_table->VcnClkLevelsEnabled)
414f02c7336SXiaojian Du 			return -EINVAL;
415f02c7336SXiaojian Du 		*freq = clk_table->VcnClocks[dpm_level].vclk;
416f02c7336SXiaojian Du 		break;
417f02c7336SXiaojian Du 	case SMU_DCLK:
418f02c7336SXiaojian Du 		if (dpm_level >= clk_table->VcnClkLevelsEnabled)
419f02c7336SXiaojian Du 			return -EINVAL;
420f02c7336SXiaojian Du 		*freq = clk_table->VcnClocks[dpm_level].dclk;
421f02c7336SXiaojian Du 		break;
422ae7b32e7SXiaojian Du 	case SMU_UCLK:
423ae7b32e7SXiaojian Du 	case SMU_MCLK:
424ae7b32e7SXiaojian Du 		if (dpm_level >= clk_table->NumDfPstatesEnabled)
425ae7b32e7SXiaojian Du 			return -EINVAL;
426ae7b32e7SXiaojian Du 		*freq = clk_table->DfPstateTable[dpm_level].memclk;
427ae7b32e7SXiaojian Du 
428ae7b32e7SXiaojian Du 		break;
429ae7b32e7SXiaojian Du 	case SMU_FCLK:
430ae7b32e7SXiaojian Du 		if (dpm_level >= clk_table->NumDfPstatesEnabled)
431ae7b32e7SXiaojian Du 			return -EINVAL;
432ae7b32e7SXiaojian Du 		*freq = clk_table->DfPstateTable[dpm_level].fclk;
433ae7b32e7SXiaojian Du 		break;
434ae7b32e7SXiaojian Du 	default:
435ae7b32e7SXiaojian Du 		return -EINVAL;
436ae7b32e7SXiaojian Du 	}
437ae7b32e7SXiaojian Du 
438ae7b32e7SXiaojian Du 	return 0;
439ae7b32e7SXiaojian Du }
440ae7b32e7SXiaojian Du 
441c98ee897SXiaojian Du static int vangogh_print_fine_grain_clk(struct smu_context *smu,
442c98ee897SXiaojian Du 			enum smu_clk_type clk_type, char *buf)
443c98ee897SXiaojian Du {
444ae7b32e7SXiaojian Du 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
445ae7b32e7SXiaojian Du 	SmuMetrics_t metrics;
446d7379efaSXiaojian Du 	struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
447ae7b32e7SXiaojian Du 	int i, size = 0, ret = 0;
448ae7b32e7SXiaojian Du 	uint32_t cur_value = 0, value = 0, count = 0;
449ae7b32e7SXiaojian Du 	bool cur_value_match_level = false;
450ae7b32e7SXiaojian Du 
451ae7b32e7SXiaojian Du 	memset(&metrics, 0, sizeof(metrics));
452ae7b32e7SXiaojian Du 
453ae7b32e7SXiaojian Du 	ret = smu_cmn_get_metrics_table(smu, &metrics, false);
454ae7b32e7SXiaojian Du 	if (ret)
455ae7b32e7SXiaojian Du 		return ret;
456c98ee897SXiaojian Du 
457c98ee897SXiaojian Du 	switch (clk_type) {
458c98ee897SXiaojian Du 	case SMU_OD_SCLK:
459d7379efaSXiaojian Du 		if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
460c98ee897SXiaojian Du 			size = sprintf(buf, "%s:\n", "OD_SCLK");
461c98ee897SXiaojian Du 			size += sprintf(buf + size, "0: %10uMhz\n",
462c98ee897SXiaojian Du 			(smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);
463c98ee897SXiaojian Du 			size += sprintf(buf + size, "1: %10uMhz\n",
464c98ee897SXiaojian Du 			(smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq);
465c98ee897SXiaojian Du 		}
466c98ee897SXiaojian Du 		break;
4670d90d0ddSHuang Rui 	case SMU_OD_CCLK:
468d7379efaSXiaojian Du 		if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
4690d90d0ddSHuang Rui 			size = sprintf(buf, "CCLK_RANGE in Core%d:\n",  smu->cpu_core_id_select);
4700d90d0ddSHuang Rui 			size += sprintf(buf + size, "0: %10uMhz\n",
4710d90d0ddSHuang Rui 			(smu->cpu_actual_soft_min_freq > 0) ? smu->cpu_actual_soft_min_freq : smu->cpu_default_soft_min_freq);
4720d90d0ddSHuang Rui 			size += sprintf(buf + size, "1: %10uMhz\n",
4730d90d0ddSHuang Rui 			(smu->cpu_actual_soft_max_freq > 0) ? smu->cpu_actual_soft_max_freq : smu->cpu_default_soft_max_freq);
4740d90d0ddSHuang Rui 		}
4750d90d0ddSHuang Rui 		break;
476c98ee897SXiaojian Du 	case SMU_OD_RANGE:
477d7379efaSXiaojian Du 		if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
478c98ee897SXiaojian Du 			size = sprintf(buf, "%s:\n", "OD_RANGE");
479c98ee897SXiaojian Du 			size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
480c98ee897SXiaojian Du 				smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);
4810d90d0ddSHuang Rui 			size += sprintf(buf + size, "CCLK: %7uMhz %10uMhz\n",
4820d90d0ddSHuang Rui 				smu->cpu_default_soft_min_freq, smu->cpu_default_soft_max_freq);
483c98ee897SXiaojian Du 		}
484c98ee897SXiaojian Du 		break;
485ae7b32e7SXiaojian Du 	case SMU_SOCCLK:
486ae7b32e7SXiaojian Du 		/* the level 3 ~ 6 of socclk use the same frequency for vangogh */
487ae7b32e7SXiaojian Du 		count = clk_table->NumSocClkLevelsEnabled;
488ae7b32e7SXiaojian Du 		cur_value = metrics.SocclkFrequency;
489ae7b32e7SXiaojian Du 		break;
490f02c7336SXiaojian Du 	case SMU_VCLK:
491f02c7336SXiaojian Du 		count = clk_table->VcnClkLevelsEnabled;
492f02c7336SXiaojian Du 		cur_value = metrics.VclkFrequency;
493f02c7336SXiaojian Du 		break;
494f02c7336SXiaojian Du 	case SMU_DCLK:
495f02c7336SXiaojian Du 		count = clk_table->VcnClkLevelsEnabled;
496f02c7336SXiaojian Du 		cur_value = metrics.DclkFrequency;
497f02c7336SXiaojian Du 		break;
498ae7b32e7SXiaojian Du 	case SMU_MCLK:
499ae7b32e7SXiaojian Du 		count = clk_table->NumDfPstatesEnabled;
500ae7b32e7SXiaojian Du 		cur_value = metrics.MemclkFrequency;
501ae7b32e7SXiaojian Du 		break;
502ae7b32e7SXiaojian Du 	case SMU_FCLK:
503ae7b32e7SXiaojian Du 		count = clk_table->NumDfPstatesEnabled;
504ae7b32e7SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetFclkFrequency, 0, &cur_value);
505ae7b32e7SXiaojian Du 		if (ret)
506ae7b32e7SXiaojian Du 			return ret;
507ae7b32e7SXiaojian Du 		break;
508ae7b32e7SXiaojian Du 	default:
509ae7b32e7SXiaojian Du 		break;
510ae7b32e7SXiaojian Du 	}
511ae7b32e7SXiaojian Du 
512ae7b32e7SXiaojian Du 	switch (clk_type) {
513ae7b32e7SXiaojian Du 	case SMU_SOCCLK:
514f02c7336SXiaojian Du 	case SMU_VCLK:
515f02c7336SXiaojian Du 	case SMU_DCLK:
516ae7b32e7SXiaojian Du 	case SMU_MCLK:
517ae7b32e7SXiaojian Du 	case SMU_FCLK:
518ae7b32e7SXiaojian Du 		for (i = 0; i < count; i++) {
519ae7b32e7SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, i, &value);
520ae7b32e7SXiaojian Du 			if (ret)
521ae7b32e7SXiaojian Du 				return ret;
522ae7b32e7SXiaojian Du 			if (!value)
523ae7b32e7SXiaojian Du 				continue;
524ae7b32e7SXiaojian Du 			size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
525ae7b32e7SXiaojian Du 					cur_value == value ? "*" : "");
526ae7b32e7SXiaojian Du 			if (cur_value == value)
527ae7b32e7SXiaojian Du 				cur_value_match_level = true;
528ae7b32e7SXiaojian Du 		}
529ae7b32e7SXiaojian Du 
530ae7b32e7SXiaojian Du 		if (!cur_value_match_level)
531ae7b32e7SXiaojian Du 			size += sprintf(buf + size, "   %uMhz *\n", cur_value);
532ae7b32e7SXiaojian Du 		break;
533c98ee897SXiaojian Du 	default:
534c98ee897SXiaojian Du 		break;
535c98ee897SXiaojian Du 	}
536c98ee897SXiaojian Du 
537c98ee897SXiaojian Du 	return size;
538c98ee897SXiaojian Du }
539c98ee897SXiaojian Du 
540d0e4e112SXiaojian Du static int vangogh_get_profiling_clk_mask(struct smu_context *smu,
541d0e4e112SXiaojian Du 					 enum amd_dpm_forced_level level,
542d0e4e112SXiaojian Du 					 uint32_t *vclk_mask,
543d0e4e112SXiaojian Du 					 uint32_t *dclk_mask,
544d0e4e112SXiaojian Du 					 uint32_t *mclk_mask,
545d0e4e112SXiaojian Du 					 uint32_t *fclk_mask,
546d0e4e112SXiaojian Du 					 uint32_t *soc_mask)
547d0e4e112SXiaojian Du {
548d0e4e112SXiaojian Du 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
549d0e4e112SXiaojian Du 
550307f049bSXiaojian Du 	if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
551d0e4e112SXiaojian Du 		if (mclk_mask)
552d0e4e112SXiaojian Du 			*mclk_mask = clk_table->NumDfPstatesEnabled - 1;
553307f049bSXiaojian Du 
554d0e4e112SXiaojian Du 		if (fclk_mask)
555d0e4e112SXiaojian Du 			*fclk_mask = clk_table->NumDfPstatesEnabled - 1;
556307f049bSXiaojian Du 
557307f049bSXiaojian Du 		if (soc_mask)
558307f049bSXiaojian Du 			*soc_mask = 0;
559d0e4e112SXiaojian Du 	} else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
560d0e4e112SXiaojian Du 		if (mclk_mask)
561d0e4e112SXiaojian Du 			*mclk_mask = 0;
562307f049bSXiaojian Du 
563d0e4e112SXiaojian Du 		if (fclk_mask)
564d0e4e112SXiaojian Du 			*fclk_mask = 0;
565d0e4e112SXiaojian Du 
566d0e4e112SXiaojian Du 		if (soc_mask)
567307f049bSXiaojian Du 			*soc_mask = 1;
568307f049bSXiaojian Du 
569307f049bSXiaojian Du 		if (vclk_mask)
570307f049bSXiaojian Du 			*vclk_mask = 1;
571307f049bSXiaojian Du 
572307f049bSXiaojian Du 		if (dclk_mask)
573307f049bSXiaojian Du 			*dclk_mask = 1;
574307f049bSXiaojian Du 	} else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD) {
575307f049bSXiaojian Du 		if (mclk_mask)
576307f049bSXiaojian Du 			*mclk_mask = 0;
577307f049bSXiaojian Du 
578307f049bSXiaojian Du 		if (fclk_mask)
579307f049bSXiaojian Du 			*fclk_mask = 0;
580307f049bSXiaojian Du 
581307f049bSXiaojian Du 		if (soc_mask)
582307f049bSXiaojian Du 			*soc_mask = 1;
583307f049bSXiaojian Du 
584307f049bSXiaojian Du 		if (vclk_mask)
585307f049bSXiaojian Du 			*vclk_mask = 1;
586307f049bSXiaojian Du 
587307f049bSXiaojian Du 		if (dclk_mask)
588307f049bSXiaojian Du 			*dclk_mask = 1;
589d0e4e112SXiaojian Du 	}
590d0e4e112SXiaojian Du 
591d0e4e112SXiaojian Du 	return 0;
592d0e4e112SXiaojian Du }
593d0e4e112SXiaojian Du 
5948f8150faSSouptick Joarder static bool vangogh_clk_dpm_is_enabled(struct smu_context *smu,
595d0e4e112SXiaojian Du 				enum smu_clk_type clk_type)
596d0e4e112SXiaojian Du {
597d0e4e112SXiaojian Du 	enum smu_feature_mask feature_id = 0;
598d0e4e112SXiaojian Du 
599d0e4e112SXiaojian Du 	switch (clk_type) {
600d0e4e112SXiaojian Du 	case SMU_MCLK:
601d0e4e112SXiaojian Du 	case SMU_UCLK:
602d0e4e112SXiaojian Du 	case SMU_FCLK:
603d0e4e112SXiaojian Du 		feature_id = SMU_FEATURE_DPM_FCLK_BIT;
604d0e4e112SXiaojian Du 		break;
605d0e4e112SXiaojian Du 	case SMU_GFXCLK:
606d0e4e112SXiaojian Du 	case SMU_SCLK:
607d0e4e112SXiaojian Du 		feature_id = SMU_FEATURE_DPM_GFXCLK_BIT;
608d0e4e112SXiaojian Du 		break;
609d0e4e112SXiaojian Du 	case SMU_SOCCLK:
610d0e4e112SXiaojian Du 		feature_id = SMU_FEATURE_DPM_SOCCLK_BIT;
611d0e4e112SXiaojian Du 		break;
612d0e4e112SXiaojian Du 	case SMU_VCLK:
613d0e4e112SXiaojian Du 	case SMU_DCLK:
614d0e4e112SXiaojian Du 		feature_id = SMU_FEATURE_VCN_DPM_BIT;
615d0e4e112SXiaojian Du 		break;
616d0e4e112SXiaojian Du 	default:
617d0e4e112SXiaojian Du 		return true;
618d0e4e112SXiaojian Du 	}
619d0e4e112SXiaojian Du 
620d0e4e112SXiaojian Du 	if (!smu_cmn_feature_is_enabled(smu, feature_id))
621d0e4e112SXiaojian Du 		return false;
622d0e4e112SXiaojian Du 
623d0e4e112SXiaojian Du 	return true;
624d0e4e112SXiaojian Du }
625d0e4e112SXiaojian Du 
626d0e4e112SXiaojian Du static int vangogh_get_dpm_ultimate_freq(struct smu_context *smu,
627d0e4e112SXiaojian Du 					enum smu_clk_type clk_type,
628d0e4e112SXiaojian Du 					uint32_t *min,
629d0e4e112SXiaojian Du 					uint32_t *max)
630d0e4e112SXiaojian Du {
631d0e4e112SXiaojian Du 	int ret = 0;
632d0e4e112SXiaojian Du 	uint32_t soc_mask;
633d0e4e112SXiaojian Du 	uint32_t vclk_mask;
634d0e4e112SXiaojian Du 	uint32_t dclk_mask;
635d0e4e112SXiaojian Du 	uint32_t mclk_mask;
636d0e4e112SXiaojian Du 	uint32_t fclk_mask;
637d0e4e112SXiaojian Du 	uint32_t clock_limit;
638d0e4e112SXiaojian Du 
639d0e4e112SXiaojian Du 	if (!vangogh_clk_dpm_is_enabled(smu, clk_type)) {
640d0e4e112SXiaojian Du 		switch (clk_type) {
641d0e4e112SXiaojian Du 		case SMU_MCLK:
642d0e4e112SXiaojian Du 		case SMU_UCLK:
643d0e4e112SXiaojian Du 			clock_limit = smu->smu_table.boot_values.uclk;
644d0e4e112SXiaojian Du 			break;
645d0e4e112SXiaojian Du 		case SMU_FCLK:
646d0e4e112SXiaojian Du 			clock_limit = smu->smu_table.boot_values.fclk;
647d0e4e112SXiaojian Du 			break;
648d0e4e112SXiaojian Du 		case SMU_GFXCLK:
649d0e4e112SXiaojian Du 		case SMU_SCLK:
650d0e4e112SXiaojian Du 			clock_limit = smu->smu_table.boot_values.gfxclk;
651d0e4e112SXiaojian Du 			break;
652d0e4e112SXiaojian Du 		case SMU_SOCCLK:
653d0e4e112SXiaojian Du 			clock_limit = smu->smu_table.boot_values.socclk;
654d0e4e112SXiaojian Du 			break;
655d0e4e112SXiaojian Du 		case SMU_VCLK:
656d0e4e112SXiaojian Du 			clock_limit = smu->smu_table.boot_values.vclk;
657d0e4e112SXiaojian Du 			break;
658d0e4e112SXiaojian Du 		case SMU_DCLK:
659d0e4e112SXiaojian Du 			clock_limit = smu->smu_table.boot_values.dclk;
660d0e4e112SXiaojian Du 			break;
661d0e4e112SXiaojian Du 		default:
662d0e4e112SXiaojian Du 			clock_limit = 0;
663d0e4e112SXiaojian Du 			break;
664d0e4e112SXiaojian Du 		}
665d0e4e112SXiaojian Du 
666d0e4e112SXiaojian Du 		/* clock in Mhz unit */
667d0e4e112SXiaojian Du 		if (min)
668d0e4e112SXiaojian Du 			*min = clock_limit / 100;
669d0e4e112SXiaojian Du 		if (max)
670d0e4e112SXiaojian Du 			*max = clock_limit / 100;
671d0e4e112SXiaojian Du 
672d0e4e112SXiaojian Du 		return 0;
673d0e4e112SXiaojian Du 	}
674d0e4e112SXiaojian Du 	if (max) {
675d0e4e112SXiaojian Du 		ret = vangogh_get_profiling_clk_mask(smu,
676d0e4e112SXiaojian Du 							AMD_DPM_FORCED_LEVEL_PROFILE_PEAK,
677d0e4e112SXiaojian Du 							&vclk_mask,
678d0e4e112SXiaojian Du 							&dclk_mask,
679d0e4e112SXiaojian Du 							&mclk_mask,
680d0e4e112SXiaojian Du 							&fclk_mask,
681d0e4e112SXiaojian Du 							&soc_mask);
682d0e4e112SXiaojian Du 		if (ret)
683d0e4e112SXiaojian Du 			goto failed;
684d0e4e112SXiaojian Du 
685d0e4e112SXiaojian Du 		switch (clk_type) {
686d0e4e112SXiaojian Du 		case SMU_UCLK:
687d0e4e112SXiaojian Du 		case SMU_MCLK:
688d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, mclk_mask, max);
689d0e4e112SXiaojian Du 			if (ret)
690d0e4e112SXiaojian Du 				goto failed;
691d0e4e112SXiaojian Du 			break;
692d0e4e112SXiaojian Du 		case SMU_SOCCLK:
693d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, soc_mask, max);
694d0e4e112SXiaojian Du 			if (ret)
695d0e4e112SXiaojian Du 				goto failed;
696d0e4e112SXiaojian Du 			break;
697d0e4e112SXiaojian Du 		case SMU_FCLK:
698d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, fclk_mask, max);
699d0e4e112SXiaojian Du 			if (ret)
700d0e4e112SXiaojian Du 				goto failed;
701d0e4e112SXiaojian Du 			break;
702d0e4e112SXiaojian Du 		case SMU_VCLK:
703d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, vclk_mask, max);
704d0e4e112SXiaojian Du 			if (ret)
705d0e4e112SXiaojian Du 				goto failed;
706d0e4e112SXiaojian Du 			break;
707d0e4e112SXiaojian Du 		case SMU_DCLK:
708d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, dclk_mask, max);
709d0e4e112SXiaojian Du 			if (ret)
710d0e4e112SXiaojian Du 				goto failed;
711d0e4e112SXiaojian Du 			break;
712d0e4e112SXiaojian Du 		default:
713d0e4e112SXiaojian Du 			ret = -EINVAL;
714d0e4e112SXiaojian Du 			goto failed;
715d0e4e112SXiaojian Du 		}
716d0e4e112SXiaojian Du 	}
717d0e4e112SXiaojian Du 	if (min) {
718d0e4e112SXiaojian Du 		switch (clk_type) {
719d0e4e112SXiaojian Du 		case SMU_UCLK:
720d0e4e112SXiaojian Du 		case SMU_MCLK:
721d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, mclk_mask, min);
722d0e4e112SXiaojian Du 			if (ret)
723d0e4e112SXiaojian Du 				goto failed;
724d0e4e112SXiaojian Du 			break;
725d0e4e112SXiaojian Du 		case SMU_SOCCLK:
726d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, soc_mask, min);
727d0e4e112SXiaojian Du 			if (ret)
728d0e4e112SXiaojian Du 				goto failed;
729d0e4e112SXiaojian Du 			break;
730d0e4e112SXiaojian Du 		case SMU_FCLK:
731d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, fclk_mask, min);
732d0e4e112SXiaojian Du 			if (ret)
733d0e4e112SXiaojian Du 				goto failed;
734d0e4e112SXiaojian Du 			break;
735d0e4e112SXiaojian Du 		case SMU_VCLK:
736d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, vclk_mask, min);
737d0e4e112SXiaojian Du 			if (ret)
738d0e4e112SXiaojian Du 				goto failed;
739d0e4e112SXiaojian Du 			break;
740d0e4e112SXiaojian Du 		case SMU_DCLK:
741d0e4e112SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, dclk_mask, min);
742d0e4e112SXiaojian Du 			if (ret)
743d0e4e112SXiaojian Du 				goto failed;
744d0e4e112SXiaojian Du 			break;
745d0e4e112SXiaojian Du 		default:
746d0e4e112SXiaojian Du 			ret = -EINVAL;
747d0e4e112SXiaojian Du 			goto failed;
748d0e4e112SXiaojian Du 		}
749d0e4e112SXiaojian Du 	}
750d0e4e112SXiaojian Du failed:
751d0e4e112SXiaojian Du 	return ret;
752d0e4e112SXiaojian Du }
753d0e4e112SXiaojian Du 
754307f049bSXiaojian Du static int vangogh_get_power_profile_mode(struct smu_context *smu,
755307f049bSXiaojian Du 					   char *buf)
756307f049bSXiaojian Du {
757307f049bSXiaojian Du 	static const char *profile_name[] = {
7582a38ca99SColin Ian King 					"BOOTUP_DEFAULT",
759f727ebebSXiaojian Du 					"3D_FULL_SCREEN",
760f727ebebSXiaojian Du 					"POWER_SAVING",
761307f049bSXiaojian Du 					"VIDEO",
762307f049bSXiaojian Du 					"VR",
763307f049bSXiaojian Du 					"COMPUTE",
764307f049bSXiaojian Du 					"CUSTOM"};
765307f049bSXiaojian Du 	uint32_t i, size = 0;
766307f049bSXiaojian Du 	int16_t workload_type = 0;
767307f049bSXiaojian Du 
768307f049bSXiaojian Du 	if (!buf)
769307f049bSXiaojian Du 		return -EINVAL;
770307f049bSXiaojian Du 
771307f049bSXiaojian Du 	for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
772307f049bSXiaojian Du 		/*
773307f049bSXiaojian Du 		 * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
774307f049bSXiaojian Du 		 * Not all profile modes are supported on vangogh.
775307f049bSXiaojian Du 		 */
776307f049bSXiaojian Du 		workload_type = smu_cmn_to_asic_specific_index(smu,
777307f049bSXiaojian Du 							       CMN2ASIC_MAPPING_WORKLOAD,
778307f049bSXiaojian Du 							       i);
779307f049bSXiaojian Du 
780307f049bSXiaojian Du 		if (workload_type < 0)
781307f049bSXiaojian Du 			continue;
782307f049bSXiaojian Du 
783307f049bSXiaojian Du 		size += sprintf(buf + size, "%2d %14s%s\n",
784307f049bSXiaojian Du 			i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");
785307f049bSXiaojian Du 	}
786307f049bSXiaojian Du 
787307f049bSXiaojian Du 	return size;
788307f049bSXiaojian Du }
789307f049bSXiaojian Du 
790d0e4e112SXiaojian Du static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
791d0e4e112SXiaojian Du {
792d0e4e112SXiaojian Du 	int workload_type, ret;
793d0e4e112SXiaojian Du 	uint32_t profile_mode = input[size];
794d0e4e112SXiaojian Du 
795d0e4e112SXiaojian Du 	if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
796d0e4e112SXiaojian Du 		dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
797d0e4e112SXiaojian Du 		return -EINVAL;
798d0e4e112SXiaojian Du 	}
799d0e4e112SXiaojian Du 
800f727ebebSXiaojian Du 	if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
801f727ebebSXiaojian Du 			profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
802f727ebebSXiaojian Du 		return 0;
803f727ebebSXiaojian Du 
804d0e4e112SXiaojian Du 	/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
805d0e4e112SXiaojian Du 	workload_type = smu_cmn_to_asic_specific_index(smu,
806d0e4e112SXiaojian Du 						       CMN2ASIC_MAPPING_WORKLOAD,
807d0e4e112SXiaojian Du 						       profile_mode);
808d0e4e112SXiaojian Du 	if (workload_type < 0) {
809d0e4e112SXiaojian Du 		dev_err_once(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
810d0e4e112SXiaojian Du 					profile_mode);
811d0e4e112SXiaojian Du 		return -EINVAL;
812d0e4e112SXiaojian Du 	}
813d0e4e112SXiaojian Du 
814d0e4e112SXiaojian Du 	ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
815d0e4e112SXiaojian Du 				    1 << workload_type,
816d0e4e112SXiaojian Du 				    NULL);
817d0e4e112SXiaojian Du 	if (ret) {
818d0e4e112SXiaojian Du 		dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
819d0e4e112SXiaojian Du 					workload_type);
820d0e4e112SXiaojian Du 		return ret;
821d0e4e112SXiaojian Du 	}
822d0e4e112SXiaojian Du 
823d0e4e112SXiaojian Du 	smu->power_profile_mode = profile_mode;
824d0e4e112SXiaojian Du 
825d0e4e112SXiaojian Du 	return 0;
826d0e4e112SXiaojian Du }
827d0e4e112SXiaojian Du 
828dd9e0b21SXiaojian Du static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
829dd9e0b21SXiaojian Du 					  enum smu_clk_type clk_type,
830dd9e0b21SXiaojian Du 					  uint32_t min,
831dd9e0b21SXiaojian Du 					  uint32_t max)
832dd9e0b21SXiaojian Du {
833dd9e0b21SXiaojian Du 	int ret = 0;
834dd9e0b21SXiaojian Du 
835dd9e0b21SXiaojian Du 	if (!vangogh_clk_dpm_is_enabled(smu, clk_type))
836dd9e0b21SXiaojian Du 		return 0;
837dd9e0b21SXiaojian Du 
838dd9e0b21SXiaojian Du 	switch (clk_type) {
839dd9e0b21SXiaojian Du 	case SMU_GFXCLK:
840dd9e0b21SXiaojian Du 	case SMU_SCLK:
841dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
842dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinGfxClk,
843dd9e0b21SXiaojian Du 							min, NULL);
844dd9e0b21SXiaojian Du 		if (ret)
845dd9e0b21SXiaojian Du 			return ret;
846dd9e0b21SXiaojian Du 
847dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
848dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxGfxClk,
849dd9e0b21SXiaojian Du 							max, NULL);
850dd9e0b21SXiaojian Du 		if (ret)
851dd9e0b21SXiaojian Du 			return ret;
852dd9e0b21SXiaojian Du 		break;
853dd9e0b21SXiaojian Du 	case SMU_FCLK:
854dd9e0b21SXiaojian Du 	case SMU_MCLK:
855dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
856dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinFclkByFreq,
857dd9e0b21SXiaojian Du 							min, NULL);
858dd9e0b21SXiaojian Du 		if (ret)
859dd9e0b21SXiaojian Du 			return ret;
860dd9e0b21SXiaojian Du 
861dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
862dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxFclkByFreq,
863dd9e0b21SXiaojian Du 							max, NULL);
864dd9e0b21SXiaojian Du 		if (ret)
865dd9e0b21SXiaojian Du 			return ret;
866dd9e0b21SXiaojian Du 		break;
867dd9e0b21SXiaojian Du 	case SMU_SOCCLK:
868dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
869dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinSocclkByFreq,
870dd9e0b21SXiaojian Du 							min, NULL);
871dd9e0b21SXiaojian Du 		if (ret)
872dd9e0b21SXiaojian Du 			return ret;
873dd9e0b21SXiaojian Du 
874dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
875dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxSocclkByFreq,
876dd9e0b21SXiaojian Du 							max, NULL);
877dd9e0b21SXiaojian Du 		if (ret)
878dd9e0b21SXiaojian Du 			return ret;
879dd9e0b21SXiaojian Du 		break;
880dd9e0b21SXiaojian Du 	case SMU_VCLK:
881dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
882dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinVcn,
883dd9e0b21SXiaojian Du 							min << 16, NULL);
884dd9e0b21SXiaojian Du 		if (ret)
885dd9e0b21SXiaojian Du 			return ret;
886dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
887dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxVcn,
888dd9e0b21SXiaojian Du 							max << 16, NULL);
889dd9e0b21SXiaojian Du 		if (ret)
890dd9e0b21SXiaojian Du 			return ret;
891dd9e0b21SXiaojian Du 		break;
892dd9e0b21SXiaojian Du 	case SMU_DCLK:
893dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
894dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinVcn,
895dd9e0b21SXiaojian Du 							min, NULL);
896dd9e0b21SXiaojian Du 		if (ret)
897dd9e0b21SXiaojian Du 			return ret;
898dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
899dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxVcn,
900dd9e0b21SXiaojian Du 							max, NULL);
901dd9e0b21SXiaojian Du 		if (ret)
902dd9e0b21SXiaojian Du 			return ret;
903dd9e0b21SXiaojian Du 		break;
904dd9e0b21SXiaojian Du 	default:
905dd9e0b21SXiaojian Du 		return -EINVAL;
906dd9e0b21SXiaojian Du 	}
907dd9e0b21SXiaojian Du 
908dd9e0b21SXiaojian Du 	return ret;
909dd9e0b21SXiaojian Du }
910dd9e0b21SXiaojian Du 
911dd9e0b21SXiaojian Du static int vangogh_force_clk_levels(struct smu_context *smu,
912dd9e0b21SXiaojian Du 				   enum smu_clk_type clk_type, uint32_t mask)
913dd9e0b21SXiaojian Du {
914dd9e0b21SXiaojian Du 	uint32_t soft_min_level = 0, soft_max_level = 0;
915dd9e0b21SXiaojian Du 	uint32_t min_freq = 0, max_freq = 0;
916dd9e0b21SXiaojian Du 	int ret = 0 ;
917dd9e0b21SXiaojian Du 
918dd9e0b21SXiaojian Du 	soft_min_level = mask ? (ffs(mask) - 1) : 0;
919dd9e0b21SXiaojian Du 	soft_max_level = mask ? (fls(mask) - 1) : 0;
920dd9e0b21SXiaojian Du 
921dd9e0b21SXiaojian Du 	switch (clk_type) {
922dd9e0b21SXiaojian Du 	case SMU_SOCCLK:
923dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu, clk_type,
924dd9e0b21SXiaojian Du 						soft_min_level, &min_freq);
925dd9e0b21SXiaojian Du 		if (ret)
926dd9e0b21SXiaojian Du 			return ret;
927dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu, clk_type,
928dd9e0b21SXiaojian Du 						soft_max_level, &max_freq);
929dd9e0b21SXiaojian Du 		if (ret)
930dd9e0b21SXiaojian Du 			return ret;
931dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
932dd9e0b21SXiaojian Du 								SMU_MSG_SetSoftMaxSocclkByFreq,
933dd9e0b21SXiaojian Du 								max_freq, NULL);
934dd9e0b21SXiaojian Du 		if (ret)
935dd9e0b21SXiaojian Du 			return ret;
936dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
937dd9e0b21SXiaojian Du 								SMU_MSG_SetHardMinSocclkByFreq,
938dd9e0b21SXiaojian Du 								min_freq, NULL);
939dd9e0b21SXiaojian Du 		if (ret)
940dd9e0b21SXiaojian Du 			return ret;
941dd9e0b21SXiaojian Du 		break;
942dd9e0b21SXiaojian Du 	case SMU_MCLK:
943dd9e0b21SXiaojian Du 	case SMU_FCLK:
944dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
945dd9e0b21SXiaojian Du 							clk_type, soft_min_level, &min_freq);
946dd9e0b21SXiaojian Du 		if (ret)
947dd9e0b21SXiaojian Du 			return ret;
948dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
949dd9e0b21SXiaojian Du 							clk_type, soft_max_level, &max_freq);
950dd9e0b21SXiaojian Du 		if (ret)
951dd9e0b21SXiaojian Du 			return ret;
952dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
953dd9e0b21SXiaojian Du 								SMU_MSG_SetSoftMaxFclkByFreq,
954dd9e0b21SXiaojian Du 								max_freq, NULL);
955dd9e0b21SXiaojian Du 		if (ret)
956dd9e0b21SXiaojian Du 			return ret;
957dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
958dd9e0b21SXiaojian Du 								SMU_MSG_SetHardMinFclkByFreq,
959dd9e0b21SXiaojian Du 								min_freq, NULL);
960dd9e0b21SXiaojian Du 		if (ret)
961dd9e0b21SXiaojian Du 			return ret;
962dd9e0b21SXiaojian Du 		break;
963dd9e0b21SXiaojian Du 	case SMU_VCLK:
964dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
965dd9e0b21SXiaojian Du 							clk_type, soft_min_level, &min_freq);
966dd9e0b21SXiaojian Du 		if (ret)
967dd9e0b21SXiaojian Du 			return ret;
968307f049bSXiaojian Du 
969dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
970dd9e0b21SXiaojian Du 							clk_type, soft_max_level, &max_freq);
971dd9e0b21SXiaojian Du 		if (ret)
972dd9e0b21SXiaojian Du 			return ret;
973307f049bSXiaojian Du 
974307f049bSXiaojian Du 
975dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
976dd9e0b21SXiaojian Du 								SMU_MSG_SetHardMinVcn,
977dd9e0b21SXiaojian Du 								min_freq << 16, NULL);
978dd9e0b21SXiaojian Du 		if (ret)
979dd9e0b21SXiaojian Du 			return ret;
980307f049bSXiaojian Du 
981307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
982307f049bSXiaojian Du 								SMU_MSG_SetSoftMaxVcn,
983307f049bSXiaojian Du 								max_freq << 16, NULL);
984307f049bSXiaojian Du 		if (ret)
985307f049bSXiaojian Du 			return ret;
986307f049bSXiaojian Du 
987dd9e0b21SXiaojian Du 		break;
988dd9e0b21SXiaojian Du 	case SMU_DCLK:
989dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
990dd9e0b21SXiaojian Du 							clk_type, soft_min_level, &min_freq);
991dd9e0b21SXiaojian Du 		if (ret)
992dd9e0b21SXiaojian Du 			return ret;
993307f049bSXiaojian Du 
994dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
995dd9e0b21SXiaojian Du 							clk_type, soft_max_level, &max_freq);
996dd9e0b21SXiaojian Du 		if (ret)
997dd9e0b21SXiaojian Du 			return ret;
998307f049bSXiaojian Du 
999dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
1000dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinVcn,
1001dd9e0b21SXiaojian Du 							min_freq, NULL);
1002dd9e0b21SXiaojian Du 		if (ret)
1003dd9e0b21SXiaojian Du 			return ret;
1004307f049bSXiaojian Du 
1005307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
1006307f049bSXiaojian Du 							SMU_MSG_SetSoftMaxVcn,
1007307f049bSXiaojian Du 							max_freq, NULL);
1008307f049bSXiaojian Du 		if (ret)
1009307f049bSXiaojian Du 			return ret;
1010307f049bSXiaojian Du 
1011dd9e0b21SXiaojian Du 		break;
1012dd9e0b21SXiaojian Du 	default:
1013dd9e0b21SXiaojian Du 		break;
1014dd9e0b21SXiaojian Du 	}
1015dd9e0b21SXiaojian Du 
1016dd9e0b21SXiaojian Du 	return ret;
1017dd9e0b21SXiaojian Du }
1018dd9e0b21SXiaojian Du 
1019dd9e0b21SXiaojian Du static int vangogh_force_dpm_limit_value(struct smu_context *smu, bool highest)
1020dd9e0b21SXiaojian Du {
1021dd9e0b21SXiaojian Du 	int ret = 0, i = 0;
1022dd9e0b21SXiaojian Du 	uint32_t min_freq, max_freq, force_freq;
1023dd9e0b21SXiaojian Du 	enum smu_clk_type clk_type;
1024dd9e0b21SXiaojian Du 
1025dd9e0b21SXiaojian Du 	enum smu_clk_type clks[] = {
1026dd9e0b21SXiaojian Du 		SMU_SOCCLK,
1027dd9e0b21SXiaojian Du 		SMU_VCLK,
1028dd9e0b21SXiaojian Du 		SMU_DCLK,
1029dd9e0b21SXiaojian Du 		SMU_MCLK,
1030dd9e0b21SXiaojian Du 		SMU_FCLK,
1031dd9e0b21SXiaojian Du 	};
1032dd9e0b21SXiaojian Du 
1033dd9e0b21SXiaojian Du 	for (i = 0; i < ARRAY_SIZE(clks); i++) {
1034dd9e0b21SXiaojian Du 		clk_type = clks[i];
1035dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_ultimate_freq(smu, clk_type, &min_freq, &max_freq);
1036dd9e0b21SXiaojian Du 		if (ret)
1037dd9e0b21SXiaojian Du 			return ret;
1038dd9e0b21SXiaojian Du 
1039dd9e0b21SXiaojian Du 		force_freq = highest ? max_freq : min_freq;
1040dd9e0b21SXiaojian Du 		ret = vangogh_set_soft_freq_limited_range(smu, clk_type, force_freq, force_freq);
1041dd9e0b21SXiaojian Du 		if (ret)
1042dd9e0b21SXiaojian Du 			return ret;
1043dd9e0b21SXiaojian Du 	}
1044dd9e0b21SXiaojian Du 
1045dd9e0b21SXiaojian Du 	return ret;
1046dd9e0b21SXiaojian Du }
1047dd9e0b21SXiaojian Du 
1048dd9e0b21SXiaojian Du static int vangogh_unforce_dpm_levels(struct smu_context *smu)
1049dd9e0b21SXiaojian Du {
1050dd9e0b21SXiaojian Du 	int ret = 0, i = 0;
1051dd9e0b21SXiaojian Du 	uint32_t min_freq, max_freq;
1052dd9e0b21SXiaojian Du 	enum smu_clk_type clk_type;
1053dd9e0b21SXiaojian Du 
1054dd9e0b21SXiaojian Du 	struct clk_feature_map {
1055dd9e0b21SXiaojian Du 		enum smu_clk_type clk_type;
1056dd9e0b21SXiaojian Du 		uint32_t	feature;
1057dd9e0b21SXiaojian Du 	} clk_feature_map[] = {
1058dd9e0b21SXiaojian Du 		{SMU_MCLK,   SMU_FEATURE_DPM_FCLK_BIT},
1059dd9e0b21SXiaojian Du 		{SMU_FCLK, SMU_FEATURE_DPM_FCLK_BIT},
1060dd9e0b21SXiaojian Du 		{SMU_SOCCLK, SMU_FEATURE_DPM_SOCCLK_BIT},
1061b0eec124SXiaojian Du 		{SMU_VCLK, SMU_FEATURE_VCN_DPM_BIT},
1062b0eec124SXiaojian Du 		{SMU_DCLK, SMU_FEATURE_VCN_DPM_BIT},
1063dd9e0b21SXiaojian Du 	};
1064dd9e0b21SXiaojian Du 
1065dd9e0b21SXiaojian Du 	for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) {
1066dd9e0b21SXiaojian Du 
1067dd9e0b21SXiaojian Du 		if (!smu_cmn_feature_is_enabled(smu, clk_feature_map[i].feature))
1068dd9e0b21SXiaojian Du 		    continue;
1069dd9e0b21SXiaojian Du 
1070dd9e0b21SXiaojian Du 		clk_type = clk_feature_map[i].clk_type;
1071dd9e0b21SXiaojian Du 
1072dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_ultimate_freq(smu, clk_type, &min_freq, &max_freq);
1073dd9e0b21SXiaojian Du 
1074dd9e0b21SXiaojian Du 		if (ret)
1075dd9e0b21SXiaojian Du 			return ret;
1076dd9e0b21SXiaojian Du 
1077dd9e0b21SXiaojian Du 		ret = vangogh_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq);
1078dd9e0b21SXiaojian Du 
1079dd9e0b21SXiaojian Du 		if (ret)
1080dd9e0b21SXiaojian Du 			return ret;
1081dd9e0b21SXiaojian Du 	}
1082dd9e0b21SXiaojian Du 
1083dd9e0b21SXiaojian Du 	return ret;
1084dd9e0b21SXiaojian Du }
1085dd9e0b21SXiaojian Du 
1086dd9e0b21SXiaojian Du static int vangogh_set_peak_clock_by_device(struct smu_context *smu)
1087dd9e0b21SXiaojian Du {
1088dd9e0b21SXiaojian Du 	int ret = 0;
1089dd9e0b21SXiaojian Du 	uint32_t socclk_freq = 0, fclk_freq = 0;
1090307f049bSXiaojian Du 	uint32_t vclk_freq = 0, dclk_freq = 0;
1091dd9e0b21SXiaojian Du 
1092dd9e0b21SXiaojian Du 	ret = vangogh_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_freq);
1093dd9e0b21SXiaojian Du 	if (ret)
1094dd9e0b21SXiaojian Du 		return ret;
1095dd9e0b21SXiaojian Du 
1096dd9e0b21SXiaojian Du 	ret = vangogh_set_soft_freq_limited_range(smu, SMU_FCLK, fclk_freq, fclk_freq);
1097dd9e0b21SXiaojian Du 	if (ret)
1098dd9e0b21SXiaojian Du 		return ret;
1099dd9e0b21SXiaojian Du 
1100dd9e0b21SXiaojian Du 	ret = vangogh_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_freq);
1101dd9e0b21SXiaojian Du 	if (ret)
1102dd9e0b21SXiaojian Du 		return ret;
1103dd9e0b21SXiaojian Du 
1104dd9e0b21SXiaojian Du 	ret = vangogh_set_soft_freq_limited_range(smu, SMU_SOCCLK, socclk_freq, socclk_freq);
1105dd9e0b21SXiaojian Du 	if (ret)
1106dd9e0b21SXiaojian Du 		return ret;
1107dd9e0b21SXiaojian Du 
1108307f049bSXiaojian Du 	ret = vangogh_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &vclk_freq);
1109307f049bSXiaojian Du 	if (ret)
1110307f049bSXiaojian Du 		return ret;
1111307f049bSXiaojian Du 
1112307f049bSXiaojian Du 	ret = vangogh_set_soft_freq_limited_range(smu, SMU_VCLK, vclk_freq, vclk_freq);
1113307f049bSXiaojian Du 	if (ret)
1114307f049bSXiaojian Du 		return ret;
1115307f049bSXiaojian Du 
1116307f049bSXiaojian Du 	ret = vangogh_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &dclk_freq);
1117307f049bSXiaojian Du 	if (ret)
1118307f049bSXiaojian Du 		return ret;
1119307f049bSXiaojian Du 
1120307f049bSXiaojian Du 	ret = vangogh_set_soft_freq_limited_range(smu, SMU_DCLK, dclk_freq, dclk_freq);
1121307f049bSXiaojian Du 	if (ret)
1122307f049bSXiaojian Du 		return ret;
1123307f049bSXiaojian Du 
1124dd9e0b21SXiaojian Du 	return ret;
1125dd9e0b21SXiaojian Du }
1126dd9e0b21SXiaojian Du 
1127ea173d15SXiaojian Du static int vangogh_set_performance_level(struct smu_context *smu,
1128ea173d15SXiaojian Du 					enum amd_dpm_forced_level level)
1129ea173d15SXiaojian Du {
1130ea173d15SXiaojian Du 	int ret = 0;
1131ea173d15SXiaojian Du 	uint32_t soc_mask, mclk_mask, fclk_mask;
1132307f049bSXiaojian Du 	uint32_t vclk_mask = 0, dclk_mask = 0;
1133ea173d15SXiaojian Du 
1134ea173d15SXiaojian Du 	switch (level) {
1135ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_HIGH:
1136d7379efaSXiaojian Du 		smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
1137d7379efaSXiaojian Du 		smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
1138d7379efaSXiaojian Du 
1139d7379efaSXiaojian Du 		smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
1140d7379efaSXiaojian Du 		smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
1141d7379efaSXiaojian Du 
1142ea173d15SXiaojian Du 		ret = vangogh_force_dpm_limit_value(smu, true);
1143ea173d15SXiaojian Du 		break;
1144ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_LOW:
1145d7379efaSXiaojian Du 		smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
1146d7379efaSXiaojian Du 		smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
1147d7379efaSXiaojian Du 
1148d7379efaSXiaojian Du 		smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
1149d7379efaSXiaojian Du 		smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
1150d7379efaSXiaojian Du 
1151ea173d15SXiaojian Du 		ret = vangogh_force_dpm_limit_value(smu, false);
1152ea173d15SXiaojian Du 		break;
1153ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_AUTO:
1154d7379efaSXiaojian Du 		smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
1155d7379efaSXiaojian Du 		smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
1156d7379efaSXiaojian Du 
1157d7379efaSXiaojian Du 		smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
1158d7379efaSXiaojian Du 		smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
1159d7379efaSXiaojian Du 
1160ea173d15SXiaojian Du 		ret = vangogh_unforce_dpm_levels(smu);
1161ea173d15SXiaojian Du 		break;
1162ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
1163d7379efaSXiaojian Du 		smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
1164d7379efaSXiaojian Du 		smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
1165d7379efaSXiaojian Du 
1166d7379efaSXiaojian Du 		smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
1167d7379efaSXiaojian Du 		smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
1168d7379efaSXiaojian Du 
1169307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
1170307f049bSXiaojian Du 					SMU_MSG_SetHardMinGfxClk,
1171307f049bSXiaojian Du 					VANGOGH_UMD_PSTATE_STANDARD_GFXCLK, NULL);
1172307f049bSXiaojian Du 		if (ret)
1173307f049bSXiaojian Du 			return ret;
1174307f049bSXiaojian Du 
1175307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
1176307f049bSXiaojian Du 					SMU_MSG_SetSoftMaxGfxClk,
1177307f049bSXiaojian Du 					VANGOGH_UMD_PSTATE_STANDARD_GFXCLK, NULL);
1178307f049bSXiaojian Du 		if (ret)
1179307f049bSXiaojian Du 			return ret;
1180307f049bSXiaojian Du 
1181307f049bSXiaojian Du 		ret = vangogh_get_profiling_clk_mask(smu, level,
1182307f049bSXiaojian Du 							&vclk_mask,
1183307f049bSXiaojian Du 							&dclk_mask,
1184307f049bSXiaojian Du 							&mclk_mask,
1185307f049bSXiaojian Du 							&fclk_mask,
1186307f049bSXiaojian Du 							&soc_mask);
1187307f049bSXiaojian Du 		if (ret)
1188307f049bSXiaojian Du 			return ret;
1189307f049bSXiaojian Du 
1190307f049bSXiaojian Du 		vangogh_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask);
1191307f049bSXiaojian Du 		vangogh_force_clk_levels(smu, SMU_FCLK, 1 << fclk_mask);
1192307f049bSXiaojian Du 		vangogh_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask);
1193307f049bSXiaojian Du 		vangogh_force_clk_levels(smu, SMU_VCLK, 1 << vclk_mask);
1194307f049bSXiaojian Du 		vangogh_force_clk_levels(smu, SMU_DCLK, 1 << dclk_mask);
1195307f049bSXiaojian Du 
1196ea173d15SXiaojian Du 		break;
1197ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
1198d7379efaSXiaojian Du 		smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
1199d7379efaSXiaojian Du 		smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
1200d7379efaSXiaojian Du 
1201d7379efaSXiaojian Du 		smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
1202d7379efaSXiaojian Du 		smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
1203d7379efaSXiaojian Du 
1204307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinVcn,
1205307f049bSXiaojian Du 								VANGOGH_UMD_PSTATE_PEAK_DCLK, NULL);
1206307f049bSXiaojian Du 		if (ret)
1207307f049bSXiaojian Du 			return ret;
1208307f049bSXiaojian Du 
1209307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxVcn,
1210307f049bSXiaojian Du 								VANGOGH_UMD_PSTATE_PEAK_DCLK, NULL);
1211307f049bSXiaojian Du 		if (ret)
1212307f049bSXiaojian Du 			return ret;
1213ea173d15SXiaojian Du 		break;
1214ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
1215d7379efaSXiaojian Du 		smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
1216d7379efaSXiaojian Du 		smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
1217d7379efaSXiaojian Du 
1218d7379efaSXiaojian Du 		smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
1219d7379efaSXiaojian Du 		smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
1220d7379efaSXiaojian Du 
1221ea173d15SXiaojian Du 		ret = vangogh_get_profiling_clk_mask(smu, level,
1222ea173d15SXiaojian Du 							NULL,
1223ea173d15SXiaojian Du 							NULL,
1224ea173d15SXiaojian Du 							&mclk_mask,
1225ea173d15SXiaojian Du 							&fclk_mask,
1226307f049bSXiaojian Du 							NULL);
1227ea173d15SXiaojian Du 		if (ret)
1228ea173d15SXiaojian Du 			return ret;
1229307f049bSXiaojian Du 
1230ea173d15SXiaojian Du 		vangogh_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask);
1231ea173d15SXiaojian Du 		vangogh_force_clk_levels(smu, SMU_FCLK, 1 << fclk_mask);
1232ea173d15SXiaojian Du 		break;
1233ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
1234d7379efaSXiaojian Du 		smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
1235d7379efaSXiaojian Du 		smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
1236d7379efaSXiaojian Du 
1237d7379efaSXiaojian Du 		smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
1238d7379efaSXiaojian Du 		smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
1239d7379efaSXiaojian Du 
1240307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
1241307f049bSXiaojian Du 				VANGOGH_UMD_PSTATE_PEAK_GFXCLK, NULL);
1242307f049bSXiaojian Du 		if (ret)
1243307f049bSXiaojian Du 			return ret;
1244307f049bSXiaojian Du 
1245307f049bSXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
1246307f049bSXiaojian Du 				VANGOGH_UMD_PSTATE_PEAK_GFXCLK, NULL);
1247307f049bSXiaojian Du 		if (ret)
1248307f049bSXiaojian Du 			return ret;
1249307f049bSXiaojian Du 
1250ea173d15SXiaojian Du 		ret = vangogh_set_peak_clock_by_device(smu);
1251ea173d15SXiaojian Du 		break;
1252ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_MANUAL:
1253ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
1254ea173d15SXiaojian Du 	default:
1255ea173d15SXiaojian Du 		break;
1256ea173d15SXiaojian Du 	}
1257ea173d15SXiaojian Du 	return ret;
1258ea173d15SXiaojian Du }
1259ea173d15SXiaojian Du 
1260271ab489SXiaojian Du static int vangogh_read_sensor(struct smu_context *smu,
1261271ab489SXiaojian Du 				 enum amd_pp_sensors sensor,
1262271ab489SXiaojian Du 				 void *data, uint32_t *size)
1263271ab489SXiaojian Du {
1264271ab489SXiaojian Du 	int ret = 0;
1265271ab489SXiaojian Du 
1266271ab489SXiaojian Du 	if (!data || !size)
1267271ab489SXiaojian Du 		return -EINVAL;
1268271ab489SXiaojian Du 
1269271ab489SXiaojian Du 	mutex_lock(&smu->sensor_lock);
1270271ab489SXiaojian Du 	switch (sensor) {
1271271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_GPU_LOAD:
12726cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
12736cc24d8dSAlex Deucher 						   METRICS_AVERAGE_GFXACTIVITY,
12746cc24d8dSAlex Deucher 						   (uint32_t *)data);
1275271ab489SXiaojian Du 		*size = 4;
1276271ab489SXiaojian Du 		break;
1277271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_GPU_POWER:
12786cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
12796cc24d8dSAlex Deucher 						   METRICS_AVERAGE_SOCKETPOWER,
12806cc24d8dSAlex Deucher 						   (uint32_t *)data);
1281271ab489SXiaojian Du 		*size = 4;
1282271ab489SXiaojian Du 		break;
1283271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_EDGE_TEMP:
12846cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
12856cc24d8dSAlex Deucher 						   METRICS_TEMPERATURE_EDGE,
12866cc24d8dSAlex Deucher 						   (uint32_t *)data);
12876cc24d8dSAlex Deucher 		*size = 4;
12886cc24d8dSAlex Deucher 		break;
1289271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
12906cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
12916cc24d8dSAlex Deucher 						   METRICS_TEMPERATURE_HOTSPOT,
12926cc24d8dSAlex Deucher 						   (uint32_t *)data);
1293271ab489SXiaojian Du 		*size = 4;
1294271ab489SXiaojian Du 		break;
1295271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_GFX_MCLK:
12966cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
12976cc24d8dSAlex Deucher 						   METRICS_AVERAGE_UCLK,
12986cc24d8dSAlex Deucher 						   (uint32_t *)data);
1299271ab489SXiaojian Du 		*(uint32_t *)data *= 100;
1300271ab489SXiaojian Du 		*size = 4;
1301271ab489SXiaojian Du 		break;
1302271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_GFX_SCLK:
13036cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
13046cc24d8dSAlex Deucher 						   METRICS_AVERAGE_GFXCLK,
13056cc24d8dSAlex Deucher 						   (uint32_t *)data);
1306271ab489SXiaojian Du 		*(uint32_t *)data *= 100;
1307271ab489SXiaojian Du 		*size = 4;
1308271ab489SXiaojian Du 		break;
1309271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_VDDGFX:
13102139d12bSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
13112139d12bSAlex Deucher 						   METRICS_VOLTAGE_VDDGFX,
13122139d12bSAlex Deucher 						   (uint32_t *)data);
13132139d12bSAlex Deucher 		*size = 4;
13142139d12bSAlex Deucher 		break;
13152139d12bSAlex Deucher 	case AMDGPU_PP_SENSOR_VDDNB:
13162139d12bSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
13172139d12bSAlex Deucher 						   METRICS_VOLTAGE_VDDSOC,
13182139d12bSAlex Deucher 						   (uint32_t *)data);
1319271ab489SXiaojian Du 		*size = 4;
1320271ab489SXiaojian Du 		break;
1321517cb957SHuang Rui 	case AMDGPU_PP_SENSOR_CPU_CLK:
1322517cb957SHuang Rui 		ret = vangogh_get_smu_metrics_data(smu,
1323517cb957SHuang Rui 						   METRICS_AVERAGE_CPUCLK,
1324517cb957SHuang Rui 						   (uint32_t *)data);
13254aef0ebcSHuang Rui 		*size = smu->cpu_core_num * sizeof(uint16_t);
1326517cb957SHuang Rui 		break;
1327271ab489SXiaojian Du 	default:
1328271ab489SXiaojian Du 		ret = -EOPNOTSUPP;
1329271ab489SXiaojian Du 		break;
1330271ab489SXiaojian Du 	}
1331271ab489SXiaojian Du 	mutex_unlock(&smu->sensor_lock);
1332271ab489SXiaojian Du 
1333271ab489SXiaojian Du 	return ret;
1334271ab489SXiaojian Du }
1335271ab489SXiaojian Du 
1336271ab489SXiaojian Du static int vangogh_set_watermarks_table(struct smu_context *smu,
1337271ab489SXiaojian Du 				       struct pp_smu_wm_range_sets *clock_ranges)
1338271ab489SXiaojian Du {
1339271ab489SXiaojian Du 	int i;
1340271ab489SXiaojian Du 	int ret = 0;
1341271ab489SXiaojian Du 	Watermarks_t *table = smu->smu_table.watermarks_table;
1342271ab489SXiaojian Du 
1343271ab489SXiaojian Du 	if (!table || !clock_ranges)
1344271ab489SXiaojian Du 		return -EINVAL;
1345271ab489SXiaojian Du 
1346271ab489SXiaojian Du 	if (clock_ranges) {
1347271ab489SXiaojian Du 		if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES ||
1348271ab489SXiaojian Du 			clock_ranges->num_writer_wm_sets > NUM_WM_RANGES)
1349271ab489SXiaojian Du 			return -EINVAL;
1350271ab489SXiaojian Du 
1351271ab489SXiaojian Du 		for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) {
1352271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].MinClock =
1353271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].min_drain_clk_mhz;
1354271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].MaxClock =
1355271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].max_drain_clk_mhz;
1356271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].MinMclk =
1357271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].min_fill_clk_mhz;
1358271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].MaxMclk =
1359271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].max_fill_clk_mhz;
1360271ab489SXiaojian Du 
1361271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].WmSetting =
1362271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].wm_inst;
1363271ab489SXiaojian Du 		}
1364271ab489SXiaojian Du 
1365271ab489SXiaojian Du 		for (i = 0; i < clock_ranges->num_writer_wm_sets; i++) {
1366271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].MinClock =
1367271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].min_fill_clk_mhz;
1368271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].MaxClock =
1369271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].max_fill_clk_mhz;
1370271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].MinMclk =
1371271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].min_drain_clk_mhz;
1372271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].MaxMclk =
1373271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].max_drain_clk_mhz;
1374271ab489SXiaojian Du 
1375271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].WmSetting =
1376271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].wm_inst;
1377271ab489SXiaojian Du 		}
1378271ab489SXiaojian Du 
1379271ab489SXiaojian Du 		smu->watermarks_bitmap |= WATERMARKS_EXIST;
1380271ab489SXiaojian Du 	}
1381271ab489SXiaojian Du 
1382271ab489SXiaojian Du 	/* pass data to smu controller */
1383271ab489SXiaojian Du 	if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
1384271ab489SXiaojian Du 	     !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
1385271ab489SXiaojian Du 		ret = smu_cmn_write_watermarks_table(smu);
1386271ab489SXiaojian Du 		if (ret) {
1387271ab489SXiaojian Du 			dev_err(smu->adev->dev, "Failed to update WMTABLE!");
1388271ab489SXiaojian Du 			return ret;
1389271ab489SXiaojian Du 		}
1390271ab489SXiaojian Du 		smu->watermarks_bitmap |= WATERMARKS_LOADED;
1391271ab489SXiaojian Du 	}
1392271ab489SXiaojian Du 
1393271ab489SXiaojian Du 	return 0;
1394f46a221bSXiaojian Du }
1395f46a221bSXiaojian Du 
1396fd253334SXiaojian Du static ssize_t vangogh_get_gpu_metrics(struct smu_context *smu,
1397fd253334SXiaojian Du 				      void **table)
1398fd253334SXiaojian Du {
1399fd253334SXiaojian Du 	struct smu_table_context *smu_table = &smu->smu_table;
1400fd253334SXiaojian Du 	struct gpu_metrics_v2_0 *gpu_metrics =
1401fd253334SXiaojian Du 		(struct gpu_metrics_v2_0 *)smu_table->gpu_metrics_table;
1402fd253334SXiaojian Du 	SmuMetrics_t metrics;
1403fd253334SXiaojian Du 	int ret = 0;
1404fd253334SXiaojian Du 
1405fd253334SXiaojian Du 	ret = smu_cmn_get_metrics_table(smu, &metrics, true);
1406fd253334SXiaojian Du 	if (ret)
1407fd253334SXiaojian Du 		return ret;
1408fd253334SXiaojian Du 
1409fd253334SXiaojian Du 	smu_v11_0_init_gpu_metrics_v2_0(gpu_metrics);
1410fd253334SXiaojian Du 
1411fd253334SXiaojian Du 	gpu_metrics->temperature_gfx = metrics.GfxTemperature;
1412fd253334SXiaojian Du 	gpu_metrics->temperature_soc = metrics.SocTemperature;
1413fd253334SXiaojian Du 	memcpy(&gpu_metrics->temperature_core[0],
1414fd253334SXiaojian Du 		&metrics.CoreTemperature[0],
1415fd253334SXiaojian Du 		sizeof(uint16_t) * 8);
1416fd253334SXiaojian Du 	gpu_metrics->temperature_l3[0] = metrics.L3Temperature[0];
1417fd253334SXiaojian Du 	gpu_metrics->temperature_l3[1] = metrics.L3Temperature[1];
1418fd253334SXiaojian Du 
1419fd253334SXiaojian Du 	gpu_metrics->average_gfx_activity = metrics.GfxActivity;
1420fd253334SXiaojian Du 	gpu_metrics->average_mm_activity = metrics.UvdActivity;
1421fd253334SXiaojian Du 
1422fd253334SXiaojian Du 	gpu_metrics->average_socket_power = metrics.CurrentSocketPower;
1423fd253334SXiaojian Du 	gpu_metrics->average_cpu_power = metrics.Power[0];
1424fd253334SXiaojian Du 	gpu_metrics->average_soc_power = metrics.Power[1];
1425c9021a6eSXiaojian Du 	gpu_metrics->average_gfx_power = metrics.Power[2];
1426fd253334SXiaojian Du 	memcpy(&gpu_metrics->average_core_power[0],
1427fd253334SXiaojian Du 		&metrics.CorePower[0],
1428fd253334SXiaojian Du 		sizeof(uint16_t) * 8);
1429fd253334SXiaojian Du 
1430fd253334SXiaojian Du 	gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency;
1431fd253334SXiaojian Du 	gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency;
1432c9021a6eSXiaojian Du 	gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency;
1433fd253334SXiaojian Du 	gpu_metrics->average_fclk_frequency = metrics.MemclkFrequency;
1434fd253334SXiaojian Du 	gpu_metrics->average_vclk_frequency = metrics.VclkFrequency;
1435c9021a6eSXiaojian Du 	gpu_metrics->average_dclk_frequency = metrics.DclkFrequency;
1436fd253334SXiaojian Du 
1437fd253334SXiaojian Du 	memcpy(&gpu_metrics->current_coreclk[0],
1438fd253334SXiaojian Du 		&metrics.CoreFrequency[0],
1439fd253334SXiaojian Du 		sizeof(uint16_t) * 8);
1440fd253334SXiaojian Du 	gpu_metrics->current_l3clk[0] = metrics.L3Frequency[0];
1441fd253334SXiaojian Du 	gpu_metrics->current_l3clk[1] = metrics.L3Frequency[1];
1442fd253334SXiaojian Du 
1443fd253334SXiaojian Du 	gpu_metrics->throttle_status = metrics.ThrottlerStatus;
1444fd253334SXiaojian Du 
1445fd253334SXiaojian Du 	*table = (void *)gpu_metrics;
1446fd253334SXiaojian Du 
1447fd253334SXiaojian Du 	return sizeof(struct gpu_metrics_v2_0);
1448fd253334SXiaojian Du }
1449fd253334SXiaojian Du 
1450c98ee897SXiaojian Du static int vangogh_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type,
1451c98ee897SXiaojian Du 					long input[], uint32_t size)
1452c98ee897SXiaojian Du {
1453c98ee897SXiaojian Du 	int ret = 0;
14540d90d0ddSHuang Rui 	int i;
1455d7379efaSXiaojian Du 	struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
1456c98ee897SXiaojian Du 
1457d7379efaSXiaojian Du 	if (!(smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL)) {
1458c98ee897SXiaojian Du 		dev_warn(smu->adev->dev, "Fine grain is not enabled!\n");
1459c98ee897SXiaojian Du 		return -EINVAL;
1460c98ee897SXiaojian Du 	}
1461c98ee897SXiaojian Du 
1462c98ee897SXiaojian Du 	switch (type) {
14630d90d0ddSHuang Rui 	case PP_OD_EDIT_CCLK_VDDC_TABLE:
14640d90d0ddSHuang Rui 		if (size != 3) {
14650d90d0ddSHuang Rui 			dev_err(smu->adev->dev, "Input parameter number not correct (should be 4 for processor)\n");
14660d90d0ddSHuang Rui 			return -EINVAL;
14670d90d0ddSHuang Rui 		}
14684aef0ebcSHuang Rui 		if (input[0] >= smu->cpu_core_num) {
14690d90d0ddSHuang Rui 			dev_err(smu->adev->dev, "core index is overflow, should be less than %d\n",
14704aef0ebcSHuang Rui 				smu->cpu_core_num);
14710d90d0ddSHuang Rui 		}
14720d90d0ddSHuang Rui 		smu->cpu_core_id_select = input[0];
14730d90d0ddSHuang Rui 		if (input[1] == 0) {
14740d90d0ddSHuang Rui 			if (input[2] < smu->cpu_default_soft_min_freq) {
14750d90d0ddSHuang Rui 				dev_warn(smu->adev->dev, "Fine grain setting minimum cclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
14760d90d0ddSHuang Rui 					input[2], smu->cpu_default_soft_min_freq);
14770d90d0ddSHuang Rui 				return -EINVAL;
14780d90d0ddSHuang Rui 			}
14790d90d0ddSHuang Rui 			smu->cpu_actual_soft_min_freq = input[2];
14800d90d0ddSHuang Rui 		} else if (input[1] == 1) {
14810d90d0ddSHuang Rui 			if (input[2] > smu->cpu_default_soft_max_freq) {
14820d90d0ddSHuang Rui 				dev_warn(smu->adev->dev, "Fine grain setting maximum cclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
14830d90d0ddSHuang Rui 					input[2], smu->cpu_default_soft_max_freq);
14840d90d0ddSHuang Rui 				return -EINVAL;
14850d90d0ddSHuang Rui 			}
14860d90d0ddSHuang Rui 			smu->cpu_actual_soft_max_freq = input[2];
14870d90d0ddSHuang Rui 		} else {
14880d90d0ddSHuang Rui 			return -EINVAL;
14890d90d0ddSHuang Rui 		}
14900d90d0ddSHuang Rui 		break;
1491c98ee897SXiaojian Du 	case PP_OD_EDIT_SCLK_VDDC_TABLE:
1492c98ee897SXiaojian Du 		if (size != 2) {
1493c98ee897SXiaojian Du 			dev_err(smu->adev->dev, "Input parameter number not correct\n");
1494c98ee897SXiaojian Du 			return -EINVAL;
1495c98ee897SXiaojian Du 		}
1496c98ee897SXiaojian Du 
1497c98ee897SXiaojian Du 		if (input[0] == 0) {
1498c98ee897SXiaojian Du 			if (input[1] < smu->gfx_default_hard_min_freq) {
1499307f049bSXiaojian Du 				dev_warn(smu->adev->dev,
1500307f049bSXiaojian Du 					"Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
1501c98ee897SXiaojian Du 					input[1], smu->gfx_default_hard_min_freq);
1502c98ee897SXiaojian Du 				return -EINVAL;
1503c98ee897SXiaojian Du 			}
1504c98ee897SXiaojian Du 			smu->gfx_actual_hard_min_freq = input[1];
1505c98ee897SXiaojian Du 		} else if (input[0] == 1) {
1506c98ee897SXiaojian Du 			if (input[1] > smu->gfx_default_soft_max_freq) {
1507307f049bSXiaojian Du 				dev_warn(smu->adev->dev,
1508307f049bSXiaojian Du 					"Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
1509c98ee897SXiaojian Du 					input[1], smu->gfx_default_soft_max_freq);
1510c98ee897SXiaojian Du 				return -EINVAL;
1511c98ee897SXiaojian Du 			}
1512c98ee897SXiaojian Du 			smu->gfx_actual_soft_max_freq = input[1];
1513c98ee897SXiaojian Du 		} else {
1514c98ee897SXiaojian Du 			return -EINVAL;
1515c98ee897SXiaojian Du 		}
1516c98ee897SXiaojian Du 		break;
1517c98ee897SXiaojian Du 	case PP_OD_RESTORE_DEFAULT_TABLE:
1518c98ee897SXiaojian Du 		if (size != 0) {
1519c98ee897SXiaojian Du 			dev_err(smu->adev->dev, "Input parameter number not correct\n");
1520c98ee897SXiaojian Du 			return -EINVAL;
1521c98ee897SXiaojian Du 		} else {
1522c98ee897SXiaojian Du 			smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
1523c98ee897SXiaojian Du 			smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
15240d90d0ddSHuang Rui 			smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
15250d90d0ddSHuang Rui 			smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
1526c98ee897SXiaojian Du 
1527c98ee897SXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
1528c98ee897SXiaojian Du 									smu->gfx_actual_hard_min_freq, NULL);
1529c98ee897SXiaojian Du 			if (ret) {
1530c98ee897SXiaojian Du 				dev_err(smu->adev->dev, "Restore the default hard min sclk failed!");
1531c98ee897SXiaojian Du 				return ret;
1532c98ee897SXiaojian Du 			}
1533c98ee897SXiaojian Du 
1534c98ee897SXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
1535c98ee897SXiaojian Du 									smu->gfx_actual_soft_max_freq, NULL);
1536c98ee897SXiaojian Du 			if (ret) {
1537c98ee897SXiaojian Du 				dev_err(smu->adev->dev, "Restore the default soft max sclk failed!");
1538c98ee897SXiaojian Du 				return ret;
1539c98ee897SXiaojian Du 			}
15400d90d0ddSHuang Rui 
15410d90d0ddSHuang Rui 			if (smu->adev->pm.fw_version < 0x43f1b00) {
15420d90d0ddSHuang Rui 				dev_warn(smu->adev->dev, "CPUSoftMax/CPUSoftMin are not supported, please update SBIOS!\n");
15430d90d0ddSHuang Rui 				break;
15440d90d0ddSHuang Rui 			}
15450d90d0ddSHuang Rui 
15464aef0ebcSHuang Rui 			for (i = 0; i < smu->cpu_core_num; i++) {
15470d90d0ddSHuang Rui 				ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinCclk,
15480d90d0ddSHuang Rui 								      (i << 20) | smu->cpu_actual_soft_min_freq,
15490d90d0ddSHuang Rui 								      NULL);
15500d90d0ddSHuang Rui 				if (ret) {
15510d90d0ddSHuang Rui 					dev_err(smu->adev->dev, "Set hard min cclk failed!");
15520d90d0ddSHuang Rui 					return ret;
15530d90d0ddSHuang Rui 				}
15540d90d0ddSHuang Rui 
15550d90d0ddSHuang Rui 				ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxCclk,
15560d90d0ddSHuang Rui 								      (i << 20) | smu->cpu_actual_soft_max_freq,
15570d90d0ddSHuang Rui 								      NULL);
15580d90d0ddSHuang Rui 				if (ret) {
15590d90d0ddSHuang Rui 					dev_err(smu->adev->dev, "Set soft max cclk failed!");
15600d90d0ddSHuang Rui 					return ret;
15610d90d0ddSHuang Rui 				}
15620d90d0ddSHuang Rui 			}
1563c98ee897SXiaojian Du 		}
1564c98ee897SXiaojian Du 		break;
1565c98ee897SXiaojian Du 	case PP_OD_COMMIT_DPM_TABLE:
1566c98ee897SXiaojian Du 		if (size != 0) {
1567c98ee897SXiaojian Du 			dev_err(smu->adev->dev, "Input parameter number not correct\n");
1568c98ee897SXiaojian Du 			return -EINVAL;
1569c98ee897SXiaojian Du 		} else {
1570c98ee897SXiaojian Du 			if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) {
1571307f049bSXiaojian Du 				dev_err(smu->adev->dev,
1572307f049bSXiaojian Du 					"The setting minimun sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n",
1573307f049bSXiaojian Du 					smu->gfx_actual_hard_min_freq,
1574307f049bSXiaojian Du 					smu->gfx_actual_soft_max_freq);
1575c98ee897SXiaojian Du 				return -EINVAL;
1576c98ee897SXiaojian Du 			}
1577c98ee897SXiaojian Du 
1578c98ee897SXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
1579c98ee897SXiaojian Du 									smu->gfx_actual_hard_min_freq, NULL);
1580c98ee897SXiaojian Du 			if (ret) {
1581c98ee897SXiaojian Du 				dev_err(smu->adev->dev, "Set hard min sclk failed!");
1582c98ee897SXiaojian Du 				return ret;
1583c98ee897SXiaojian Du 			}
1584c98ee897SXiaojian Du 
1585c98ee897SXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
1586c98ee897SXiaojian Du 									smu->gfx_actual_soft_max_freq, NULL);
1587c98ee897SXiaojian Du 			if (ret) {
1588c98ee897SXiaojian Du 				dev_err(smu->adev->dev, "Set soft max sclk failed!");
1589c98ee897SXiaojian Du 				return ret;
1590c98ee897SXiaojian Du 			}
15910d90d0ddSHuang Rui 
15920d90d0ddSHuang Rui 			if (smu->adev->pm.fw_version < 0x43f1b00) {
15930d90d0ddSHuang Rui 				dev_warn(smu->adev->dev, "CPUSoftMax/CPUSoftMin are not supported, please update SBIOS!\n");
15940d90d0ddSHuang Rui 				break;
15950d90d0ddSHuang Rui 			}
15960d90d0ddSHuang Rui 
15970d90d0ddSHuang Rui 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinCclk,
15980d90d0ddSHuang Rui 							      ((smu->cpu_core_id_select << 20)
15990d90d0ddSHuang Rui 							       | smu->cpu_actual_soft_min_freq),
16000d90d0ddSHuang Rui 							      NULL);
16010d90d0ddSHuang Rui 			if (ret) {
16020d90d0ddSHuang Rui 				dev_err(smu->adev->dev, "Set hard min cclk failed!");
16030d90d0ddSHuang Rui 				return ret;
16040d90d0ddSHuang Rui 			}
16050d90d0ddSHuang Rui 
16060d90d0ddSHuang Rui 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxCclk,
16070d90d0ddSHuang Rui 							      ((smu->cpu_core_id_select << 20)
16080d90d0ddSHuang Rui 							       | smu->cpu_actual_soft_max_freq),
16090d90d0ddSHuang Rui 							      NULL);
16100d90d0ddSHuang Rui 			if (ret) {
16110d90d0ddSHuang Rui 				dev_err(smu->adev->dev, "Set soft max cclk failed!");
16120d90d0ddSHuang Rui 				return ret;
16130d90d0ddSHuang Rui 			}
1614c98ee897SXiaojian Du 		}
1615c98ee897SXiaojian Du 		break;
1616c98ee897SXiaojian Du 	default:
1617c98ee897SXiaojian Du 		return -ENOSYS;
1618c98ee897SXiaojian Du 	}
1619c98ee897SXiaojian Du 
1620c98ee897SXiaojian Du 	return ret;
1621c98ee897SXiaojian Du }
1622c98ee897SXiaojian Du 
1623fce8a4acSJinzhou Su static int vangogh_set_default_dpm_tables(struct smu_context *smu)
1624c98ee897SXiaojian Du {
1625c98ee897SXiaojian Du 	struct smu_table_context *smu_table = &smu->smu_table;
1626c98ee897SXiaojian Du 
1627c98ee897SXiaojian Du 	return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false);
1628c98ee897SXiaojian Du }
1629c98ee897SXiaojian Du 
1630c98ee897SXiaojian Du static int vangogh_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
1631c98ee897SXiaojian Du {
1632c98ee897SXiaojian Du 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
1633c98ee897SXiaojian Du 
1634c98ee897SXiaojian Du 	smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
1635c98ee897SXiaojian Du 	smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
1636c98ee897SXiaojian Du 	smu->gfx_actual_hard_min_freq = 0;
1637c98ee897SXiaojian Du 	smu->gfx_actual_soft_max_freq = 0;
1638c98ee897SXiaojian Du 
16390d90d0ddSHuang Rui 	smu->cpu_default_soft_min_freq = 1400;
16400d90d0ddSHuang Rui 	smu->cpu_default_soft_max_freq = 3500;
16410d90d0ddSHuang Rui 	smu->cpu_actual_soft_min_freq = 0;
16420d90d0ddSHuang Rui 	smu->cpu_actual_soft_max_freq = 0;
16430d90d0ddSHuang Rui 
1644c98ee897SXiaojian Du 	return 0;
1645c98ee897SXiaojian Du }
1646c98ee897SXiaojian Du 
1647ae7b32e7SXiaojian Du static int vangogh_get_dpm_clock_table(struct smu_context *smu, struct dpm_clocks *clock_table)
1648ae7b32e7SXiaojian Du {
1649ae7b32e7SXiaojian Du 	DpmClocks_t *table = smu->smu_table.clocks_table;
1650ae7b32e7SXiaojian Du 	int i;
1651ae7b32e7SXiaojian Du 
1652ae7b32e7SXiaojian Du 	if (!clock_table || !table)
1653ae7b32e7SXiaojian Du 		return -EINVAL;
1654ae7b32e7SXiaojian Du 
1655ae7b32e7SXiaojian Du 	for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) {
1656ae7b32e7SXiaojian Du 		clock_table->SocClocks[i].Freq = table->SocClocks[i];
1657ae7b32e7SXiaojian Du 		clock_table->SocClocks[i].Vol = table->SocVoltage[i];
1658ae7b32e7SXiaojian Du 	}
1659ae7b32e7SXiaojian Du 
1660ae7b32e7SXiaojian Du 	for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
1661ae7b32e7SXiaojian Du 		clock_table->FClocks[i].Freq = table->DfPstateTable[i].fclk;
1662ae7b32e7SXiaojian Du 		clock_table->FClocks[i].Vol = table->DfPstateTable[i].voltage;
1663ae7b32e7SXiaojian Du 	}
1664ae7b32e7SXiaojian Du 
1665ae7b32e7SXiaojian Du 	for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
1666ae7b32e7SXiaojian Du 		clock_table->MemClocks[i].Freq = table->DfPstateTable[i].memclk;
1667ae7b32e7SXiaojian Du 		clock_table->MemClocks[i].Vol = table->DfPstateTable[i].voltage;
1668ae7b32e7SXiaojian Du 	}
1669ae7b32e7SXiaojian Du 
1670ae7b32e7SXiaojian Du 	return 0;
1671ae7b32e7SXiaojian Du }
1672ae7b32e7SXiaojian Du 
1673ae7b32e7SXiaojian Du 
1674a0f55287SXiaomeng Hou static int vangogh_system_features_control(struct smu_context *smu, bool en)
1675a0f55287SXiaomeng Hou {
16769e3a6ab7SXiaomeng Hou 	struct amdgpu_device *adev = smu->adev;
1677aedebd40SHuang Rui 	struct smu_feature *feature = &smu->smu_feature;
1678aedebd40SHuang Rui 	uint32_t feature_mask[2];
1679aedebd40SHuang Rui 	int ret = 0;
16809e3a6ab7SXiaomeng Hou 
16819e3a6ab7SXiaomeng Hou 	if (adev->pm.fw_version >= 0x43f1700)
1682aedebd40SHuang Rui 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_RlcPowerNotify,
1683a0f55287SXiaomeng Hou 						      en ? RLC_STATUS_NORMAL : RLC_STATUS_OFF, NULL);
1684aedebd40SHuang Rui 
1685aedebd40SHuang Rui 	bitmap_zero(feature->enabled, feature->feature_num);
1686aedebd40SHuang Rui 	bitmap_zero(feature->supported, feature->feature_num);
1687aedebd40SHuang Rui 
1688aedebd40SHuang Rui 	if (!en)
1689aedebd40SHuang Rui 		return ret;
1690aedebd40SHuang Rui 
1691aedebd40SHuang Rui 	ret = smu_cmn_get_enabled_32_bits_mask(smu, feature_mask, 2);
1692aedebd40SHuang Rui 	if (ret)
1693aedebd40SHuang Rui 		return ret;
1694aedebd40SHuang Rui 
1695aedebd40SHuang Rui 	bitmap_copy(feature->enabled, (unsigned long *)&feature_mask,
1696aedebd40SHuang Rui 		    feature->feature_num);
1697aedebd40SHuang Rui 	bitmap_copy(feature->supported, (unsigned long *)&feature_mask,
1698aedebd40SHuang Rui 		    feature->feature_num);
1699aedebd40SHuang Rui 
17009e3a6ab7SXiaomeng Hou 	return 0;
1701a0f55287SXiaomeng Hou }
1702a0f55287SXiaomeng Hou 
1703eefdf047SJinzhou Su static int vangogh_post_smu_init(struct smu_context *smu)
1704eefdf047SJinzhou Su {
1705eefdf047SJinzhou Su 	struct amdgpu_device *adev = smu->adev;
1706eefdf047SJinzhou Su 	uint32_t tmp;
17073313ef18SJinzhou Su 	int ret = 0;
1708eefdf047SJinzhou Su 	uint8_t aon_bits = 0;
1709eefdf047SJinzhou Su 	/* Two CUs in one WGP */
1710eefdf047SJinzhou Su 	uint32_t req_active_wgps = adev->gfx.cu_info.number/2;
1711eefdf047SJinzhou Su 	uint32_t total_cu = adev->gfx.config.max_cu_per_sh *
1712eefdf047SJinzhou Su 		adev->gfx.config.max_sh_per_se * adev->gfx.config.max_shader_engines;
1713eefdf047SJinzhou Su 
17143313ef18SJinzhou Su 	/* allow message will be sent after enable message on Vangogh*/
1715*bb377febSJinzhou Su 	if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_GFXCLK_BIT) &&
1716*bb377febSJinzhou Su 			(adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)) {
17173313ef18SJinzhou Su 		ret = smu_cmn_send_smc_msg(smu, SMU_MSG_EnableGfxOff, NULL);
17183313ef18SJinzhou Su 		if (ret) {
17193313ef18SJinzhou Su 			dev_err(adev->dev, "Failed to Enable GfxOff!\n");
17203313ef18SJinzhou Su 			return ret;
17213313ef18SJinzhou Su 		}
1722*bb377febSJinzhou Su 	} else {
1723*bb377febSJinzhou Su 		adev->pm.pp_feature &= ~PP_GFXOFF_MASK;
1724*bb377febSJinzhou Su 		dev_info(adev->dev, "If GFX DPM or power gate disabled, disable GFXOFF\n");
1725*bb377febSJinzhou Su 	}
17263313ef18SJinzhou Su 
1727eefdf047SJinzhou Su 	/* if all CUs are active, no need to power off any WGPs */
1728eefdf047SJinzhou Su 	if (total_cu == adev->gfx.cu_info.number)
1729eefdf047SJinzhou Su 		return 0;
1730eefdf047SJinzhou Su 
1731eefdf047SJinzhou Su 	/*
1732eefdf047SJinzhou Su 	 * Calculate the total bits number of always on WGPs for all SA/SEs in
1733eefdf047SJinzhou Su 	 * RLC_PG_ALWAYS_ON_WGP_MASK.
1734eefdf047SJinzhou Su 	 */
1735eefdf047SJinzhou Su 	tmp = RREG32_KIQ(SOC15_REG_OFFSET(GC, 0, mmRLC_PG_ALWAYS_ON_WGP_MASK));
1736eefdf047SJinzhou Su 	tmp &= RLC_PG_ALWAYS_ON_WGP_MASK__AON_WGP_MASK_MASK;
1737eefdf047SJinzhou Su 
1738eefdf047SJinzhou Su 	aon_bits = hweight32(tmp) * adev->gfx.config.max_sh_per_se * adev->gfx.config.max_shader_engines;
1739eefdf047SJinzhou Su 
1740eefdf047SJinzhou Su 	/* Do not request any WGPs less than set in the AON_WGP_MASK */
1741eefdf047SJinzhou Su 	if (aon_bits > req_active_wgps) {
1742eefdf047SJinzhou Su 		dev_info(adev->dev, "Number of always on WGPs greater than active WGPs: WGP power save not requested.\n");
1743eefdf047SJinzhou Su 		return 0;
1744eefdf047SJinzhou Su 	} else {
1745eefdf047SJinzhou Su 		return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_RequestActiveWgp, req_active_wgps, NULL);
1746eefdf047SJinzhou Su 	}
1747eefdf047SJinzhou Su }
1748eefdf047SJinzhou Su 
174974353883SHuang Rui static int vangogh_mode_reset(struct smu_context *smu, int type)
175074353883SHuang Rui {
175174353883SHuang Rui 	int ret = 0, index = 0;
175274353883SHuang Rui 
175374353883SHuang Rui 	index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG,
175474353883SHuang Rui 					       SMU_MSG_GfxDeviceDriverReset);
175574353883SHuang Rui 	if (index < 0)
175674353883SHuang Rui 		return index == -EACCES ? 0 : index;
175774353883SHuang Rui 
175874353883SHuang Rui 	mutex_lock(&smu->message_lock);
175974353883SHuang Rui 
176074353883SHuang Rui 	ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, type);
176174353883SHuang Rui 
176274353883SHuang Rui 	mutex_unlock(&smu->message_lock);
176374353883SHuang Rui 
176474353883SHuang Rui 	mdelay(10);
176574353883SHuang Rui 
176674353883SHuang Rui 	return ret;
176774353883SHuang Rui }
176874353883SHuang Rui 
176920e157c7SAlex Deucher static int vangogh_mode2_reset(struct smu_context *smu)
177020e157c7SAlex Deucher {
177174353883SHuang Rui 	return vangogh_mode_reset(smu, SMU_RESET_MODE_2);
177220e157c7SAlex Deucher }
177320e157c7SAlex Deucher 
1774f46a221bSXiaojian Du static const struct pptable_funcs vangogh_ppt_funcs = {
1775271ab489SXiaojian Du 
1776f46a221bSXiaojian Du 	.check_fw_status = smu_v11_0_check_fw_status,
1777f46a221bSXiaojian Du 	.check_fw_version = smu_v11_0_check_fw_version,
1778f46a221bSXiaojian Du 	.init_smc_tables = vangogh_init_smc_tables,
1779f46a221bSXiaojian Du 	.fini_smc_tables = smu_v11_0_fini_smc_tables,
1780f46a221bSXiaojian Du 	.init_power = smu_v11_0_init_power,
1781f46a221bSXiaojian Du 	.fini_power = smu_v11_0_fini_power,
1782f46a221bSXiaojian Du 	.register_irq_handler = smu_v11_0_register_irq_handler,
1783f46a221bSXiaojian Du 	.notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
1784f46a221bSXiaojian Du 	.send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
1785f46a221bSXiaojian Du 	.send_smc_msg = smu_cmn_send_smc_msg,
1786271ab489SXiaojian Du 	.dpm_set_vcn_enable = vangogh_dpm_set_vcn_enable,
1787271ab489SXiaojian Du 	.dpm_set_jpeg_enable = vangogh_dpm_set_jpeg_enable,
1788f46a221bSXiaojian Du 	.is_dpm_running = vangogh_is_dpm_running,
1789271ab489SXiaojian Du 	.read_sensor = vangogh_read_sensor,
1790271ab489SXiaojian Du 	.get_enabled_mask = smu_cmn_get_enabled_32_bits_mask,
1791f46a221bSXiaojian Du 	.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
1792271ab489SXiaojian Du 	.set_watermarks_table = vangogh_set_watermarks_table,
1793271ab489SXiaojian Du 	.set_driver_table_location = smu_v11_0_set_driver_table_location,
1794f46a221bSXiaojian Du 	.interrupt_work = smu_v11_0_interrupt_work,
1795fd253334SXiaojian Du 	.get_gpu_metrics = vangogh_get_gpu_metrics,
1796c98ee897SXiaojian Du 	.od_edit_dpm_table = vangogh_od_edit_dpm_table,
1797c98ee897SXiaojian Du 	.print_clk_levels = vangogh_print_fine_grain_clk,
1798c98ee897SXiaojian Du 	.set_default_dpm_table = vangogh_set_default_dpm_tables,
1799c98ee897SXiaojian Du 	.set_fine_grain_gfx_freq_parameters = vangogh_set_fine_grain_gfx_freq_parameters,
1800a0f55287SXiaomeng Hou 	.system_features_control = vangogh_system_features_control,
1801d0e4e112SXiaojian Du 	.feature_is_enabled = smu_cmn_feature_is_enabled,
1802d0e4e112SXiaojian Du 	.set_power_profile_mode = vangogh_set_power_profile_mode,
1803307f049bSXiaojian Du 	.get_power_profile_mode = vangogh_get_power_profile_mode,
1804ae7b32e7SXiaojian Du 	.get_dpm_clock_table = vangogh_get_dpm_clock_table,
1805dd9e0b21SXiaojian Du 	.force_clk_levels = vangogh_force_clk_levels,
1806ea173d15SXiaojian Du 	.set_performance_level = vangogh_set_performance_level,
1807eefdf047SJinzhou Su 	.post_init = vangogh_post_smu_init,
180820e157c7SAlex Deucher 	.mode2_reset = vangogh_mode2_reset,
1809b58ce1feSJinzhou Su 	.gfx_off_control = smu_v11_0_gfx_off_control,
1810f46a221bSXiaojian Du };
1811f46a221bSXiaojian Du 
1812f46a221bSXiaojian Du void vangogh_set_ppt_funcs(struct smu_context *smu)
1813f46a221bSXiaojian Du {
1814f46a221bSXiaojian Du 	smu->ppt_funcs = &vangogh_ppt_funcs;
1815f46a221bSXiaojian Du 	smu->message_map = vangogh_message_map;
1816f46a221bSXiaojian Du 	smu->feature_map = vangogh_feature_mask_map;
1817f46a221bSXiaojian Du 	smu->table_map = vangogh_table_map;
1818ec3b35c8SXiaojian Du 	smu->workload_map = vangogh_workload_map;
1819f46a221bSXiaojian Du 	smu->is_apu = true;
1820f46a221bSXiaojian Du }
1821