0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <asm/div64.h>
0025 #include "smu7_thermal.h"
0026 #include "smu7_hwmgr.h"
0027 #include "smu7_common.h"
0028
0029 int smu7_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
0030 struct phm_fan_speed_info *fan_speed_info)
0031 {
0032 if (hwmgr->thermal_controller.fanInfo.bNoFan)
0033 return -ENODEV;
0034
0035 fan_speed_info->supports_percent_read = true;
0036 fan_speed_info->supports_percent_write = true;
0037 fan_speed_info->min_percent = 0;
0038 fan_speed_info->max_percent = 100;
0039
0040 if (PP_CAP(PHM_PlatformCaps_FanSpeedInTableIsRPM) &&
0041 hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
0042 fan_speed_info->supports_rpm_read = true;
0043 fan_speed_info->supports_rpm_write = true;
0044 fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
0045 fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
0046 } else {
0047 fan_speed_info->min_rpm = 0;
0048 fan_speed_info->max_rpm = 0;
0049 }
0050
0051 return 0;
0052 }
0053
0054 int smu7_fan_ctrl_get_fan_speed_pwm(struct pp_hwmgr *hwmgr,
0055 uint32_t *speed)
0056 {
0057 uint32_t duty100;
0058 uint32_t duty;
0059 uint64_t tmp64;
0060
0061 if (hwmgr->thermal_controller.fanInfo.bNoFan)
0062 return -ENODEV;
0063
0064 duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0065 CG_FDO_CTRL1, FMAX_DUTY100);
0066 duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0067 CG_THERMAL_STATUS, FDO_PWM_DUTY);
0068
0069 if (duty100 == 0)
0070 return -EINVAL;
0071
0072
0073 tmp64 = (uint64_t)duty * 255;
0074 do_div(tmp64, duty100);
0075 *speed = MIN((uint32_t)tmp64, 255);
0076
0077 return 0;
0078 }
0079
0080 int smu7_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
0081 {
0082 uint32_t tach_period;
0083 uint32_t crystal_clock_freq;
0084
0085 if (hwmgr->thermal_controller.fanInfo.bNoFan ||
0086 !hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
0087 return -ENODEV;
0088
0089 tach_period = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0090 CG_TACH_STATUS, TACH_PERIOD);
0091
0092 if (tach_period == 0)
0093 return -EINVAL;
0094
0095 crystal_clock_freq = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev);
0096
0097 *speed = 60 * crystal_clock_freq * 10000 / tach_period;
0098
0099 return 0;
0100 }
0101
0102
0103
0104
0105
0106
0107
0108 int smu7_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
0109 {
0110 if (hwmgr->fan_ctrl_is_in_default_mode) {
0111 hwmgr->fan_ctrl_default_mode =
0112 PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0113 CG_FDO_CTRL2, FDO_PWM_MODE);
0114 hwmgr->tmin =
0115 PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0116 CG_FDO_CTRL2, TMIN);
0117 hwmgr->fan_ctrl_is_in_default_mode = false;
0118 }
0119
0120 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0121 CG_FDO_CTRL2, TMIN, 0);
0122 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0123 CG_FDO_CTRL2, FDO_PWM_MODE, mode);
0124
0125 return 0;
0126 }
0127
0128
0129
0130
0131
0132
0133 int smu7_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
0134 {
0135 if (!hwmgr->fan_ctrl_is_in_default_mode) {
0136 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0137 CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
0138 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0139 CG_FDO_CTRL2, TMIN, hwmgr->tmin);
0140 hwmgr->fan_ctrl_is_in_default_mode = true;
0141 }
0142
0143 return 0;
0144 }
0145
0146 int smu7_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
0147 {
0148 int result;
0149
0150 if (PP_CAP(PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
0151 result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_StartFanControl,
0152 FAN_CONTROL_FUZZY, NULL);
0153
0154 if (PP_CAP(PHM_PlatformCaps_FanSpeedInTableIsRPM))
0155 hwmgr->hwmgr_func->set_max_fan_rpm_output(hwmgr,
0156 hwmgr->thermal_controller.
0157 advanceFanControlParameters.usMaxFanRPM);
0158 else
0159 hwmgr->hwmgr_func->set_max_fan_pwm_output(hwmgr,
0160 hwmgr->thermal_controller.
0161 advanceFanControlParameters.usMaxFanPWM);
0162
0163 } else {
0164 result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_StartFanControl,
0165 FAN_CONTROL_TABLE, NULL);
0166 }
0167
0168 if (!result && hwmgr->thermal_controller.
0169 advanceFanControlParameters.ucTargetTemperature)
0170 result = smum_send_msg_to_smc_with_parameter(hwmgr,
0171 PPSMC_MSG_SetFanTemperatureTarget,
0172 hwmgr->thermal_controller.
0173 advanceFanControlParameters.ucTargetTemperature,
0174 NULL);
0175
0176 if (!result &&
0177 (hwmgr->chip_id == CHIP_POLARIS10 ||
0178 hwmgr->chip_id == CHIP_POLARIS11 ||
0179 hwmgr->chip_id == CHIP_POLARIS12) &&
0180 hwmgr->thermal_controller.advanceFanControlParameters.ucEnableZeroRPM &&
0181 !PP_CAP(PHM_PlatformCaps_customThermalManagement))
0182 result = smum_send_msg_to_smc(hwmgr,
0183 PPSMC_MSG_EnableZeroRpm,
0184 NULL);
0185
0186 hwmgr->fan_ctrl_enabled = true;
0187
0188 return result;
0189 }
0190
0191
0192 int smu7_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
0193 {
0194 hwmgr->fan_ctrl_enabled = false;
0195 return smum_send_msg_to_smc(hwmgr, PPSMC_StopFanControl, NULL);
0196 }
0197
0198
0199
0200
0201
0202
0203 int smu7_fan_ctrl_set_fan_speed_pwm(struct pp_hwmgr *hwmgr,
0204 uint32_t speed)
0205 {
0206 uint32_t duty100;
0207 uint32_t duty;
0208 uint64_t tmp64;
0209
0210 if (hwmgr->thermal_controller.fanInfo.bNoFan)
0211 return 0;
0212
0213 speed = MIN(speed, 255);
0214
0215 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
0216 smu7_fan_ctrl_stop_smc_fan_control(hwmgr);
0217
0218 duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0219 CG_FDO_CTRL1, FMAX_DUTY100);
0220
0221 if (duty100 == 0)
0222 return -EINVAL;
0223
0224 tmp64 = (uint64_t)speed * duty100;
0225 do_div(tmp64, 255);
0226 duty = (uint32_t)tmp64;
0227
0228 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0229 CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
0230
0231 return smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
0232 }
0233
0234
0235
0236
0237
0238
0239 int smu7_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
0240 {
0241 int result;
0242
0243 if (hwmgr->thermal_controller.fanInfo.bNoFan)
0244 return 0;
0245
0246 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) {
0247 result = smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
0248 if (!result)
0249 result = smu7_fan_ctrl_start_smc_fan_control(hwmgr);
0250 } else
0251 result = smu7_fan_ctrl_set_default_mode(hwmgr);
0252
0253 return result;
0254 }
0255
0256
0257
0258
0259
0260
0261
0262 int smu7_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
0263 {
0264 uint32_t tach_period;
0265 uint32_t crystal_clock_freq;
0266
0267 if (hwmgr->thermal_controller.fanInfo.bNoFan ||
0268 (hwmgr->thermal_controller.fanInfo.
0269 ucTachometerPulsesPerRevolution == 0) ||
0270 speed == 0 ||
0271 (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) ||
0272 (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM))
0273 return 0;
0274
0275 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
0276 smu7_fan_ctrl_stop_smc_fan_control(hwmgr);
0277
0278 crystal_clock_freq = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev);
0279
0280 tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
0281
0282 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0283 CG_TACH_CTRL, TARGET_PERIOD, tach_period);
0284
0285 return smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC_RPM);
0286 }
0287
0288
0289
0290
0291
0292
0293 int smu7_thermal_get_temperature(struct pp_hwmgr *hwmgr)
0294 {
0295 int temp;
0296
0297 temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0298 CG_MULT_THERMAL_STATUS, CTF_TEMP);
0299
0300
0301 if (temp & 0x200)
0302 temp = SMU7_THERMAL_MAXIMUM_TEMP_READING;
0303 else
0304 temp = temp & 0x1ff;
0305
0306 temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
0307
0308 return temp;
0309 }
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319 static int smu7_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
0320 int low_temp, int high_temp)
0321 {
0322 int low = SMU7_THERMAL_MINIMUM_ALERT_TEMP *
0323 PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
0324 int high = SMU7_THERMAL_MAXIMUM_ALERT_TEMP *
0325 PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
0326
0327 if (low < low_temp)
0328 low = low_temp;
0329 if (high > high_temp)
0330 high = high_temp;
0331
0332 if (low > high)
0333 return -EINVAL;
0334
0335 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0336 CG_THERMAL_INT, DIG_THERM_INTH,
0337 (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
0338 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0339 CG_THERMAL_INT, DIG_THERM_INTL,
0340 (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
0341 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0342 CG_THERMAL_CTRL, DIG_THERM_DPM,
0343 (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
0344
0345 return 0;
0346 }
0347
0348
0349
0350
0351
0352
0353 static int smu7_thermal_initialize(struct pp_hwmgr *hwmgr)
0354 {
0355 if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
0356 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0357 CG_TACH_CTRL, EDGE_PER_REV,
0358 hwmgr->thermal_controller.fanInfo.
0359 ucTachometerPulsesPerRevolution - 1);
0360
0361 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0362 CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
0363
0364 return 0;
0365 }
0366
0367
0368
0369
0370
0371
0372 static void smu7_thermal_enable_alert(struct pp_hwmgr *hwmgr)
0373 {
0374 uint32_t alert;
0375
0376 alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0377 CG_THERMAL_INT, THERM_INT_MASK);
0378 alert &= ~(SMU7_THERMAL_HIGH_ALERT_MASK | SMU7_THERMAL_LOW_ALERT_MASK);
0379 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0380 CG_THERMAL_INT, THERM_INT_MASK, alert);
0381
0382
0383 smum_send_msg_to_smc(hwmgr, PPSMC_MSG_Thermal_Cntl_Enable, NULL);
0384 }
0385
0386
0387
0388
0389
0390 int smu7_thermal_disable_alert(struct pp_hwmgr *hwmgr)
0391 {
0392 uint32_t alert;
0393
0394 alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0395 CG_THERMAL_INT, THERM_INT_MASK);
0396 alert |= (SMU7_THERMAL_HIGH_ALERT_MASK | SMU7_THERMAL_LOW_ALERT_MASK);
0397 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
0398 CG_THERMAL_INT, THERM_INT_MASK, alert);
0399
0400
0401 return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_Thermal_Cntl_Disable, NULL);
0402 }
0403
0404
0405
0406
0407
0408
0409 int smu7_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
0410 {
0411 int result = smu7_thermal_disable_alert(hwmgr);
0412
0413 if (!hwmgr->thermal_controller.fanInfo.bNoFan)
0414 smu7_fan_ctrl_set_default_mode(hwmgr);
0415
0416 return result;
0417 }
0418
0419
0420
0421
0422
0423
0424 static int smu7_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr)
0425 {
0426
0427
0428
0429
0430
0431 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) {
0432 smu7_fan_ctrl_start_smc_fan_control(hwmgr);
0433 smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
0434 }
0435
0436 return 0;
0437 }
0438
0439 int smu7_start_thermal_controller(struct pp_hwmgr *hwmgr,
0440 struct PP_TemperatureRange *range)
0441 {
0442 int ret = 0;
0443
0444 if (range == NULL)
0445 return -EINVAL;
0446
0447 smu7_thermal_initialize(hwmgr);
0448 ret = smu7_thermal_set_temperature_range(hwmgr, range->min, range->max);
0449 if (ret)
0450 return -EINVAL;
0451 smu7_thermal_enable_alert(hwmgr);
0452 ret = smum_thermal_avfs_enable(hwmgr);
0453 if (ret)
0454 return -EINVAL;
0455
0456
0457
0458
0459
0460
0461 smum_thermal_setup_fan_table(hwmgr);
0462 smu7_thermal_start_smc_fan_control(hwmgr);
0463 return 0;
0464 }
0465
0466
0467
0468 int smu7_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
0469 {
0470 if (!hwmgr->thermal_controller.fanInfo.bNoFan)
0471 smu7_fan_ctrl_set_default_mode(hwmgr);
0472 return 0;
0473 }
0474