1 /* 2 * Copyright 2016 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 */ 23 24 #include <asm/div64.h> 25 #include "smu7_thermal.h" 26 #include "smu7_hwmgr.h" 27 #include "smu7_common.h" 28 29 int smu7_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, 30 struct phm_fan_speed_info *fan_speed_info) 31 { 32 if (hwmgr->thermal_controller.fanInfo.bNoFan) 33 return -ENODEV; 34 35 fan_speed_info->supports_percent_read = true; 36 fan_speed_info->supports_percent_write = true; 37 fan_speed_info->min_percent = 0; 38 fan_speed_info->max_percent = 100; 39 40 if (PP_CAP(PHM_PlatformCaps_FanSpeedInTableIsRPM) && 41 hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) { 42 fan_speed_info->supports_rpm_read = true; 43 fan_speed_info->supports_rpm_write = true; 44 fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM; 45 fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM; 46 } else { 47 fan_speed_info->min_rpm = 0; 48 fan_speed_info->max_rpm = 0; 49 } 50 51 return 0; 52 } 53 54 int smu7_fan_ctrl_get_fan_speed_pwm(struct pp_hwmgr *hwmgr, 55 uint32_t *speed) 56 { 57 uint32_t duty100; 58 uint32_t duty; 59 uint64_t tmp64; 60 61 if (hwmgr->thermal_controller.fanInfo.bNoFan) 62 return -ENODEV; 63 64 duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 65 CG_FDO_CTRL1, FMAX_DUTY100); 66 duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 67 CG_THERMAL_STATUS, FDO_PWM_DUTY); 68 69 if (duty100 == 0) 70 return -EINVAL; 71 72 73 tmp64 = (uint64_t)duty * 255; 74 do_div(tmp64, duty100); 75 *speed = min_t(uint32_t, tmp64, 255); 76 77 return 0; 78 } 79 80 int smu7_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed) 81 { 82 uint32_t tach_period; 83 uint32_t crystal_clock_freq; 84 85 if (hwmgr->thermal_controller.fanInfo.bNoFan || 86 !hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) 87 return -ENODEV; 88 89 tach_period = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 90 CG_TACH_STATUS, TACH_PERIOD); 91 92 if (tach_period == 0) 93 return -EINVAL; 94 95 crystal_clock_freq = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev); 96 97 *speed = 60 * crystal_clock_freq * 10000 / tach_period; 98 99 return 0; 100 } 101 102 /** 103 * smu7_fan_ctrl_set_static_mode - Set Fan Speed Control to static mode, so that the user can decide what speed to use. 104 * @hwmgr: the address of the powerplay hardware manager. 105 * @mode: the fan control mode, 0 default, 1 by percent, 5, by RPM 106 * Exception: Should always succeed. 107 */ 108 int smu7_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode) 109 { 110 if (hwmgr->fan_ctrl_is_in_default_mode) { 111 hwmgr->fan_ctrl_default_mode = 112 PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 113 CG_FDO_CTRL2, FDO_PWM_MODE); 114 hwmgr->tmin = 115 PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 116 CG_FDO_CTRL2, TMIN); 117 hwmgr->fan_ctrl_is_in_default_mode = false; 118 } 119 120 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 121 CG_FDO_CTRL2, TMIN, 0); 122 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 123 CG_FDO_CTRL2, FDO_PWM_MODE, mode); 124 125 return 0; 126 } 127 128 /** 129 * smu7_fan_ctrl_set_default_mode - Reset Fan Speed Control to default mode. 130 * @hwmgr: the address of the powerplay hardware manager. 131 * Exception: Should always succeed. 132 */ 133 int smu7_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr) 134 { 135 if (!hwmgr->fan_ctrl_is_in_default_mode) { 136 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 137 CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode); 138 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 139 CG_FDO_CTRL2, TMIN, hwmgr->tmin); 140 hwmgr->fan_ctrl_is_in_default_mode = true; 141 } 142 143 return 0; 144 } 145 146 int smu7_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr) 147 { 148 int result; 149 150 if (PP_CAP(PHM_PlatformCaps_ODFuzzyFanControlSupport)) { 151 result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_StartFanControl, 152 FAN_CONTROL_FUZZY, NULL); 153 154 if (PP_CAP(PHM_PlatformCaps_FanSpeedInTableIsRPM)) 155 hwmgr->hwmgr_func->set_max_fan_rpm_output(hwmgr, 156 hwmgr->thermal_controller. 157 advanceFanControlParameters.usMaxFanRPM); 158 else 159 hwmgr->hwmgr_func->set_max_fan_pwm_output(hwmgr, 160 hwmgr->thermal_controller. 161 advanceFanControlParameters.usMaxFanPWM); 162 163 } else { 164 result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_StartFanControl, 165 FAN_CONTROL_TABLE, NULL); 166 } 167 168 if (!result && hwmgr->thermal_controller. 169 advanceFanControlParameters.ucTargetTemperature) 170 result = smum_send_msg_to_smc_with_parameter(hwmgr, 171 PPSMC_MSG_SetFanTemperatureTarget, 172 hwmgr->thermal_controller. 173 advanceFanControlParameters.ucTargetTemperature, 174 NULL); 175 176 if (!result && 177 (hwmgr->chip_id == CHIP_POLARIS10 || 178 hwmgr->chip_id == CHIP_POLARIS11 || 179 hwmgr->chip_id == CHIP_POLARIS12) && 180 hwmgr->thermal_controller.advanceFanControlParameters.ucEnableZeroRPM && 181 !PP_CAP(PHM_PlatformCaps_customThermalManagement)) 182 result = smum_send_msg_to_smc(hwmgr, 183 PPSMC_MSG_EnableZeroRpm, 184 NULL); 185 186 hwmgr->fan_ctrl_enabled = true; 187 188 return result; 189 } 190 191 192 int smu7_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr) 193 { 194 hwmgr->fan_ctrl_enabled = false; 195 return smum_send_msg_to_smc(hwmgr, PPSMC_StopFanControl, NULL); 196 } 197 198 /** 199 * smu7_fan_ctrl_set_fan_speed_pwm - Set Fan Speed in PWM. 200 * @hwmgr: the address of the powerplay hardware manager. 201 * @speed: is the pwm value (0 - 255) to be set. 202 */ 203 int smu7_fan_ctrl_set_fan_speed_pwm(struct pp_hwmgr *hwmgr, 204 uint32_t speed) 205 { 206 uint32_t duty100; 207 uint32_t duty; 208 uint64_t tmp64; 209 210 if (hwmgr->thermal_controller.fanInfo.bNoFan) 211 return 0; 212 213 speed = min_t(uint32_t, speed, 255); 214 215 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) 216 smu7_fan_ctrl_stop_smc_fan_control(hwmgr); 217 218 duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 219 CG_FDO_CTRL1, FMAX_DUTY100); 220 221 if (duty100 == 0) 222 return -EINVAL; 223 224 tmp64 = (uint64_t)speed * duty100; 225 do_div(tmp64, 255); 226 duty = (uint32_t)tmp64; 227 228 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 229 CG_FDO_CTRL0, FDO_STATIC_DUTY, duty); 230 231 return smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); 232 } 233 234 /** 235 * smu7_fan_ctrl_reset_fan_speed_to_default - Reset Fan Speed to default. 236 * @hwmgr: the address of the powerplay hardware manager. 237 * Exception: Always succeeds. 238 */ 239 int smu7_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr) 240 { 241 int result; 242 243 if (hwmgr->thermal_controller.fanInfo.bNoFan) 244 return 0; 245 246 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) { 247 result = smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); 248 if (!result) 249 result = smu7_fan_ctrl_start_smc_fan_control(hwmgr); 250 } else 251 result = smu7_fan_ctrl_set_default_mode(hwmgr); 252 253 return result; 254 } 255 256 /** 257 * smu7_fan_ctrl_set_fan_speed_rpm - Set Fan Speed in RPM. 258 * @hwmgr: the address of the powerplay hardware manager. 259 * @speed: is the percentage value (min - max) to be set. 260 * Exception: Fails is the speed not lie between min and max. 261 */ 262 int smu7_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed) 263 { 264 uint32_t tach_period; 265 uint32_t crystal_clock_freq; 266 267 if (hwmgr->thermal_controller.fanInfo.bNoFan || 268 (hwmgr->thermal_controller.fanInfo. 269 ucTachometerPulsesPerRevolution == 0) || 270 speed == 0 || 271 (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) || 272 (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM)) 273 return 0; 274 275 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) 276 smu7_fan_ctrl_stop_smc_fan_control(hwmgr); 277 278 crystal_clock_freq = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev); 279 280 tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed); 281 282 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 283 CG_TACH_CTRL, TARGET_PERIOD, tach_period); 284 285 return smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC_RPM); 286 } 287 288 /** 289 * smu7_thermal_get_temperature - Reads the remote temperature from the SIslands thermal controller. 290 * 291 * @hwmgr: The address of the hardware manager. 292 */ 293 int smu7_thermal_get_temperature(struct pp_hwmgr *hwmgr) 294 { 295 int temp; 296 297 temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 298 CG_MULT_THERMAL_STATUS, CTF_TEMP); 299 300 /* Bit 9 means the reading is lower than the lowest usable value. */ 301 if (temp & 0x200) 302 temp = SMU7_THERMAL_MAXIMUM_TEMP_READING; 303 else 304 temp = temp & 0x1ff; 305 306 temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES; 307 308 return temp; 309 } 310 311 /** 312 * smu7_thermal_set_temperature_range - Set the requested temperature range for high and low alert signals 313 * 314 * @hwmgr: The address of the hardware manager. 315 * @low_temp: Temperature to be programmed for high alert signals 316 * @high_temp: Temperature to be programmed for low alert signals 317 * Exception: PP_Result_BadInput if the input data is not valid. 318 */ 319 static int smu7_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, 320 int low_temp, int high_temp) 321 { 322 int low = SMU7_THERMAL_MINIMUM_ALERT_TEMP * 323 PP_TEMPERATURE_UNITS_PER_CENTIGRADES; 324 int high = SMU7_THERMAL_MAXIMUM_ALERT_TEMP * 325 PP_TEMPERATURE_UNITS_PER_CENTIGRADES; 326 327 if (low < low_temp) 328 low = low_temp; 329 if (high > high_temp) 330 high = high_temp; 331 332 if (low > high) 333 return -EINVAL; 334 335 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 336 CG_THERMAL_INT, DIG_THERM_INTH, 337 (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); 338 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 339 CG_THERMAL_INT, DIG_THERM_INTL, 340 (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); 341 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 342 CG_THERMAL_CTRL, DIG_THERM_DPM, 343 (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); 344 345 return 0; 346 } 347 348 /** 349 * smu7_thermal_initialize - Programs thermal controller one-time setting registers 350 * 351 * @hwmgr: The address of the hardware manager. 352 */ 353 static int smu7_thermal_initialize(struct pp_hwmgr *hwmgr) 354 { 355 if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) 356 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 357 CG_TACH_CTRL, EDGE_PER_REV, 358 hwmgr->thermal_controller.fanInfo. 359 ucTachometerPulsesPerRevolution - 1); 360 361 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 362 CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28); 363 364 return 0; 365 } 366 367 /** 368 * smu7_thermal_enable_alert - Enable thermal alerts on the RV770 thermal controller. 369 * 370 * @hwmgr: The address of the hardware manager. 371 */ 372 static void smu7_thermal_enable_alert(struct pp_hwmgr *hwmgr) 373 { 374 uint32_t alert; 375 376 alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 377 CG_THERMAL_INT, THERM_INT_MASK); 378 alert &= ~(SMU7_THERMAL_HIGH_ALERT_MASK | SMU7_THERMAL_LOW_ALERT_MASK); 379 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 380 CG_THERMAL_INT, THERM_INT_MASK, alert); 381 382 /* send message to SMU to enable internal thermal interrupts */ 383 smum_send_msg_to_smc(hwmgr, PPSMC_MSG_Thermal_Cntl_Enable, NULL); 384 } 385 386 /** 387 * smu7_thermal_disable_alert - Disable thermal alerts on the RV770 thermal controller. 388 * @hwmgr: The address of the hardware manager. 389 */ 390 int smu7_thermal_disable_alert(struct pp_hwmgr *hwmgr) 391 { 392 uint32_t alert; 393 394 alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 395 CG_THERMAL_INT, THERM_INT_MASK); 396 alert |= (SMU7_THERMAL_HIGH_ALERT_MASK | SMU7_THERMAL_LOW_ALERT_MASK); 397 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 398 CG_THERMAL_INT, THERM_INT_MASK, alert); 399 400 /* send message to SMU to disable internal thermal interrupts */ 401 return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_Thermal_Cntl_Disable, NULL); 402 } 403 404 /** 405 * smu7_thermal_stop_thermal_controller - Uninitialize the thermal controller. 406 * Currently just disables alerts. 407 * @hwmgr: The address of the hardware manager. 408 */ 409 int smu7_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr) 410 { 411 int result = smu7_thermal_disable_alert(hwmgr); 412 413 if (!hwmgr->thermal_controller.fanInfo.bNoFan) 414 smu7_fan_ctrl_set_default_mode(hwmgr); 415 416 return result; 417 } 418 419 /** 420 * smu7_thermal_start_smc_fan_control - Start the fan control on the SMC. 421 * @hwmgr: the address of the powerplay hardware manager. 422 * Return: result from set temperature range routine 423 */ 424 static int smu7_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr) 425 { 426 /* If the fantable setup has failed we could have disabled 427 * PHM_PlatformCaps_MicrocodeFanControl even after 428 * this function was included in the table. 429 * Make sure that we still think controlling the fan is OK. 430 */ 431 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) { 432 smu7_fan_ctrl_start_smc_fan_control(hwmgr); 433 smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); 434 } 435 436 return 0; 437 } 438 439 int smu7_start_thermal_controller(struct pp_hwmgr *hwmgr, 440 struct PP_TemperatureRange *range) 441 { 442 int ret = 0; 443 444 if (range == NULL) 445 return -EINVAL; 446 447 smu7_thermal_initialize(hwmgr); 448 ret = smu7_thermal_set_temperature_range(hwmgr, range->min, range->max); 449 if (ret) 450 return -EINVAL; 451 smu7_thermal_enable_alert(hwmgr); 452 ret = smum_thermal_avfs_enable(hwmgr); 453 if (ret) 454 return -EINVAL; 455 456 /* We should restrict performance levels to low before we halt the SMC. 457 * On the other hand we are still in boot state when we do this 458 * so it would be pointless. 459 * If this assumption changes we have to revisit this table. 460 */ 461 smum_thermal_setup_fan_table(hwmgr); 462 smu7_thermal_start_smc_fan_control(hwmgr); 463 return 0; 464 } 465 466 467 468 int smu7_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr) 469 { 470 if (!hwmgr->thermal_controller.fanInfo.bNoFan) 471 smu7_fan_ctrl_set_default_mode(hwmgr); 472 return 0; 473 } 474 475