Home | History | Annotate | Line # | Download | only in powerplay
      1 /*	$NetBSD: amdgpu_smu_v12_0.c,v 1.2 2021/12/18 23:45:26 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2019 Advanced Micro Devices, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 #include <sys/cdefs.h>
     26 __KERNEL_RCSID(0, "$NetBSD: amdgpu_smu_v12_0.c,v 1.2 2021/12/18 23:45:26 riastradh Exp $");
     27 
     28 #include "pp_debug.h"
     29 #include <linux/firmware.h>
     30 #include "amdgpu.h"
     31 #include "amdgpu_smu.h"
     32 #include "smu_internal.h"
     33 #include "atomfirmware.h"
     34 #include "amdgpu_atomfirmware.h"
     35 #include "smu_v12_0.h"
     36 #include "soc15_common.h"
     37 #include "atom.h"
     38 
     39 #include "asic_reg/mp/mp_12_0_0_offset.h"
     40 #include "asic_reg/mp/mp_12_0_0_sh_mask.h"
     41 
     42 #define smnMP1_FIRMWARE_FLAGS                                0x3010024
     43 
     44 #define mmSMUIO_GFX_MISC_CNTL                                0x00c8
     45 #define mmSMUIO_GFX_MISC_CNTL_BASE_IDX                       0
     46 #define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK          0x00000006L
     47 #define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT        0x1
     48 
     49 int smu_v12_0_send_msg_without_waiting(struct smu_context *smu,
     50 					      uint16_t msg)
     51 {
     52 	struct amdgpu_device *adev = smu->adev;
     53 
     54 	WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, msg);
     55 	return 0;
     56 }
     57 
     58 int smu_v12_0_read_arg(struct smu_context *smu, uint32_t *arg)
     59 {
     60 	struct amdgpu_device *adev = smu->adev;
     61 
     62 	*arg = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82);
     63 	return 0;
     64 }
     65 
     66 int smu_v12_0_wait_for_response(struct smu_context *smu)
     67 {
     68 	struct amdgpu_device *adev = smu->adev;
     69 	uint32_t cur_value, i;
     70 
     71 	for (i = 0; i < adev->usec_timeout; i++) {
     72 		cur_value = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90);
     73 		if ((cur_value & MP1_C2PMSG_90__CONTENT_MASK) != 0)
     74 			return cur_value == 0x1 ? 0 : -EIO;
     75 
     76 		udelay(1);
     77 	}
     78 
     79 	/* timeout means wrong logic */
     80 	return -ETIME;
     81 }
     82 
     83 int
     84 smu_v12_0_send_msg_with_param(struct smu_context *smu,
     85 			      enum smu_message_type msg,
     86 			      uint32_t param)
     87 {
     88 	struct amdgpu_device *adev = smu->adev;
     89 	int ret = 0, index = 0;
     90 
     91 	index = smu_msg_get_index(smu, msg);
     92 	if (index < 0)
     93 		return index;
     94 
     95 	ret = smu_v12_0_wait_for_response(smu);
     96 	if (ret) {
     97 		pr_err("Msg issuing pre-check failed and "
     98 		       "SMU may be not in the right state!\n");
     99 		return ret;
    100 	}
    101 
    102 	WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0);
    103 
    104 	WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82, param);
    105 
    106 	smu_v12_0_send_msg_without_waiting(smu, (uint16_t)index);
    107 
    108 	ret = smu_v12_0_wait_for_response(smu);
    109 	if (ret)
    110 		pr_err("Failed to send message 0x%x, response 0x%x param 0x%x\n",
    111 		       index, ret, param);
    112 
    113 	return ret;
    114 }
    115 
    116 int smu_v12_0_check_fw_status(struct smu_context *smu)
    117 {
    118 	struct amdgpu_device *adev = smu->adev;
    119 	uint32_t mp1_fw_flags;
    120 
    121 	mp1_fw_flags = RREG32_PCIE(MP1_Public |
    122 		(smnMP1_FIRMWARE_FLAGS & 0xffffffff));
    123 
    124 	if ((mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >>
    125 		MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT)
    126 		return 0;
    127 
    128 	return -EIO;
    129 }
    130 
    131 int smu_v12_0_check_fw_version(struct smu_context *smu)
    132 {
    133 	uint32_t if_version = 0xff, smu_version = 0xff;
    134 	uint16_t smu_major;
    135 	uint8_t smu_minor, smu_debug;
    136 	int ret = 0;
    137 
    138 	ret = smu_get_smc_version(smu, &if_version, &smu_version);
    139 	if (ret)
    140 		return ret;
    141 
    142 	smu_major = (smu_version >> 16) & 0xffff;
    143 	smu_minor = (smu_version >> 8) & 0xff;
    144 	smu_debug = (smu_version >> 0) & 0xff;
    145 
    146 	/*
    147 	 * 1. if_version mismatch is not critical as our fw is designed
    148 	 * to be backward compatible.
    149 	 * 2. New fw usually brings some optimizations. But that's visible
    150 	 * only on the paired driver.
    151 	 * Considering above, we just leave user a warning message instead
    152 	 * of halt driver loading.
    153 	 */
    154 	if (if_version != smu->smc_if_version) {
    155 		pr_info("smu driver if version = 0x%08x, smu fw if version = 0x%08x, "
    156 			"smu fw version = 0x%08x (%d.%d.%d)\n",
    157 			smu->smc_if_version, if_version,
    158 			smu_version, smu_major, smu_minor, smu_debug);
    159 		pr_warn("SMU driver if version not matched\n");
    160 	}
    161 
    162 	return ret;
    163 }
    164 
    165 int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate)
    166 {
    167 	if (!smu->is_apu)
    168 		return 0;
    169 
    170 	if (gate)
    171 		return smu_send_smc_msg(smu, SMU_MSG_PowerDownSdma);
    172 	else
    173 		return smu_send_smc_msg(smu, SMU_MSG_PowerUpSdma);
    174 }
    175 
    176 int smu_v12_0_powergate_vcn(struct smu_context *smu, bool gate)
    177 {
    178 	if (!smu->is_apu)
    179 		return 0;
    180 
    181 	if (gate)
    182 		return smu_send_smc_msg(smu, SMU_MSG_PowerDownVcn);
    183 	else
    184 		return smu_send_smc_msg(smu, SMU_MSG_PowerUpVcn);
    185 }
    186 
    187 int smu_v12_0_powergate_jpeg(struct smu_context *smu, bool gate)
    188 {
    189 	if (!smu->is_apu)
    190 		return 0;
    191 
    192 	if (gate)
    193 		return smu_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0);
    194 	else
    195 		return smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0);
    196 }
    197 
    198 int smu_v12_0_set_gfx_cgpg(struct smu_context *smu, bool enable)
    199 {
    200 	if (!(smu->adev->pg_flags & AMD_PG_SUPPORT_GFX_PG))
    201 		return 0;
    202 
    203 	return smu_v12_0_send_msg_with_param(smu,
    204 		SMU_MSG_SetGfxCGPG, enable ? 1 : 0);
    205 }
    206 
    207 int smu_v12_0_read_sensor(struct smu_context *smu,
    208 				 enum amd_pp_sensors sensor,
    209 				 void *data, uint32_t *size)
    210 {
    211 	int ret = 0;
    212 
    213 	if(!data || !size)
    214 		return -EINVAL;
    215 
    216 	switch (sensor) {
    217 	case AMDGPU_PP_SENSOR_GFX_MCLK:
    218 		ret = smu_get_current_clk_freq(smu, SMU_UCLK, (uint32_t *)data);
    219 		*size = 4;
    220 		break;
    221 	case AMDGPU_PP_SENSOR_GFX_SCLK:
    222 		ret = smu_get_current_clk_freq(smu, SMU_GFXCLK, (uint32_t *)data);
    223 		*size = 4;
    224 		break;
    225 	case AMDGPU_PP_SENSOR_MIN_FAN_RPM:
    226 		*(uint32_t *)data = 0;
    227 		*size = 4;
    228 		break;
    229 	default:
    230 		ret = smu_common_read_sensor(smu, sensor, data, size);
    231 		break;
    232 	}
    233 
    234 	if (ret)
    235 		*size = 0;
    236 
    237 	return ret;
    238 }
    239 
    240 /**
    241  * smu_v12_0_get_gfxoff_status - get gfxoff status
    242  *
    243  * @smu: amdgpu_device pointer
    244  *
    245  * This function will be used to get gfxoff status
    246  *
    247  * Returns 0=GFXOFF(default).
    248  * Returns 1=Transition out of GFX State.
    249  * Returns 2=Not in GFXOFF.
    250  * Returns 3=Transition into GFXOFF.
    251  */
    252 uint32_t smu_v12_0_get_gfxoff_status(struct smu_context *smu)
    253 {
    254 	uint32_t reg;
    255 	uint32_t gfxOff_Status = 0;
    256 	struct amdgpu_device *adev = smu->adev;
    257 
    258 	reg = RREG32_SOC15(SMUIO, 0, mmSMUIO_GFX_MISC_CNTL);
    259 	gfxOff_Status = (reg & SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK)
    260 		>> SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT;
    261 
    262 	return gfxOff_Status;
    263 }
    264 
    265 int smu_v12_0_gfx_off_control(struct smu_context *smu, bool enable)
    266 {
    267 	int ret = 0, timeout = 500;
    268 
    269 	if (enable) {
    270 		ret = smu_send_smc_msg(smu, SMU_MSG_AllowGfxOff);
    271 
    272 	} else {
    273 		ret = smu_send_smc_msg(smu, SMU_MSG_DisallowGfxOff);
    274 
    275 		/* confirm gfx is back to "on" state, timeout is 0.5 second */
    276 		while (!(smu_v12_0_get_gfxoff_status(smu) == 2)) {
    277 			msleep(1);
    278 			timeout--;
    279 			if (timeout == 0) {
    280 				DRM_ERROR("disable gfxoff timeout and failed!\n");
    281 				break;
    282 			}
    283 		}
    284 	}
    285 
    286 	return ret;
    287 }
    288 
    289 int smu_v12_0_init_smc_tables(struct smu_context *smu)
    290 {
    291 	struct smu_table_context *smu_table = &smu->smu_table;
    292 	struct smu_table *tables = NULL;
    293 
    294 	if (smu_table->tables)
    295 		return -EINVAL;
    296 
    297 	tables = kcalloc(SMU_TABLE_COUNT, sizeof(struct smu_table),
    298 			 GFP_KERNEL);
    299 	if (!tables)
    300 		return -ENOMEM;
    301 
    302 	smu_table->tables = tables;
    303 
    304 	return smu_tables_init(smu, tables);
    305 }
    306 
    307 int smu_v12_0_fini_smc_tables(struct smu_context *smu)
    308 {
    309 	struct smu_table_context *smu_table = &smu->smu_table;
    310 
    311 	if (!smu_table->tables)
    312 		return -EINVAL;
    313 
    314 	kfree(smu_table->clocks_table);
    315 	kfree(smu_table->tables);
    316 
    317 	smu_table->clocks_table = NULL;
    318 	smu_table->tables = NULL;
    319 
    320 	return 0;
    321 }
    322 
    323 int smu_v12_0_populate_smc_tables(struct smu_context *smu)
    324 {
    325 	struct smu_table_context *smu_table = &smu->smu_table;
    326 
    327 	return smu_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false);
    328 }
    329 
    330 int smu_v12_0_get_enabled_mask(struct smu_context *smu,
    331 				      uint32_t *feature_mask, uint32_t num)
    332 {
    333 	uint32_t feature_mask_high = 0, feature_mask_low = 0;
    334 	int ret = 0;
    335 
    336 	if (!feature_mask || num < 2)
    337 		return -EINVAL;
    338 
    339 	ret = smu_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesHigh);
    340 	if (ret)
    341 		return ret;
    342 	ret = smu_read_smc_arg(smu, &feature_mask_high);
    343 	if (ret)
    344 		return ret;
    345 
    346 	ret = smu_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesLow);
    347 	if (ret)
    348 		return ret;
    349 	ret = smu_read_smc_arg(smu, &feature_mask_low);
    350 	if (ret)
    351 		return ret;
    352 
    353 	feature_mask[0] = feature_mask_low;
    354 	feature_mask[1] = feature_mask_high;
    355 
    356 	return ret;
    357 }
    358 
    359 int smu_v12_0_get_current_clk_freq(struct smu_context *smu,
    360 					  enum smu_clk_type clk_id,
    361 					  uint32_t *value)
    362 {
    363 	int ret = 0;
    364 	uint32_t freq = 0;
    365 
    366 	if (clk_id >= SMU_CLK_COUNT || !value)
    367 		return -EINVAL;
    368 
    369 	ret = smu_get_current_clk_freq_by_table(smu, clk_id, &freq);
    370 	if (ret)
    371 		return ret;
    372 
    373 	freq *= 100;
    374 	*value = freq;
    375 
    376 	return ret;
    377 }
    378 
    379 int smu_v12_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type,
    380 						 uint32_t *min, uint32_t *max)
    381 {
    382 	int ret = 0;
    383 	uint32_t mclk_mask, soc_mask;
    384 
    385 	if (max) {
    386 		ret = smu_get_profiling_clk_mask(smu, AMD_DPM_FORCED_LEVEL_PROFILE_PEAK,
    387 						 NULL,
    388 						 &mclk_mask,
    389 						 &soc_mask);
    390 		if (ret)
    391 			goto failed;
    392 
    393 		switch (clk_type) {
    394 		case SMU_GFXCLK:
    395 		case SMU_SCLK:
    396 			ret = smu_send_smc_msg(smu, SMU_MSG_GetMaxGfxclkFrequency);
    397 			if (ret) {
    398 				pr_err("Attempt to get max GX frequency from SMC Failed !\n");
    399 				goto failed;
    400 			}
    401 			ret = smu_read_smc_arg(smu, max);
    402 			if (ret)
    403 				goto failed;
    404 			break;
    405 		case SMU_UCLK:
    406 		case SMU_FCLK:
    407 		case SMU_MCLK:
    408 			ret = smu_get_dpm_clk_limited(smu, clk_type, mclk_mask, max);
    409 			if (ret)
    410 				goto failed;
    411 			break;
    412 		case SMU_SOCCLK:
    413 			ret = smu_get_dpm_clk_limited(smu, clk_type, soc_mask, max);
    414 			if (ret)
    415 				goto failed;
    416 			break;
    417 		default:
    418 			ret = -EINVAL;
    419 			goto failed;
    420 		}
    421 	}
    422 
    423 	if (min) {
    424 		switch (clk_type) {
    425 		case SMU_GFXCLK:
    426 		case SMU_SCLK:
    427 			ret = smu_send_smc_msg(smu, SMU_MSG_GetMinGfxclkFrequency);
    428 			if (ret) {
    429 				pr_err("Attempt to get min GX frequency from SMC Failed !\n");
    430 				goto failed;
    431 			}
    432 			ret = smu_read_smc_arg(smu, min);
    433 			if (ret)
    434 				goto failed;
    435 			break;
    436 		case SMU_UCLK:
    437 		case SMU_FCLK:
    438 		case SMU_MCLK:
    439 			ret = smu_get_dpm_clk_limited(smu, clk_type, 0, min);
    440 			if (ret)
    441 				goto failed;
    442 			break;
    443 		case SMU_SOCCLK:
    444 			ret = smu_get_dpm_clk_limited(smu, clk_type, 0, min);
    445 			if (ret)
    446 				goto failed;
    447 			break;
    448 		default:
    449 			ret = -EINVAL;
    450 			goto failed;
    451 		}
    452 	}
    453 failed:
    454 	return ret;
    455 }
    456 
    457 int smu_v12_0_mode2_reset(struct smu_context *smu){
    458 	return smu_v12_0_send_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, SMU_RESET_MODE_2);
    459 }
    460 
    461 int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type,
    462 			    uint32_t min, uint32_t max)
    463 {
    464 	int ret = 0;
    465 
    466 	if (max < min)
    467 		return -EINVAL;
    468 
    469 	switch (clk_type) {
    470 	case SMU_GFXCLK:
    471 	case SMU_SCLK:
    472 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, min);
    473 		if (ret)
    474 			return ret;
    475 
    476 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, max);
    477 		if (ret)
    478 			return ret;
    479 	break;
    480 	case SMU_FCLK:
    481 	case SMU_MCLK:
    482 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min);
    483 		if (ret)
    484 			return ret;
    485 
    486 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxFclkByFreq, max);
    487 		if (ret)
    488 			return ret;
    489 	break;
    490 	case SMU_SOCCLK:
    491 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinSocclkByFreq, min);
    492 		if (ret)
    493 			return ret;
    494 
    495 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxSocclkByFreq, max);
    496 		if (ret)
    497 			return ret;
    498 	break;
    499 	case SMU_VCLK:
    500 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinVcn, min);
    501 		if (ret)
    502 			return ret;
    503 
    504 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxVcn, max);
    505 		if (ret)
    506 			return ret;
    507 	break;
    508 	default:
    509 		return -EINVAL;
    510 	}
    511 
    512 	return ret;
    513 }
    514 
    515 int smu_v12_0_set_driver_table_location(struct smu_context *smu)
    516 {
    517 	struct smu_table *driver_table = &smu->smu_table.driver_table;
    518 	int ret = 0;
    519 
    520 	if (driver_table->mc_address) {
    521 		ret = smu_send_smc_msg_with_param(smu,
    522 				SMU_MSG_SetDriverDramAddrHigh,
    523 				upper_32_bits(driver_table->mc_address));
    524 		if (!ret)
    525 			ret = smu_send_smc_msg_with_param(smu,
    526 				SMU_MSG_SetDriverDramAddrLow,
    527 				lower_32_bits(driver_table->mc_address));
    528 	}
    529 
    530 	return ret;
    531 }
    532