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