Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2016 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
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  * smu7_fan_ctrl_set_static_mode - Set Fan Speed Control to static mode, so that the user can decide what speed to use.
0104  * @hwmgr:  the address of the powerplay hardware manager.
0105  * @mode:   the fan control mode, 0 default, 1 by percent, 5, by RPM
0106  * Exception: Should always succeed.
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  * smu7_fan_ctrl_set_default_mode - Reset Fan Speed Control to default mode.
0130  * @hwmgr:  the address of the powerplay hardware manager.
0131  * Exception: Should always succeed.
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  * smu7_fan_ctrl_set_fan_speed_pwm - Set Fan Speed in PWM.
0200  * @hwmgr: the address of the powerplay hardware manager.
0201  * @speed: is the pwm value (0 - 255) to be set.
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 * smu7_fan_ctrl_reset_fan_speed_to_default - Reset Fan Speed to default.
0236 * @hwmgr:  the address of the powerplay hardware manager.
0237 * Exception: Always succeeds.
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  * smu7_fan_ctrl_set_fan_speed_rpm - Set Fan Speed in RPM.
0258  * @hwmgr: the address of the powerplay hardware manager.
0259  * @speed: is the percentage value (min - max) to be set.
0260  * Exception: Fails is the speed not lie between min and max.
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  * smu7_thermal_get_temperature - Reads the remote temperature from the SIslands thermal controller.
0290  *
0291  * @hwmgr: The address of the hardware manager.
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     /* Bit 9 means the reading is lower than the lowest usable value. */
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  * smu7_thermal_set_temperature_range - Set the requested temperature range for high and low alert signals
0313  *
0314  * @hwmgr: The address of the hardware manager.
0315  * @low_temp: Temperature to be programmed for high alert signals
0316  * @high_temp: Temperature to be programmed for low alert signals
0317  * Exception: PP_Result_BadInput if the input data is not valid.
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  * smu7_thermal_initialize - Programs thermal controller one-time setting registers
0350  *
0351  * @hwmgr: The address of the hardware manager.
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  * smu7_thermal_enable_alert - Enable thermal alerts on the RV770 thermal controller.
0369  *
0370  * @hwmgr: The address of the hardware manager.
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     /* send message to SMU to enable internal thermal interrupts */
0383     smum_send_msg_to_smc(hwmgr, PPSMC_MSG_Thermal_Cntl_Enable, NULL);
0384 }
0385 
0386 /**
0387  * smu7_thermal_disable_alert - Disable thermal alerts on the RV770 thermal controller.
0388  * @hwmgr: The address of the hardware manager.
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     /* send message to SMU to disable internal thermal interrupts */
0401     return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_Thermal_Cntl_Disable, NULL);
0402 }
0403 
0404 /**
0405  * smu7_thermal_stop_thermal_controller - Uninitialize the thermal controller.
0406  * Currently just disables alerts.
0407  * @hwmgr: The address of the hardware manager.
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  * smu7_thermal_start_smc_fan_control - Start the fan control on the SMC.
0421  * @hwmgr:  the address of the powerplay hardware manager.
0422  * Return:   result from set temperature range routine
0423  */
0424 static int smu7_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr)
0425 {
0426 /* If the fantable setup has failed we could have disabled
0427  * PHM_PlatformCaps_MicrocodeFanControl even after
0428  * this function was included in the table.
0429  * Make sure that we still think controlling the fan is OK.
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 /* We should restrict performance levels to low before we halt the SMC.
0457  * On the other hand we are still in boot state when we do this
0458  * so it would be pointless.
0459  * If this assumption changes we have to revisit this table.
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