1e098bc96SEvan Quan /* 2e098bc96SEvan Quan * Copyright 2016 Advanced Micro Devices, Inc. 3e098bc96SEvan Quan * 4e098bc96SEvan Quan * Permission is hereby granted, free of charge, to any person obtaining a 5e098bc96SEvan Quan * copy of this software and associated documentation files (the "Software"), 6e098bc96SEvan Quan * to deal in the Software without restriction, including without limitation 7e098bc96SEvan Quan * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8e098bc96SEvan Quan * and/or sell copies of the Software, and to permit persons to whom the 9e098bc96SEvan Quan * Software is furnished to do so, subject to the following conditions: 10e098bc96SEvan Quan * 11e098bc96SEvan Quan * The above copyright notice and this permission notice shall be included in 12e098bc96SEvan Quan * all copies or substantial portions of the Software. 13e098bc96SEvan Quan * 14e098bc96SEvan Quan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15e098bc96SEvan Quan * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16e098bc96SEvan Quan * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17e098bc96SEvan Quan * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18e098bc96SEvan Quan * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19e098bc96SEvan Quan * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20e098bc96SEvan Quan * OTHER DEALINGS IN THE SOFTWARE. 21e098bc96SEvan Quan * 22e098bc96SEvan Quan */ 23e098bc96SEvan Quan 24e098bc96SEvan Quan #include "vega10_thermal.h" 25e098bc96SEvan Quan #include "vega10_hwmgr.h" 26e098bc96SEvan Quan #include "vega10_smumgr.h" 27e098bc96SEvan Quan #include "vega10_ppsmc.h" 28e098bc96SEvan Quan #include "vega10_inc.h" 29e098bc96SEvan Quan #include "soc15_common.h" 30e098bc96SEvan Quan #include "pp_debug.h" 31e098bc96SEvan Quan 32e098bc96SEvan Quan static int vega10_get_current_rpm(struct pp_hwmgr *hwmgr, uint32_t *current_rpm) 33e098bc96SEvan Quan { 34e098bc96SEvan Quan smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentRpm, current_rpm); 35e098bc96SEvan Quan return 0; 36e098bc96SEvan Quan } 37e098bc96SEvan Quan 38e098bc96SEvan Quan int vega10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, 39e098bc96SEvan Quan struct phm_fan_speed_info *fan_speed_info) 40e098bc96SEvan Quan { 41e098bc96SEvan Quan 42e098bc96SEvan Quan if (hwmgr->thermal_controller.fanInfo.bNoFan) 43e098bc96SEvan Quan return 0; 44e098bc96SEvan Quan 45e098bc96SEvan Quan fan_speed_info->supports_percent_read = true; 46e098bc96SEvan Quan fan_speed_info->supports_percent_write = true; 47e098bc96SEvan Quan fan_speed_info->min_percent = 0; 48e098bc96SEvan Quan fan_speed_info->max_percent = 100; 49e098bc96SEvan Quan 50e098bc96SEvan Quan if (PP_CAP(PHM_PlatformCaps_FanSpeedInTableIsRPM) && 51e098bc96SEvan Quan hwmgr->thermal_controller.fanInfo. 52e098bc96SEvan Quan ucTachometerPulsesPerRevolution) { 53e098bc96SEvan Quan fan_speed_info->supports_rpm_read = true; 54e098bc96SEvan Quan fan_speed_info->supports_rpm_write = true; 55e098bc96SEvan Quan fan_speed_info->min_rpm = 56e098bc96SEvan Quan hwmgr->thermal_controller.fanInfo.ulMinRPM; 57e098bc96SEvan Quan fan_speed_info->max_rpm = 58e098bc96SEvan Quan hwmgr->thermal_controller.fanInfo.ulMaxRPM; 59e098bc96SEvan Quan } else { 60e098bc96SEvan Quan fan_speed_info->min_rpm = 0; 61e098bc96SEvan Quan fan_speed_info->max_rpm = 0; 62e098bc96SEvan Quan } 63e098bc96SEvan Quan 64e098bc96SEvan Quan return 0; 65e098bc96SEvan Quan } 66e098bc96SEvan Quan 67e098bc96SEvan Quan int vega10_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, 68e098bc96SEvan Quan uint32_t *speed) 69e098bc96SEvan Quan { 70e098bc96SEvan Quan uint32_t current_rpm; 71e098bc96SEvan Quan uint32_t percent = 0; 72e098bc96SEvan Quan 73e098bc96SEvan Quan if (hwmgr->thermal_controller.fanInfo.bNoFan) 74e098bc96SEvan Quan return 0; 75e098bc96SEvan Quan 76e098bc96SEvan Quan if (vega10_get_current_rpm(hwmgr, ¤t_rpm)) 77e098bc96SEvan Quan return -1; 78e098bc96SEvan Quan 79e098bc96SEvan Quan if (hwmgr->thermal_controller. 80e098bc96SEvan Quan advanceFanControlParameters.usMaxFanRPM != 0) 81e098bc96SEvan Quan percent = current_rpm * 100 / 82e098bc96SEvan Quan hwmgr->thermal_controller. 83e098bc96SEvan Quan advanceFanControlParameters.usMaxFanRPM; 84e098bc96SEvan Quan 85e098bc96SEvan Quan *speed = percent > 100 ? 100 : percent; 86e098bc96SEvan Quan 87e098bc96SEvan Quan return 0; 88e098bc96SEvan Quan } 89e098bc96SEvan Quan 90e098bc96SEvan Quan int vega10_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed) 91e098bc96SEvan Quan { 92e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev; 93e098bc96SEvan Quan struct vega10_hwmgr *data = hwmgr->backend; 94e098bc96SEvan Quan uint32_t tach_period; 95e098bc96SEvan Quan uint32_t crystal_clock_freq; 96e098bc96SEvan Quan int result = 0; 97e098bc96SEvan Quan 98e098bc96SEvan Quan if (hwmgr->thermal_controller.fanInfo.bNoFan) 99e098bc96SEvan Quan return -1; 100e098bc96SEvan Quan 101e098bc96SEvan Quan if (data->smu_features[GNLD_FAN_CONTROL].supported) { 102e098bc96SEvan Quan result = vega10_get_current_rpm(hwmgr, speed); 103e098bc96SEvan Quan } else { 104e098bc96SEvan Quan tach_period = 105e098bc96SEvan Quan REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_STATUS), 106e098bc96SEvan Quan CG_TACH_STATUS, 107e098bc96SEvan Quan TACH_PERIOD); 108e098bc96SEvan Quan 109e098bc96SEvan Quan if (tach_period == 0) 110e098bc96SEvan Quan return -EINVAL; 111e098bc96SEvan Quan 112e098bc96SEvan Quan crystal_clock_freq = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev); 113e098bc96SEvan Quan 114e098bc96SEvan Quan *speed = 60 * crystal_clock_freq * 10000 / tach_period; 115e098bc96SEvan Quan } 116e098bc96SEvan Quan 117e098bc96SEvan Quan return result; 118e098bc96SEvan Quan } 119e098bc96SEvan Quan 120e098bc96SEvan Quan /** 121*d9261648SLee Jones * vega10_fan_ctrl_set_static_mode - Set Fan Speed Control to static mode, 122e098bc96SEvan Quan * so that the user can decide what speed to use. 123*d9261648SLee Jones * @hwmgr: the address of the powerplay hardware manager. 124*d9261648SLee Jones * @mode: the fan control mode, 0 default, 1 by percent, 5, by RPM 125*d9261648SLee Jones * Exception: Should always succeed. 126e098bc96SEvan Quan */ 127e098bc96SEvan Quan int vega10_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode) 128e098bc96SEvan Quan { 129e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev; 130e098bc96SEvan Quan 131e098bc96SEvan Quan if (hwmgr->fan_ctrl_is_in_default_mode) { 132e098bc96SEvan Quan hwmgr->fan_ctrl_default_mode = 133e098bc96SEvan Quan REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2), 134e098bc96SEvan Quan CG_FDO_CTRL2, FDO_PWM_MODE); 135e098bc96SEvan Quan hwmgr->tmin = 136e098bc96SEvan Quan REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2), 137e098bc96SEvan Quan CG_FDO_CTRL2, TMIN); 138e098bc96SEvan Quan hwmgr->fan_ctrl_is_in_default_mode = false; 139e098bc96SEvan Quan } 140e098bc96SEvan Quan 141e098bc96SEvan Quan WREG32_SOC15(THM, 0, mmCG_FDO_CTRL2, 142e098bc96SEvan Quan REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2), 143e098bc96SEvan Quan CG_FDO_CTRL2, TMIN, 0)); 144e098bc96SEvan Quan WREG32_SOC15(THM, 0, mmCG_FDO_CTRL2, 145e098bc96SEvan Quan REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2), 146e098bc96SEvan Quan CG_FDO_CTRL2, FDO_PWM_MODE, mode)); 147e098bc96SEvan Quan 148e098bc96SEvan Quan return 0; 149e098bc96SEvan Quan } 150e098bc96SEvan Quan 151e098bc96SEvan Quan /** 152*d9261648SLee Jones * vega10_fan_ctrl_set_default_mode - Reset Fan Speed Control to default mode. 153*d9261648SLee Jones * @hwmgr: the address of the powerplay hardware manager. 154*d9261648SLee Jones * Exception: Should always succeed. 155e098bc96SEvan Quan */ 156e098bc96SEvan Quan int vega10_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr) 157e098bc96SEvan Quan { 158e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev; 159e098bc96SEvan Quan 160e098bc96SEvan Quan if (!hwmgr->fan_ctrl_is_in_default_mode) { 161e098bc96SEvan Quan WREG32_SOC15(THM, 0, mmCG_FDO_CTRL2, 162e098bc96SEvan Quan REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2), 163e098bc96SEvan Quan CG_FDO_CTRL2, FDO_PWM_MODE, 164e098bc96SEvan Quan hwmgr->fan_ctrl_default_mode)); 165e098bc96SEvan Quan WREG32_SOC15(THM, 0, mmCG_FDO_CTRL2, 166e098bc96SEvan Quan REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2), 167e098bc96SEvan Quan CG_FDO_CTRL2, TMIN, 168e098bc96SEvan Quan hwmgr->tmin << CG_FDO_CTRL2__TMIN__SHIFT)); 169e098bc96SEvan Quan hwmgr->fan_ctrl_is_in_default_mode = true; 170e098bc96SEvan Quan } 171e098bc96SEvan Quan 172e098bc96SEvan Quan return 0; 173e098bc96SEvan Quan } 174e098bc96SEvan Quan 175e098bc96SEvan Quan /** 176*d9261648SLee Jones * vega10_enable_fan_control_feature - Enables the SMC Fan Control Feature. 177e098bc96SEvan Quan * 178*d9261648SLee Jones * @hwmgr: the address of the powerplay hardware manager. 179*d9261648SLee Jones * Return: 0 on success. -1 otherwise. 180e098bc96SEvan Quan */ 181e098bc96SEvan Quan static int vega10_enable_fan_control_feature(struct pp_hwmgr *hwmgr) 182e098bc96SEvan Quan { 183e098bc96SEvan Quan struct vega10_hwmgr *data = hwmgr->backend; 184e098bc96SEvan Quan 185e098bc96SEvan Quan if (data->smu_features[GNLD_FAN_CONTROL].supported) { 186e098bc96SEvan Quan PP_ASSERT_WITH_CODE(!vega10_enable_smc_features( 187e098bc96SEvan Quan hwmgr, true, 188e098bc96SEvan Quan data->smu_features[GNLD_FAN_CONTROL]. 189e098bc96SEvan Quan smu_feature_bitmap), 190e098bc96SEvan Quan "Attempt to Enable FAN CONTROL feature Failed!", 191e098bc96SEvan Quan return -1); 192e098bc96SEvan Quan data->smu_features[GNLD_FAN_CONTROL].enabled = true; 193e098bc96SEvan Quan } 194e098bc96SEvan Quan 195e098bc96SEvan Quan return 0; 196e098bc96SEvan Quan } 197e098bc96SEvan Quan 198e098bc96SEvan Quan static int vega10_disable_fan_control_feature(struct pp_hwmgr *hwmgr) 199e098bc96SEvan Quan { 200e098bc96SEvan Quan struct vega10_hwmgr *data = hwmgr->backend; 201e098bc96SEvan Quan 202e098bc96SEvan Quan if (data->smu_features[GNLD_FAN_CONTROL].supported) { 203e098bc96SEvan Quan PP_ASSERT_WITH_CODE(!vega10_enable_smc_features( 204e098bc96SEvan Quan hwmgr, false, 205e098bc96SEvan Quan data->smu_features[GNLD_FAN_CONTROL]. 206e098bc96SEvan Quan smu_feature_bitmap), 207e098bc96SEvan Quan "Attempt to Enable FAN CONTROL feature Failed!", 208e098bc96SEvan Quan return -1); 209e098bc96SEvan Quan data->smu_features[GNLD_FAN_CONTROL].enabled = false; 210e098bc96SEvan Quan } 211e098bc96SEvan Quan 212e098bc96SEvan Quan return 0; 213e098bc96SEvan Quan } 214e098bc96SEvan Quan 215e098bc96SEvan Quan int vega10_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr) 216e098bc96SEvan Quan { 217e098bc96SEvan Quan if (hwmgr->thermal_controller.fanInfo.bNoFan) 218e098bc96SEvan Quan return -1; 219e098bc96SEvan Quan 220e098bc96SEvan Quan PP_ASSERT_WITH_CODE(!vega10_enable_fan_control_feature(hwmgr), 221e098bc96SEvan Quan "Attempt to Enable SMC FAN CONTROL Feature Failed!", 222e098bc96SEvan Quan return -1); 223e098bc96SEvan Quan 224e098bc96SEvan Quan return 0; 225e098bc96SEvan Quan } 226e098bc96SEvan Quan 227e098bc96SEvan Quan 228e098bc96SEvan Quan int vega10_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr) 229e098bc96SEvan Quan { 230e098bc96SEvan Quan struct vega10_hwmgr *data = hwmgr->backend; 231e098bc96SEvan Quan 232e098bc96SEvan Quan if (hwmgr->thermal_controller.fanInfo.bNoFan) 233e098bc96SEvan Quan return -1; 234e098bc96SEvan Quan 235e098bc96SEvan Quan if (data->smu_features[GNLD_FAN_CONTROL].supported) { 236e098bc96SEvan Quan PP_ASSERT_WITH_CODE(!vega10_disable_fan_control_feature(hwmgr), 237e098bc96SEvan Quan "Attempt to Disable SMC FAN CONTROL Feature Failed!", 238e098bc96SEvan Quan return -1); 239e098bc96SEvan Quan } 240e098bc96SEvan Quan return 0; 241e098bc96SEvan Quan } 242e098bc96SEvan Quan 243e098bc96SEvan Quan /** 244*d9261648SLee Jones * vega10_fan_ctrl_set_fan_speed_percent - Set Fan Speed in percent. 245*d9261648SLee Jones * @hwmgr: the address of the powerplay hardware manager. 246*d9261648SLee Jones * @speed: is the percentage value (0% - 100%) to be set. 247*d9261648SLee Jones * Exception: Fails is the 100% setting appears to be 0. 248e098bc96SEvan Quan */ 249e098bc96SEvan Quan int vega10_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, 250e098bc96SEvan Quan uint32_t speed) 251e098bc96SEvan Quan { 252e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev; 253e098bc96SEvan Quan uint32_t duty100; 254e098bc96SEvan Quan uint32_t duty; 255e098bc96SEvan Quan uint64_t tmp64; 256e098bc96SEvan Quan 257e098bc96SEvan Quan if (hwmgr->thermal_controller.fanInfo.bNoFan) 258e098bc96SEvan Quan return 0; 259e098bc96SEvan Quan 260e098bc96SEvan Quan if (speed > 100) 261e098bc96SEvan Quan speed = 100; 262e098bc96SEvan Quan 263e098bc96SEvan Quan if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) 264e098bc96SEvan Quan vega10_fan_ctrl_stop_smc_fan_control(hwmgr); 265e098bc96SEvan Quan 266e098bc96SEvan Quan duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1), 267e098bc96SEvan Quan CG_FDO_CTRL1, FMAX_DUTY100); 268e098bc96SEvan Quan 269e098bc96SEvan Quan if (duty100 == 0) 270e098bc96SEvan Quan return -EINVAL; 271e098bc96SEvan Quan 272e098bc96SEvan Quan tmp64 = (uint64_t)speed * duty100; 273e098bc96SEvan Quan do_div(tmp64, 100); 274e098bc96SEvan Quan duty = (uint32_t)tmp64; 275e098bc96SEvan Quan 276e098bc96SEvan Quan WREG32_SOC15(THM, 0, mmCG_FDO_CTRL0, 277e098bc96SEvan Quan REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL0), 278e098bc96SEvan Quan CG_FDO_CTRL0, FDO_STATIC_DUTY, duty)); 279e098bc96SEvan Quan 280e098bc96SEvan Quan return vega10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); 281e098bc96SEvan Quan } 282e098bc96SEvan Quan 283e098bc96SEvan Quan /** 284*d9261648SLee Jones * vega10_fan_ctrl_reset_fan_speed_to_default - Reset Fan Speed to default. 285*d9261648SLee Jones * @hwmgr: the address of the powerplay hardware manager. 286*d9261648SLee Jones * Exception: Always succeeds. 287e098bc96SEvan Quan */ 288e098bc96SEvan Quan int vega10_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr) 289e098bc96SEvan Quan { 290e098bc96SEvan Quan if (hwmgr->thermal_controller.fanInfo.bNoFan) 291e098bc96SEvan Quan return 0; 292e098bc96SEvan Quan 293e098bc96SEvan Quan if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) 294e098bc96SEvan Quan return vega10_fan_ctrl_start_smc_fan_control(hwmgr); 295e098bc96SEvan Quan else 296e098bc96SEvan Quan return vega10_fan_ctrl_set_default_mode(hwmgr); 297e098bc96SEvan Quan } 298e098bc96SEvan Quan 299e098bc96SEvan Quan /** 300*d9261648SLee Jones * vega10_fan_ctrl_set_fan_speed_rpm - Set Fan Speed in RPM. 301*d9261648SLee Jones * @hwmgr: the address of the powerplay hardware manager. 302*d9261648SLee Jones * @speed: is the percentage value (min - max) to be set. 303*d9261648SLee Jones * Exception: Fails is the speed not lie between min and max. 304e098bc96SEvan Quan */ 305e098bc96SEvan Quan int vega10_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed) 306e098bc96SEvan Quan { 307e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev; 308e098bc96SEvan Quan uint32_t tach_period; 309e098bc96SEvan Quan uint32_t crystal_clock_freq; 310e098bc96SEvan Quan int result = 0; 311e098bc96SEvan Quan 312e098bc96SEvan Quan if (hwmgr->thermal_controller.fanInfo.bNoFan || 313e098bc96SEvan Quan speed == 0 || 314e098bc96SEvan Quan (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) || 315e098bc96SEvan Quan (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM)) 316e098bc96SEvan Quan return -1; 317e098bc96SEvan Quan 318e098bc96SEvan Quan if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) 319e098bc96SEvan Quan result = vega10_fan_ctrl_stop_smc_fan_control(hwmgr); 320e098bc96SEvan Quan 321e098bc96SEvan Quan if (!result) { 322e098bc96SEvan Quan crystal_clock_freq = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev); 323e098bc96SEvan Quan tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed); 324e098bc96SEvan Quan WREG32_SOC15(THM, 0, mmCG_TACH_CTRL, 325e098bc96SEvan Quan REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL), 326e098bc96SEvan Quan CG_TACH_CTRL, TARGET_PERIOD, 327e098bc96SEvan Quan tach_period)); 328e098bc96SEvan Quan } 329e098bc96SEvan Quan return vega10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC_RPM); 330e098bc96SEvan Quan } 331e098bc96SEvan Quan 332e098bc96SEvan Quan /** 333*d9261648SLee Jones * vega10_thermal_get_temperature - Reads the remote temperature from the SIslands thermal controller. 334e098bc96SEvan Quan * 335*d9261648SLee Jones * @hwmgr: The address of the hardware manager. 336e098bc96SEvan Quan */ 337e098bc96SEvan Quan int vega10_thermal_get_temperature(struct pp_hwmgr *hwmgr) 338e098bc96SEvan Quan { 339e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev; 340e098bc96SEvan Quan int temp; 341e098bc96SEvan Quan 342e098bc96SEvan Quan temp = RREG32_SOC15(THM, 0, mmCG_MULT_THERMAL_STATUS); 343e098bc96SEvan Quan 344e098bc96SEvan Quan temp = (temp & CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >> 345e098bc96SEvan Quan CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT; 346e098bc96SEvan Quan 347e098bc96SEvan Quan temp = temp & 0x1ff; 348e098bc96SEvan Quan 349e098bc96SEvan Quan temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES; 350e098bc96SEvan Quan 351e098bc96SEvan Quan return temp; 352e098bc96SEvan Quan } 353e098bc96SEvan Quan 354e098bc96SEvan Quan /** 355*d9261648SLee Jones * vega10_thermal_set_temperature_range - Set the requested temperature range for high and low alert signals 356e098bc96SEvan Quan * 357*d9261648SLee Jones * @hwmgr: The address of the hardware manager. 358*d9261648SLee Jones * @range: Temperature range to be programmed for 359e098bc96SEvan Quan * high and low alert signals 360*d9261648SLee Jones * Exception: PP_Result_BadInput if the input data is not valid. 361e098bc96SEvan Quan */ 362e098bc96SEvan Quan static int vega10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, 363e098bc96SEvan Quan struct PP_TemperatureRange *range) 364e098bc96SEvan Quan { 36573239232SEvan Quan struct phm_ppt_v2_information *pp_table_info = 36673239232SEvan Quan (struct phm_ppt_v2_information *)(hwmgr->pptable); 36773239232SEvan Quan struct phm_tdp_table *tdp_table = pp_table_info->tdp_table; 368e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev; 3691887544dSEvan Quan int low = VEGA10_THERMAL_MINIMUM_ALERT_TEMP; 3701887544dSEvan Quan int high = VEGA10_THERMAL_MAXIMUM_ALERT_TEMP; 371e098bc96SEvan Quan uint32_t val; 372e098bc96SEvan Quan 3731887544dSEvan Quan /* compare them in unit celsius degree */ 3741887544dSEvan Quan if (low < range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES) 3751887544dSEvan Quan low = range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES; 376e1b08ae5SEvan Quan 377e1b08ae5SEvan Quan /* 378e1b08ae5SEvan Quan * As a common sense, usSoftwareShutdownTemp should be bigger 379e1b08ae5SEvan Quan * than ThotspotLimit. For any invalid usSoftwareShutdownTemp, 380e1b08ae5SEvan Quan * we will just use the max possible setting VEGA10_THERMAL_MAXIMUM_ALERT_TEMP 381e1b08ae5SEvan Quan * to avoid false alarms. 382e1b08ae5SEvan Quan */ 383e1b08ae5SEvan Quan if ((tdp_table->usSoftwareShutdownTemp > 384e1b08ae5SEvan Quan range->hotspot_crit_max / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)) { 38573239232SEvan Quan if (high > tdp_table->usSoftwareShutdownTemp) 38673239232SEvan Quan high = tdp_table->usSoftwareShutdownTemp; 387e1b08ae5SEvan Quan } 388e098bc96SEvan Quan 389e098bc96SEvan Quan if (low > high) 390e098bc96SEvan Quan return -EINVAL; 391e098bc96SEvan Quan 392e098bc96SEvan Quan val = RREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL); 393e098bc96SEvan Quan 394e098bc96SEvan Quan val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5); 395e098bc96SEvan Quan val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1); 3961887544dSEvan Quan val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, high); 3971887544dSEvan Quan val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, low); 398e098bc96SEvan Quan val &= (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK) & 399e098bc96SEvan Quan (~THM_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK) & 400e098bc96SEvan Quan (~THM_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK); 401e098bc96SEvan Quan 402e098bc96SEvan Quan WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL, val); 403e098bc96SEvan Quan 404e098bc96SEvan Quan return 0; 405e098bc96SEvan Quan } 406e098bc96SEvan Quan 407e098bc96SEvan Quan /** 408*d9261648SLee Jones * vega10_thermal_initialize - Programs thermal controller one-time setting registers 409e098bc96SEvan Quan * 410*d9261648SLee Jones * @hwmgr: The address of the hardware manager. 411e098bc96SEvan Quan */ 412e098bc96SEvan Quan static int vega10_thermal_initialize(struct pp_hwmgr *hwmgr) 413e098bc96SEvan Quan { 414e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev; 415e098bc96SEvan Quan 416e098bc96SEvan Quan if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) { 417e098bc96SEvan Quan WREG32_SOC15(THM, 0, mmCG_TACH_CTRL, 418e098bc96SEvan Quan REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL), 419e098bc96SEvan Quan CG_TACH_CTRL, EDGE_PER_REV, 420e098bc96SEvan Quan hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution - 1)); 421e098bc96SEvan Quan } 422e098bc96SEvan Quan 423e098bc96SEvan Quan WREG32_SOC15(THM, 0, mmCG_FDO_CTRL2, 424e098bc96SEvan Quan REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2), 425e098bc96SEvan Quan CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28)); 426e098bc96SEvan Quan 427e098bc96SEvan Quan return 0; 428e098bc96SEvan Quan } 429e098bc96SEvan Quan 430e098bc96SEvan Quan /** 431*d9261648SLee Jones * vega10_thermal_enable_alert - Enable thermal alerts on the RV770 thermal controller. 432e098bc96SEvan Quan * 433*d9261648SLee Jones * @hwmgr: The address of the hardware manager. 434e098bc96SEvan Quan */ 435e098bc96SEvan Quan static int vega10_thermal_enable_alert(struct pp_hwmgr *hwmgr) 436e098bc96SEvan Quan { 437e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev; 438e098bc96SEvan Quan struct vega10_hwmgr *data = hwmgr->backend; 439e098bc96SEvan Quan uint32_t val = 0; 440e098bc96SEvan Quan 441e098bc96SEvan Quan if (data->smu_features[GNLD_FW_CTF].supported) { 442e098bc96SEvan Quan if (data->smu_features[GNLD_FW_CTF].enabled) 443e098bc96SEvan Quan printk("[Thermal_EnableAlert] FW CTF Already Enabled!\n"); 444e098bc96SEvan Quan 445e098bc96SEvan Quan PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr, 446e098bc96SEvan Quan true, 447e098bc96SEvan Quan data->smu_features[GNLD_FW_CTF].smu_feature_bitmap), 448e098bc96SEvan Quan "Attempt to Enable FW CTF feature Failed!", 449e098bc96SEvan Quan return -1); 450e098bc96SEvan Quan data->smu_features[GNLD_FW_CTF].enabled = true; 451e098bc96SEvan Quan } 452e098bc96SEvan Quan 453e098bc96SEvan Quan val |= (1 << THM_THERMAL_INT_ENA__THERM_INTH_CLR__SHIFT); 454e098bc96SEvan Quan val |= (1 << THM_THERMAL_INT_ENA__THERM_INTL_CLR__SHIFT); 455e098bc96SEvan Quan val |= (1 << THM_THERMAL_INT_ENA__THERM_TRIGGER_CLR__SHIFT); 456e098bc96SEvan Quan 457e098bc96SEvan Quan WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_ENA, val); 458e098bc96SEvan Quan 459e098bc96SEvan Quan return 0; 460e098bc96SEvan Quan } 461e098bc96SEvan Quan 462e098bc96SEvan Quan /** 463*d9261648SLee Jones * vega10_thermal_disable_alert - Disable thermal alerts on the RV770 thermal controller. 464*d9261648SLee Jones * @hwmgr: The address of the hardware manager. 465e098bc96SEvan Quan */ 466e098bc96SEvan Quan int vega10_thermal_disable_alert(struct pp_hwmgr *hwmgr) 467e098bc96SEvan Quan { 468e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev; 469e098bc96SEvan Quan struct vega10_hwmgr *data = hwmgr->backend; 470e098bc96SEvan Quan 471e098bc96SEvan Quan if (data->smu_features[GNLD_FW_CTF].supported) { 472e098bc96SEvan Quan if (!data->smu_features[GNLD_FW_CTF].enabled) 473e098bc96SEvan Quan printk("[Thermal_EnableAlert] FW CTF Already disabled!\n"); 474e098bc96SEvan Quan 475e098bc96SEvan Quan 476e098bc96SEvan Quan PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr, 477e098bc96SEvan Quan false, 478e098bc96SEvan Quan data->smu_features[GNLD_FW_CTF].smu_feature_bitmap), 479e098bc96SEvan Quan "Attempt to disable FW CTF feature Failed!", 480e098bc96SEvan Quan return -1); 481e098bc96SEvan Quan data->smu_features[GNLD_FW_CTF].enabled = false; 482e098bc96SEvan Quan } 483e098bc96SEvan Quan 484e098bc96SEvan Quan WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_ENA, 0); 485e098bc96SEvan Quan 486e098bc96SEvan Quan return 0; 487e098bc96SEvan Quan } 488e098bc96SEvan Quan 489e098bc96SEvan Quan /** 490*d9261648SLee Jones * vega10_thermal_stop_thermal_controller - Uninitialize the thermal controller. 491e098bc96SEvan Quan * Currently just disables alerts. 492*d9261648SLee Jones * @hwmgr: The address of the hardware manager. 493e098bc96SEvan Quan */ 494e098bc96SEvan Quan int vega10_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr) 495e098bc96SEvan Quan { 496e098bc96SEvan Quan int result = vega10_thermal_disable_alert(hwmgr); 497e098bc96SEvan Quan 498e098bc96SEvan Quan if (!hwmgr->thermal_controller.fanInfo.bNoFan) 499e098bc96SEvan Quan vega10_fan_ctrl_set_default_mode(hwmgr); 500e098bc96SEvan Quan 501e098bc96SEvan Quan return result; 502e098bc96SEvan Quan } 503e098bc96SEvan Quan 504e098bc96SEvan Quan /** 505*d9261648SLee Jones * vega10_thermal_setup_fan_table - Set up the fan table to control the fan using the SMC. 506*d9261648SLee Jones * @hwmgr: the address of the powerplay hardware manager. 507*d9261648SLee Jones * Return: result from set temperature range routine 508e098bc96SEvan Quan */ 509e098bc96SEvan Quan static int vega10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) 510e098bc96SEvan Quan { 511e098bc96SEvan Quan int ret; 512e098bc96SEvan Quan struct vega10_hwmgr *data = hwmgr->backend; 513e098bc96SEvan Quan PPTable_t *table = &(data->smc_state_table.pp_table); 514e098bc96SEvan Quan 515e098bc96SEvan Quan if (!data->smu_features[GNLD_FAN_CONTROL].supported) 516e098bc96SEvan Quan return 0; 517e098bc96SEvan Quan 518e098bc96SEvan Quan table->FanMaximumRpm = (uint16_t)hwmgr->thermal_controller. 519e098bc96SEvan Quan advanceFanControlParameters.usMaxFanRPM; 520e098bc96SEvan Quan table->FanThrottlingRpm = hwmgr->thermal_controller. 521e098bc96SEvan Quan advanceFanControlParameters.usFanRPMMaxLimit; 522e098bc96SEvan Quan table->FanAcousticLimitRpm = (uint16_t)(hwmgr->thermal_controller. 523e098bc96SEvan Quan advanceFanControlParameters.ulMinFanSCLKAcousticLimit); 524e098bc96SEvan Quan table->FanTargetTemperature = hwmgr->thermal_controller. 525e098bc96SEvan Quan advanceFanControlParameters.usTMax; 526e098bc96SEvan Quan 527e098bc96SEvan Quan smum_send_msg_to_smc_with_parameter(hwmgr, 528e098bc96SEvan Quan PPSMC_MSG_SetFanTemperatureTarget, 529e098bc96SEvan Quan (uint32_t)table->FanTargetTemperature, 530e098bc96SEvan Quan NULL); 531e098bc96SEvan Quan 532e098bc96SEvan Quan table->FanPwmMin = hwmgr->thermal_controller. 533e098bc96SEvan Quan advanceFanControlParameters.usPWMMin * 255 / 100; 534e098bc96SEvan Quan table->FanTargetGfxclk = (uint16_t)(hwmgr->thermal_controller. 535e098bc96SEvan Quan advanceFanControlParameters.ulTargetGfxClk); 536e098bc96SEvan Quan table->FanGainEdge = hwmgr->thermal_controller. 537e098bc96SEvan Quan advanceFanControlParameters.usFanGainEdge; 538e098bc96SEvan Quan table->FanGainHotspot = hwmgr->thermal_controller. 539e098bc96SEvan Quan advanceFanControlParameters.usFanGainHotspot; 540e098bc96SEvan Quan table->FanGainLiquid = hwmgr->thermal_controller. 541e098bc96SEvan Quan advanceFanControlParameters.usFanGainLiquid; 542e098bc96SEvan Quan table->FanGainVrVddc = hwmgr->thermal_controller. 543e098bc96SEvan Quan advanceFanControlParameters.usFanGainVrVddc; 544e098bc96SEvan Quan table->FanGainVrMvdd = hwmgr->thermal_controller. 545e098bc96SEvan Quan advanceFanControlParameters.usFanGainVrMvdd; 546e098bc96SEvan Quan table->FanGainPlx = hwmgr->thermal_controller. 547e098bc96SEvan Quan advanceFanControlParameters.usFanGainPlx; 548e098bc96SEvan Quan table->FanGainHbm = hwmgr->thermal_controller. 549e098bc96SEvan Quan advanceFanControlParameters.usFanGainHbm; 550e098bc96SEvan Quan table->FanZeroRpmEnable = hwmgr->thermal_controller. 551e098bc96SEvan Quan advanceFanControlParameters.ucEnableZeroRPM; 552e098bc96SEvan Quan table->FanStopTemp = hwmgr->thermal_controller. 553e098bc96SEvan Quan advanceFanControlParameters.usZeroRPMStopTemperature; 554e098bc96SEvan Quan table->FanStartTemp = hwmgr->thermal_controller. 555e098bc96SEvan Quan advanceFanControlParameters.usZeroRPMStartTemperature; 556e098bc96SEvan Quan 557e098bc96SEvan Quan ret = smum_smc_table_manager(hwmgr, 558e098bc96SEvan Quan (uint8_t *)(&(data->smc_state_table.pp_table)), 559e098bc96SEvan Quan PPTABLE, false); 560e098bc96SEvan Quan if (ret) 561e098bc96SEvan Quan pr_info("Failed to update Fan Control Table in PPTable!"); 562e098bc96SEvan Quan 563e098bc96SEvan Quan return ret; 564e098bc96SEvan Quan } 565e098bc96SEvan Quan 566e098bc96SEvan Quan int vega10_enable_mgpu_fan_boost(struct pp_hwmgr *hwmgr) 567e098bc96SEvan Quan { 568e098bc96SEvan Quan struct vega10_hwmgr *data = hwmgr->backend; 569e098bc96SEvan Quan PPTable_t *table = &(data->smc_state_table.pp_table); 570e098bc96SEvan Quan int ret; 571e098bc96SEvan Quan 572e098bc96SEvan Quan if (!data->smu_features[GNLD_FAN_CONTROL].supported) 573e098bc96SEvan Quan return 0; 574e098bc96SEvan Quan 575e098bc96SEvan Quan if (!hwmgr->thermal_controller.advanceFanControlParameters. 576e098bc96SEvan Quan usMGpuThrottlingRPMLimit) 577e098bc96SEvan Quan return 0; 578e098bc96SEvan Quan 579e098bc96SEvan Quan table->FanThrottlingRpm = hwmgr->thermal_controller. 580e098bc96SEvan Quan advanceFanControlParameters.usMGpuThrottlingRPMLimit; 581e098bc96SEvan Quan 582e098bc96SEvan Quan ret = smum_smc_table_manager(hwmgr, 583e098bc96SEvan Quan (uint8_t *)(&(data->smc_state_table.pp_table)), 584e098bc96SEvan Quan PPTABLE, false); 585e098bc96SEvan Quan if (ret) { 586e098bc96SEvan Quan pr_info("Failed to update fan control table in pptable!"); 587e098bc96SEvan Quan return ret; 588e098bc96SEvan Quan } 589e098bc96SEvan Quan 590e098bc96SEvan Quan ret = vega10_disable_fan_control_feature(hwmgr); 591e098bc96SEvan Quan if (ret) { 592e098bc96SEvan Quan pr_info("Attempt to disable SMC fan control feature failed!"); 593e098bc96SEvan Quan return ret; 594e098bc96SEvan Quan } 595e098bc96SEvan Quan 596e098bc96SEvan Quan ret = vega10_enable_fan_control_feature(hwmgr); 597e098bc96SEvan Quan if (ret) 598e098bc96SEvan Quan pr_info("Attempt to enable SMC fan control feature failed!"); 599e098bc96SEvan Quan 600e098bc96SEvan Quan return ret; 601e098bc96SEvan Quan } 602e098bc96SEvan Quan 603e098bc96SEvan Quan /** 604*d9261648SLee Jones * vega10_thermal_start_smc_fan_control - Start the fan control on the SMC. 605*d9261648SLee Jones * @hwmgr: the address of the powerplay hardware manager. 606*d9261648SLee Jones * Return: result from set temperature range routine 607e098bc96SEvan Quan */ 608e098bc96SEvan Quan static int vega10_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr) 609e098bc96SEvan Quan { 610e098bc96SEvan Quan /* If the fantable setup has failed we could have disabled 611e098bc96SEvan Quan * PHM_PlatformCaps_MicrocodeFanControl even after 612e098bc96SEvan Quan * this function was included in the table. 613e098bc96SEvan Quan * Make sure that we still think controlling the fan is OK. 614e098bc96SEvan Quan */ 615e098bc96SEvan Quan if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) 616e098bc96SEvan Quan vega10_fan_ctrl_start_smc_fan_control(hwmgr); 617e098bc96SEvan Quan 618e098bc96SEvan Quan return 0; 619e098bc96SEvan Quan } 620e098bc96SEvan Quan 621e098bc96SEvan Quan 622e098bc96SEvan Quan int vega10_start_thermal_controller(struct pp_hwmgr *hwmgr, 623e098bc96SEvan Quan struct PP_TemperatureRange *range) 624e098bc96SEvan Quan { 625e098bc96SEvan Quan int ret = 0; 626e098bc96SEvan Quan 627e098bc96SEvan Quan if (range == NULL) 628e098bc96SEvan Quan return -EINVAL; 629e098bc96SEvan Quan 630e098bc96SEvan Quan vega10_thermal_initialize(hwmgr); 631e098bc96SEvan Quan ret = vega10_thermal_set_temperature_range(hwmgr, range); 632e098bc96SEvan Quan if (ret) 633e098bc96SEvan Quan return -EINVAL; 634e098bc96SEvan Quan 635e098bc96SEvan Quan vega10_thermal_enable_alert(hwmgr); 636e098bc96SEvan Quan /* We should restrict performance levels to low before we halt the SMC. 637e098bc96SEvan Quan * On the other hand we are still in boot state when we do this 638e098bc96SEvan Quan * so it would be pointless. 639e098bc96SEvan Quan * If this assumption changes we have to revisit this table. 640e098bc96SEvan Quan */ 641e098bc96SEvan Quan ret = vega10_thermal_setup_fan_table(hwmgr); 642e098bc96SEvan Quan if (ret) 643e098bc96SEvan Quan return -EINVAL; 644e098bc96SEvan Quan 645e098bc96SEvan Quan vega10_thermal_start_smc_fan_control(hwmgr); 646e098bc96SEvan Quan 647e098bc96SEvan Quan return 0; 648e098bc96SEvan Quan }; 649e098bc96SEvan Quan 650e098bc96SEvan Quan 651e098bc96SEvan Quan 652e098bc96SEvan Quan 653e098bc96SEvan Quan int vega10_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr) 654e098bc96SEvan Quan { 655e098bc96SEvan Quan if (!hwmgr->thermal_controller.fanInfo.bNoFan) { 656e098bc96SEvan Quan vega10_fan_ctrl_set_default_mode(hwmgr); 657e098bc96SEvan Quan vega10_fan_ctrl_stop_smc_fan_control(hwmgr); 658e098bc96SEvan Quan } 659e098bc96SEvan Quan return 0; 660e098bc96SEvan Quan } 661