Home | History | Annotate | Line # | Download | only in hwmgr
      1 /*	$NetBSD: amdgpu_vega20_thermal.c,v 1.2 2021/12/18 23:45:26 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2018 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 
     26 #include <sys/cdefs.h>
     27 __KERNEL_RCSID(0, "$NetBSD: amdgpu_vega20_thermal.c,v 1.2 2021/12/18 23:45:26 riastradh Exp $");
     28 
     29 #include "vega20_thermal.h"
     30 #include "vega20_hwmgr.h"
     31 #include "vega20_smumgr.h"
     32 #include "vega20_ppsmc.h"
     33 #include "vega20_inc.h"
     34 #include "soc15_common.h"
     35 #include "pp_debug.h"
     36 
     37 static int vega20_disable_fan_control_feature(struct pp_hwmgr *hwmgr)
     38 {
     39 	struct vega20_hwmgr *data = hwmgr->backend;
     40 	int ret = 0;
     41 
     42 	if (data->smu_features[GNLD_FAN_CONTROL].supported) {
     43 		ret = vega20_enable_smc_features(
     44 				hwmgr, false,
     45 				data->smu_features[GNLD_FAN_CONTROL].
     46 				smu_feature_bitmap);
     47 		PP_ASSERT_WITH_CODE(!ret,
     48 				"Disable FAN CONTROL feature Failed!",
     49 				return ret);
     50 		data->smu_features[GNLD_FAN_CONTROL].enabled = false;
     51 	}
     52 
     53 	return ret;
     54 }
     55 
     56 int vega20_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
     57 {
     58 	struct vega20_hwmgr *data = hwmgr->backend;
     59 
     60 	if (data->smu_features[GNLD_FAN_CONTROL].supported)
     61 		return vega20_disable_fan_control_feature(hwmgr);
     62 
     63 	return 0;
     64 }
     65 
     66 static int vega20_enable_fan_control_feature(struct pp_hwmgr *hwmgr)
     67 {
     68 	struct vega20_hwmgr *data = hwmgr->backend;
     69 	int ret = 0;
     70 
     71 	if (data->smu_features[GNLD_FAN_CONTROL].supported) {
     72 		ret = vega20_enable_smc_features(
     73 				hwmgr, true,
     74 				data->smu_features[GNLD_FAN_CONTROL].
     75 				smu_feature_bitmap);
     76 		PP_ASSERT_WITH_CODE(!ret,
     77 				"Enable FAN CONTROL feature Failed!",
     78 				return ret);
     79 		data->smu_features[GNLD_FAN_CONTROL].enabled = true;
     80 	}
     81 
     82 	return ret;
     83 }
     84 
     85 int vega20_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
     86 {
     87 	struct vega20_hwmgr *data = hwmgr->backend;
     88 
     89 	if (data->smu_features[GNLD_FAN_CONTROL].supported)
     90 		return vega20_enable_fan_control_feature(hwmgr);
     91 
     92 	return 0;
     93 }
     94 
     95 static int vega20_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
     96 {
     97 	struct amdgpu_device *adev = hwmgr->adev;
     98 
     99 	WREG32_SOC15(THM, 0, mmCG_FDO_CTRL2,
    100 			REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2),
    101 				CG_FDO_CTRL2, TMIN, 0));
    102 	WREG32_SOC15(THM, 0, mmCG_FDO_CTRL2,
    103 			REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2),
    104 				CG_FDO_CTRL2, FDO_PWM_MODE, mode));
    105 
    106 	return 0;
    107 }
    108 
    109 static int vega20_get_current_rpm(struct pp_hwmgr *hwmgr, uint32_t *current_rpm)
    110 {
    111 	int ret = 0;
    112 
    113 	PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr,
    114 				PPSMC_MSG_GetCurrentRpm)) == 0,
    115 			"Attempt to get current RPM from SMC Failed!",
    116 			return ret);
    117 	*current_rpm = smum_get_argument(hwmgr);
    118 
    119 	return 0;
    120 }
    121 
    122 int vega20_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
    123 		uint32_t *speed)
    124 {
    125 	struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    126 	PPTable_t *pp_table = &(data->smc_state_table.pp_table);
    127 	uint32_t current_rpm, percent = 0;
    128 	int ret = 0;
    129 
    130 	ret = vega20_get_current_rpm(hwmgr, &current_rpm);
    131 	if (ret)
    132 		return ret;
    133 
    134 	percent = current_rpm * 100 / pp_table->FanMaximumRpm;
    135 
    136 	*speed = percent > 100 ? 100 : percent;
    137 
    138 	return 0;
    139 }
    140 
    141 int vega20_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
    142 		uint32_t speed)
    143 {
    144 	struct amdgpu_device *adev = hwmgr->adev;
    145 	uint32_t duty100;
    146 	uint32_t duty;
    147 	uint64_t tmp64;
    148 
    149 	if (speed > 100)
    150 		speed = 100;
    151 
    152 	if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
    153 		vega20_fan_ctrl_stop_smc_fan_control(hwmgr);
    154 
    155 	duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1),
    156 				    CG_FDO_CTRL1, FMAX_DUTY100);
    157 
    158 	if (duty100 == 0)
    159 		return -EINVAL;
    160 
    161 	tmp64 = (uint64_t)speed * duty100;
    162 	do_div(tmp64, 100);
    163 	duty = (uint32_t)tmp64;
    164 
    165 	WREG32_SOC15(THM, 0, mmCG_FDO_CTRL0,
    166 		REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL0),
    167 			CG_FDO_CTRL0, FDO_STATIC_DUTY, duty));
    168 
    169 	return vega20_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
    170 }
    171 
    172 int vega20_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
    173 		struct phm_fan_speed_info *fan_speed_info)
    174 {
    175 	memset(fan_speed_info, 0, sizeof(*fan_speed_info));
    176 	fan_speed_info->supports_percent_read = true;
    177 	fan_speed_info->supports_percent_write = true;
    178 	fan_speed_info->supports_rpm_read = true;
    179 	fan_speed_info->supports_rpm_write = true;
    180 
    181 	return 0;
    182 }
    183 
    184 int vega20_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
    185 {
    186 	*speed = 0;
    187 
    188 	return vega20_get_current_rpm(hwmgr, speed);
    189 }
    190 
    191 int vega20_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
    192 {
    193 	struct amdgpu_device *adev = hwmgr->adev;
    194 	uint32_t tach_period, crystal_clock_freq;
    195 	int result = 0;
    196 
    197 	if (!speed)
    198 		return -EINVAL;
    199 
    200 	if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) {
    201 		result = vega20_fan_ctrl_stop_smc_fan_control(hwmgr);
    202 		if (result)
    203 			return result;
    204 	}
    205 
    206 	crystal_clock_freq = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev);
    207 	tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
    208 	WREG32_SOC15(THM, 0, mmCG_TACH_CTRL,
    209 			REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL),
    210 				CG_TACH_CTRL, TARGET_PERIOD,
    211 				tach_period));
    212 
    213 	return vega20_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC_RPM);
    214 }
    215 
    216 /**
    217 * Reads the remote temperature from the SIslands thermal controller.
    218 *
    219 * @param    hwmgr The address of the hardware manager.
    220 */
    221 int vega20_thermal_get_temperature(struct pp_hwmgr *hwmgr)
    222 {
    223 	struct amdgpu_device *adev = hwmgr->adev;
    224 	int temp = 0;
    225 
    226 	temp = RREG32_SOC15(THM, 0, mmCG_MULT_THERMAL_STATUS);
    227 
    228 	temp = (temp & CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >>
    229 			CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT;
    230 
    231 	temp = temp & 0x1ff;
    232 
    233 	temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
    234 	return temp;
    235 }
    236 
    237 /**
    238 * Set the requested temperature range for high and low alert signals
    239 *
    240 * @param    hwmgr The address of the hardware manager.
    241 * @param    range Temperature range to be programmed for
    242 *           high and low alert signals
    243 * @exception PP_Result_BadInput if the input data is not valid.
    244 */
    245 static int vega20_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
    246 		struct PP_TemperatureRange *range)
    247 {
    248 	struct amdgpu_device *adev = hwmgr->adev;
    249 	int low = VEGA20_THERMAL_MINIMUM_ALERT_TEMP *
    250 			PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
    251 	int high = VEGA20_THERMAL_MAXIMUM_ALERT_TEMP *
    252 			PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
    253 	uint32_t val;
    254 
    255 	if (low < range->min)
    256 		low = range->min;
    257 	if (high > range->max)
    258 		high = range->max;
    259 
    260 	if (low > high)
    261 		return -EINVAL;
    262 
    263 	val = RREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL);
    264 
    265 	val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5);
    266 	val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1);
    267 	val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
    268 	val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
    269 	val = val & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK);
    270 
    271 	WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL, val);
    272 
    273 	return 0;
    274 }
    275 
    276 /**
    277 * Enable thermal alerts on the RV770 thermal controller.
    278 *
    279 * @param    hwmgr The address of the hardware manager.
    280 */
    281 static int vega20_thermal_enable_alert(struct pp_hwmgr *hwmgr)
    282 {
    283 	struct amdgpu_device *adev = hwmgr->adev;
    284 	uint32_t val = 0;
    285 
    286 	val |= (1 << THM_THERMAL_INT_ENA__THERM_INTH_CLR__SHIFT);
    287 	val |= (1 << THM_THERMAL_INT_ENA__THERM_INTL_CLR__SHIFT);
    288 	val |= (1 << THM_THERMAL_INT_ENA__THERM_TRIGGER_CLR__SHIFT);
    289 
    290 	WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_ENA, val);
    291 
    292 	return 0;
    293 }
    294 
    295 /**
    296 * Disable thermal alerts on the RV770 thermal controller.
    297 * @param    hwmgr The address of the hardware manager.
    298 */
    299 int vega20_thermal_disable_alert(struct pp_hwmgr *hwmgr)
    300 {
    301 	struct amdgpu_device *adev = hwmgr->adev;
    302 
    303 	WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_ENA, 0);
    304 
    305 	return 0;
    306 }
    307 
    308 /**
    309 * Uninitialize the thermal controller.
    310 * Currently just disables alerts.
    311 * @param    hwmgr The address of the hardware manager.
    312 */
    313 int vega20_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
    314 {
    315 	int result = vega20_thermal_disable_alert(hwmgr);
    316 
    317 	return result;
    318 }
    319 
    320 /**
    321 * Set up the fan table to control the fan using the SMC.
    322 * @param    hwmgr  the address of the powerplay hardware manager.
    323 * @param    pInput the pointer to input data
    324 * @param    pOutput the pointer to output data
    325 * @param    pStorage the pointer to temporary storage
    326 * @param    Result the last failure code
    327 * @return   result from set temperature range routine
    328 */
    329 static int vega20_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
    330 {
    331 	int ret;
    332 	struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    333 	PPTable_t *table = &(data->smc_state_table.pp_table);
    334 
    335 	ret = smum_send_msg_to_smc_with_parameter(hwmgr,
    336 				PPSMC_MSG_SetFanTemperatureTarget,
    337 				(uint32_t)table->FanTargetTemperature);
    338 
    339 	return ret;
    340 }
    341 
    342 int vega20_start_thermal_controller(struct pp_hwmgr *hwmgr,
    343 				struct PP_TemperatureRange *range)
    344 {
    345 	int ret = 0;
    346 
    347 	if (range == NULL)
    348 		return -EINVAL;
    349 
    350 	ret = vega20_thermal_set_temperature_range(hwmgr, range);
    351 	if (ret)
    352 		return ret;
    353 
    354 	ret = vega20_thermal_enable_alert(hwmgr);
    355 	if (ret)
    356 		return ret;
    357 
    358 	ret = vega20_thermal_setup_fan_table(hwmgr);
    359 
    360 	return ret;
    361 };
    362