1/*
2 * Copyright 2020 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 */
23
24#define SWSMU_CODE_LAYER_L2
25
26#include "amdgpu.h"
27#include "amdgpu_smu.h"
28#include "smu_v13_0.h"
29#include "smu13_driver_if_yellow_carp.h"
30#include "yellow_carp_ppt.h"
31#include "smu_v13_0_1_ppsmc.h"
32#include "smu_v13_0_1_pmfw.h"
33#include "smu_cmn.h"
34
35/*
36 * DO NOT use these for err/warn/info/debug messages.
37 * Use dev_err, dev_warn, dev_info and dev_dbg instead.
38 * They are more MGPU friendly.
39 */
40#undef pr_err
41#undef pr_warn
42#undef pr_info
43#undef pr_debug
44
45#define regSMUIO_GFX_MISC_CNTL  						0x00c5
46#define regSMUIO_GFX_MISC_CNTL_BASE_IDX					0
47#define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK		0x00000006L
48#define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT          0x1L
49
50#define SMU_13_0_8_UMD_PSTATE_GFXCLK                   533
51#define SMU_13_0_8_UMD_PSTATE_SOCCLK                   533
52#define SMU_13_0_8_UMD_PSTATE_FCLK                     800
53
54#define SMU_13_0_1_UMD_PSTATE_GFXCLK					700
55#define SMU_13_0_1_UMD_PSTATE_SOCCLK		              678
56#define SMU_13_0_1_UMD_PSTATE_FCLK			          1800
57
58#define FEATURE_MASK(feature) (1ULL << feature)
59#define SMC_DPM_FEATURE ( \
60	FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \
61	FEATURE_MASK(FEATURE_VCN_DPM_BIT)	 | \
62	FEATURE_MASK(FEATURE_FCLK_DPM_BIT)	 | \
63	FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT)	 | \
64	FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT)	 | \
65	FEATURE_MASK(FEATURE_LCLK_DPM_BIT)	 | \
66	FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT)	 | \
67	FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \
68	FEATURE_MASK(FEATURE_GFX_DPM_BIT))
69
70static struct cmn2asic_msg_mapping yellow_carp_message_map[SMU_MSG_MAX_COUNT] = {
71	MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,			1),
72	MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion,		1),
73	MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion,		1),
74	MSG_MAP(EnableGfxOff,                   PPSMC_MSG_EnableGfxOff,			1),
75	MSG_MAP(AllowGfxOff,                    PPSMC_MSG_AllowGfxOff,			1),
76	MSG_MAP(DisallowGfxOff,                 PPSMC_MSG_DisallowGfxOff,		1),
77	MSG_MAP(PowerDownVcn,                   PPSMC_MSG_PowerDownVcn,			1),
78	MSG_MAP(PowerUpVcn,                     PPSMC_MSG_PowerUpVcn,			1),
79	MSG_MAP(SetHardMinVcn,                  PPSMC_MSG_SetHardMinVcn,		1),
80	MSG_MAP(PrepareMp1ForUnload,            PPSMC_MSG_PrepareMp1ForUnload,      1),
81	MSG_MAP(SetDriverDramAddrHigh,          PPSMC_MSG_SetDriverDramAddrHigh,	1),
82	MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverDramAddrLow,		1),
83	MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram,	1),
84	MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu,	1),
85	MSG_MAP(GfxDeviceDriverReset,           PPSMC_MSG_GfxDeviceDriverReset,		1),
86	MSG_MAP(GetEnabledSmuFeatures,          PPSMC_MSG_GetEnabledSmuFeatures,	1),
87	MSG_MAP(SetHardMinSocclkByFreq,         PPSMC_MSG_SetHardMinSocclkByFreq,	1),
88	MSG_MAP(SetSoftMinVcn,                  PPSMC_MSG_SetSoftMinVcn,		1),
89	MSG_MAP(GetGfxclkFrequency,             PPSMC_MSG_GetGfxclkFrequency,		1),
90	MSG_MAP(GetFclkFrequency,               PPSMC_MSG_GetFclkFrequency,		1),
91	MSG_MAP(SetSoftMaxGfxClk,               PPSMC_MSG_SetSoftMaxGfxClk,		1),
92	MSG_MAP(SetHardMinGfxClk,               PPSMC_MSG_SetHardMinGfxClk,		1),
93	MSG_MAP(SetSoftMaxSocclkByFreq,         PPSMC_MSG_SetSoftMaxSocclkByFreq,	1),
94	MSG_MAP(SetSoftMaxFclkByFreq,           PPSMC_MSG_SetSoftMaxFclkByFreq,		1),
95	MSG_MAP(SetSoftMaxVcn,                  PPSMC_MSG_SetSoftMaxVcn,		1),
96	MSG_MAP(SetPowerLimitPercentage,        PPSMC_MSG_SetPowerLimitPercentage,	1),
97	MSG_MAP(PowerDownJpeg,                  PPSMC_MSG_PowerDownJpeg,		1),
98	MSG_MAP(PowerUpJpeg,                    PPSMC_MSG_PowerUpJpeg,			1),
99	MSG_MAP(SetHardMinFclkByFreq,           PPSMC_MSG_SetHardMinFclkByFreq,		1),
100	MSG_MAP(SetSoftMinSocclkByFreq,         PPSMC_MSG_SetSoftMinSocclkByFreq,	1),
101};
102
103static struct cmn2asic_mapping yellow_carp_feature_mask_map[SMU_FEATURE_COUNT] = {
104	FEA_MAP(CCLK_DPM),
105	FEA_MAP(FAN_CONTROLLER),
106	FEA_MAP(PPT),
107	FEA_MAP(TDC),
108	FEA_MAP(THERMAL),
109	FEA_MAP(ULV),
110	FEA_MAP(VCN_DPM),
111	FEA_MAP_REVERSE(FCLK),
112	FEA_MAP_REVERSE(SOCCLK),
113	FEA_MAP(LCLK_DPM),
114	FEA_MAP(SHUBCLK_DPM),
115	FEA_MAP(DCFCLK_DPM),
116	FEA_MAP_HALF_REVERSE(GFX),
117	FEA_MAP(DS_GFXCLK),
118	FEA_MAP(DS_SOCCLK),
119	FEA_MAP(DS_LCLK),
120	FEA_MAP(DS_DCFCLK),
121	FEA_MAP(DS_FCLK),
122	FEA_MAP(DS_MP1CLK),
123	FEA_MAP(DS_MP0CLK),
124	FEA_MAP(GFX_DEM),
125	FEA_MAP(PSI),
126	FEA_MAP(PROCHOT),
127	FEA_MAP(CPUOFF),
128	FEA_MAP(STAPM),
129	FEA_MAP(S0I3),
130	FEA_MAP(PERF_LIMIT),
131	FEA_MAP(CORE_DLDO),
132	FEA_MAP(RSMU_LOW_POWER),
133	FEA_MAP(SMN_LOW_POWER),
134	FEA_MAP(THM_LOW_POWER),
135	FEA_MAP(SMUIO_LOW_POWER),
136	FEA_MAP(MP1_LOW_POWER),
137	FEA_MAP(DS_VCN),
138	FEA_MAP(CPPC),
139	FEA_MAP(DF_CSTATES),
140	FEA_MAP(MSMU_LOW_POWER),
141	FEA_MAP(ATHUB_PG),
142};
143
144static struct cmn2asic_mapping yellow_carp_table_map[SMU_TABLE_COUNT] = {
145	TAB_MAP_VALID(WATERMARKS),
146	TAB_MAP_VALID(SMU_METRICS),
147	TAB_MAP_VALID(CUSTOM_DPM),
148	TAB_MAP_VALID(DPMCLOCKS),
149};
150
151static int yellow_carp_init_smc_tables(struct smu_context *smu)
152{
153	struct smu_table_context *smu_table = &smu->smu_table;
154	struct smu_table *tables = smu_table->tables;
155
156	SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
157		PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
158	SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
159		PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
160	SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
161		PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
162
163	smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
164	if (!smu_table->clocks_table)
165		goto err0_out;
166
167	smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
168	if (!smu_table->metrics_table)
169		goto err1_out;
170	smu_table->metrics_time = 0;
171
172	smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
173	if (!smu_table->watermarks_table)
174		goto err2_out;
175
176	smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_1);
177	smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
178	if (!smu_table->gpu_metrics_table)
179		goto err3_out;
180
181	return 0;
182
183err3_out:
184	kfree(smu_table->watermarks_table);
185err2_out:
186	kfree(smu_table->metrics_table);
187err1_out:
188	kfree(smu_table->clocks_table);
189err0_out:
190	return -ENOMEM;
191}
192
193static int yellow_carp_fini_smc_tables(struct smu_context *smu)
194{
195	struct smu_table_context *smu_table = &smu->smu_table;
196
197	kfree(smu_table->clocks_table);
198	smu_table->clocks_table = NULL;
199
200	kfree(smu_table->metrics_table);
201	smu_table->metrics_table = NULL;
202
203	kfree(smu_table->watermarks_table);
204	smu_table->watermarks_table = NULL;
205
206	kfree(smu_table->gpu_metrics_table);
207	smu_table->gpu_metrics_table = NULL;
208
209	return 0;
210}
211
212static int yellow_carp_system_features_control(struct smu_context *smu, bool en)
213{
214	struct amdgpu_device *adev = smu->adev;
215	int ret = 0;
216
217	if (!en && !adev->in_s0ix)
218		ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL);
219
220	return ret;
221}
222
223static int yellow_carp_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
224{
225	int ret = 0;
226
227	/* vcn dpm on is a prerequisite for vcn power gate messages */
228	if (enable)
229		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn,
230						      0, NULL);
231	else
232		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn,
233						      0, NULL);
234
235	return ret;
236}
237
238static int yellow_carp_dpm_set_jpeg_enable(struct smu_context *smu, bool enable)
239{
240	int ret = 0;
241
242	if (enable)
243		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg,
244						      0, NULL);
245	else
246		ret = smu_cmn_send_smc_msg_with_param(smu,
247						      SMU_MSG_PowerDownJpeg, 0,
248						      NULL);
249
250	return ret;
251}
252
253
254static bool yellow_carp_is_dpm_running(struct smu_context *smu)
255{
256	int ret = 0;
257	uint64_t feature_enabled;
258
259	ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
260
261	if (ret)
262		return false;
263
264	return !!(feature_enabled & SMC_DPM_FEATURE);
265}
266
267static int yellow_carp_post_smu_init(struct smu_context *smu)
268{
269	struct amdgpu_device *adev = smu->adev;
270	int ret = 0;
271
272	/* allow message will be sent after enable message on Yellow Carp*/
273	ret = smu_cmn_send_smc_msg(smu, SMU_MSG_EnableGfxOff, NULL);
274	if (ret)
275		dev_err(adev->dev, "Failed to Enable GfxOff!\n");
276	return ret;
277}
278
279static int yellow_carp_mode_reset(struct smu_context *smu, int type)
280{
281	int ret = 0;
282
283	ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, type, NULL);
284	if (ret)
285		dev_err(smu->adev->dev, "Failed to mode reset!\n");
286
287	return ret;
288}
289
290static int yellow_carp_mode2_reset(struct smu_context *smu)
291{
292	return yellow_carp_mode_reset(smu, SMU_RESET_MODE_2);
293}
294
295
296static void yellow_carp_get_ss_power_percent(SmuMetrics_t *metrics,
297					uint32_t *apu_percent, uint32_t *dgpu_percent)
298{
299	uint32_t apu_boost = 0;
300	uint32_t dgpu_boost = 0;
301	uint16_t apu_limit = 0;
302	uint16_t dgpu_limit = 0;
303	uint16_t apu_power = 0;
304	uint16_t dgpu_power = 0;
305
306	/* APU and dGPU power values are reported in milli Watts
307	 * and STAPM power limits are in Watts */
308	apu_power = metrics->ApuPower/1000;
309	apu_limit = metrics->StapmOpnLimit;
310	if (apu_power > apu_limit && apu_limit != 0)
311		apu_boost =  ((apu_power - apu_limit) * 100) / apu_limit;
312	apu_boost = (apu_boost > 100) ? 100 : apu_boost;
313
314	dgpu_power = metrics->dGpuPower/1000;
315	if (metrics->StapmCurrentLimit > metrics->StapmOpnLimit)
316		dgpu_limit = metrics->StapmCurrentLimit - metrics->StapmOpnLimit;
317	if (dgpu_power > dgpu_limit && dgpu_limit != 0)
318		dgpu_boost = ((dgpu_power - dgpu_limit) * 100) / dgpu_limit;
319	dgpu_boost = (dgpu_boost > 100) ? 100 : dgpu_boost;
320
321	if (dgpu_boost >= apu_boost)
322		apu_boost = 0;
323	else
324		dgpu_boost = 0;
325
326	*apu_percent = apu_boost;
327	*dgpu_percent = dgpu_boost;
328
329}
330
331static int yellow_carp_get_smu_metrics_data(struct smu_context *smu,
332							MetricsMember_t member,
333							uint32_t *value)
334{
335	struct smu_table_context *smu_table = &smu->smu_table;
336
337	SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
338	int ret = 0;
339	uint32_t apu_percent = 0;
340	uint32_t dgpu_percent = 0;
341
342	ret = smu_cmn_get_metrics_table(smu, NULL, false);
343	if (ret)
344		return ret;
345
346	switch (member) {
347	case METRICS_AVERAGE_GFXCLK:
348		*value = metrics->GfxclkFrequency;
349		break;
350	case METRICS_AVERAGE_SOCCLK:
351		*value = metrics->SocclkFrequency;
352		break;
353	case METRICS_AVERAGE_VCLK:
354		*value = metrics->VclkFrequency;
355		break;
356	case METRICS_AVERAGE_DCLK:
357		*value = metrics->DclkFrequency;
358		break;
359	case METRICS_AVERAGE_UCLK:
360		*value = metrics->MemclkFrequency;
361		break;
362	case METRICS_AVERAGE_GFXACTIVITY:
363		*value = metrics->GfxActivity / 100;
364		break;
365	case METRICS_AVERAGE_VCNACTIVITY:
366		*value = metrics->UvdActivity;
367		break;
368	case METRICS_CURR_SOCKETPOWER:
369		*value = (metrics->CurrentSocketPower << 8) / 1000;
370		break;
371	case METRICS_TEMPERATURE_EDGE:
372		*value = metrics->GfxTemperature / 100 *
373		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
374		break;
375	case METRICS_TEMPERATURE_HOTSPOT:
376		*value = metrics->SocTemperature / 100 *
377		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
378		break;
379	case METRICS_THROTTLER_STATUS:
380		*value = metrics->ThrottlerStatus;
381		break;
382	case METRICS_VOLTAGE_VDDGFX:
383		*value = metrics->Voltage[0];
384		break;
385	case METRICS_VOLTAGE_VDDSOC:
386		*value = metrics->Voltage[1];
387		break;
388	case METRICS_SS_APU_SHARE:
389		/* return the percentage of APU power boost
390		 * with respect to APU's power limit.
391		 */
392		yellow_carp_get_ss_power_percent(metrics, &apu_percent, &dgpu_percent);
393		*value = apu_percent;
394		break;
395	case METRICS_SS_DGPU_SHARE:
396		/* return the percentage of dGPU power boost
397		 * with respect to dGPU's power limit.
398		 */
399		yellow_carp_get_ss_power_percent(metrics, &apu_percent, &dgpu_percent);
400		*value = dgpu_percent;
401		break;
402	default:
403		*value = UINT_MAX;
404		break;
405	}
406
407	return ret;
408}
409
410static int yellow_carp_read_sensor(struct smu_context *smu,
411					enum amd_pp_sensors sensor,
412					void *data, uint32_t *size)
413{
414	int ret = 0;
415
416	if (!data || !size)
417		return -EINVAL;
418
419	switch (sensor) {
420	case AMDGPU_PP_SENSOR_GPU_LOAD:
421		ret = yellow_carp_get_smu_metrics_data(smu,
422								METRICS_AVERAGE_GFXACTIVITY,
423								(uint32_t *)data);
424		*size = 4;
425		break;
426	case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
427		ret = yellow_carp_get_smu_metrics_data(smu,
428								METRICS_CURR_SOCKETPOWER,
429								(uint32_t *)data);
430		*size = 4;
431		break;
432	case AMDGPU_PP_SENSOR_EDGE_TEMP:
433		ret = yellow_carp_get_smu_metrics_data(smu,
434								METRICS_TEMPERATURE_EDGE,
435								(uint32_t *)data);
436		*size = 4;
437		break;
438	case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
439		ret = yellow_carp_get_smu_metrics_data(smu,
440								METRICS_TEMPERATURE_HOTSPOT,
441								(uint32_t *)data);
442		*size = 4;
443		break;
444	case AMDGPU_PP_SENSOR_GFX_MCLK:
445		ret = yellow_carp_get_smu_metrics_data(smu,
446								METRICS_AVERAGE_UCLK,
447								(uint32_t *)data);
448		*(uint32_t *)data *= 100;
449		*size = 4;
450		break;
451	case AMDGPU_PP_SENSOR_GFX_SCLK:
452		ret = yellow_carp_get_smu_metrics_data(smu,
453								METRICS_AVERAGE_GFXCLK,
454								(uint32_t *)data);
455		*(uint32_t *)data *= 100;
456		*size = 4;
457		break;
458	case AMDGPU_PP_SENSOR_VDDGFX:
459		ret = yellow_carp_get_smu_metrics_data(smu,
460								METRICS_VOLTAGE_VDDGFX,
461								(uint32_t *)data);
462		*size = 4;
463		break;
464	case AMDGPU_PP_SENSOR_VDDNB:
465		ret = yellow_carp_get_smu_metrics_data(smu,
466								METRICS_VOLTAGE_VDDSOC,
467								(uint32_t *)data);
468		*size = 4;
469		break;
470	case AMDGPU_PP_SENSOR_SS_APU_SHARE:
471		ret = yellow_carp_get_smu_metrics_data(smu,
472						       METRICS_SS_APU_SHARE,
473						       (uint32_t *)data);
474		*size = 4;
475		break;
476	case AMDGPU_PP_SENSOR_SS_DGPU_SHARE:
477		ret = yellow_carp_get_smu_metrics_data(smu,
478						       METRICS_SS_DGPU_SHARE,
479						       (uint32_t *)data);
480		*size = 4;
481		break;
482	case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
483	default:
484		ret = -EOPNOTSUPP;
485		break;
486	}
487
488	return ret;
489}
490
491static int yellow_carp_set_watermarks_table(struct smu_context *smu,
492				struct pp_smu_wm_range_sets *clock_ranges)
493{
494	int i;
495	int ret = 0;
496	Watermarks_t *table = smu->smu_table.watermarks_table;
497
498	if (!table || !clock_ranges)
499		return -EINVAL;
500
501	if (clock_ranges) {
502		if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES ||
503			clock_ranges->num_writer_wm_sets > NUM_WM_RANGES)
504			return -EINVAL;
505
506		for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) {
507			table->WatermarkRow[WM_DCFCLK][i].MinClock =
508				clock_ranges->reader_wm_sets[i].min_drain_clk_mhz;
509			table->WatermarkRow[WM_DCFCLK][i].MaxClock =
510				clock_ranges->reader_wm_sets[i].max_drain_clk_mhz;
511			table->WatermarkRow[WM_DCFCLK][i].MinMclk =
512				clock_ranges->reader_wm_sets[i].min_fill_clk_mhz;
513			table->WatermarkRow[WM_DCFCLK][i].MaxMclk =
514				clock_ranges->reader_wm_sets[i].max_fill_clk_mhz;
515
516			table->WatermarkRow[WM_DCFCLK][i].WmSetting =
517				clock_ranges->reader_wm_sets[i].wm_inst;
518		}
519
520		for (i = 0; i < clock_ranges->num_writer_wm_sets; i++) {
521			table->WatermarkRow[WM_SOCCLK][i].MinClock =
522				clock_ranges->writer_wm_sets[i].min_fill_clk_mhz;
523			table->WatermarkRow[WM_SOCCLK][i].MaxClock =
524				clock_ranges->writer_wm_sets[i].max_fill_clk_mhz;
525			table->WatermarkRow[WM_SOCCLK][i].MinMclk =
526				clock_ranges->writer_wm_sets[i].min_drain_clk_mhz;
527			table->WatermarkRow[WM_SOCCLK][i].MaxMclk =
528				clock_ranges->writer_wm_sets[i].max_drain_clk_mhz;
529
530			table->WatermarkRow[WM_SOCCLK][i].WmSetting =
531				clock_ranges->writer_wm_sets[i].wm_inst;
532		}
533
534		smu->watermarks_bitmap |= WATERMARKS_EXIST;
535	}
536
537	/* pass data to smu controller */
538	if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
539	     !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
540		ret = smu_cmn_write_watermarks_table(smu);
541		if (ret) {
542			dev_err(smu->adev->dev, "Failed to update WMTABLE!");
543			return ret;
544		}
545		smu->watermarks_bitmap |= WATERMARKS_LOADED;
546	}
547
548	return 0;
549}
550
551static ssize_t yellow_carp_get_gpu_metrics(struct smu_context *smu,
552						void **table)
553{
554	struct smu_table_context *smu_table = &smu->smu_table;
555	struct gpu_metrics_v2_1 *gpu_metrics =
556		(struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table;
557	SmuMetrics_t metrics;
558	int ret = 0;
559
560	ret = smu_cmn_get_metrics_table(smu, &metrics, true);
561	if (ret)
562		return ret;
563
564	smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 1);
565
566	gpu_metrics->temperature_gfx = metrics.GfxTemperature;
567	gpu_metrics->temperature_soc = metrics.SocTemperature;
568	memcpy(&gpu_metrics->temperature_core[0],
569		&metrics.CoreTemperature[0],
570		sizeof(uint16_t) * 8);
571	gpu_metrics->temperature_l3[0] = metrics.L3Temperature;
572
573	gpu_metrics->average_gfx_activity = metrics.GfxActivity;
574	gpu_metrics->average_mm_activity = metrics.UvdActivity;
575
576	gpu_metrics->average_socket_power = metrics.CurrentSocketPower;
577	gpu_metrics->average_gfx_power = metrics.Power[0];
578	gpu_metrics->average_soc_power = metrics.Power[1];
579	memcpy(&gpu_metrics->average_core_power[0],
580		&metrics.CorePower[0],
581		sizeof(uint16_t) * 8);
582
583	gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency;
584	gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency;
585	gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency;
586	gpu_metrics->average_fclk_frequency = metrics.MemclkFrequency;
587	gpu_metrics->average_vclk_frequency = metrics.VclkFrequency;
588	gpu_metrics->average_dclk_frequency = metrics.DclkFrequency;
589
590	memcpy(&gpu_metrics->current_coreclk[0],
591		&metrics.CoreFrequency[0],
592		sizeof(uint16_t) * 8);
593	gpu_metrics->current_l3clk[0] = metrics.L3Frequency;
594
595	gpu_metrics->throttle_status = metrics.ThrottlerStatus;
596
597	gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
598
599	*table = (void *)gpu_metrics;
600
601	return sizeof(struct gpu_metrics_v2_1);
602}
603
604/**
605 * yellow_carp_get_gfxoff_status - get gfxoff status
606 *
607 * @smu: smu_context pointer
608 *
609 * This function will be used to get gfxoff status
610 *
611 * Returns 0=GFXOFF(default).
612 * Returns 1=Transition out of GFX State.
613 * Returns 2=Not in GFXOFF.
614 * Returns 3=Transition into GFXOFF.
615 */
616static uint32_t yellow_carp_get_gfxoff_status(struct smu_context *smu)
617{
618	uint32_t reg;
619	uint32_t gfxoff_status = 0;
620	struct amdgpu_device *adev = smu->adev;
621
622	reg = RREG32_SOC15(SMUIO, 0, regSMUIO_GFX_MISC_CNTL);
623	gfxoff_status = (reg & SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK)
624		>> SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT;
625
626	return gfxoff_status;
627}
628
629static int yellow_carp_set_default_dpm_tables(struct smu_context *smu)
630{
631	struct smu_table_context *smu_table = &smu->smu_table;
632
633	return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false);
634}
635
636static int yellow_carp_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type,
637					long input[], uint32_t size)
638{
639	struct smu_dpm_context *smu_dpm = &(smu->smu_dpm);
640	int ret = 0;
641
642	/* Only allowed in manual mode */
643	if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
644		return -EINVAL;
645
646	switch (type) {
647	case PP_OD_EDIT_SCLK_VDDC_TABLE:
648		if (size != 2) {
649			dev_err(smu->adev->dev, "Input parameter number not correct\n");
650			return -EINVAL;
651		}
652
653		if (input[0] == 0) {
654			if (input[1] < smu->gfx_default_hard_min_freq) {
655				dev_warn(smu->adev->dev,
656					"Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
657					input[1], smu->gfx_default_hard_min_freq);
658				return -EINVAL;
659			}
660			smu->gfx_actual_hard_min_freq = input[1];
661		} else if (input[0] == 1) {
662			if (input[1] > smu->gfx_default_soft_max_freq) {
663				dev_warn(smu->adev->dev,
664					"Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
665					input[1], smu->gfx_default_soft_max_freq);
666				return -EINVAL;
667			}
668			smu->gfx_actual_soft_max_freq = input[1];
669		} else {
670			return -EINVAL;
671		}
672		break;
673	case PP_OD_RESTORE_DEFAULT_TABLE:
674		if (size != 0) {
675			dev_err(smu->adev->dev, "Input parameter number not correct\n");
676			return -EINVAL;
677		} else {
678			smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
679			smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
680		}
681		break;
682	case PP_OD_COMMIT_DPM_TABLE:
683		if (size != 0) {
684			dev_err(smu->adev->dev, "Input parameter number not correct\n");
685			return -EINVAL;
686		} else {
687			if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) {
688				dev_err(smu->adev->dev,
689					"The setting minimum sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n",
690					smu->gfx_actual_hard_min_freq,
691					smu->gfx_actual_soft_max_freq);
692				return -EINVAL;
693			}
694
695			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
696									smu->gfx_actual_hard_min_freq, NULL);
697			if (ret) {
698				dev_err(smu->adev->dev, "Set hard min sclk failed!");
699				return ret;
700			}
701
702			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
703									smu->gfx_actual_soft_max_freq, NULL);
704			if (ret) {
705				dev_err(smu->adev->dev, "Set soft max sclk failed!");
706				return ret;
707			}
708		}
709		break;
710	default:
711		return -ENOSYS;
712	}
713
714	return ret;
715}
716
717static int yellow_carp_get_current_clk_freq(struct smu_context *smu,
718						enum smu_clk_type clk_type,
719						uint32_t *value)
720{
721	MetricsMember_t member_type;
722
723	switch (clk_type) {
724	case SMU_SOCCLK:
725		member_type = METRICS_AVERAGE_SOCCLK;
726		break;
727	case SMU_VCLK:
728	    member_type = METRICS_AVERAGE_VCLK;
729		break;
730	case SMU_DCLK:
731		member_type = METRICS_AVERAGE_DCLK;
732		break;
733	case SMU_MCLK:
734		member_type = METRICS_AVERAGE_UCLK;
735		break;
736	case SMU_FCLK:
737		return smu_cmn_send_smc_msg_with_param(smu,
738				SMU_MSG_GetFclkFrequency, 0, value);
739	case SMU_GFXCLK:
740	case SMU_SCLK:
741		return smu_cmn_send_smc_msg_with_param(smu,
742				SMU_MSG_GetGfxclkFrequency, 0, value);
743		break;
744	default:
745		return -EINVAL;
746	}
747
748	return yellow_carp_get_smu_metrics_data(smu, member_type, value);
749}
750
751static int yellow_carp_get_dpm_level_count(struct smu_context *smu,
752						enum smu_clk_type clk_type,
753						uint32_t *count)
754{
755	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
756
757	switch (clk_type) {
758	case SMU_SOCCLK:
759		*count = clk_table->NumSocClkLevelsEnabled;
760		break;
761	case SMU_VCLK:
762		*count = clk_table->VcnClkLevelsEnabled;
763		break;
764	case SMU_DCLK:
765		*count = clk_table->VcnClkLevelsEnabled;
766		break;
767	case SMU_MCLK:
768		*count = clk_table->NumDfPstatesEnabled;
769		break;
770	case SMU_FCLK:
771		*count = clk_table->NumDfPstatesEnabled;
772		break;
773	default:
774		break;
775	}
776
777	return 0;
778}
779
780static int yellow_carp_get_dpm_freq_by_index(struct smu_context *smu,
781						enum smu_clk_type clk_type,
782						uint32_t dpm_level,
783						uint32_t *freq)
784{
785	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
786
787	if (!clk_table || clk_type >= SMU_CLK_COUNT)
788		return -EINVAL;
789
790	switch (clk_type) {
791	case SMU_SOCCLK:
792		if (dpm_level >= clk_table->NumSocClkLevelsEnabled)
793			return -EINVAL;
794		*freq = clk_table->SocClocks[dpm_level];
795		break;
796	case SMU_VCLK:
797		if (dpm_level >= clk_table->VcnClkLevelsEnabled)
798			return -EINVAL;
799		*freq = clk_table->VClocks[dpm_level];
800		break;
801	case SMU_DCLK:
802		if (dpm_level >= clk_table->VcnClkLevelsEnabled)
803			return -EINVAL;
804		*freq = clk_table->DClocks[dpm_level];
805		break;
806	case SMU_UCLK:
807	case SMU_MCLK:
808		if (dpm_level >= clk_table->NumDfPstatesEnabled)
809			return -EINVAL;
810		*freq = clk_table->DfPstateTable[dpm_level].MemClk;
811		break;
812	case SMU_FCLK:
813		if (dpm_level >= clk_table->NumDfPstatesEnabled)
814			return -EINVAL;
815		*freq = clk_table->DfPstateTable[dpm_level].FClk;
816		break;
817	default:
818		return -EINVAL;
819	}
820
821	return 0;
822}
823
824static bool yellow_carp_clk_dpm_is_enabled(struct smu_context *smu,
825						enum smu_clk_type clk_type)
826{
827	enum smu_feature_mask feature_id = 0;
828
829	switch (clk_type) {
830	case SMU_MCLK:
831	case SMU_UCLK:
832	case SMU_FCLK:
833		feature_id = SMU_FEATURE_DPM_FCLK_BIT;
834		break;
835	case SMU_GFXCLK:
836	case SMU_SCLK:
837		feature_id = SMU_FEATURE_DPM_GFXCLK_BIT;
838		break;
839	case SMU_SOCCLK:
840		feature_id = SMU_FEATURE_DPM_SOCCLK_BIT;
841		break;
842	case SMU_VCLK:
843	case SMU_DCLK:
844		feature_id = SMU_FEATURE_VCN_DPM_BIT;
845		break;
846	default:
847		return true;
848	}
849
850	return smu_cmn_feature_is_enabled(smu, feature_id);
851}
852
853static int yellow_carp_get_dpm_ultimate_freq(struct smu_context *smu,
854							enum smu_clk_type clk_type,
855							uint32_t *min,
856							uint32_t *max)
857{
858	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
859	uint32_t clock_limit;
860	uint32_t max_dpm_level, min_dpm_level;
861	int ret = 0;
862
863	if (!yellow_carp_clk_dpm_is_enabled(smu, clk_type)) {
864		switch (clk_type) {
865		case SMU_MCLK:
866		case SMU_UCLK:
867			clock_limit = smu->smu_table.boot_values.uclk;
868			break;
869		case SMU_FCLK:
870			clock_limit = smu->smu_table.boot_values.fclk;
871			break;
872		case SMU_GFXCLK:
873		case SMU_SCLK:
874			clock_limit = smu->smu_table.boot_values.gfxclk;
875			break;
876		case SMU_SOCCLK:
877			clock_limit = smu->smu_table.boot_values.socclk;
878			break;
879		case SMU_VCLK:
880			clock_limit = smu->smu_table.boot_values.vclk;
881			break;
882		case SMU_DCLK:
883			clock_limit = smu->smu_table.boot_values.dclk;
884			break;
885		default:
886			clock_limit = 0;
887			break;
888		}
889
890		/* clock in Mhz unit */
891		if (min)
892			*min = clock_limit / 100;
893		if (max)
894			*max = clock_limit / 100;
895
896		return 0;
897	}
898
899	if (max) {
900		switch (clk_type) {
901		case SMU_GFXCLK:
902		case SMU_SCLK:
903			*max = clk_table->MaxGfxClk;
904			break;
905		case SMU_MCLK:
906		case SMU_UCLK:
907		case SMU_FCLK:
908			max_dpm_level = 0;
909			break;
910		case SMU_SOCCLK:
911			max_dpm_level = clk_table->NumSocClkLevelsEnabled - 1;
912			break;
913		case SMU_VCLK:
914		case SMU_DCLK:
915			max_dpm_level = clk_table->VcnClkLevelsEnabled - 1;
916			break;
917		default:
918			ret = -EINVAL;
919			goto failed;
920		}
921
922		if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
923			ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, max_dpm_level, max);
924			if (ret)
925				goto failed;
926		}
927	}
928
929	if (min) {
930		switch (clk_type) {
931		case SMU_GFXCLK:
932		case SMU_SCLK:
933			*min = clk_table->MinGfxClk;
934			break;
935		case SMU_MCLK:
936		case SMU_UCLK:
937		case SMU_FCLK:
938			min_dpm_level = clk_table->NumDfPstatesEnabled - 1;
939			break;
940		case SMU_SOCCLK:
941			min_dpm_level = 0;
942			break;
943		case SMU_VCLK:
944		case SMU_DCLK:
945			min_dpm_level = 0;
946			break;
947		default:
948			ret = -EINVAL;
949			goto failed;
950		}
951
952		if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
953			ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, min_dpm_level, min);
954			if (ret)
955				goto failed;
956		}
957	}
958
959failed:
960	return ret;
961}
962
963static int yellow_carp_set_soft_freq_limited_range(struct smu_context *smu,
964							enum smu_clk_type clk_type,
965							uint32_t min,
966							uint32_t max)
967{
968	enum smu_message_type msg_set_min, msg_set_max;
969	uint32_t min_clk = min;
970	uint32_t max_clk = max;
971
972	int ret = 0;
973
974	if (!yellow_carp_clk_dpm_is_enabled(smu, clk_type))
975		return -EINVAL;
976
977	switch (clk_type) {
978	case SMU_GFXCLK:
979	case SMU_SCLK:
980		msg_set_min = SMU_MSG_SetHardMinGfxClk;
981		msg_set_max = SMU_MSG_SetSoftMaxGfxClk;
982		break;
983	case SMU_FCLK:
984		msg_set_min = SMU_MSG_SetHardMinFclkByFreq;
985		msg_set_max = SMU_MSG_SetSoftMaxFclkByFreq;
986		break;
987	case SMU_SOCCLK:
988		msg_set_min = SMU_MSG_SetHardMinSocclkByFreq;
989		msg_set_max = SMU_MSG_SetSoftMaxSocclkByFreq;
990		break;
991	case SMU_VCLK:
992	case SMU_DCLK:
993		msg_set_min = SMU_MSG_SetHardMinVcn;
994		msg_set_max = SMU_MSG_SetSoftMaxVcn;
995		break;
996	default:
997		return -EINVAL;
998	}
999
1000	if (clk_type == SMU_VCLK) {
1001		min_clk = min << SMU_13_VCLK_SHIFT;
1002		max_clk = max << SMU_13_VCLK_SHIFT;
1003	}
1004
1005	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min_clk, NULL);
1006
1007	if (ret)
1008		goto out;
1009
1010	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max_clk, NULL);
1011	if (ret)
1012		goto out;
1013
1014out:
1015	return ret;
1016}
1017
1018static uint32_t yellow_carp_get_umd_pstate_clk_default(struct smu_context *smu,
1019					enum smu_clk_type clk_type)
1020{
1021	uint32_t clk_limit = 0;
1022	struct amdgpu_device *adev = smu->adev;
1023
1024	switch (clk_type) {
1025	case SMU_GFXCLK:
1026	case SMU_SCLK:
1027		if ((amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 8))
1028			clk_limit = SMU_13_0_8_UMD_PSTATE_GFXCLK;
1029		if ((amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 1) ||
1030			(amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 3))
1031			clk_limit = SMU_13_0_1_UMD_PSTATE_GFXCLK;
1032		break;
1033	case SMU_SOCCLK:
1034		if ((amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 8))
1035			clk_limit = SMU_13_0_8_UMD_PSTATE_SOCCLK;
1036		if ((amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 1) ||
1037			(amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 3))
1038			clk_limit = SMU_13_0_1_UMD_PSTATE_SOCCLK;
1039		break;
1040	case SMU_FCLK:
1041		if ((amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 8))
1042			clk_limit = SMU_13_0_8_UMD_PSTATE_FCLK;
1043		if ((amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 1) ||
1044			(amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 3))
1045			clk_limit = SMU_13_0_1_UMD_PSTATE_FCLK;
1046		break;
1047	default:
1048		break;
1049	}
1050
1051	return clk_limit;
1052}
1053
1054static int yellow_carp_print_clk_levels(struct smu_context *smu,
1055				enum smu_clk_type clk_type, char *buf)
1056{
1057	int i, idx, size = 0, ret = 0;
1058	uint32_t cur_value = 0, value = 0, count = 0;
1059	uint32_t min, max;
1060	uint32_t clk_limit = 0;
1061
1062	smu_cmn_get_sysfs_buf(&buf, &size);
1063
1064	switch (clk_type) {
1065	case SMU_OD_SCLK:
1066		size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
1067		size += sysfs_emit_at(buf, size, "0: %10uMhz\n",
1068		(smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);
1069		size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
1070		(smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq);
1071		break;
1072	case SMU_OD_RANGE:
1073		size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
1074		size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
1075						smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);
1076		break;
1077	case SMU_SOCCLK:
1078	case SMU_VCLK:
1079	case SMU_DCLK:
1080	case SMU_MCLK:
1081	case SMU_FCLK:
1082		ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value);
1083		if (ret)
1084			goto print_clk_out;
1085
1086		ret = yellow_carp_get_dpm_level_count(smu, clk_type, &count);
1087		if (ret)
1088			goto print_clk_out;
1089
1090		for (i = 0; i < count; i++) {
1091			idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i;
1092			ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, idx, &value);
1093			if (ret)
1094				goto print_clk_out;
1095
1096			size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value,
1097					cur_value == value ? "*" : "");
1098		}
1099		break;
1100	case SMU_GFXCLK:
1101	case SMU_SCLK:
1102		clk_limit = yellow_carp_get_umd_pstate_clk_default(smu, clk_type);
1103		ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value);
1104		if (ret)
1105			goto print_clk_out;
1106		min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq;
1107		max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq;
1108		if (cur_value  == max)
1109			i = 2;
1110		else if (cur_value == min)
1111			i = 0;
1112		else
1113			i = 1;
1114		size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min,
1115				i == 0 ? "*" : "");
1116		size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
1117				i == 1 ? cur_value : clk_limit,
1118				i == 1 ? "*" : "");
1119		size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max,
1120				i == 2 ? "*" : "");
1121		break;
1122	default:
1123		break;
1124	}
1125
1126print_clk_out:
1127	return size;
1128}
1129
1130static int yellow_carp_force_clk_levels(struct smu_context *smu,
1131				enum smu_clk_type clk_type, uint32_t mask)
1132{
1133	uint32_t soft_min_level = 0, soft_max_level = 0;
1134	uint32_t min_freq = 0, max_freq = 0;
1135	int ret = 0;
1136
1137	soft_min_level = mask ? (ffs(mask) - 1) : 0;
1138	soft_max_level = mask ? (fls(mask) - 1) : 0;
1139
1140	switch (clk_type) {
1141	case SMU_SOCCLK:
1142	case SMU_FCLK:
1143	case SMU_VCLK:
1144	case SMU_DCLK:
1145		ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq);
1146		if (ret)
1147			goto force_level_out;
1148
1149		ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq);
1150		if (ret)
1151			goto force_level_out;
1152
1153		ret = yellow_carp_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq);
1154		if (ret)
1155			goto force_level_out;
1156		break;
1157	default:
1158		ret = -EINVAL;
1159		break;
1160	}
1161
1162force_level_out:
1163	return ret;
1164}
1165
1166static int yellow_carp_get_dpm_profile_freq(struct smu_context *smu,
1167					enum amd_dpm_forced_level level,
1168					enum smu_clk_type clk_type,
1169					uint32_t *min_clk,
1170					uint32_t *max_clk)
1171{
1172	int ret = 0;
1173	uint32_t clk_limit = 0;
1174
1175	clk_limit = yellow_carp_get_umd_pstate_clk_default(smu, clk_type);
1176
1177	switch (clk_type) {
1178	case SMU_GFXCLK:
1179	case SMU_SCLK:
1180		if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
1181			yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &clk_limit);
1182		else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK)
1183			yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &clk_limit, NULL);
1184		break;
1185	case SMU_SOCCLK:
1186		if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
1187			yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &clk_limit);
1188		break;
1189	case SMU_FCLK:
1190		if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
1191			yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &clk_limit);
1192		else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK)
1193			yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &clk_limit, NULL);
1194		break;
1195	case SMU_VCLK:
1196		yellow_carp_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &clk_limit);
1197		break;
1198	case SMU_DCLK:
1199		yellow_carp_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &clk_limit);
1200		break;
1201	default:
1202		ret = -EINVAL;
1203		break;
1204	}
1205	*min_clk = *max_clk = clk_limit;
1206	return ret;
1207}
1208
1209static int yellow_carp_set_performance_level(struct smu_context *smu,
1210						enum amd_dpm_forced_level level)
1211{
1212	struct amdgpu_device *adev = smu->adev;
1213	uint32_t sclk_min = 0, sclk_max = 0;
1214	uint32_t fclk_min = 0, fclk_max = 0;
1215	uint32_t socclk_min = 0, socclk_max = 0;
1216	uint32_t vclk_min = 0, vclk_max = 0;
1217	uint32_t dclk_min = 0, dclk_max = 0;
1218
1219	int ret = 0;
1220
1221	switch (level) {
1222	case AMD_DPM_FORCED_LEVEL_HIGH:
1223		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_max);
1224		yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_max);
1225		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_max);
1226		yellow_carp_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &vclk_max);
1227		yellow_carp_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &dclk_max);
1228		sclk_min = sclk_max;
1229		fclk_min = fclk_max;
1230		socclk_min = socclk_max;
1231		vclk_min = vclk_max;
1232		dclk_min = dclk_max;
1233		break;
1234	case AMD_DPM_FORCED_LEVEL_LOW:
1235		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, NULL);
1236		yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, NULL);
1237		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, NULL);
1238		yellow_carp_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, NULL);
1239		yellow_carp_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, NULL);
1240		sclk_max = sclk_min;
1241		fclk_max = fclk_min;
1242		socclk_max = socclk_min;
1243		vclk_max = vclk_min;
1244		dclk_max = dclk_min;
1245		break;
1246	case AMD_DPM_FORCED_LEVEL_AUTO:
1247		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, &sclk_max);
1248		yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, &fclk_max);
1249		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, &socclk_max);
1250		yellow_carp_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, &vclk_max);
1251		yellow_carp_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, &dclk_max);
1252		break;
1253	case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
1254	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
1255	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
1256	case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
1257		yellow_carp_get_dpm_profile_freq(smu, level, SMU_SCLK, &sclk_min, &sclk_max);
1258		yellow_carp_get_dpm_profile_freq(smu, level, SMU_FCLK, &fclk_min, &fclk_max);
1259		yellow_carp_get_dpm_profile_freq(smu, level, SMU_SOCCLK, &socclk_min, &socclk_max);
1260		yellow_carp_get_dpm_profile_freq(smu, level, SMU_VCLK, &vclk_min, &vclk_max);
1261		yellow_carp_get_dpm_profile_freq(smu, level, SMU_DCLK, &dclk_min, &dclk_max);
1262		break;
1263	case AMD_DPM_FORCED_LEVEL_MANUAL:
1264	case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
1265		return 0;
1266	default:
1267		dev_err(adev->dev, "Invalid performance level %d\n", level);
1268		return -EINVAL;
1269	}
1270
1271	if (sclk_min && sclk_max) {
1272		ret = yellow_carp_set_soft_freq_limited_range(smu,
1273							    SMU_SCLK,
1274							    sclk_min,
1275							    sclk_max);
1276		if (ret)
1277			return ret;
1278
1279		smu->gfx_actual_hard_min_freq = sclk_min;
1280		smu->gfx_actual_soft_max_freq = sclk_max;
1281	}
1282
1283	if (fclk_min && fclk_max) {
1284		ret = yellow_carp_set_soft_freq_limited_range(smu,
1285							    SMU_FCLK,
1286							    fclk_min,
1287							    fclk_max);
1288		if (ret)
1289			return ret;
1290	}
1291
1292	if (socclk_min && socclk_max) {
1293		ret = yellow_carp_set_soft_freq_limited_range(smu,
1294							    SMU_SOCCLK,
1295							    socclk_min,
1296							    socclk_max);
1297		if (ret)
1298			return ret;
1299	}
1300
1301	if (vclk_min && vclk_max) {
1302		ret = yellow_carp_set_soft_freq_limited_range(smu,
1303							      SMU_VCLK,
1304							      vclk_min,
1305							      vclk_max);
1306		if (ret)
1307			return ret;
1308	}
1309
1310	if (dclk_min && dclk_max) {
1311		ret = yellow_carp_set_soft_freq_limited_range(smu,
1312							      SMU_DCLK,
1313							      dclk_min,
1314							      dclk_max);
1315		if (ret)
1316			return ret;
1317	}
1318
1319	return ret;
1320}
1321
1322static int yellow_carp_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
1323{
1324	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
1325
1326	smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
1327	smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
1328	smu->gfx_actual_hard_min_freq = 0;
1329	smu->gfx_actual_soft_max_freq = 0;
1330
1331	return 0;
1332}
1333
1334static const struct pptable_funcs yellow_carp_ppt_funcs = {
1335	.check_fw_status = smu_v13_0_check_fw_status,
1336	.check_fw_version = smu_v13_0_check_fw_version,
1337	.init_smc_tables = yellow_carp_init_smc_tables,
1338	.fini_smc_tables = yellow_carp_fini_smc_tables,
1339	.get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values,
1340	.system_features_control = yellow_carp_system_features_control,
1341	.send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
1342	.send_smc_msg = smu_cmn_send_smc_msg,
1343	.dpm_set_vcn_enable = yellow_carp_dpm_set_vcn_enable,
1344	.dpm_set_jpeg_enable = yellow_carp_dpm_set_jpeg_enable,
1345	.set_default_dpm_table = yellow_carp_set_default_dpm_tables,
1346	.read_sensor = yellow_carp_read_sensor,
1347	.is_dpm_running = yellow_carp_is_dpm_running,
1348	.set_watermarks_table = yellow_carp_set_watermarks_table,
1349	.get_gpu_metrics = yellow_carp_get_gpu_metrics,
1350	.get_enabled_mask = smu_cmn_get_enabled_mask,
1351	.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
1352	.set_driver_table_location = smu_v13_0_set_driver_table_location,
1353	.gfx_off_control = smu_v13_0_gfx_off_control,
1354	.get_gfx_off_status = yellow_carp_get_gfxoff_status,
1355	.post_init = yellow_carp_post_smu_init,
1356	.mode2_reset = yellow_carp_mode2_reset,
1357	.get_dpm_ultimate_freq = yellow_carp_get_dpm_ultimate_freq,
1358	.od_edit_dpm_table = yellow_carp_od_edit_dpm_table,
1359	.print_clk_levels = yellow_carp_print_clk_levels,
1360	.force_clk_levels = yellow_carp_force_clk_levels,
1361	.set_performance_level = yellow_carp_set_performance_level,
1362	.set_fine_grain_gfx_freq_parameters = yellow_carp_set_fine_grain_gfx_freq_parameters,
1363};
1364
1365void yellow_carp_set_ppt_funcs(struct smu_context *smu)
1366{
1367	smu->ppt_funcs = &yellow_carp_ppt_funcs;
1368	smu->message_map = yellow_carp_message_map;
1369	smu->feature_map = yellow_carp_feature_mask_map;
1370	smu->table_map = yellow_carp_table_map;
1371	smu->is_apu = true;
1372	smu->smc_driver_if_version = SMU13_YELLOW_CARP_DRIVER_IF_VERSION;
1373	smu_v13_0_set_smu_mailbox_registers(smu);
1374}
1375