Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2018 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 "vega20_thermal.h"
0025 #include "vega20_hwmgr.h"
0026 #include "vega20_smumgr.h"
0027 #include "vega20_ppsmc.h"
0028 #include "vega20_inc.h"
0029 #include "soc15_common.h"
0030 #include "pp_debug.h"
0031 
0032 static int vega20_disable_fan_control_feature(struct pp_hwmgr *hwmgr)
0033 {
0034     struct vega20_hwmgr *data = hwmgr->backend;
0035     int ret = 0;
0036 
0037     if (data->smu_features[GNLD_FAN_CONTROL].supported) {
0038         ret = vega20_enable_smc_features(
0039                 hwmgr, false,
0040                 data->smu_features[GNLD_FAN_CONTROL].
0041                 smu_feature_bitmap);
0042         PP_ASSERT_WITH_CODE(!ret,
0043                 "Disable FAN CONTROL feature Failed!",
0044                 return ret);
0045         data->smu_features[GNLD_FAN_CONTROL].enabled = false;
0046     }
0047 
0048     return ret;
0049 }
0050 
0051 int vega20_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
0052 {
0053     struct vega20_hwmgr *data = hwmgr->backend;
0054 
0055     if (data->smu_features[GNLD_FAN_CONTROL].supported)
0056         return vega20_disable_fan_control_feature(hwmgr);
0057 
0058     return 0;
0059 }
0060 
0061 static int vega20_enable_fan_control_feature(struct pp_hwmgr *hwmgr)
0062 {
0063     struct vega20_hwmgr *data = hwmgr->backend;
0064     int ret = 0;
0065 
0066     if (data->smu_features[GNLD_FAN_CONTROL].supported) {
0067         ret = vega20_enable_smc_features(
0068                 hwmgr, true,
0069                 data->smu_features[GNLD_FAN_CONTROL].
0070                 smu_feature_bitmap);
0071         PP_ASSERT_WITH_CODE(!ret,
0072                 "Enable FAN CONTROL feature Failed!",
0073                 return ret);
0074         data->smu_features[GNLD_FAN_CONTROL].enabled = true;
0075     }
0076 
0077     return ret;
0078 }
0079 
0080 int vega20_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
0081 {
0082     struct vega20_hwmgr *data = hwmgr->backend;
0083 
0084     if (data->smu_features[GNLD_FAN_CONTROL].supported)
0085         return vega20_enable_fan_control_feature(hwmgr);
0086 
0087     return 0;
0088 }
0089 
0090 static int vega20_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
0091 {
0092     struct amdgpu_device *adev = hwmgr->adev;
0093 
0094     WREG32_SOC15(THM, 0, mmCG_FDO_CTRL2,
0095             REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2),
0096                 CG_FDO_CTRL2, TMIN, 0));
0097     WREG32_SOC15(THM, 0, mmCG_FDO_CTRL2,
0098             REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2),
0099                 CG_FDO_CTRL2, FDO_PWM_MODE, mode));
0100 
0101     return 0;
0102 }
0103 
0104 static int vega20_get_current_rpm(struct pp_hwmgr *hwmgr, uint32_t *current_rpm)
0105 {
0106     int ret = 0;
0107 
0108     PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr,
0109                 PPSMC_MSG_GetCurrentRpm,
0110                 current_rpm)) == 0,
0111             "Attempt to get current RPM from SMC Failed!",
0112             return ret);
0113 
0114     return 0;
0115 }
0116 
0117 int vega20_fan_ctrl_get_fan_speed_pwm(struct pp_hwmgr *hwmgr,
0118         uint32_t *speed)
0119 {
0120     struct amdgpu_device *adev = hwmgr->adev;
0121     uint32_t duty100, duty;
0122     uint64_t tmp64;
0123 
0124     duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1),
0125                 CG_FDO_CTRL1, FMAX_DUTY100);
0126     duty = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_THERMAL_STATUS),
0127                 CG_THERMAL_STATUS, FDO_PWM_DUTY);
0128 
0129     if (!duty100)
0130         return -EINVAL;
0131 
0132     tmp64 = (uint64_t)duty * 255;
0133     do_div(tmp64, duty100);
0134     *speed = MIN((uint32_t)tmp64, 255);
0135 
0136     return 0;
0137 }
0138 
0139 int vega20_fan_ctrl_set_fan_speed_pwm(struct pp_hwmgr *hwmgr,
0140         uint32_t speed)
0141 {
0142     struct amdgpu_device *adev = hwmgr->adev;
0143     uint32_t duty100;
0144     uint32_t duty;
0145     uint64_t tmp64;
0146 
0147     speed = MIN(speed, 255);
0148 
0149     if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
0150         vega20_fan_ctrl_stop_smc_fan_control(hwmgr);
0151 
0152     duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1),
0153                     CG_FDO_CTRL1, FMAX_DUTY100);
0154 
0155     if (duty100 == 0)
0156         return -EINVAL;
0157 
0158     tmp64 = (uint64_t)speed * duty100;
0159     do_div(tmp64, 255);
0160     duty = (uint32_t)tmp64;
0161 
0162     WREG32_SOC15(THM, 0, mmCG_FDO_CTRL0,
0163         REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL0),
0164             CG_FDO_CTRL0, FDO_STATIC_DUTY, duty));
0165 
0166     return vega20_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
0167 }
0168 
0169 int vega20_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
0170         struct phm_fan_speed_info *fan_speed_info)
0171 {
0172     memset(fan_speed_info, 0, sizeof(*fan_speed_info));
0173     fan_speed_info->supports_percent_read = true;
0174     fan_speed_info->supports_percent_write = true;
0175     fan_speed_info->supports_rpm_read = true;
0176     fan_speed_info->supports_rpm_write = true;
0177 
0178     return 0;
0179 }
0180 
0181 int vega20_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
0182 {
0183     *speed = 0;
0184 
0185     return vega20_get_current_rpm(hwmgr, speed);
0186 }
0187 
0188 int vega20_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
0189 {
0190     struct amdgpu_device *adev = hwmgr->adev;
0191     uint32_t tach_period, crystal_clock_freq;
0192     int result = 0;
0193 
0194     if (!speed)
0195         return -EINVAL;
0196 
0197     if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) {
0198         result = vega20_fan_ctrl_stop_smc_fan_control(hwmgr);
0199         if (result)
0200             return result;
0201     }
0202 
0203     crystal_clock_freq = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev);
0204     tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
0205     WREG32_SOC15(THM, 0, mmCG_TACH_CTRL,
0206             REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL),
0207                 CG_TACH_CTRL, TARGET_PERIOD,
0208                 tach_period));
0209 
0210     return vega20_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC_RPM);
0211 }
0212 
0213 /**
0214  * vega20_thermal_get_temperature - Reads the remote temperature from the SIslands thermal controller.
0215  *
0216  * @hwmgr: The address of the hardware manager.
0217  */
0218 int vega20_thermal_get_temperature(struct pp_hwmgr *hwmgr)
0219 {
0220     struct amdgpu_device *adev = hwmgr->adev;
0221     int temp = 0;
0222 
0223     temp = RREG32_SOC15(THM, 0, mmCG_MULT_THERMAL_STATUS);
0224 
0225     temp = (temp & CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >>
0226             CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT;
0227 
0228     temp = temp & 0x1ff;
0229 
0230     temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
0231     return temp;
0232 }
0233 
0234 /**
0235  * vega20_thermal_set_temperature_range - Set the requested temperature range for high and low alert signals
0236  *
0237  * @hwmgr: The address of the hardware manager.
0238  * @range: Temperature range to be programmed for high and low alert signals
0239  * Exception: PP_Result_BadInput if the input data is not valid.
0240  */
0241 static int vega20_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
0242         struct PP_TemperatureRange *range)
0243 {
0244     struct phm_ppt_v3_information *pptable_information =
0245         (struct phm_ppt_v3_information *)hwmgr->pptable;
0246     struct amdgpu_device *adev = hwmgr->adev;
0247     int low = VEGA20_THERMAL_MINIMUM_ALERT_TEMP;
0248     int high = VEGA20_THERMAL_MAXIMUM_ALERT_TEMP;
0249     uint32_t val;
0250 
0251     /* compare them in unit celsius degree */
0252     if (low < range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)
0253         low = range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
0254     if (high > pptable_information->us_software_shutdown_temp)
0255         high = pptable_information->us_software_shutdown_temp;
0256 
0257     if (low > high)
0258         return -EINVAL;
0259 
0260     val = RREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL);
0261 
0262     val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5);
0263     val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1);
0264     val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, high);
0265     val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, low);
0266     val = val & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK);
0267 
0268     WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL, val);
0269 
0270     return 0;
0271 }
0272 
0273 /**
0274  * vega20_thermal_enable_alert - Enable thermal alerts on the RV770 thermal controller.
0275  *
0276  * @hwmgr: The address of the hardware manager.
0277  */
0278 static int vega20_thermal_enable_alert(struct pp_hwmgr *hwmgr)
0279 {
0280     struct amdgpu_device *adev = hwmgr->adev;
0281     uint32_t val = 0;
0282 
0283     val |= (1 << THM_THERMAL_INT_ENA__THERM_INTH_CLR__SHIFT);
0284     val |= (1 << THM_THERMAL_INT_ENA__THERM_INTL_CLR__SHIFT);
0285     val |= (1 << THM_THERMAL_INT_ENA__THERM_TRIGGER_CLR__SHIFT);
0286 
0287     WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_ENA, val);
0288 
0289     return 0;
0290 }
0291 
0292 /**
0293  * vega20_thermal_disable_alert - Disable thermal alerts on the RV770 thermal controller.
0294  * @hwmgr: The address of the hardware manager.
0295  */
0296 int vega20_thermal_disable_alert(struct pp_hwmgr *hwmgr)
0297 {
0298     struct amdgpu_device *adev = hwmgr->adev;
0299 
0300     WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_ENA, 0);
0301 
0302     return 0;
0303 }
0304 
0305 /**
0306  * vega20_thermal_stop_thermal_controller - Uninitialize the thermal controller.
0307  * Currently just disables alerts.
0308  * @hwmgr: The address of the hardware manager.
0309  */
0310 int vega20_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
0311 {
0312     int result = vega20_thermal_disable_alert(hwmgr);
0313 
0314     return result;
0315 }
0316 
0317 /**
0318  * vega20_thermal_setup_fan_table - Set up the fan table to control the fan using the SMC.
0319  * @hwmgr:  the address of the powerplay hardware manager.
0320  */
0321 static int vega20_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
0322 {
0323     int ret;
0324     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
0325     PPTable_t *table = &(data->smc_state_table.pp_table);
0326 
0327     ret = smum_send_msg_to_smc_with_parameter(hwmgr,
0328                 PPSMC_MSG_SetFanTemperatureTarget,
0329                 (uint32_t)table->FanTargetTemperature,
0330                 NULL);
0331 
0332     return ret;
0333 }
0334 
0335 int vega20_start_thermal_controller(struct pp_hwmgr *hwmgr,
0336                 struct PP_TemperatureRange *range)
0337 {
0338     int ret = 0;
0339 
0340     if (range == NULL)
0341         return -EINVAL;
0342 
0343     ret = vega20_thermal_set_temperature_range(hwmgr, range);
0344     if (ret)
0345         return ret;
0346 
0347     ret = vega20_thermal_enable_alert(hwmgr);
0348     if (ret)
0349         return ret;
0350 
0351     ret = vega20_thermal_setup_fan_table(hwmgr);
0352 
0353     return ret;
0354 };