cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cyan_skillfish_ppt.c (17379B)


      1/*
      2 * Copyright 2021 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_v11_0.h"
     29#include "smu11_driver_if_cyan_skillfish.h"
     30#include "cyan_skillfish_ppt.h"
     31#include "smu_v11_8_ppsmc.h"
     32#include "smu_v11_8_pmfw.h"
     33#include "smu_cmn.h"
     34#include "soc15_common.h"
     35
     36/*
     37 * DO NOT use these for err/warn/info/debug messages.
     38 * Use dev_err, dev_warn, dev_info and dev_dbg instead.
     39 * They are more MGPU friendly.
     40 */
     41
     42#undef pr_err
     43#undef pr_warn
     44#undef pr_info
     45#undef pr_debug
     46
     47/* unit: MHz */
     48#define CYAN_SKILLFISH_SCLK_MIN			1000
     49#define CYAN_SKILLFISH_SCLK_MAX			2000
     50
     51/* unit: mV */
     52#define CYAN_SKILLFISH_VDDC_MIN			700
     53#define CYAN_SKILLFISH_VDDC_MAX			1129
     54#define CYAN_SKILLFISH_VDDC_MAGIC			5118 // 0x13fe
     55
     56static struct gfx_user_settings {
     57	uint32_t sclk;
     58	uint32_t vddc;
     59} cyan_skillfish_user_settings;
     60
     61static uint32_t cyan_skillfish_sclk_default;
     62
     63#define FEATURE_MASK(feature) (1ULL << feature)
     64#define SMC_DPM_FEATURE ( \
     65	FEATURE_MASK(FEATURE_FCLK_DPM_BIT)	|	\
     66	FEATURE_MASK(FEATURE_SOC_DPM_BIT)	|	\
     67	FEATURE_MASK(FEATURE_GFX_DPM_BIT))
     68
     69static struct cmn2asic_msg_mapping cyan_skillfish_message_map[SMU_MSG_MAX_COUNT] = {
     70	MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,			0),
     71	MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion,		0),
     72	MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion,		0),
     73	MSG_MAP(SetDriverDramAddrHigh,          PPSMC_MSG_SetDriverTableDramAddrHigh,	0),
     74	MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverTableDramAddrLow,	0),
     75	MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram,	0),
     76	MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu,	0),
     77	MSG_MAP(GetEnabledSmuFeatures,          PPSMC_MSG_GetEnabledSmuFeatures,	0),
     78	MSG_MAP(RequestGfxclk,                  PPSMC_MSG_RequestGfxclk,		0),
     79	MSG_MAP(ForceGfxVid,                    PPSMC_MSG_ForceGfxVid,			0),
     80	MSG_MAP(UnforceGfxVid,                  PPSMC_MSG_UnforceGfxVid,		0),
     81};
     82
     83static struct cmn2asic_mapping cyan_skillfish_table_map[SMU_TABLE_COUNT] = {
     84	TAB_MAP_VALID(SMU_METRICS),
     85};
     86
     87static int cyan_skillfish_tables_init(struct smu_context *smu)
     88{
     89	struct smu_table_context *smu_table = &smu->smu_table;
     90	struct smu_table *tables = smu_table->tables;
     91
     92	SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS,
     93				sizeof(SmuMetrics_t),
     94				PAGE_SIZE,
     95				AMDGPU_GEM_DOMAIN_VRAM);
     96
     97	smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
     98	if (!smu_table->metrics_table)
     99		goto err0_out;
    100
    101	smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_2);
    102	smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
    103	if (!smu_table->gpu_metrics_table)
    104		goto err1_out;
    105
    106	smu_table->metrics_time = 0;
    107
    108	return 0;
    109
    110err1_out:
    111	smu_table->gpu_metrics_table_size = 0;
    112	kfree(smu_table->metrics_table);
    113err0_out:
    114	return -ENOMEM;
    115}
    116
    117static int cyan_skillfish_init_smc_tables(struct smu_context *smu)
    118{
    119	int ret = 0;
    120
    121	ret = cyan_skillfish_tables_init(smu);
    122	if (ret)
    123		return ret;
    124
    125	return smu_v11_0_init_smc_tables(smu);
    126}
    127
    128static int
    129cyan_skillfish_get_smu_metrics_data(struct smu_context *smu,
    130					MetricsMember_t member,
    131					uint32_t *value)
    132{
    133	struct smu_table_context *smu_table = &smu->smu_table;
    134	SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
    135	int ret = 0;
    136
    137	ret = smu_cmn_get_metrics_table(smu, NULL, false);
    138	if (ret)
    139		return ret;
    140
    141	switch (member) {
    142	case METRICS_CURR_GFXCLK:
    143		*value = metrics->Current.GfxclkFrequency;
    144		break;
    145	case METRICS_CURR_SOCCLK:
    146		*value = metrics->Current.SocclkFrequency;
    147		break;
    148	case METRICS_CURR_VCLK:
    149		*value = metrics->Current.VclkFrequency;
    150		break;
    151	case METRICS_CURR_DCLK:
    152		*value = metrics->Current.DclkFrequency;
    153		break;
    154	case METRICS_CURR_UCLK:
    155		*value = metrics->Current.MemclkFrequency;
    156		break;
    157	case METRICS_AVERAGE_SOCKETPOWER:
    158		*value = (metrics->Current.CurrentSocketPower << 8) /
    159				1000;
    160		break;
    161	case METRICS_TEMPERATURE_EDGE:
    162		*value = metrics->Current.GfxTemperature / 100 *
    163				SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
    164		break;
    165	case METRICS_TEMPERATURE_HOTSPOT:
    166		*value = metrics->Current.SocTemperature / 100 *
    167				SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
    168		break;
    169	case METRICS_VOLTAGE_VDDSOC:
    170		*value = metrics->Current.Voltage[0];
    171		break;
    172	case METRICS_VOLTAGE_VDDGFX:
    173		*value = metrics->Current.Voltage[1];
    174		break;
    175	case METRICS_THROTTLER_STATUS:
    176		*value = metrics->Current.ThrottlerStatus;
    177		break;
    178	default:
    179		*value = UINT_MAX;
    180		break;
    181	}
    182
    183	return ret;
    184}
    185
    186static int cyan_skillfish_read_sensor(struct smu_context *smu,
    187					enum amd_pp_sensors sensor,
    188					void *data,
    189					uint32_t *size)
    190{
    191	int ret = 0;
    192
    193	if (!data || !size)
    194		return -EINVAL;
    195
    196	switch (sensor) {
    197	case AMDGPU_PP_SENSOR_GFX_SCLK:
    198		ret = cyan_skillfish_get_smu_metrics_data(smu,
    199						   METRICS_CURR_GFXCLK,
    200						   (uint32_t *)data);
    201		*(uint32_t *)data *= 100;
    202		*size = 4;
    203		break;
    204	case AMDGPU_PP_SENSOR_GFX_MCLK:
    205		ret = cyan_skillfish_get_smu_metrics_data(smu,
    206						   METRICS_CURR_UCLK,
    207						   (uint32_t *)data);
    208		*(uint32_t *)data *= 100;
    209		*size = 4;
    210		break;
    211	case AMDGPU_PP_SENSOR_GPU_POWER:
    212		ret = cyan_skillfish_get_smu_metrics_data(smu,
    213						   METRICS_AVERAGE_SOCKETPOWER,
    214						   (uint32_t *)data);
    215		*size = 4;
    216		break;
    217	case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
    218		ret = cyan_skillfish_get_smu_metrics_data(smu,
    219						   METRICS_TEMPERATURE_HOTSPOT,
    220						   (uint32_t *)data);
    221		*size = 4;
    222		break;
    223	case AMDGPU_PP_SENSOR_EDGE_TEMP:
    224		ret = cyan_skillfish_get_smu_metrics_data(smu,
    225						   METRICS_TEMPERATURE_EDGE,
    226						   (uint32_t *)data);
    227		*size = 4;
    228		break;
    229	case AMDGPU_PP_SENSOR_VDDNB:
    230		ret = cyan_skillfish_get_smu_metrics_data(smu,
    231						   METRICS_VOLTAGE_VDDSOC,
    232						   (uint32_t *)data);
    233		*size = 4;
    234		break;
    235	case AMDGPU_PP_SENSOR_VDDGFX:
    236		ret = cyan_skillfish_get_smu_metrics_data(smu,
    237						   METRICS_VOLTAGE_VDDGFX,
    238						   (uint32_t *)data);
    239		*size = 4;
    240		break;
    241	default:
    242		ret = -EOPNOTSUPP;
    243		break;
    244	}
    245
    246	return ret;
    247}
    248
    249static int cyan_skillfish_get_current_clk_freq(struct smu_context *smu,
    250						enum smu_clk_type clk_type,
    251						uint32_t *value)
    252{
    253	MetricsMember_t member_type;
    254
    255	switch (clk_type) {
    256	case SMU_GFXCLK:
    257	case SMU_SCLK:
    258		member_type = METRICS_CURR_GFXCLK;
    259		break;
    260	case SMU_FCLK:
    261	case SMU_MCLK:
    262		member_type = METRICS_CURR_UCLK;
    263		break;
    264	case SMU_SOCCLK:
    265		member_type = METRICS_CURR_SOCCLK;
    266		break;
    267	case SMU_VCLK:
    268		member_type = METRICS_CURR_VCLK;
    269		break;
    270	case SMU_DCLK:
    271		member_type = METRICS_CURR_DCLK;
    272		break;
    273	default:
    274		return -EINVAL;
    275	}
    276
    277	return cyan_skillfish_get_smu_metrics_data(smu, member_type, value);
    278}
    279
    280static int cyan_skillfish_print_clk_levels(struct smu_context *smu,
    281					enum smu_clk_type clk_type,
    282					char *buf)
    283{
    284	int ret = 0, size = 0;
    285	uint32_t cur_value = 0;
    286	int i;
    287
    288	smu_cmn_get_sysfs_buf(&buf, &size);
    289
    290	switch (clk_type) {
    291	case SMU_OD_SCLK:
    292		ret  = cyan_skillfish_get_smu_metrics_data(smu, METRICS_CURR_GFXCLK, &cur_value);
    293		if (ret)
    294			return ret;
    295		size += sysfs_emit_at(buf, size,"%s:\n", "OD_SCLK");
    296		size += sysfs_emit_at(buf, size, "0: %uMhz *\n", cur_value);
    297		break;
    298	case SMU_OD_VDDC_CURVE:
    299		ret  = cyan_skillfish_get_smu_metrics_data(smu, METRICS_VOLTAGE_VDDGFX, &cur_value);
    300		if (ret)
    301			return ret;
    302		size += sysfs_emit_at(buf, size,"%s:\n", "OD_VDDC");
    303		size += sysfs_emit_at(buf, size, "0: %umV *\n", cur_value);
    304		break;
    305	case SMU_OD_RANGE:
    306		size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
    307		size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
    308						CYAN_SKILLFISH_SCLK_MIN, CYAN_SKILLFISH_SCLK_MAX);
    309		size += sysfs_emit_at(buf, size, "VDDC: %7umV  %10umV\n",
    310						CYAN_SKILLFISH_VDDC_MIN, CYAN_SKILLFISH_VDDC_MAX);
    311		break;
    312	case SMU_FCLK:
    313	case SMU_MCLK:
    314	case SMU_SOCCLK:
    315	case SMU_VCLK:
    316	case SMU_DCLK:
    317		ret = cyan_skillfish_get_current_clk_freq(smu, clk_type, &cur_value);
    318		if (ret)
    319			return ret;
    320		size += sysfs_emit_at(buf, size, "0: %uMhz *\n", cur_value);
    321		break;
    322	case SMU_SCLK:
    323	case SMU_GFXCLK:
    324		ret = cyan_skillfish_get_current_clk_freq(smu, clk_type, &cur_value);
    325		if (ret)
    326			return ret;
    327		if (cur_value  == CYAN_SKILLFISH_SCLK_MAX)
    328			i = 2;
    329		else if (cur_value == CYAN_SKILLFISH_SCLK_MIN)
    330			i = 0;
    331		else
    332			i = 1;
    333		size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", CYAN_SKILLFISH_SCLK_MIN,
    334				i == 0 ? "*" : "");
    335		size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
    336				i == 1 ? cur_value : cyan_skillfish_sclk_default,
    337				i == 1 ? "*" : "");
    338		size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", CYAN_SKILLFISH_SCLK_MAX,
    339				i == 2 ? "*" : "");
    340		break;
    341	default:
    342		dev_warn(smu->adev->dev, "Unsupported clock type\n");
    343		return ret;
    344	}
    345
    346	return size;
    347}
    348
    349static bool cyan_skillfish_is_dpm_running(struct smu_context *smu)
    350{
    351	struct amdgpu_device *adev = smu->adev;
    352	int ret = 0;
    353	uint64_t feature_enabled;
    354
    355	/* we need to re-init after suspend so return false */
    356	if (adev->in_suspend)
    357		return false;
    358
    359	ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
    360	if (ret)
    361		return false;
    362
    363	/*
    364	 * cyan_skillfish specific, query default sclk inseted of hard code.
    365	 */
    366	if (!cyan_skillfish_sclk_default)
    367		cyan_skillfish_get_smu_metrics_data(smu, METRICS_CURR_GFXCLK,
    368			&cyan_skillfish_sclk_default);
    369
    370	return !!(feature_enabled & SMC_DPM_FEATURE);
    371}
    372
    373static ssize_t cyan_skillfish_get_gpu_metrics(struct smu_context *smu,
    374						void **table)
    375{
    376	struct smu_table_context *smu_table = &smu->smu_table;
    377	struct gpu_metrics_v2_2 *gpu_metrics =
    378		(struct gpu_metrics_v2_2 *)smu_table->gpu_metrics_table;
    379	SmuMetrics_t metrics;
    380	int i, ret = 0;
    381
    382	ret = smu_cmn_get_metrics_table(smu, &metrics, true);
    383	if (ret)
    384		return ret;
    385
    386	smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 2);
    387
    388	gpu_metrics->temperature_gfx = metrics.Current.GfxTemperature;
    389	gpu_metrics->temperature_soc = metrics.Current.SocTemperature;
    390
    391	gpu_metrics->average_socket_power = metrics.Current.CurrentSocketPower;
    392	gpu_metrics->average_soc_power = metrics.Current.Power[0];
    393	gpu_metrics->average_gfx_power = metrics.Current.Power[1];
    394
    395	gpu_metrics->average_gfxclk_frequency = metrics.Average.GfxclkFrequency;
    396	gpu_metrics->average_socclk_frequency = metrics.Average.SocclkFrequency;
    397	gpu_metrics->average_uclk_frequency = metrics.Average.MemclkFrequency;
    398	gpu_metrics->average_fclk_frequency = metrics.Average.MemclkFrequency;
    399	gpu_metrics->average_vclk_frequency = metrics.Average.VclkFrequency;
    400	gpu_metrics->average_dclk_frequency = metrics.Average.DclkFrequency;
    401
    402	gpu_metrics->current_gfxclk = metrics.Current.GfxclkFrequency;
    403	gpu_metrics->current_socclk = metrics.Current.SocclkFrequency;
    404	gpu_metrics->current_uclk = metrics.Current.MemclkFrequency;
    405	gpu_metrics->current_fclk = metrics.Current.MemclkFrequency;
    406	gpu_metrics->current_vclk = metrics.Current.VclkFrequency;
    407	gpu_metrics->current_dclk = metrics.Current.DclkFrequency;
    408
    409	for (i = 0; i < 6; i++) {
    410		gpu_metrics->temperature_core[i] = metrics.Current.CoreTemperature[i];
    411		gpu_metrics->average_core_power[i] = metrics.Average.CorePower[i];
    412		gpu_metrics->current_coreclk[i] = metrics.Current.CoreFrequency[i];
    413	}
    414
    415	for (i = 0; i < 2; i++) {
    416		gpu_metrics->temperature_l3[i] = metrics.Current.L3Temperature[i];
    417		gpu_metrics->current_l3clk[i] = metrics.Current.L3Frequency[i];
    418	}
    419
    420	gpu_metrics->throttle_status = metrics.Current.ThrottlerStatus;
    421	gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
    422
    423	*table = (void *)gpu_metrics;
    424
    425	return sizeof(struct gpu_metrics_v2_2);
    426}
    427
    428static int cyan_skillfish_od_edit_dpm_table(struct smu_context *smu,
    429					enum PP_OD_DPM_TABLE_COMMAND type,
    430					long input[], uint32_t size)
    431{
    432	int ret = 0;
    433	uint32_t vid;
    434
    435	switch (type) {
    436	case PP_OD_EDIT_VDDC_CURVE:
    437		if (size != 3 || input[0] != 0) {
    438			dev_err(smu->adev->dev, "Invalid parameter!\n");
    439			return -EINVAL;
    440		}
    441
    442		if (input[1] < CYAN_SKILLFISH_SCLK_MIN ||
    443			input[1] > CYAN_SKILLFISH_SCLK_MAX) {
    444			dev_err(smu->adev->dev, "Invalid sclk! Valid sclk range: %uMHz - %uMhz\n",
    445					CYAN_SKILLFISH_SCLK_MIN, CYAN_SKILLFISH_SCLK_MAX);
    446			return -EINVAL;
    447		}
    448
    449		if (input[2] < CYAN_SKILLFISH_VDDC_MIN ||
    450			input[2] > CYAN_SKILLFISH_VDDC_MAX) {
    451			dev_err(smu->adev->dev, "Invalid vddc! Valid vddc range: %umV - %umV\n",
    452					CYAN_SKILLFISH_VDDC_MIN, CYAN_SKILLFISH_VDDC_MAX);
    453			return -EINVAL;
    454		}
    455
    456		cyan_skillfish_user_settings.sclk = input[1];
    457		cyan_skillfish_user_settings.vddc = input[2];
    458
    459		break;
    460	case PP_OD_RESTORE_DEFAULT_TABLE:
    461		if (size != 0) {
    462			dev_err(smu->adev->dev, "Invalid parameter!\n");
    463			return -EINVAL;
    464		}
    465
    466		cyan_skillfish_user_settings.sclk = cyan_skillfish_sclk_default;
    467		cyan_skillfish_user_settings.vddc = CYAN_SKILLFISH_VDDC_MAGIC;
    468
    469		break;
    470	case PP_OD_COMMIT_DPM_TABLE:
    471		if (size != 0) {
    472			dev_err(smu->adev->dev, "Invalid parameter!\n");
    473			return -EINVAL;
    474		}
    475
    476		if (cyan_skillfish_user_settings.sclk < CYAN_SKILLFISH_SCLK_MIN ||
    477		    cyan_skillfish_user_settings.sclk > CYAN_SKILLFISH_SCLK_MAX) {
    478			dev_err(smu->adev->dev, "Invalid sclk! Valid sclk range: %uMHz - %uMhz\n",
    479					CYAN_SKILLFISH_SCLK_MIN, CYAN_SKILLFISH_SCLK_MAX);
    480			return -EINVAL;
    481		}
    482
    483		if ((cyan_skillfish_user_settings.vddc != CYAN_SKILLFISH_VDDC_MAGIC) &&
    484			(cyan_skillfish_user_settings.vddc < CYAN_SKILLFISH_VDDC_MIN ||
    485			cyan_skillfish_user_settings.vddc > CYAN_SKILLFISH_VDDC_MAX)) {
    486			dev_err(smu->adev->dev, "Invalid vddc! Valid vddc range: %umV - %umV\n",
    487					CYAN_SKILLFISH_VDDC_MIN, CYAN_SKILLFISH_VDDC_MAX);
    488			return -EINVAL;
    489		}
    490
    491		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_RequestGfxclk,
    492					cyan_skillfish_user_settings.sclk, NULL);
    493		if (ret) {
    494			dev_err(smu->adev->dev, "Set sclk failed!\n");
    495			return ret;
    496		}
    497
    498		if (cyan_skillfish_user_settings.vddc == CYAN_SKILLFISH_VDDC_MAGIC) {
    499			ret = smu_cmn_send_smc_msg(smu, SMU_MSG_UnforceGfxVid, NULL);
    500			if (ret) {
    501				dev_err(smu->adev->dev, "Unforce vddc failed!\n");
    502				return ret;
    503			}
    504		} else {
    505			/*
    506			 * PMFW accepts SVI2 VID code, convert voltage to VID:
    507			 * vid = (uint32_t)((1.55 - voltage) * 160.0 + 0.00001)
    508			 */
    509			vid = (1550 - cyan_skillfish_user_settings.vddc) * 160 / 1000;
    510			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ForceGfxVid, vid, NULL);
    511			if (ret) {
    512				dev_err(smu->adev->dev, "Force vddc failed!\n");
    513				return ret;
    514			}
    515		}
    516
    517		break;
    518	default:
    519		return -EOPNOTSUPP;
    520	}
    521
    522	return ret;
    523}
    524
    525static int cyan_skillfish_get_dpm_ultimate_freq(struct smu_context *smu,
    526						enum smu_clk_type clk_type,
    527						uint32_t *min,
    528						uint32_t *max)
    529{
    530	int ret = 0;
    531	uint32_t low, high;
    532
    533	switch (clk_type) {
    534	case SMU_GFXCLK:
    535	case SMU_SCLK:
    536		low = CYAN_SKILLFISH_SCLK_MIN;
    537		high = CYAN_SKILLFISH_SCLK_MAX;
    538		break;
    539	default:
    540		ret = cyan_skillfish_get_current_clk_freq(smu, clk_type, &low);
    541		if (ret)
    542			return ret;
    543		high = low;
    544		break;
    545	}
    546
    547	if (min)
    548		*min = low;
    549	if (max)
    550		*max = high;
    551
    552	return 0;
    553}
    554
    555static int cyan_skillfish_get_enabled_mask(struct smu_context *smu,
    556					   uint64_t *feature_mask)
    557{
    558	if (!feature_mask)
    559		return -EINVAL;
    560	memset(feature_mask, 0xff, sizeof(*feature_mask));
    561
    562	return 0;
    563}
    564
    565static const struct pptable_funcs cyan_skillfish_ppt_funcs = {
    566
    567	.check_fw_status = smu_v11_0_check_fw_status,
    568	.check_fw_version = smu_v11_0_check_fw_version,
    569	.init_power = smu_v11_0_init_power,
    570	.fini_power = smu_v11_0_fini_power,
    571	.init_smc_tables = cyan_skillfish_init_smc_tables,
    572	.fini_smc_tables = smu_v11_0_fini_smc_tables,
    573	.read_sensor = cyan_skillfish_read_sensor,
    574	.print_clk_levels = cyan_skillfish_print_clk_levels,
    575	.get_enabled_mask = cyan_skillfish_get_enabled_mask,
    576	.is_dpm_running = cyan_skillfish_is_dpm_running,
    577	.get_gpu_metrics = cyan_skillfish_get_gpu_metrics,
    578	.od_edit_dpm_table = cyan_skillfish_od_edit_dpm_table,
    579	.get_dpm_ultimate_freq = cyan_skillfish_get_dpm_ultimate_freq,
    580	.register_irq_handler = smu_v11_0_register_irq_handler,
    581	.notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
    582	.send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
    583	.send_smc_msg = smu_cmn_send_smc_msg,
    584	.set_driver_table_location = smu_v11_0_set_driver_table_location,
    585	.interrupt_work = smu_v11_0_interrupt_work,
    586};
    587
    588void cyan_skillfish_set_ppt_funcs(struct smu_context *smu)
    589{
    590	smu->ppt_funcs = &cyan_skillfish_ppt_funcs;
    591	smu->message_map = cyan_skillfish_message_map;
    592	smu->table_map = cyan_skillfish_table_map;
    593	smu->is_apu = true;
    594}