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"
37f46a221bSXiaojian Du 
38f46a221bSXiaojian Du /*
39f46a221bSXiaojian Du  * DO NOT use these for err/warn/info/debug messages.
40f46a221bSXiaojian Du  * Use dev_err, dev_warn, dev_info and dev_dbg instead.
41f46a221bSXiaojian Du  * They are more MGPU friendly.
42f46a221bSXiaojian Du  */
43f46a221bSXiaojian Du #undef pr_err
44f46a221bSXiaojian Du #undef pr_warn
45f46a221bSXiaojian Du #undef pr_info
46f46a221bSXiaojian Du #undef pr_debug
47f46a221bSXiaojian Du 
48f46a221bSXiaojian Du #define FEATURE_MASK(feature) (1ULL << feature)
49f46a221bSXiaojian Du #define SMC_DPM_FEATURE ( \
50f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \
51f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_VCN_DPM_BIT)	 | \
52f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_FCLK_DPM_BIT)	 | \
53f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT)	 | \
54f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT)	 | \
55f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_LCLK_DPM_BIT)	 | \
56f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT)	 | \
57f46a221bSXiaojian Du 	FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \
58271ab489SXiaojian Du 	FEATURE_MASK(FEATURE_GFX_DPM_BIT))
59f46a221bSXiaojian Du 
60f46a221bSXiaojian Du static struct cmn2asic_msg_mapping vangogh_message_map[SMU_MSG_MAX_COUNT] = {
61271ab489SXiaojian Du 	MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,			0),
62271ab489SXiaojian Du 	MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion,		0),
63271ab489SXiaojian Du 	MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion,	0),
64271ab489SXiaojian Du 	MSG_MAP(EnableGfxOff,                   PPSMC_MSG_EnableGfxOff,			0),
65271ab489SXiaojian Du 	MSG_MAP(DisallowGfxOff,                 PPSMC_MSG_DisableGfxOff,		0),
66271ab489SXiaojian Du 	MSG_MAP(PowerDownIspByTile,             PPSMC_MSG_PowerDownIspByTile,	0),
67271ab489SXiaojian Du 	MSG_MAP(PowerUpIspByTile,               PPSMC_MSG_PowerUpIspByTile,		0),
68271ab489SXiaojian Du 	MSG_MAP(PowerDownVcn,                   PPSMC_MSG_PowerDownVcn,			0),
69271ab489SXiaojian Du 	MSG_MAP(PowerUpVcn,                     PPSMC_MSG_PowerUpVcn,			0),
70a0f55287SXiaomeng Hou 	MSG_MAP(RlcPowerNotify,                 PPSMC_MSG_RlcPowerNotify,		0),
71271ab489SXiaojian Du 	MSG_MAP(SetHardMinVcn,                  PPSMC_MSG_SetHardMinVcn,		0),
72271ab489SXiaojian Du 	MSG_MAP(SetSoftMinGfxclk,               PPSMC_MSG_SetSoftMinGfxclk,		0),
73271ab489SXiaojian Du 	MSG_MAP(ActiveProcessNotify,            PPSMC_MSG_ActiveProcessNotify,		0),
74271ab489SXiaojian Du 	MSG_MAP(SetHardMinIspiclkByFreq,        PPSMC_MSG_SetHardMinIspiclkByFreq,	0),
75271ab489SXiaojian Du 	MSG_MAP(SetHardMinIspxclkByFreq,        PPSMC_MSG_SetHardMinIspxclkByFreq,	0),
76271ab489SXiaojian Du 	MSG_MAP(SetDriverDramAddrHigh,          PPSMC_MSG_SetDriverDramAddrHigh,	0),
77271ab489SXiaojian Du 	MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverDramAddrLow,		0),
78271ab489SXiaojian Du 	MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram,	0),
79271ab489SXiaojian Du 	MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu,	0),
80271ab489SXiaojian Du 	MSG_MAP(GfxDeviceDriverReset,           PPSMC_MSG_GfxDeviceDriverReset,		0),
81271ab489SXiaojian Du 	MSG_MAP(GetEnabledSmuFeatures,          PPSMC_MSG_GetEnabledSmuFeatures,	0),
82271ab489SXiaojian Du 	MSG_MAP(Spare1,                         PPSMC_MSG_spare1,					0),
83271ab489SXiaojian Du 	MSG_MAP(SetHardMinSocclkByFreq,         PPSMC_MSG_SetHardMinSocclkByFreq,	0),
84271ab489SXiaojian Du 	MSG_MAP(SetSoftMinFclk,                 PPSMC_MSG_SetSoftMinFclk,		0),
85271ab489SXiaojian Du 	MSG_MAP(SetSoftMinVcn,                  PPSMC_MSG_SetSoftMinVcn,		0),
86271ab489SXiaojian Du 	MSG_MAP(EnablePostCode,                 PPSMC_MSG_EnablePostCode,		0),
87271ab489SXiaojian Du 	MSG_MAP(GetGfxclkFrequency,             PPSMC_MSG_GetGfxclkFrequency,	0),
88271ab489SXiaojian Du 	MSG_MAP(GetFclkFrequency,               PPSMC_MSG_GetFclkFrequency,		0),
89271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxGfxClk,               PPSMC_MSG_SetSoftMaxGfxClk,		0),
90271ab489SXiaojian Du 	MSG_MAP(SetHardMinGfxClk,               PPSMC_MSG_SetHardMinGfxClk,		0),
91271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxSocclkByFreq,         PPSMC_MSG_SetSoftMaxSocclkByFreq,	0),
92271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxFclkByFreq,           PPSMC_MSG_SetSoftMaxFclkByFreq,		0),
93271ab489SXiaojian Du 	MSG_MAP(SetSoftMaxVcn,                  PPSMC_MSG_SetSoftMaxVcn,			0),
94271ab489SXiaojian Du 	MSG_MAP(Spare2,                         PPSMC_MSG_spare2,					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 
181f46a221bSXiaojian Du static int vangogh_tables_init(struct smu_context *smu)
182f46a221bSXiaojian Du {
183f46a221bSXiaojian Du 	struct smu_table_context *smu_table = &smu->smu_table;
184f46a221bSXiaojian Du 	struct smu_table *tables = smu_table->tables;
185f46a221bSXiaojian Du 
186f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
187f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
188f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
189f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
190f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
191f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
192f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE,
193f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
194f46a221bSXiaojian Du 	SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF, sizeof(DpmActivityMonitorCoeffExt_t),
195f46a221bSXiaojian Du 		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
196f46a221bSXiaojian Du 	smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
197f46a221bSXiaojian Du 	if (!smu_table->metrics_table)
198f46a221bSXiaojian Du 		goto err0_out;
199f46a221bSXiaojian Du 	smu_table->metrics_time = 0;
200f46a221bSXiaojian Du 
201f46a221bSXiaojian Du 	smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_0);
202f46a221bSXiaojian Du 	smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
203f46a221bSXiaojian Du 	if (!smu_table->gpu_metrics_table)
204f46a221bSXiaojian Du 		goto err1_out;
205f46a221bSXiaojian Du 
206f46a221bSXiaojian Du 	smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
207f46a221bSXiaojian Du 	if (!smu_table->watermarks_table)
208f46a221bSXiaojian Du 		goto err2_out;
209f46a221bSXiaojian Du 
210c98ee897SXiaojian Du 	smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
211c98ee897SXiaojian Du 	if (!smu_table->clocks_table)
212c98ee897SXiaojian Du 		goto err3_out;
213c98ee897SXiaojian Du 
214f46a221bSXiaojian Du 	return 0;
215f46a221bSXiaojian Du 
216c98ee897SXiaojian Du err3_out:
217c98ee897SXiaojian Du 	kfree(smu_table->clocks_table);
218f46a221bSXiaojian Du err2_out:
219f46a221bSXiaojian Du 	kfree(smu_table->gpu_metrics_table);
220f46a221bSXiaojian Du err1_out:
221f46a221bSXiaojian Du 	kfree(smu_table->metrics_table);
222f46a221bSXiaojian Du err0_out:
223f46a221bSXiaojian Du 	return -ENOMEM;
224f46a221bSXiaojian Du }
225f46a221bSXiaojian Du 
226271ab489SXiaojian Du static int vangogh_get_smu_metrics_data(struct smu_context *smu,
227271ab489SXiaojian Du 				       MetricsMember_t member,
228271ab489SXiaojian Du 				       uint32_t *value)
229271ab489SXiaojian Du {
230271ab489SXiaojian Du 	struct smu_table_context *smu_table = &smu->smu_table;
231271ab489SXiaojian Du 
232271ab489SXiaojian Du 	SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
233271ab489SXiaojian Du 	int ret = 0;
234271ab489SXiaojian Du 
235271ab489SXiaojian Du 	mutex_lock(&smu->metrics_lock);
236271ab489SXiaojian Du 
237271ab489SXiaojian Du 	ret = smu_cmn_get_metrics_table_locked(smu,
238271ab489SXiaojian Du 					       NULL,
239271ab489SXiaojian Du 					       false);
240271ab489SXiaojian Du 	if (ret) {
241271ab489SXiaojian Du 		mutex_unlock(&smu->metrics_lock);
242271ab489SXiaojian Du 		return ret;
243271ab489SXiaojian Du 	}
244271ab489SXiaojian Du 
245271ab489SXiaojian Du 	switch (member) {
246271ab489SXiaojian Du 	case METRICS_AVERAGE_GFXCLK:
247271ab489SXiaojian Du 		*value = metrics->GfxclkFrequency;
248271ab489SXiaojian Du 		break;
249271ab489SXiaojian Du 	case METRICS_AVERAGE_SOCCLK:
250271ab489SXiaojian Du 		*value = metrics->SocclkFrequency;
251271ab489SXiaojian Du 		break;
252f02c7336SXiaojian Du 	case METRICS_AVERAGE_VCLK:
253f02c7336SXiaojian Du 		*value = metrics->VclkFrequency;
254f02c7336SXiaojian Du 		break;
255f02c7336SXiaojian Du 	case METRICS_AVERAGE_DCLK:
256f02c7336SXiaojian Du 		*value = metrics->DclkFrequency;
257f02c7336SXiaojian Du 		break;
258271ab489SXiaojian Du 	case METRICS_AVERAGE_UCLK:
259271ab489SXiaojian Du 		*value = metrics->MemclkFrequency;
260271ab489SXiaojian Du 		break;
261271ab489SXiaojian Du 	case METRICS_AVERAGE_GFXACTIVITY:
262271ab489SXiaojian Du 		*value = metrics->GfxActivity / 100;
263271ab489SXiaojian Du 		break;
264271ab489SXiaojian Du 	case METRICS_AVERAGE_VCNACTIVITY:
265271ab489SXiaojian Du 		*value = metrics->UvdActivity;
266271ab489SXiaojian Du 		break;
267271ab489SXiaojian Du 	case METRICS_AVERAGE_SOCKETPOWER:
26823289a22SXiaojian Du 		*value = (metrics->CurrentSocketPower << 8) /
26923289a22SXiaojian Du 		1000 ;
270271ab489SXiaojian Du 		break;
271271ab489SXiaojian Du 	case METRICS_TEMPERATURE_EDGE:
272271ab489SXiaojian Du 		*value = metrics->GfxTemperature / 100 *
273271ab489SXiaojian Du 		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
274271ab489SXiaojian Du 		break;
275271ab489SXiaojian Du 	case METRICS_TEMPERATURE_HOTSPOT:
276271ab489SXiaojian Du 		*value = metrics->SocTemperature / 100 *
277271ab489SXiaojian Du 		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
278271ab489SXiaojian Du 		break;
279271ab489SXiaojian Du 	case METRICS_THROTTLER_STATUS:
280271ab489SXiaojian Du 		*value = metrics->ThrottlerStatus;
281271ab489SXiaojian Du 		break;
2822139d12bSAlex Deucher 	case METRICS_VOLTAGE_VDDGFX:
2832139d12bSAlex Deucher 		*value = metrics->Voltage[2];
2842139d12bSAlex Deucher 		break;
2852139d12bSAlex Deucher 	case METRICS_VOLTAGE_VDDSOC:
2862139d12bSAlex Deucher 		*value = metrics->Voltage[1];
2872139d12bSAlex Deucher 		break;
288271ab489SXiaojian Du 	default:
289271ab489SXiaojian Du 		*value = UINT_MAX;
290271ab489SXiaojian Du 		break;
291271ab489SXiaojian Du 	}
292271ab489SXiaojian Du 
293271ab489SXiaojian Du 	mutex_unlock(&smu->metrics_lock);
294271ab489SXiaojian Du 
295271ab489SXiaojian Du 	return ret;
296271ab489SXiaojian Du }
297271ab489SXiaojian Du 
298f46a221bSXiaojian Du static int vangogh_allocate_dpm_context(struct smu_context *smu)
299f46a221bSXiaojian Du {
300f46a221bSXiaojian Du 	struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
301f46a221bSXiaojian Du 
302f46a221bSXiaojian Du 	smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context),
303f46a221bSXiaojian Du 				       GFP_KERNEL);
304f46a221bSXiaojian Du 	if (!smu_dpm->dpm_context)
305f46a221bSXiaojian Du 		return -ENOMEM;
306f46a221bSXiaojian Du 
307f46a221bSXiaojian Du 	smu_dpm->dpm_context_size = sizeof(struct smu_11_0_dpm_context);
308f46a221bSXiaojian Du 
309f46a221bSXiaojian Du 	return 0;
310f46a221bSXiaojian Du }
311f46a221bSXiaojian Du 
312f46a221bSXiaojian Du static int vangogh_init_smc_tables(struct smu_context *smu)
313f46a221bSXiaojian Du {
314f46a221bSXiaojian Du 	int ret = 0;
315f46a221bSXiaojian Du 
316f46a221bSXiaojian Du 	ret = vangogh_tables_init(smu);
317f46a221bSXiaojian Du 	if (ret)
318f46a221bSXiaojian Du 		return ret;
319f46a221bSXiaojian Du 
320f46a221bSXiaojian Du 	ret = vangogh_allocate_dpm_context(smu);
321f46a221bSXiaojian Du 	if (ret)
322f46a221bSXiaojian Du 		return ret;
323f46a221bSXiaojian Du 
324f46a221bSXiaojian Du 	return smu_v11_0_init_smc_tables(smu);
325f46a221bSXiaojian Du }
326f46a221bSXiaojian Du 
327f46a221bSXiaojian Du static int vangogh_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
328f46a221bSXiaojian Du {
329f46a221bSXiaojian Du 	int ret = 0;
330f46a221bSXiaojian Du 
331f46a221bSXiaojian Du 	if (enable) {
332f46a221bSXiaojian Du 		/* vcn dpm on is a prerequisite for vcn power gate messages */
333271ab489SXiaojian Du 		if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
334f46a221bSXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 0, NULL);
335f46a221bSXiaojian Du 			if (ret)
336f46a221bSXiaojian Du 				return ret;
337f46a221bSXiaojian Du 		}
338f46a221bSXiaojian Du 	} else {
339271ab489SXiaojian Du 		if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
340f46a221bSXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn, 0, NULL);
341f46a221bSXiaojian Du 			if (ret)
342f46a221bSXiaojian Du 				return ret;
343f46a221bSXiaojian Du 		}
344f46a221bSXiaojian Du 	}
345f46a221bSXiaojian Du 
346f46a221bSXiaojian Du 	return ret;
347f46a221bSXiaojian Du }
348f46a221bSXiaojian Du 
349f46a221bSXiaojian Du static int vangogh_dpm_set_jpeg_enable(struct smu_context *smu, bool enable)
350f46a221bSXiaojian Du {
351f46a221bSXiaojian Du 	int ret = 0;
352f46a221bSXiaojian Du 
353f46a221bSXiaojian Du 	if (enable) {
354271ab489SXiaojian Du 		if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) {
355f46a221bSXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0, NULL);
356f46a221bSXiaojian Du 			if (ret)
357f46a221bSXiaojian Du 				return ret;
358f46a221bSXiaojian Du 		}
359f46a221bSXiaojian Du 	} else {
360271ab489SXiaojian Du 		if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) {
361f46a221bSXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0, NULL);
362f46a221bSXiaojian Du 			if (ret)
363f46a221bSXiaojian Du 				return ret;
364f46a221bSXiaojian Du 		}
365f46a221bSXiaojian Du 	}
366f46a221bSXiaojian Du 
367f46a221bSXiaojian Du 	return ret;
368f46a221bSXiaojian Du }
369f46a221bSXiaojian Du 
370f46a221bSXiaojian Du static int vangogh_get_allowed_feature_mask(struct smu_context *smu,
371f46a221bSXiaojian Du 					    uint32_t *feature_mask,
372f46a221bSXiaojian Du 					    uint32_t num)
373f46a221bSXiaojian Du {
374f46a221bSXiaojian Du 	struct amdgpu_device *adev = smu->adev;
375f46a221bSXiaojian Du 
376f46a221bSXiaojian Du 	if (num > 2)
377f46a221bSXiaojian Du 		return -EINVAL;
378f46a221bSXiaojian Du 
379f46a221bSXiaojian Du 	memset(feature_mask, 0, sizeof(uint32_t) * num);
380f46a221bSXiaojian Du 
381f46a221bSXiaojian Du 	*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_DPM_BIT)
382f46a221bSXiaojian Du 				| FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT)
38354800b58SXiaojian Du 				| FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT)
38454800b58SXiaojian Du 				| FEATURE_MASK(FEATURE_VCN_DPM_BIT)
38554800b58SXiaojian Du 				| FEATURE_MASK(FEATURE_FCLK_DPM_BIT)
38654800b58SXiaojian Du 				| FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)
387f46a221bSXiaojian Du 				| FEATURE_MASK(FEATURE_DS_SOCCLK_BIT)
388f46a221bSXiaojian Du 				| FEATURE_MASK(FEATURE_PPT_BIT)
389f46a221bSXiaojian Du 				| FEATURE_MASK(FEATURE_TDC_BIT)
390f46a221bSXiaojian Du 				| FEATURE_MASK(FEATURE_FAN_CONTROLLER_BIT)
391f46a221bSXiaojian Du 				| FEATURE_MASK(FEATURE_DS_LCLK_BIT)
392f46a221bSXiaojian Du 				| FEATURE_MASK(FEATURE_DS_DCFCLK_BIT);
393f46a221bSXiaojian Du 
394f46a221bSXiaojian Du 	if (adev->pm.pp_feature & PP_SOCCLK_DPM_MASK)
395f46a221bSXiaojian Du 		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT);
396f46a221bSXiaojian Du 
397f46a221bSXiaojian Du 	if (adev->pm.pp_feature & PP_DCEFCLK_DPM_MASK)
398f46a221bSXiaojian Du 		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT);
399f46a221bSXiaojian Du 
40054800b58SXiaojian Du 	if (adev->pm.pp_feature & PP_MCLK_DPM_MASK)
40154800b58SXiaojian Du 		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FCLK_DPM_BIT);
40254800b58SXiaojian Du 
40354800b58SXiaojian Du 	if (adev->pm.pp_feature & PP_SCLK_DPM_MASK)
40454800b58SXiaojian Du 		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_DPM_BIT);
40554800b58SXiaojian Du 
406f46a221bSXiaojian Du 	if (smu->adev->pg_flags & AMD_PG_SUPPORT_ATHUB)
407f46a221bSXiaojian Du 		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_PG_BIT);
408f46a221bSXiaojian Du 
409f46a221bSXiaojian Du 	return 0;
410f46a221bSXiaojian Du }
411f46a221bSXiaojian Du 
412f46a221bSXiaojian Du static bool vangogh_is_dpm_running(struct smu_context *smu)
413f46a221bSXiaojian Du {
414271ab489SXiaojian Du 	int ret = 0;
415271ab489SXiaojian Du 	uint32_t feature_mask[2];
416271ab489SXiaojian Du 	uint64_t feature_enabled;
417f46a221bSXiaojian Du 
418271ab489SXiaojian Du 	ret = smu_cmn_get_enabled_32_bits_mask(smu, feature_mask, 2);
419271ab489SXiaojian Du 
420271ab489SXiaojian Du 	if (ret)
421f46a221bSXiaojian Du 		return false;
422f46a221bSXiaojian Du 
423271ab489SXiaojian Du 	feature_enabled = (unsigned long)((uint64_t)feature_mask[0] |
424271ab489SXiaojian Du 				((uint64_t)feature_mask[1] << 32));
425271ab489SXiaojian Du 
426271ab489SXiaojian Du 	return !!(feature_enabled & SMC_DPM_FEATURE);
427271ab489SXiaojian Du }
428271ab489SXiaojian Du 
429ae7b32e7SXiaojian Du static int vangogh_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type clk_type,
430ae7b32e7SXiaojian Du 						uint32_t dpm_level, uint32_t *freq)
431ae7b32e7SXiaojian Du {
432ae7b32e7SXiaojian Du 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
433ae7b32e7SXiaojian Du 
434ae7b32e7SXiaojian Du 	if (!clk_table || clk_type >= SMU_CLK_COUNT)
435ae7b32e7SXiaojian Du 		return -EINVAL;
436ae7b32e7SXiaojian Du 
437ae7b32e7SXiaojian Du 	switch (clk_type) {
438ae7b32e7SXiaojian Du 	case SMU_SOCCLK:
439ae7b32e7SXiaojian Du 		if (dpm_level >= clk_table->NumSocClkLevelsEnabled)
440ae7b32e7SXiaojian Du 			return -EINVAL;
441ae7b32e7SXiaojian Du 		*freq = clk_table->SocClocks[dpm_level];
442ae7b32e7SXiaojian Du 		break;
443f02c7336SXiaojian Du 	case SMU_VCLK:
444f02c7336SXiaojian Du 		if (dpm_level >= clk_table->VcnClkLevelsEnabled)
445f02c7336SXiaojian Du 			return -EINVAL;
446f02c7336SXiaojian Du 		*freq = clk_table->VcnClocks[dpm_level].vclk;
447f02c7336SXiaojian Du 		break;
448f02c7336SXiaojian Du 	case SMU_DCLK:
449f02c7336SXiaojian Du 		if (dpm_level >= clk_table->VcnClkLevelsEnabled)
450f02c7336SXiaojian Du 			return -EINVAL;
451f02c7336SXiaojian Du 		*freq = clk_table->VcnClocks[dpm_level].dclk;
452f02c7336SXiaojian Du 		break;
453ae7b32e7SXiaojian Du 	case SMU_UCLK:
454ae7b32e7SXiaojian Du 	case SMU_MCLK:
455ae7b32e7SXiaojian Du 		if (dpm_level >= clk_table->NumDfPstatesEnabled)
456ae7b32e7SXiaojian Du 			return -EINVAL;
457ae7b32e7SXiaojian Du 		*freq = clk_table->DfPstateTable[dpm_level].memclk;
458ae7b32e7SXiaojian Du 
459ae7b32e7SXiaojian Du 		break;
460ae7b32e7SXiaojian Du 	case SMU_FCLK:
461ae7b32e7SXiaojian Du 		if (dpm_level >= clk_table->NumDfPstatesEnabled)
462ae7b32e7SXiaojian Du 			return -EINVAL;
463ae7b32e7SXiaojian Du 		*freq = clk_table->DfPstateTable[dpm_level].fclk;
464ae7b32e7SXiaojian Du 		break;
465ae7b32e7SXiaojian Du 	default:
466ae7b32e7SXiaojian Du 		return -EINVAL;
467ae7b32e7SXiaojian Du 	}
468ae7b32e7SXiaojian Du 
469ae7b32e7SXiaojian Du 	return 0;
470ae7b32e7SXiaojian Du }
471ae7b32e7SXiaojian Du 
472c98ee897SXiaojian Du static int vangogh_print_fine_grain_clk(struct smu_context *smu,
473c98ee897SXiaojian Du 			enum smu_clk_type clk_type, char *buf)
474c98ee897SXiaojian Du {
475ae7b32e7SXiaojian Du 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
476ae7b32e7SXiaojian Du 	SmuMetrics_t metrics;
477ae7b32e7SXiaojian Du 	int i, size = 0, ret = 0;
478ae7b32e7SXiaojian Du 	uint32_t cur_value = 0, value = 0, count = 0;
479ae7b32e7SXiaojian Du 	bool cur_value_match_level = false;
480ae7b32e7SXiaojian Du 
481ae7b32e7SXiaojian Du 	memset(&metrics, 0, sizeof(metrics));
482ae7b32e7SXiaojian Du 
483ae7b32e7SXiaojian Du 	ret = smu_cmn_get_metrics_table(smu, &metrics, false);
484ae7b32e7SXiaojian Du 	if (ret)
485ae7b32e7SXiaojian Du 		return ret;
486c98ee897SXiaojian Du 
487c98ee897SXiaojian Du 	switch (clk_type) {
488c98ee897SXiaojian Du 	case SMU_OD_SCLK:
489c98ee897SXiaojian Du 		if (smu->od_enabled) {
490c98ee897SXiaojian Du 			size = sprintf(buf, "%s:\n", "OD_SCLK");
491c98ee897SXiaojian Du 			size += sprintf(buf + size, "0: %10uMhz\n",
492c98ee897SXiaojian Du 			(smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);
493c98ee897SXiaojian Du 			size += sprintf(buf + size, "1: %10uMhz\n",
494c98ee897SXiaojian Du 			(smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq);
495c98ee897SXiaojian Du 		}
496c98ee897SXiaojian Du 		break;
497c98ee897SXiaojian Du 	case SMU_OD_RANGE:
498c98ee897SXiaojian Du 		if (smu->od_enabled) {
499c98ee897SXiaojian Du 			size = sprintf(buf, "%s:\n", "OD_RANGE");
500c98ee897SXiaojian Du 			size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
501c98ee897SXiaojian Du 				smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);
502c98ee897SXiaojian Du 		}
503c98ee897SXiaojian Du 		break;
504ae7b32e7SXiaojian Du 	case SMU_SOCCLK:
505ae7b32e7SXiaojian Du 		/* the level 3 ~ 6 of socclk use the same frequency for vangogh */
506ae7b32e7SXiaojian Du 		count = clk_table->NumSocClkLevelsEnabled;
507ae7b32e7SXiaojian Du 		cur_value = metrics.SocclkFrequency;
508ae7b32e7SXiaojian Du 		break;
509f02c7336SXiaojian Du 	case SMU_VCLK:
510f02c7336SXiaojian Du 		count = clk_table->VcnClkLevelsEnabled;
511f02c7336SXiaojian Du 		cur_value = metrics.VclkFrequency;
512f02c7336SXiaojian Du 		break;
513f02c7336SXiaojian Du 	case SMU_DCLK:
514f02c7336SXiaojian Du 		count = clk_table->VcnClkLevelsEnabled;
515f02c7336SXiaojian Du 		cur_value = metrics.DclkFrequency;
516f02c7336SXiaojian Du 		break;
517ae7b32e7SXiaojian Du 	case SMU_MCLK:
518ae7b32e7SXiaojian Du 		count = clk_table->NumDfPstatesEnabled;
519ae7b32e7SXiaojian Du 		cur_value = metrics.MemclkFrequency;
520ae7b32e7SXiaojian Du 		break;
521ae7b32e7SXiaojian Du 	case SMU_FCLK:
522ae7b32e7SXiaojian Du 		count = clk_table->NumDfPstatesEnabled;
523ae7b32e7SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetFclkFrequency, 0, &cur_value);
524ae7b32e7SXiaojian Du 		if (ret)
525ae7b32e7SXiaojian Du 			return ret;
526ae7b32e7SXiaojian Du 		break;
527ae7b32e7SXiaojian Du 	default:
528ae7b32e7SXiaojian Du 		break;
529ae7b32e7SXiaojian Du 	}
530ae7b32e7SXiaojian Du 
531ae7b32e7SXiaojian Du 	switch (clk_type) {
532ae7b32e7SXiaojian Du 	case SMU_SOCCLK:
533f02c7336SXiaojian Du 	case SMU_VCLK:
534f02c7336SXiaojian Du 	case SMU_DCLK:
535ae7b32e7SXiaojian Du 	case SMU_MCLK:
536ae7b32e7SXiaojian Du 	case SMU_FCLK:
537ae7b32e7SXiaojian Du 		for (i = 0; i < count; i++) {
538ae7b32e7SXiaojian Du 			ret = vangogh_get_dpm_clk_limited(smu, clk_type, i, &value);
539ae7b32e7SXiaojian Du 			if (ret)
540ae7b32e7SXiaojian Du 				return ret;
541ae7b32e7SXiaojian Du 			if (!value)
542ae7b32e7SXiaojian Du 				continue;
543ae7b32e7SXiaojian Du 			size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
544ae7b32e7SXiaojian Du 					cur_value == value ? "*" : "");
545ae7b32e7SXiaojian Du 			if (cur_value == value)
546ae7b32e7SXiaojian Du 				cur_value_match_level = true;
547ae7b32e7SXiaojian Du 		}
548ae7b32e7SXiaojian Du 
549ae7b32e7SXiaojian Du 		if (!cur_value_match_level)
550ae7b32e7SXiaojian Du 			size += sprintf(buf + size, "   %uMhz *\n", cur_value);
551ae7b32e7SXiaojian Du 		break;
552c98ee897SXiaojian Du 	default:
553c98ee897SXiaojian Du 		break;
554c98ee897SXiaojian Du 	}
555c98ee897SXiaojian Du 
556c98ee897SXiaojian Du 	return size;
557c98ee897SXiaojian Du }
558c98ee897SXiaojian Du 
559d0e4e112SXiaojian Du static int vangogh_get_profiling_clk_mask(struct smu_context *smu,
560d0e4e112SXiaojian Du 					 enum amd_dpm_forced_level level,
561d0e4e112SXiaojian Du 					 uint32_t *vclk_mask,
562d0e4e112SXiaojian Du 					 uint32_t *dclk_mask,
563d0e4e112SXiaojian Du 					 uint32_t *mclk_mask,
564d0e4e112SXiaojian Du 					 uint32_t *fclk_mask,
565d0e4e112SXiaojian Du 					 uint32_t *soc_mask)
566d0e4e112SXiaojian Du {
567d0e4e112SXiaojian Du 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
568d0e4e112SXiaojian Du 
569d0e4e112SXiaojian Du 	if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
570d0e4e112SXiaojian Du 		if (soc_mask)
571d0e4e112SXiaojian Du 			*soc_mask = 0;
572d0e4e112SXiaojian Du 	} else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
573d0e4e112SXiaojian Du 		if (mclk_mask)
574d0e4e112SXiaojian Du 			/* mclk levels are in reverse order */
575d0e4e112SXiaojian Du 			*mclk_mask = clk_table->NumDfPstatesEnabled - 1;
576d0e4e112SXiaojian Du 			/* fclk levels are in reverse order */
577d0e4e112SXiaojian Du 		if (fclk_mask)
578d0e4e112SXiaojian Du 			*fclk_mask = clk_table->NumDfPstatesEnabled - 1;
579d0e4e112SXiaojian Du 	} else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
580d0e4e112SXiaojian Du 		if (mclk_mask)
581d0e4e112SXiaojian Du 			/* mclk levels are in reverse order */
582d0e4e112SXiaojian Du 			*mclk_mask = 0;
583d0e4e112SXiaojian Du 			/* fclk levels are in reverse order */
584d0e4e112SXiaojian Du 		if (fclk_mask)
585d0e4e112SXiaojian Du 			*fclk_mask = 0;
586d0e4e112SXiaojian Du 
587d0e4e112SXiaojian Du 		if (soc_mask)
588d0e4e112SXiaojian Du 			*soc_mask = clk_table->NumSocClkLevelsEnabled - 1;
589d0e4e112SXiaojian Du 	}
590d0e4e112SXiaojian Du 
591d0e4e112SXiaojian Du 	return 0;
592d0e4e112SXiaojian Du }
593d0e4e112SXiaojian Du 
594d0e4e112SXiaojian Du 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 
754d0e4e112SXiaojian Du static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
755d0e4e112SXiaojian Du {
756d0e4e112SXiaojian Du 	int workload_type, ret;
757d0e4e112SXiaojian Du 	uint32_t profile_mode = input[size];
758d0e4e112SXiaojian Du 
759d0e4e112SXiaojian Du 	if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
760d0e4e112SXiaojian Du 		dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
761d0e4e112SXiaojian Du 		return -EINVAL;
762d0e4e112SXiaojian Du 	}
763d0e4e112SXiaojian Du 
764d0e4e112SXiaojian Du 	/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
765d0e4e112SXiaojian Du 	workload_type = smu_cmn_to_asic_specific_index(smu,
766d0e4e112SXiaojian Du 						       CMN2ASIC_MAPPING_WORKLOAD,
767d0e4e112SXiaojian Du 						       profile_mode);
768d0e4e112SXiaojian Du 	if (workload_type < 0) {
769d0e4e112SXiaojian Du 		dev_err_once(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
770d0e4e112SXiaojian Du 					profile_mode);
771d0e4e112SXiaojian Du 		return -EINVAL;
772d0e4e112SXiaojian Du 	}
773d0e4e112SXiaojian Du 
774d0e4e112SXiaojian Du 	ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
775d0e4e112SXiaojian Du 				    1 << workload_type,
776d0e4e112SXiaojian Du 				    NULL);
777d0e4e112SXiaojian Du 	if (ret) {
778d0e4e112SXiaojian Du 		dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
779d0e4e112SXiaojian Du 					workload_type);
780d0e4e112SXiaojian Du 		return ret;
781d0e4e112SXiaojian Du 	}
782d0e4e112SXiaojian Du 
783d0e4e112SXiaojian Du 	smu->power_profile_mode = profile_mode;
784d0e4e112SXiaojian Du 
785d0e4e112SXiaojian Du 	return 0;
786d0e4e112SXiaojian Du }
787d0e4e112SXiaojian Du 
788dd9e0b21SXiaojian Du static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
789dd9e0b21SXiaojian Du 					  enum smu_clk_type clk_type,
790dd9e0b21SXiaojian Du 					  uint32_t min,
791dd9e0b21SXiaojian Du 					  uint32_t max)
792dd9e0b21SXiaojian Du {
793dd9e0b21SXiaojian Du 	int ret = 0;
794dd9e0b21SXiaojian Du 
795dd9e0b21SXiaojian Du 	if (!vangogh_clk_dpm_is_enabled(smu, clk_type))
796dd9e0b21SXiaojian Du 		return 0;
797dd9e0b21SXiaojian Du 
798dd9e0b21SXiaojian Du 	switch (clk_type) {
799dd9e0b21SXiaojian Du 	case SMU_GFXCLK:
800dd9e0b21SXiaojian Du 	case SMU_SCLK:
801dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
802dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinGfxClk,
803dd9e0b21SXiaojian Du 							min, NULL);
804dd9e0b21SXiaojian Du 		if (ret)
805dd9e0b21SXiaojian Du 			return ret;
806dd9e0b21SXiaojian Du 
807dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
808dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxGfxClk,
809dd9e0b21SXiaojian Du 							max, NULL);
810dd9e0b21SXiaojian Du 		if (ret)
811dd9e0b21SXiaojian Du 			return ret;
812dd9e0b21SXiaojian Du 		break;
813dd9e0b21SXiaojian Du 	case SMU_FCLK:
814dd9e0b21SXiaojian Du 	case SMU_MCLK:
815dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
816dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinFclkByFreq,
817dd9e0b21SXiaojian Du 							min, NULL);
818dd9e0b21SXiaojian Du 		if (ret)
819dd9e0b21SXiaojian Du 			return ret;
820dd9e0b21SXiaojian Du 
821dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
822dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxFclkByFreq,
823dd9e0b21SXiaojian Du 							max, NULL);
824dd9e0b21SXiaojian Du 		if (ret)
825dd9e0b21SXiaojian Du 			return ret;
826dd9e0b21SXiaojian Du 		break;
827dd9e0b21SXiaojian Du 	case SMU_SOCCLK:
828dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
829dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinSocclkByFreq,
830dd9e0b21SXiaojian Du 							min, NULL);
831dd9e0b21SXiaojian Du 		if (ret)
832dd9e0b21SXiaojian Du 			return ret;
833dd9e0b21SXiaojian Du 
834dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
835dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxSocclkByFreq,
836dd9e0b21SXiaojian Du 							max, NULL);
837dd9e0b21SXiaojian Du 		if (ret)
838dd9e0b21SXiaojian Du 			return ret;
839dd9e0b21SXiaojian Du 		break;
840dd9e0b21SXiaojian Du 	case SMU_VCLK:
841dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
842dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinVcn,
843dd9e0b21SXiaojian Du 							min << 16, NULL);
844dd9e0b21SXiaojian Du 		if (ret)
845dd9e0b21SXiaojian Du 			return ret;
846dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
847dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxVcn,
848dd9e0b21SXiaojian Du 							max << 16, NULL);
849dd9e0b21SXiaojian Du 		if (ret)
850dd9e0b21SXiaojian Du 			return ret;
851dd9e0b21SXiaojian Du 		break;
852dd9e0b21SXiaojian Du 	case SMU_DCLK:
853dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
854dd9e0b21SXiaojian Du 							SMU_MSG_SetHardMinVcn,
855dd9e0b21SXiaojian Du 							min, NULL);
856dd9e0b21SXiaojian Du 		if (ret)
857dd9e0b21SXiaojian Du 			return ret;
858dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
859dd9e0b21SXiaojian Du 							SMU_MSG_SetSoftMaxVcn,
860dd9e0b21SXiaojian Du 							max, NULL);
861dd9e0b21SXiaojian Du 		if (ret)
862dd9e0b21SXiaojian Du 			return ret;
863dd9e0b21SXiaojian Du 		break;
864dd9e0b21SXiaojian Du 	default:
865dd9e0b21SXiaojian Du 		return -EINVAL;
866dd9e0b21SXiaojian Du 	}
867dd9e0b21SXiaojian Du 
868dd9e0b21SXiaojian Du 	return ret;
869dd9e0b21SXiaojian Du }
870dd9e0b21SXiaojian Du 
871dd9e0b21SXiaojian Du static int vangogh_force_clk_levels(struct smu_context *smu,
872dd9e0b21SXiaojian Du 				   enum smu_clk_type clk_type, uint32_t mask)
873dd9e0b21SXiaojian Du {
874dd9e0b21SXiaojian Du 	uint32_t soft_min_level = 0, soft_max_level = 0;
875dd9e0b21SXiaojian Du 	uint32_t min_freq = 0, max_freq = 0;
876dd9e0b21SXiaojian Du 	int ret = 0 ;
877dd9e0b21SXiaojian Du 
878dd9e0b21SXiaojian Du 	soft_min_level = mask ? (ffs(mask) - 1) : 0;
879dd9e0b21SXiaojian Du 	soft_max_level = mask ? (fls(mask) - 1) : 0;
880dd9e0b21SXiaojian Du 
881dd9e0b21SXiaojian Du 	switch (clk_type) {
882dd9e0b21SXiaojian Du 	case SMU_SOCCLK:
883dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu, clk_type,
884dd9e0b21SXiaojian Du 						soft_min_level, &min_freq);
885dd9e0b21SXiaojian Du 		if (ret)
886dd9e0b21SXiaojian Du 			return ret;
887dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu, clk_type,
888dd9e0b21SXiaojian Du 						soft_max_level, &max_freq);
889dd9e0b21SXiaojian Du 		if (ret)
890dd9e0b21SXiaojian Du 			return ret;
891dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
892dd9e0b21SXiaojian Du 								SMU_MSG_SetSoftMaxSocclkByFreq,
893dd9e0b21SXiaojian Du 								max_freq, NULL);
894dd9e0b21SXiaojian Du 		if (ret)
895dd9e0b21SXiaojian Du 			return ret;
896dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
897dd9e0b21SXiaojian Du 								SMU_MSG_SetHardMinSocclkByFreq,
898dd9e0b21SXiaojian Du 								min_freq, NULL);
899dd9e0b21SXiaojian Du 		if (ret)
900dd9e0b21SXiaojian Du 			return ret;
901dd9e0b21SXiaojian Du 		break;
902dd9e0b21SXiaojian Du 	case SMU_MCLK:
903dd9e0b21SXiaojian Du 	case SMU_FCLK:
904dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
905dd9e0b21SXiaojian Du 							clk_type, soft_min_level, &min_freq);
906dd9e0b21SXiaojian Du 		if (ret)
907dd9e0b21SXiaojian Du 			return ret;
908dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
909dd9e0b21SXiaojian Du 							clk_type, soft_max_level, &max_freq);
910dd9e0b21SXiaojian Du 		if (ret)
911dd9e0b21SXiaojian Du 			return ret;
912dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
913dd9e0b21SXiaojian Du 								SMU_MSG_SetSoftMaxFclkByFreq,
914dd9e0b21SXiaojian Du 								max_freq, NULL);
915dd9e0b21SXiaojian Du 		if (ret)
916dd9e0b21SXiaojian Du 			return ret;
917dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
918dd9e0b21SXiaojian Du 								SMU_MSG_SetHardMinFclkByFreq,
919dd9e0b21SXiaojian Du 								min_freq, NULL);
920dd9e0b21SXiaojian Du 		if (ret)
921dd9e0b21SXiaojian Du 			return ret;
922dd9e0b21SXiaojian Du 		break;
923dd9e0b21SXiaojian Du 	case SMU_VCLK:
924dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
925dd9e0b21SXiaojian Du 							clk_type, soft_min_level, &min_freq);
926dd9e0b21SXiaojian Du 		if (ret)
927dd9e0b21SXiaojian Du 			return ret;
928dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_clk_limited(smu,
929dd9e0b21SXiaojian Du 							clk_type, soft_max_level, &max_freq);
930dd9e0b21SXiaojian Du 		if (ret)
931dd9e0b21SXiaojian Du 			return ret;
932dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
933dd9e0b21SXiaojian Du 								SMU_MSG_SetSoftMaxVcn,
934dd9e0b21SXiaojian Du 								max_freq << 16, NULL);
935dd9e0b21SXiaojian Du 		if (ret)
936dd9e0b21SXiaojian Du 			return ret;
937dd9e0b21SXiaojian Du 		ret = smu_cmn_send_smc_msg_with_param(smu,
938dd9e0b21SXiaojian Du 								SMU_MSG_SetHardMinVcn,
939dd9e0b21SXiaojian Du 								min_freq << 16, NULL);
940dd9e0b21SXiaojian Du 		if (ret)
941dd9e0b21SXiaojian Du 			return ret;
942dd9e0b21SXiaojian Du 		break;
943dd9e0b21SXiaojian Du 	case SMU_DCLK:
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_SetSoftMaxVcn,
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_SetHardMinVcn,
959dd9e0b21SXiaojian Du 							min_freq, NULL);
960dd9e0b21SXiaojian Du 		if (ret)
961dd9e0b21SXiaojian Du 			return ret;
962dd9e0b21SXiaojian Du 		break;
963dd9e0b21SXiaojian Du 	default:
964dd9e0b21SXiaojian Du 		break;
965dd9e0b21SXiaojian Du 	}
966dd9e0b21SXiaojian Du 
967dd9e0b21SXiaojian Du 	return ret;
968dd9e0b21SXiaojian Du }
969dd9e0b21SXiaojian Du 
970dd9e0b21SXiaojian Du static int vangogh_force_dpm_limit_value(struct smu_context *smu, bool highest)
971dd9e0b21SXiaojian Du {
972dd9e0b21SXiaojian Du 	int ret = 0, i = 0;
973dd9e0b21SXiaojian Du 	uint32_t min_freq, max_freq, force_freq;
974dd9e0b21SXiaojian Du 	enum smu_clk_type clk_type;
975dd9e0b21SXiaojian Du 
976dd9e0b21SXiaojian Du 	enum smu_clk_type clks[] = {
977dd9e0b21SXiaojian Du 		SMU_SOCCLK,
978dd9e0b21SXiaojian Du 		SMU_VCLK,
979dd9e0b21SXiaojian Du 		SMU_DCLK,
980dd9e0b21SXiaojian Du 		SMU_MCLK,
981dd9e0b21SXiaojian Du 		SMU_FCLK,
982dd9e0b21SXiaojian Du 	};
983dd9e0b21SXiaojian Du 
984dd9e0b21SXiaojian Du 	for (i = 0; i < ARRAY_SIZE(clks); i++) {
985dd9e0b21SXiaojian Du 		clk_type = clks[i];
986dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_ultimate_freq(smu, clk_type, &min_freq, &max_freq);
987dd9e0b21SXiaojian Du 		if (ret)
988dd9e0b21SXiaojian Du 			return ret;
989dd9e0b21SXiaojian Du 
990dd9e0b21SXiaojian Du 		force_freq = highest ? max_freq : min_freq;
991dd9e0b21SXiaojian Du 		ret = vangogh_set_soft_freq_limited_range(smu, clk_type, force_freq, force_freq);
992dd9e0b21SXiaojian Du 		if (ret)
993dd9e0b21SXiaojian Du 			return ret;
994dd9e0b21SXiaojian Du 	}
995dd9e0b21SXiaojian Du 
996dd9e0b21SXiaojian Du 	return ret;
997dd9e0b21SXiaojian Du }
998dd9e0b21SXiaojian Du 
999dd9e0b21SXiaojian Du static int vangogh_unforce_dpm_levels(struct smu_context *smu)
1000dd9e0b21SXiaojian Du {
1001dd9e0b21SXiaojian Du 	int ret = 0, i = 0;
1002dd9e0b21SXiaojian Du 	uint32_t min_freq, max_freq;
1003dd9e0b21SXiaojian Du 	enum smu_clk_type clk_type;
1004dd9e0b21SXiaojian Du 
1005dd9e0b21SXiaojian Du 	struct clk_feature_map {
1006dd9e0b21SXiaojian Du 		enum smu_clk_type clk_type;
1007dd9e0b21SXiaojian Du 		uint32_t	feature;
1008dd9e0b21SXiaojian Du 	} clk_feature_map[] = {
1009dd9e0b21SXiaojian Du 		{SMU_MCLK,   SMU_FEATURE_DPM_FCLK_BIT},
1010dd9e0b21SXiaojian Du 		{SMU_FCLK, SMU_FEATURE_DPM_FCLK_BIT},
1011dd9e0b21SXiaojian Du 		{SMU_SOCCLK, SMU_FEATURE_DPM_SOCCLK_BIT},
1012*b0eec124SXiaojian Du 		{SMU_VCLK, SMU_FEATURE_VCN_DPM_BIT},
1013*b0eec124SXiaojian Du 		{SMU_DCLK, SMU_FEATURE_VCN_DPM_BIT},
1014dd9e0b21SXiaojian Du 	};
1015dd9e0b21SXiaojian Du 
1016dd9e0b21SXiaojian Du 	for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) {
1017dd9e0b21SXiaojian Du 
1018dd9e0b21SXiaojian Du 		if (!smu_cmn_feature_is_enabled(smu, clk_feature_map[i].feature))
1019dd9e0b21SXiaojian Du 		    continue;
1020dd9e0b21SXiaojian Du 
1021dd9e0b21SXiaojian Du 		clk_type = clk_feature_map[i].clk_type;
1022dd9e0b21SXiaojian Du 
1023dd9e0b21SXiaojian Du 		ret = vangogh_get_dpm_ultimate_freq(smu, clk_type, &min_freq, &max_freq);
1024dd9e0b21SXiaojian Du 
1025dd9e0b21SXiaojian Du 		if (ret)
1026dd9e0b21SXiaojian Du 			return ret;
1027dd9e0b21SXiaojian Du 
1028dd9e0b21SXiaojian Du 		ret = vangogh_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq);
1029dd9e0b21SXiaojian Du 
1030dd9e0b21SXiaojian Du 		if (ret)
1031dd9e0b21SXiaojian Du 			return ret;
1032dd9e0b21SXiaojian Du 	}
1033dd9e0b21SXiaojian Du 
1034dd9e0b21SXiaojian Du 	return ret;
1035dd9e0b21SXiaojian Du }
1036dd9e0b21SXiaojian Du 
1037dd9e0b21SXiaojian Du static int vangogh_set_peak_clock_by_device(struct smu_context *smu)
1038dd9e0b21SXiaojian Du {
1039dd9e0b21SXiaojian Du 	int ret = 0;
1040dd9e0b21SXiaojian Du 	uint32_t socclk_freq = 0, fclk_freq = 0;
1041dd9e0b21SXiaojian Du 
1042dd9e0b21SXiaojian Du 	ret = vangogh_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_freq);
1043dd9e0b21SXiaojian Du 	if (ret)
1044dd9e0b21SXiaojian Du 		return ret;
1045dd9e0b21SXiaojian Du 
1046dd9e0b21SXiaojian Du 	ret = vangogh_set_soft_freq_limited_range(smu, SMU_FCLK, fclk_freq, fclk_freq);
1047dd9e0b21SXiaojian Du 	if (ret)
1048dd9e0b21SXiaojian Du 		return ret;
1049dd9e0b21SXiaojian Du 
1050dd9e0b21SXiaojian Du 	ret = vangogh_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_freq);
1051dd9e0b21SXiaojian Du 	if (ret)
1052dd9e0b21SXiaojian Du 		return ret;
1053dd9e0b21SXiaojian Du 
1054dd9e0b21SXiaojian Du 	ret = vangogh_set_soft_freq_limited_range(smu, SMU_SOCCLK, socclk_freq, socclk_freq);
1055dd9e0b21SXiaojian Du 	if (ret)
1056dd9e0b21SXiaojian Du 		return ret;
1057dd9e0b21SXiaojian Du 
1058dd9e0b21SXiaojian Du 	return ret;
1059dd9e0b21SXiaojian Du }
1060dd9e0b21SXiaojian Du 
1061ea173d15SXiaojian Du static int vangogh_set_performance_level(struct smu_context *smu,
1062ea173d15SXiaojian Du 					enum amd_dpm_forced_level level)
1063ea173d15SXiaojian Du {
1064ea173d15SXiaojian Du 	int ret = 0;
1065ea173d15SXiaojian Du 	uint32_t soc_mask, mclk_mask, fclk_mask;
1066ea173d15SXiaojian Du 
1067ea173d15SXiaojian Du 	switch (level) {
1068ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_HIGH:
1069ea173d15SXiaojian Du 		ret = vangogh_force_dpm_limit_value(smu, true);
1070ea173d15SXiaojian Du 		break;
1071ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_LOW:
1072ea173d15SXiaojian Du 		ret = vangogh_force_dpm_limit_value(smu, false);
1073ea173d15SXiaojian Du 		break;
1074ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_AUTO:
1075ea173d15SXiaojian Du 		ret = vangogh_unforce_dpm_levels(smu);
1076ea173d15SXiaojian Du 		break;
1077ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
1078ea173d15SXiaojian Du 		break;
1079ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
1080ea173d15SXiaojian Du 		break;
1081ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
1082ea173d15SXiaojian Du 		ret = vangogh_get_profiling_clk_mask(smu, level,
1083ea173d15SXiaojian Du 							NULL,
1084ea173d15SXiaojian Du 							NULL,
1085ea173d15SXiaojian Du 							&mclk_mask,
1086ea173d15SXiaojian Du 							&fclk_mask,
1087ea173d15SXiaojian Du 							&soc_mask);
1088ea173d15SXiaojian Du 		if (ret)
1089ea173d15SXiaojian Du 			return ret;
1090ea173d15SXiaojian Du 		vangogh_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask);
1091ea173d15SXiaojian Du 		vangogh_force_clk_levels(smu, SMU_FCLK, 1 << fclk_mask);
1092ea173d15SXiaojian Du 		vangogh_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask);
1093ea173d15SXiaojian Du 		break;
1094ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
1095ea173d15SXiaojian Du 		ret = vangogh_set_peak_clock_by_device(smu);
1096ea173d15SXiaojian Du 		break;
1097ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_MANUAL:
1098ea173d15SXiaojian Du 	case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
1099ea173d15SXiaojian Du 	default:
1100ea173d15SXiaojian Du 		break;
1101ea173d15SXiaojian Du 	}
1102ea173d15SXiaojian Du 	return ret;
1103ea173d15SXiaojian Du }
1104ea173d15SXiaojian Du 
1105271ab489SXiaojian Du static int vangogh_read_sensor(struct smu_context *smu,
1106271ab489SXiaojian Du 				 enum amd_pp_sensors sensor,
1107271ab489SXiaojian Du 				 void *data, uint32_t *size)
1108271ab489SXiaojian Du {
1109271ab489SXiaojian Du 	int ret = 0;
1110271ab489SXiaojian Du 
1111271ab489SXiaojian Du 	if (!data || !size)
1112271ab489SXiaojian Du 		return -EINVAL;
1113271ab489SXiaojian Du 
1114271ab489SXiaojian Du 	mutex_lock(&smu->sensor_lock);
1115271ab489SXiaojian Du 	switch (sensor) {
1116271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_GPU_LOAD:
11176cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
11186cc24d8dSAlex Deucher 						   METRICS_AVERAGE_GFXACTIVITY,
11196cc24d8dSAlex Deucher 						   (uint32_t *)data);
1120271ab489SXiaojian Du 		*size = 4;
1121271ab489SXiaojian Du 		break;
1122271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_GPU_POWER:
11236cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
11246cc24d8dSAlex Deucher 						   METRICS_AVERAGE_SOCKETPOWER,
11256cc24d8dSAlex Deucher 						   (uint32_t *)data);
1126271ab489SXiaojian Du 		*size = 4;
1127271ab489SXiaojian Du 		break;
1128271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_EDGE_TEMP:
11296cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
11306cc24d8dSAlex Deucher 						   METRICS_TEMPERATURE_EDGE,
11316cc24d8dSAlex Deucher 						   (uint32_t *)data);
11326cc24d8dSAlex Deucher 		*size = 4;
11336cc24d8dSAlex Deucher 		break;
1134271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
11356cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
11366cc24d8dSAlex Deucher 						   METRICS_TEMPERATURE_HOTSPOT,
11376cc24d8dSAlex Deucher 						   (uint32_t *)data);
1138271ab489SXiaojian Du 		*size = 4;
1139271ab489SXiaojian Du 		break;
1140271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_GFX_MCLK:
11416cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
11426cc24d8dSAlex Deucher 						   METRICS_AVERAGE_UCLK,
11436cc24d8dSAlex Deucher 						   (uint32_t *)data);
1144271ab489SXiaojian Du 		*(uint32_t *)data *= 100;
1145271ab489SXiaojian Du 		*size = 4;
1146271ab489SXiaojian Du 		break;
1147271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_GFX_SCLK:
11486cc24d8dSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
11496cc24d8dSAlex Deucher 						   METRICS_AVERAGE_GFXCLK,
11506cc24d8dSAlex Deucher 						   (uint32_t *)data);
1151271ab489SXiaojian Du 		*(uint32_t *)data *= 100;
1152271ab489SXiaojian Du 		*size = 4;
1153271ab489SXiaojian Du 		break;
1154271ab489SXiaojian Du 	case AMDGPU_PP_SENSOR_VDDGFX:
11552139d12bSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
11562139d12bSAlex Deucher 						   METRICS_VOLTAGE_VDDGFX,
11572139d12bSAlex Deucher 						   (uint32_t *)data);
11582139d12bSAlex Deucher 		*size = 4;
11592139d12bSAlex Deucher 		break;
11602139d12bSAlex Deucher 	case AMDGPU_PP_SENSOR_VDDNB:
11612139d12bSAlex Deucher 		ret = vangogh_get_smu_metrics_data(smu,
11622139d12bSAlex Deucher 						   METRICS_VOLTAGE_VDDSOC,
11632139d12bSAlex Deucher 						   (uint32_t *)data);
1164271ab489SXiaojian Du 		*size = 4;
1165271ab489SXiaojian Du 		break;
1166271ab489SXiaojian Du 	default:
1167271ab489SXiaojian Du 		ret = -EOPNOTSUPP;
1168271ab489SXiaojian Du 		break;
1169271ab489SXiaojian Du 	}
1170271ab489SXiaojian Du 	mutex_unlock(&smu->sensor_lock);
1171271ab489SXiaojian Du 
1172271ab489SXiaojian Du 	return ret;
1173271ab489SXiaojian Du }
1174271ab489SXiaojian Du 
1175271ab489SXiaojian Du static int vangogh_set_watermarks_table(struct smu_context *smu,
1176271ab489SXiaojian Du 				       struct pp_smu_wm_range_sets *clock_ranges)
1177271ab489SXiaojian Du {
1178271ab489SXiaojian Du 	int i;
1179271ab489SXiaojian Du 	int ret = 0;
1180271ab489SXiaojian Du 	Watermarks_t *table = smu->smu_table.watermarks_table;
1181271ab489SXiaojian Du 
1182271ab489SXiaojian Du 	if (!table || !clock_ranges)
1183271ab489SXiaojian Du 		return -EINVAL;
1184271ab489SXiaojian Du 
1185271ab489SXiaojian Du 	if (clock_ranges) {
1186271ab489SXiaojian Du 		if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES ||
1187271ab489SXiaojian Du 			clock_ranges->num_writer_wm_sets > NUM_WM_RANGES)
1188271ab489SXiaojian Du 			return -EINVAL;
1189271ab489SXiaojian Du 
1190271ab489SXiaojian Du 		for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) {
1191271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].MinClock =
1192271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].min_drain_clk_mhz;
1193271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].MaxClock =
1194271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].max_drain_clk_mhz;
1195271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].MinMclk =
1196271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].min_fill_clk_mhz;
1197271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].MaxMclk =
1198271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].max_fill_clk_mhz;
1199271ab489SXiaojian Du 
1200271ab489SXiaojian Du 			table->WatermarkRow[WM_DCFCLK][i].WmSetting =
1201271ab489SXiaojian Du 				clock_ranges->reader_wm_sets[i].wm_inst;
1202271ab489SXiaojian Du 		}
1203271ab489SXiaojian Du 
1204271ab489SXiaojian Du 		for (i = 0; i < clock_ranges->num_writer_wm_sets; i++) {
1205271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].MinClock =
1206271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].min_fill_clk_mhz;
1207271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].MaxClock =
1208271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].max_fill_clk_mhz;
1209271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].MinMclk =
1210271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].min_drain_clk_mhz;
1211271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].MaxMclk =
1212271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].max_drain_clk_mhz;
1213271ab489SXiaojian Du 
1214271ab489SXiaojian Du 			table->WatermarkRow[WM_SOCCLK][i].WmSetting =
1215271ab489SXiaojian Du 				clock_ranges->writer_wm_sets[i].wm_inst;
1216271ab489SXiaojian Du 		}
1217271ab489SXiaojian Du 
1218271ab489SXiaojian Du 		smu->watermarks_bitmap |= WATERMARKS_EXIST;
1219271ab489SXiaojian Du 	}
1220271ab489SXiaojian Du 
1221271ab489SXiaojian Du 	/* pass data to smu controller */
1222271ab489SXiaojian Du 	if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
1223271ab489SXiaojian Du 	     !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
1224271ab489SXiaojian Du 		ret = smu_cmn_write_watermarks_table(smu);
1225271ab489SXiaojian Du 		if (ret) {
1226271ab489SXiaojian Du 			dev_err(smu->adev->dev, "Failed to update WMTABLE!");
1227271ab489SXiaojian Du 			return ret;
1228271ab489SXiaojian Du 		}
1229271ab489SXiaojian Du 		smu->watermarks_bitmap |= WATERMARKS_LOADED;
1230271ab489SXiaojian Du 	}
1231271ab489SXiaojian Du 
1232271ab489SXiaojian Du 	return 0;
1233f46a221bSXiaojian Du }
1234f46a221bSXiaojian Du 
1235fd253334SXiaojian Du static ssize_t vangogh_get_gpu_metrics(struct smu_context *smu,
1236fd253334SXiaojian Du 				      void **table)
1237fd253334SXiaojian Du {
1238fd253334SXiaojian Du 	struct smu_table_context *smu_table = &smu->smu_table;
1239fd253334SXiaojian Du 	struct gpu_metrics_v2_0 *gpu_metrics =
1240fd253334SXiaojian Du 		(struct gpu_metrics_v2_0 *)smu_table->gpu_metrics_table;
1241fd253334SXiaojian Du 	SmuMetrics_t metrics;
1242fd253334SXiaojian Du 	int ret = 0;
1243fd253334SXiaojian Du 
1244fd253334SXiaojian Du 	ret = smu_cmn_get_metrics_table(smu, &metrics, true);
1245fd253334SXiaojian Du 	if (ret)
1246fd253334SXiaojian Du 		return ret;
1247fd253334SXiaojian Du 
1248fd253334SXiaojian Du 	smu_v11_0_init_gpu_metrics_v2_0(gpu_metrics);
1249fd253334SXiaojian Du 
1250fd253334SXiaojian Du 	gpu_metrics->temperature_gfx = metrics.GfxTemperature;
1251fd253334SXiaojian Du 	gpu_metrics->temperature_soc = metrics.SocTemperature;
1252fd253334SXiaojian Du 	memcpy(&gpu_metrics->temperature_core[0],
1253fd253334SXiaojian Du 		&metrics.CoreTemperature[0],
1254fd253334SXiaojian Du 		sizeof(uint16_t) * 8);
1255fd253334SXiaojian Du 	gpu_metrics->temperature_l3[0] = metrics.L3Temperature[0];
1256fd253334SXiaojian Du 	gpu_metrics->temperature_l3[1] = metrics.L3Temperature[1];
1257fd253334SXiaojian Du 
1258fd253334SXiaojian Du 	gpu_metrics->average_gfx_activity = metrics.GfxActivity;
1259fd253334SXiaojian Du 	gpu_metrics->average_mm_activity = metrics.UvdActivity;
1260fd253334SXiaojian Du 
1261fd253334SXiaojian Du 	gpu_metrics->average_socket_power = metrics.CurrentSocketPower;
1262fd253334SXiaojian Du 	gpu_metrics->average_cpu_power = metrics.Power[0];
1263fd253334SXiaojian Du 	gpu_metrics->average_soc_power = metrics.Power[1];
1264fd253334SXiaojian Du 	memcpy(&gpu_metrics->average_core_power[0],
1265fd253334SXiaojian Du 		&metrics.CorePower[0],
1266fd253334SXiaojian Du 		sizeof(uint16_t) * 8);
1267fd253334SXiaojian Du 
1268fd253334SXiaojian Du 	gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency;
1269fd253334SXiaojian Du 	gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency;
1270fd253334SXiaojian Du 	gpu_metrics->average_fclk_frequency = metrics.MemclkFrequency;
1271fd253334SXiaojian Du 	gpu_metrics->average_vclk_frequency = metrics.VclkFrequency;
1272fd253334SXiaojian Du 
1273fd253334SXiaojian Du 	memcpy(&gpu_metrics->current_coreclk[0],
1274fd253334SXiaojian Du 		&metrics.CoreFrequency[0],
1275fd253334SXiaojian Du 		sizeof(uint16_t) * 8);
1276fd253334SXiaojian Du 	gpu_metrics->current_l3clk[0] = metrics.L3Frequency[0];
1277fd253334SXiaojian Du 	gpu_metrics->current_l3clk[1] = metrics.L3Frequency[1];
1278fd253334SXiaojian Du 
1279fd253334SXiaojian Du 	gpu_metrics->throttle_status = metrics.ThrottlerStatus;
1280fd253334SXiaojian Du 
1281fd253334SXiaojian Du 	*table = (void *)gpu_metrics;
1282fd253334SXiaojian Du 
1283fd253334SXiaojian Du 	return sizeof(struct gpu_metrics_v2_0);
1284fd253334SXiaojian Du }
1285fd253334SXiaojian Du 
1286c98ee897SXiaojian Du static int vangogh_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type,
1287c98ee897SXiaojian Du 							long input[], uint32_t size)
1288c98ee897SXiaojian Du {
1289c98ee897SXiaojian Du 	int ret = 0;
1290c98ee897SXiaojian Du 
1291c98ee897SXiaojian Du 	if (!smu->od_enabled) {
1292c98ee897SXiaojian Du 		dev_warn(smu->adev->dev, "Fine grain is not enabled!\n");
1293c98ee897SXiaojian Du 		return -EINVAL;
1294c98ee897SXiaojian Du 	}
1295c98ee897SXiaojian Du 
1296c98ee897SXiaojian Du 	switch (type) {
1297c98ee897SXiaojian Du 	case PP_OD_EDIT_SCLK_VDDC_TABLE:
1298c98ee897SXiaojian Du 		if (size != 2) {
1299c98ee897SXiaojian Du 			dev_err(smu->adev->dev, "Input parameter number not correct\n");
1300c98ee897SXiaojian Du 			return -EINVAL;
1301c98ee897SXiaojian Du 		}
1302c98ee897SXiaojian Du 
1303c98ee897SXiaojian Du 		if (input[0] == 0) {
1304c98ee897SXiaojian Du 			if (input[1] < smu->gfx_default_hard_min_freq) {
130517863170SColin Ian King 				dev_warn(smu->adev->dev, "Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
1306c98ee897SXiaojian Du 					input[1], smu->gfx_default_hard_min_freq);
1307c98ee897SXiaojian Du 				return -EINVAL;
1308c98ee897SXiaojian Du 			}
1309c98ee897SXiaojian Du 			smu->gfx_actual_hard_min_freq = input[1];
1310c98ee897SXiaojian Du 		} else if (input[0] == 1) {
1311c98ee897SXiaojian Du 			if (input[1] > smu->gfx_default_soft_max_freq) {
131217863170SColin Ian King 				dev_warn(smu->adev->dev, "Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
1313c98ee897SXiaojian Du 					input[1], smu->gfx_default_soft_max_freq);
1314c98ee897SXiaojian Du 				return -EINVAL;
1315c98ee897SXiaojian Du 			}
1316c98ee897SXiaojian Du 			smu->gfx_actual_soft_max_freq = input[1];
1317c98ee897SXiaojian Du 		} else {
1318c98ee897SXiaojian Du 			return -EINVAL;
1319c98ee897SXiaojian Du 		}
1320c98ee897SXiaojian Du 		break;
1321c98ee897SXiaojian Du 	case PP_OD_RESTORE_DEFAULT_TABLE:
1322c98ee897SXiaojian Du 		if (size != 0) {
1323c98ee897SXiaojian Du 			dev_err(smu->adev->dev, "Input parameter number not correct\n");
1324c98ee897SXiaojian Du 			return -EINVAL;
1325c98ee897SXiaojian Du 		} else {
1326c98ee897SXiaojian Du 			smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
1327c98ee897SXiaojian Du 			smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
1328c98ee897SXiaojian Du 
1329c98ee897SXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
1330c98ee897SXiaojian Du 									smu->gfx_actual_hard_min_freq, NULL);
1331c98ee897SXiaojian Du 			if (ret) {
1332c98ee897SXiaojian Du 				dev_err(smu->adev->dev, "Restore the default hard min sclk failed!");
1333c98ee897SXiaojian Du 				return ret;
1334c98ee897SXiaojian Du 			}
1335c98ee897SXiaojian Du 
1336c98ee897SXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
1337c98ee897SXiaojian Du 									smu->gfx_actual_soft_max_freq, NULL);
1338c98ee897SXiaojian Du 			if (ret) {
1339c98ee897SXiaojian Du 				dev_err(smu->adev->dev, "Restore the default soft max sclk failed!");
1340c98ee897SXiaojian Du 				return ret;
1341c98ee897SXiaojian Du 			}
1342c98ee897SXiaojian Du 		}
1343c98ee897SXiaojian Du 		break;
1344c98ee897SXiaojian Du 	case PP_OD_COMMIT_DPM_TABLE:
1345c98ee897SXiaojian Du 		if (size != 0) {
1346c98ee897SXiaojian Du 			dev_err(smu->adev->dev, "Input parameter number not correct\n");
1347c98ee897SXiaojian Du 			return -EINVAL;
1348c98ee897SXiaojian Du 		} else {
1349c98ee897SXiaojian Du 			if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) {
1350c98ee897SXiaojian Du 				dev_err(smu->adev->dev, "The setting minimun sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n",
1351c98ee897SXiaojian Du 				smu->gfx_actual_hard_min_freq, smu->gfx_actual_soft_max_freq);
1352c98ee897SXiaojian Du 				return -EINVAL;
1353c98ee897SXiaojian Du 			}
1354c98ee897SXiaojian Du 
1355c98ee897SXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
1356c98ee897SXiaojian Du 									smu->gfx_actual_hard_min_freq, NULL);
1357c98ee897SXiaojian Du 			if (ret) {
1358c98ee897SXiaojian Du 				dev_err(smu->adev->dev, "Set hard min sclk failed!");
1359c98ee897SXiaojian Du 				return ret;
1360c98ee897SXiaojian Du 			}
1361c98ee897SXiaojian Du 
1362c98ee897SXiaojian Du 			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
1363c98ee897SXiaojian Du 									smu->gfx_actual_soft_max_freq, NULL);
1364c98ee897SXiaojian Du 			if (ret) {
1365c98ee897SXiaojian Du 				dev_err(smu->adev->dev, "Set soft max sclk failed!");
1366c98ee897SXiaojian Du 				return ret;
1367c98ee897SXiaojian Du 			}
1368c98ee897SXiaojian Du 		}
1369c98ee897SXiaojian Du 		break;
1370c98ee897SXiaojian Du 	default:
1371c98ee897SXiaojian Du 		return -ENOSYS;
1372c98ee897SXiaojian Du 	}
1373c98ee897SXiaojian Du 
1374c98ee897SXiaojian Du 	return ret;
1375c98ee897SXiaojian Du }
1376c98ee897SXiaojian Du 
1377fce8a4acSJinzhou Su static int vangogh_set_default_dpm_tables(struct smu_context *smu)
1378c98ee897SXiaojian Du {
1379c98ee897SXiaojian Du 	struct smu_table_context *smu_table = &smu->smu_table;
1380c98ee897SXiaojian Du 
1381c98ee897SXiaojian Du 	return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false);
1382c98ee897SXiaojian Du }
1383c98ee897SXiaojian Du 
1384c98ee897SXiaojian Du static int vangogh_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
1385c98ee897SXiaojian Du {
1386c98ee897SXiaojian Du 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
1387c98ee897SXiaojian Du 
1388c98ee897SXiaojian Du 	smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
1389c98ee897SXiaojian Du 	smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
1390c98ee897SXiaojian Du 	smu->gfx_actual_hard_min_freq = 0;
1391c98ee897SXiaojian Du 	smu->gfx_actual_soft_max_freq = 0;
1392c98ee897SXiaojian Du 
1393c98ee897SXiaojian Du 	return 0;
1394c98ee897SXiaojian Du }
1395c98ee897SXiaojian Du 
1396ae7b32e7SXiaojian Du static int vangogh_get_dpm_clock_table(struct smu_context *smu, struct dpm_clocks *clock_table)
1397ae7b32e7SXiaojian Du {
1398ae7b32e7SXiaojian Du 	DpmClocks_t *table = smu->smu_table.clocks_table;
1399ae7b32e7SXiaojian Du 	int i;
1400ae7b32e7SXiaojian Du 
1401ae7b32e7SXiaojian Du 	if (!clock_table || !table)
1402ae7b32e7SXiaojian Du 		return -EINVAL;
1403ae7b32e7SXiaojian Du 
1404ae7b32e7SXiaojian Du 	for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) {
1405ae7b32e7SXiaojian Du 		clock_table->SocClocks[i].Freq = table->SocClocks[i];
1406ae7b32e7SXiaojian Du 		clock_table->SocClocks[i].Vol = table->SocVoltage[i];
1407ae7b32e7SXiaojian Du 	}
1408ae7b32e7SXiaojian Du 
1409ae7b32e7SXiaojian Du 	for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
1410ae7b32e7SXiaojian Du 		clock_table->FClocks[i].Freq = table->DfPstateTable[i].fclk;
1411ae7b32e7SXiaojian Du 		clock_table->FClocks[i].Vol = table->DfPstateTable[i].voltage;
1412ae7b32e7SXiaojian Du 	}
1413ae7b32e7SXiaojian Du 
1414ae7b32e7SXiaojian Du 	for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
1415ae7b32e7SXiaojian Du 		clock_table->MemClocks[i].Freq = table->DfPstateTable[i].memclk;
1416ae7b32e7SXiaojian Du 		clock_table->MemClocks[i].Vol = table->DfPstateTable[i].voltage;
1417ae7b32e7SXiaojian Du 	}
1418ae7b32e7SXiaojian Du 
1419ae7b32e7SXiaojian Du 	return 0;
1420ae7b32e7SXiaojian Du }
1421ae7b32e7SXiaojian Du 
1422ae7b32e7SXiaojian Du 
1423a0f55287SXiaomeng Hou static int vangogh_system_features_control(struct smu_context *smu, bool en)
1424a0f55287SXiaomeng Hou {
14259e3a6ab7SXiaomeng Hou 	struct amdgpu_device *adev = smu->adev;
14269e3a6ab7SXiaomeng Hou 
14279e3a6ab7SXiaomeng Hou 	if (adev->pm.fw_version >= 0x43f1700)
1428a0f55287SXiaomeng Hou 		return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_RlcPowerNotify,
1429a0f55287SXiaomeng Hou 						en ? RLC_STATUS_NORMAL : RLC_STATUS_OFF, NULL);
14309e3a6ab7SXiaomeng Hou 	else
14319e3a6ab7SXiaomeng Hou 		return 0;
1432a0f55287SXiaomeng Hou }
1433a0f55287SXiaomeng Hou 
1434eefdf047SJinzhou Su static int vangogh_post_smu_init(struct smu_context *smu)
1435eefdf047SJinzhou Su {
1436eefdf047SJinzhou Su 	struct amdgpu_device *adev = smu->adev;
1437eefdf047SJinzhou Su 	uint32_t tmp;
1438eefdf047SJinzhou Su 	uint8_t aon_bits = 0;
1439eefdf047SJinzhou Su 	/* Two CUs in one WGP */
1440eefdf047SJinzhou Su 	uint32_t req_active_wgps = adev->gfx.cu_info.number/2;
1441eefdf047SJinzhou Su 	uint32_t total_cu = adev->gfx.config.max_cu_per_sh *
1442eefdf047SJinzhou Su 		adev->gfx.config.max_sh_per_se * adev->gfx.config.max_shader_engines;
1443eefdf047SJinzhou Su 
1444eefdf047SJinzhou Su 	/* if all CUs are active, no need to power off any WGPs */
1445eefdf047SJinzhou Su 	if (total_cu == adev->gfx.cu_info.number)
1446eefdf047SJinzhou Su 		return 0;
1447eefdf047SJinzhou Su 
1448eefdf047SJinzhou Su 	/*
1449eefdf047SJinzhou Su 	 * Calculate the total bits number of always on WGPs for all SA/SEs in
1450eefdf047SJinzhou Su 	 * RLC_PG_ALWAYS_ON_WGP_MASK.
1451eefdf047SJinzhou Su 	 */
1452eefdf047SJinzhou Su 	tmp = RREG32_KIQ(SOC15_REG_OFFSET(GC, 0, mmRLC_PG_ALWAYS_ON_WGP_MASK));
1453eefdf047SJinzhou Su 	tmp &= RLC_PG_ALWAYS_ON_WGP_MASK__AON_WGP_MASK_MASK;
1454eefdf047SJinzhou Su 
1455eefdf047SJinzhou Su 	aon_bits = hweight32(tmp) * adev->gfx.config.max_sh_per_se * adev->gfx.config.max_shader_engines;
1456eefdf047SJinzhou Su 
1457eefdf047SJinzhou Su 	/* Do not request any WGPs less than set in the AON_WGP_MASK */
1458eefdf047SJinzhou Su 	if (aon_bits > req_active_wgps) {
1459eefdf047SJinzhou Su 		dev_info(adev->dev, "Number of always on WGPs greater than active WGPs: WGP power save not requested.\n");
1460eefdf047SJinzhou Su 		return 0;
1461eefdf047SJinzhou Su 	} else {
1462eefdf047SJinzhou Su 		return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_RequestActiveWgp, req_active_wgps, NULL);
1463eefdf047SJinzhou Su 	}
1464eefdf047SJinzhou Su }
1465eefdf047SJinzhou Su 
1466f46a221bSXiaojian Du static const struct pptable_funcs vangogh_ppt_funcs = {
1467271ab489SXiaojian Du 
1468f46a221bSXiaojian Du 	.check_fw_status = smu_v11_0_check_fw_status,
1469f46a221bSXiaojian Du 	.check_fw_version = smu_v11_0_check_fw_version,
1470f46a221bSXiaojian Du 	.init_smc_tables = vangogh_init_smc_tables,
1471f46a221bSXiaojian Du 	.fini_smc_tables = smu_v11_0_fini_smc_tables,
1472f46a221bSXiaojian Du 	.init_power = smu_v11_0_init_power,
1473f46a221bSXiaojian Du 	.fini_power = smu_v11_0_fini_power,
1474f46a221bSXiaojian Du 	.register_irq_handler = smu_v11_0_register_irq_handler,
1475f46a221bSXiaojian Du 	.get_allowed_feature_mask = vangogh_get_allowed_feature_mask,
1476f46a221bSXiaojian Du 	.notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
1477f46a221bSXiaojian Du 	.send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
1478f46a221bSXiaojian Du 	.send_smc_msg = smu_cmn_send_smc_msg,
1479271ab489SXiaojian Du 	.dpm_set_vcn_enable = vangogh_dpm_set_vcn_enable,
1480271ab489SXiaojian Du 	.dpm_set_jpeg_enable = vangogh_dpm_set_jpeg_enable,
1481f46a221bSXiaojian Du 	.is_dpm_running = vangogh_is_dpm_running,
1482271ab489SXiaojian Du 	.read_sensor = vangogh_read_sensor,
1483271ab489SXiaojian Du 	.get_enabled_mask = smu_cmn_get_enabled_32_bits_mask,
1484f46a221bSXiaojian Du 	.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
1485271ab489SXiaojian Du 	.set_watermarks_table = vangogh_set_watermarks_table,
1486271ab489SXiaojian Du 	.set_driver_table_location = smu_v11_0_set_driver_table_location,
1487f46a221bSXiaojian Du 	.interrupt_work = smu_v11_0_interrupt_work,
1488fd253334SXiaojian Du 	.get_gpu_metrics = vangogh_get_gpu_metrics,
1489c98ee897SXiaojian Du 	.od_edit_dpm_table = vangogh_od_edit_dpm_table,
1490c98ee897SXiaojian Du 	.print_clk_levels = vangogh_print_fine_grain_clk,
1491c98ee897SXiaojian Du 	.set_default_dpm_table = vangogh_set_default_dpm_tables,
1492c98ee897SXiaojian Du 	.set_fine_grain_gfx_freq_parameters = vangogh_set_fine_grain_gfx_freq_parameters,
1493a0f55287SXiaomeng Hou 	.system_features_control = vangogh_system_features_control,
1494d0e4e112SXiaojian Du 	.feature_is_enabled = smu_cmn_feature_is_enabled,
1495d0e4e112SXiaojian Du 	.set_power_profile_mode = vangogh_set_power_profile_mode,
1496ae7b32e7SXiaojian Du 	.get_dpm_clock_table = vangogh_get_dpm_clock_table,
1497dd9e0b21SXiaojian Du 	.force_clk_levels = vangogh_force_clk_levels,
1498ea173d15SXiaojian Du 	.set_performance_level = vangogh_set_performance_level,
1499eefdf047SJinzhou Su 	.post_init = vangogh_post_smu_init,
1500f46a221bSXiaojian Du };
1501f46a221bSXiaojian Du 
1502f46a221bSXiaojian Du void vangogh_set_ppt_funcs(struct smu_context *smu)
1503f46a221bSXiaojian Du {
1504f46a221bSXiaojian Du 	smu->ppt_funcs = &vangogh_ppt_funcs;
1505f46a221bSXiaojian Du 	smu->message_map = vangogh_message_map;
1506f46a221bSXiaojian Du 	smu->feature_map = vangogh_feature_mask_map;
1507f46a221bSXiaojian Du 	smu->table_map = vangogh_table_map;
1508f46a221bSXiaojian Du 	smu->is_apu = true;
1509f46a221bSXiaojian Du }
1510