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_percent(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 * 100; 74 do_div(tmp64, duty100); 75 *speed = (uint32_t)tmp64; 76 77 if (*speed > 100) 78 *speed = 100; 79 80 return 0; 81 } 82 83 int smu7_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed) 84 { 85 uint32_t tach_period; 86 uint32_t crystal_clock_freq; 87 88 if (hwmgr->thermal_controller.fanInfo.bNoFan || 89 !hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) 90 return -ENODEV; 91 92 tach_period = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 93 CG_TACH_STATUS, TACH_PERIOD); 94 95 if (tach_period == 0) 96 return -EINVAL; 97 98 crystal_clock_freq = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev); 99 100 *speed = 60 * crystal_clock_freq * 10000 / tach_period; 101 102 return 0; 103 } 104 105 /** 106 * smu7_fan_ctrl_set_static_mode - Set Fan Speed Control to static mode, so that the user can decide what speed to use. 107 * @hwmgr: the address of the powerplay hardware manager. 108 * @mode: the fan control mode, 0 default, 1 by percent, 5, by RPM 109 * Exception: Should always succeed. 110 */ 111 int smu7_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode) 112 { 113 if (hwmgr->fan_ctrl_is_in_default_mode) { 114 hwmgr->fan_ctrl_default_mode = 115 PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 116 CG_FDO_CTRL2, FDO_PWM_MODE); 117 hwmgr->tmin = 118 PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 119 CG_FDO_CTRL2, TMIN); 120 hwmgr->fan_ctrl_is_in_default_mode = false; 121 } 122 123 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 124 CG_FDO_CTRL2, TMIN, 0); 125 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 126 CG_FDO_CTRL2, FDO_PWM_MODE, mode); 127 128 return 0; 129 } 130 131 /** 132 * Reset Fan Speed Control to default mode. 133 * @hwmgr: the address of the powerplay hardware manager. 134 * Exception: Should always succeed. 135 */ 136 int smu7_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr) 137 { 138 if (!hwmgr->fan_ctrl_is_in_default_mode) { 139 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 140 CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode); 141 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 142 CG_FDO_CTRL2, TMIN, hwmgr->tmin); 143 hwmgr->fan_ctrl_is_in_default_mode = true; 144 } 145 146 return 0; 147 } 148 149 int smu7_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr) 150 { 151 int result; 152 153 if (PP_CAP(PHM_PlatformCaps_ODFuzzyFanControlSupport)) { 154 result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_StartFanControl, 155 FAN_CONTROL_FUZZY, NULL); 156 157 if (PP_CAP(PHM_PlatformCaps_FanSpeedInTableIsRPM)) 158 hwmgr->hwmgr_func->set_max_fan_rpm_output(hwmgr, 159 hwmgr->thermal_controller. 160 advanceFanControlParameters.usMaxFanRPM); 161 else 162 hwmgr->hwmgr_func->set_max_fan_pwm_output(hwmgr, 163 hwmgr->thermal_controller. 164 advanceFanControlParameters.usMaxFanPWM); 165 166 } else { 167 result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_StartFanControl, 168 FAN_CONTROL_TABLE, NULL); 169 } 170 171 if (!result && hwmgr->thermal_controller. 172 advanceFanControlParameters.ucTargetTemperature) 173 result = smum_send_msg_to_smc_with_parameter(hwmgr, 174 PPSMC_MSG_SetFanTemperatureTarget, 175 hwmgr->thermal_controller. 176 advanceFanControlParameters.ucTargetTemperature, 177 NULL); 178 179 if (!result && 180 (hwmgr->chip_id == CHIP_POLARIS10 || 181 hwmgr->chip_id == CHIP_POLARIS11 || 182 hwmgr->chip_id == CHIP_POLARIS12) && 183 hwmgr->thermal_controller.advanceFanControlParameters.ucEnableZeroRPM && 184 !PP_CAP(PHM_PlatformCaps_customThermalManagement)) 185 result = smum_send_msg_to_smc(hwmgr, 186 PPSMC_MSG_EnableZeroRpm, 187 NULL); 188 189 hwmgr->fan_ctrl_enabled = true; 190 191 return result; 192 } 193 194 195 int smu7_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr) 196 { 197 hwmgr->fan_ctrl_enabled = false; 198 return smum_send_msg_to_smc(hwmgr, PPSMC_StopFanControl, NULL); 199 } 200 201 /** 202 * smu7_fan_ctrl_set_fan_speed_percent - Set Fan Speed in percent. 203 * @hwmgr: the address of the powerplay hardware manager. 204 * @speed: is the percentage value (0% - 100%) to be set. 205 * Exception: Fails is the 100% setting appears to be 0. 206 */ 207 int smu7_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, 208 uint32_t speed) 209 { 210 uint32_t duty100; 211 uint32_t duty; 212 uint64_t tmp64; 213 214 if (hwmgr->thermal_controller.fanInfo.bNoFan) 215 return 0; 216 217 if (speed > 100) 218 speed = 100; 219 220 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) 221 smu7_fan_ctrl_stop_smc_fan_control(hwmgr); 222 223 duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 224 CG_FDO_CTRL1, FMAX_DUTY100); 225 226 if (duty100 == 0) 227 return -EINVAL; 228 229 tmp64 = (uint64_t)speed * duty100; 230 do_div(tmp64, 100); 231 duty = (uint32_t)tmp64; 232 233 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 234 CG_FDO_CTRL0, FDO_STATIC_DUTY, duty); 235 236 return smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); 237 } 238 239 /** 240 * smu7_fan_ctrl_reset_fan_speed_to_default - Reset Fan Speed to default. 241 * @hwmgr: the address of the powerplay hardware manager. 242 * Exception: Always succeeds. 243 */ 244 int smu7_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr) 245 { 246 int result; 247 248 if (hwmgr->thermal_controller.fanInfo.bNoFan) 249 return 0; 250 251 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) { 252 result = smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); 253 if (!result) 254 result = smu7_fan_ctrl_start_smc_fan_control(hwmgr); 255 } else 256 result = smu7_fan_ctrl_set_default_mode(hwmgr); 257 258 return result; 259 } 260 261 /** 262 * smu7_fan_ctrl_set_fan_speed_rpm - Set Fan Speed in RPM. 263 * @hwmgr: the address of the powerplay hardware manager. 264 * @speed: is the percentage value (min - max) to be set. 265 * Exception: Fails is the speed not lie between min and max. 266 */ 267 int smu7_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed) 268 { 269 uint32_t tach_period; 270 uint32_t crystal_clock_freq; 271 272 if (hwmgr->thermal_controller.fanInfo.bNoFan || 273 (hwmgr->thermal_controller.fanInfo. 274 ucTachometerPulsesPerRevolution == 0) || 275 speed == 0 || 276 (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) || 277 (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM)) 278 return 0; 279 280 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) 281 smu7_fan_ctrl_stop_smc_fan_control(hwmgr); 282 283 crystal_clock_freq = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev); 284 285 tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed); 286 287 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 288 CG_TACH_CTRL, TARGET_PERIOD, tach_period); 289 290 return smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC_RPM); 291 } 292 293 /** 294 * smu7_thermal_get_temperature - Reads the remote temperature from the SIslands thermal controller. 295 * 296 * @hwmgr: The address of the hardware manager. 297 */ 298 int smu7_thermal_get_temperature(struct pp_hwmgr *hwmgr) 299 { 300 int temp; 301 302 temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 303 CG_MULT_THERMAL_STATUS, CTF_TEMP); 304 305 /* Bit 9 means the reading is lower than the lowest usable value. */ 306 if (temp & 0x200) 307 temp = SMU7_THERMAL_MAXIMUM_TEMP_READING; 308 else 309 temp = temp & 0x1ff; 310 311 temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES; 312 313 return temp; 314 } 315 316 /** 317 * smu7_thermal_set_temperature_range - Set the requested temperature range for high and low alert signals 318 * 319 * @hwmgr: The address of the hardware manager. 320 * @low_temp: Temperature to be programmed for high alert signals 321 * @high_temp: Temperature to be programmed for low alert signals 322 * Exception: PP_Result_BadInput if the input data is not valid. 323 */ 324 static int smu7_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, 325 int low_temp, int high_temp) 326 { 327 int low = SMU7_THERMAL_MINIMUM_ALERT_TEMP * 328 PP_TEMPERATURE_UNITS_PER_CENTIGRADES; 329 int high = SMU7_THERMAL_MAXIMUM_ALERT_TEMP * 330 PP_TEMPERATURE_UNITS_PER_CENTIGRADES; 331 332 if (low < low_temp) 333 low = low_temp; 334 if (high > high_temp) 335 high = high_temp; 336 337 if (low > high) 338 return -EINVAL; 339 340 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 341 CG_THERMAL_INT, DIG_THERM_INTH, 342 (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); 343 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 344 CG_THERMAL_INT, DIG_THERM_INTL, 345 (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); 346 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 347 CG_THERMAL_CTRL, DIG_THERM_DPM, 348 (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); 349 350 return 0; 351 } 352 353 /** 354 * smu7_thermal_initialize - Programs thermal controller one-time setting registers 355 * 356 * @hwmgr: The address of the hardware manager. 357 */ 358 static int smu7_thermal_initialize(struct pp_hwmgr *hwmgr) 359 { 360 if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) 361 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 362 CG_TACH_CTRL, EDGE_PER_REV, 363 hwmgr->thermal_controller.fanInfo. 364 ucTachometerPulsesPerRevolution - 1); 365 366 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 367 CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28); 368 369 return 0; 370 } 371 372 /** 373 * smu7_thermal_enable_alert - Enable thermal alerts on the RV770 thermal controller. 374 * 375 * @hwmgr: The address of the hardware manager. 376 */ 377 static void smu7_thermal_enable_alert(struct pp_hwmgr *hwmgr) 378 { 379 uint32_t alert; 380 381 alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 382 CG_THERMAL_INT, THERM_INT_MASK); 383 alert &= ~(SMU7_THERMAL_HIGH_ALERT_MASK | SMU7_THERMAL_LOW_ALERT_MASK); 384 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 385 CG_THERMAL_INT, THERM_INT_MASK, alert); 386 387 /* send message to SMU to enable internal thermal interrupts */ 388 smum_send_msg_to_smc(hwmgr, PPSMC_MSG_Thermal_Cntl_Enable, NULL); 389 } 390 391 /** 392 * smu7_thermal_disable_alert - Disable thermal alerts on the RV770 thermal controller. 393 * @hwmgr: The address of the hardware manager. 394 */ 395 int smu7_thermal_disable_alert(struct pp_hwmgr *hwmgr) 396 { 397 uint32_t alert; 398 399 alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 400 CG_THERMAL_INT, THERM_INT_MASK); 401 alert |= (SMU7_THERMAL_HIGH_ALERT_MASK | SMU7_THERMAL_LOW_ALERT_MASK); 402 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, 403 CG_THERMAL_INT, THERM_INT_MASK, alert); 404 405 /* send message to SMU to disable internal thermal interrupts */ 406 return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_Thermal_Cntl_Disable, NULL); 407 } 408 409 /** 410 * smu7_thermal_stop_thermal_controller - Uninitialize the thermal controller. 411 * Currently just disables alerts. 412 * @hwmgr: The address of the hardware manager. 413 */ 414 int smu7_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr) 415 { 416 int result = smu7_thermal_disable_alert(hwmgr); 417 418 if (!hwmgr->thermal_controller.fanInfo.bNoFan) 419 smu7_fan_ctrl_set_default_mode(hwmgr); 420 421 return result; 422 } 423 424 /** 425 * smu7_thermal_start_smc_fan_control - Start the fan control on the SMC. 426 * @hwmgr: the address of the powerplay hardware manager. 427 * Return: result from set temperature range routine 428 */ 429 static int smu7_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr) 430 { 431 /* If the fantable setup has failed we could have disabled 432 * PHM_PlatformCaps_MicrocodeFanControl even after 433 * this function was included in the table. 434 * Make sure that we still think controlling the fan is OK. 435 */ 436 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) { 437 smu7_fan_ctrl_start_smc_fan_control(hwmgr); 438 smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); 439 } 440 441 return 0; 442 } 443 444 int smu7_start_thermal_controller(struct pp_hwmgr *hwmgr, 445 struct PP_TemperatureRange *range) 446 { 447 int ret = 0; 448 449 if (range == NULL) 450 return -EINVAL; 451 452 smu7_thermal_initialize(hwmgr); 453 ret = smu7_thermal_set_temperature_range(hwmgr, range->min, range->max); 454 if (ret) 455 return -EINVAL; 456 smu7_thermal_enable_alert(hwmgr); 457 ret = smum_thermal_avfs_enable(hwmgr); 458 if (ret) 459 return -EINVAL; 460 461 /* We should restrict performance levels to low before we halt the SMC. 462 * On the other hand we are still in boot state when we do this 463 * so it would be pointless. 464 * If this assumption changes we have to revisit this table. 465 */ 466 smum_thermal_setup_fan_table(hwmgr); 467 smu7_thermal_start_smc_fan_control(hwmgr); 468 return 0; 469 } 470 471 472 473 int smu7_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr) 474 { 475 if (!hwmgr->thermal_controller.fanInfo.bNoFan) 476 smu7_fan_ctrl_set_default_mode(hwmgr); 477 return 0; 478 } 479 480