Smooth fan speed changes (#190)

* SMOOTH_FANS, SMOOTH_FANS_UP, SMOOTH_FANS_DOWN build flags to smooth fan speed changes.
Defaults 40, set SMOOTH_FANS=0 to disable and keep sharp fan speed changes

* fix for ACPI CPU temperature

* allow for a floor to be set for fan smoothing and specifically configure oryp6/7 to start smoothing at 25% to mitigate fan buzzing below 25%

* update default config values for fans

* update all devices to use defaults for heatup, cooldown, update galp5 fan curves

* Decrease default cooldown time from 20 to 10

Co-authored-by: Jacob Kauffmann <jacob@system76.com>
This commit is contained in:
Winston Hoy
2021-06-14 16:22:29 -04:00
committed by GitHub
parent b7368e8202
commit 8ea0403850
14 changed files with 123 additions and 74 deletions

View File

@ -4,15 +4,20 @@
#include <common/debug.h>
#include <ec/pwm.h>
bool fan_max = false;
#define max_speed PWM_DUTY(100)
#define min_speed PWM_DUTY(0)
#ifndef SYNC_FANS
#define SYNC_FANS 1
#if SMOOTH_FANS != 0
static const uint8_t max_jump_up = (MAX_FAN_SPEED - MIN_FAN_SPEED) / (uint8_t) SMOOTH_FANS_UP;
static const uint8_t max_jump_down = (MAX_FAN_SPEED - MIN_FAN_SPEED) / (uint8_t) SMOOTH_FANS_DOWN;
#else
static const uint8_t max_jump_up = MAX_FAN_SPEED - MIN_FAN_SPEED;
static const uint8_t max_jump_down = MAX_FAN_SPEED - MIN_FAN_SPEED;
#endif
static const uint8_t min_speed_to_smooth = PWM_DUTY(SMOOTH_FANS_MIN);
bool fan_max = false;
uint8_t last_duty_dgpu = 0;
uint8_t last_duty_peci = 0;
void fan_reset(void) {
// Do not manually set fans to maximum speed
fan_max = false;
@ -30,7 +35,7 @@ uint8_t fan_duty(const struct Fan * fan, int16_t temp) __reentrant {
} else if (temp < cur->temp) {
// If lower than first temp, return 0%
if (i == 0) {
return min_speed;
return MIN_FAN_SPEED;
} else {
const struct FanPoint * prev = &fan->points[i - 1];
@ -52,26 +57,30 @@ uint8_t fan_duty(const struct Fan * fan, int16_t temp) __reentrant {
}
// If no point is found, return 100%
return max_speed;
return MAX_FAN_SPEED;
}
void fan_duty_set(uint8_t peci_fan_duty, uint8_t dgpu_fan_duty) __reentrant {
#if SYNC_FANS != 0
peci_fan_duty = peci_fan_duty > dgpu_fan_duty ? peci_fan_duty : dgpu_fan_duty;
dgpu_fan_duty = peci_fan_duty > dgpu_fan_duty ? peci_fan_duty : dgpu_fan_duty;
#endif
#if SYNC_FANS != 0
peci_fan_duty = peci_fan_duty > dgpu_fan_duty ? peci_fan_duty : dgpu_fan_duty;
dgpu_fan_duty = peci_fan_duty > dgpu_fan_duty ? peci_fan_duty : dgpu_fan_duty;
#endif
// set PECI fan duty
if (peci_fan_duty != DCR2) {
DCR2 = peci_fan_duty;
DEBUG("PECI fan_duty=%d\n", peci_fan_duty);
}
// set PECI fan duty
if (peci_fan_duty != DCR2) {
DEBUG("PECI fan_duty_raw=%d\n", peci_fan_duty);
last_duty_peci = peci_fan_duty = fan_smooth(last_duty_peci, peci_fan_duty);
DCR2 = fan_max ? MAX_FAN_SPEED : peci_fan_duty;
DEBUG("PECI fan_duty_smoothed=%d\n", peci_fan_duty);
}
// set dGPU fan duty
if (dgpu_fan_duty != DCR4) {
DCR4 = dgpu_fan_duty;
DEBUG("DGPU fan_duty=%d\n", dgpu_fan_duty);
}
// set dGPU fan duty
if (dgpu_fan_duty != DCR4) {
DEBUG("DGPU fan_duty_raw=%d\n", dgpu_fan_duty);
last_duty_dgpu = dgpu_fan_duty = fan_smooth(last_duty_dgpu, dgpu_fan_duty);
DCR4 = fan_max ? MAX_FAN_SPEED : dgpu_fan_duty;
DEBUG("DGPU fan_duty_smoothed=%d\n", dgpu_fan_duty);
}
}
uint8_t fan_heatup(const struct Fan * fan, uint8_t duty) __reentrant {
@ -105,3 +114,35 @@ uint8_t fan_cooldown(const struct Fan * fan, uint8_t duty) __reentrant {
return highest;
}
uint8_t fan_smooth(uint8_t last_duty, uint8_t duty) __reentrant {
uint8_t next_duty = duty;
// ramping down
if (duty < last_duty) {
// out of bounds (lower) safeguard
uint8_t smoothed = last_duty < MIN_FAN_SPEED + max_jump_down
? MIN_FAN_SPEED
: last_duty - max_jump_down;
// use smoothed value if above min and if smoothed is closer than raw
if (last_duty > min_speed_to_smooth && smoothed > duty) {
next_duty = smoothed;
}
}
// ramping up
if (duty > last_duty) {
// out of bounds (higher) safeguard
uint8_t smoothed = last_duty > MAX_FAN_SPEED - max_jump_up
? MAX_FAN_SPEED
: last_duty + max_jump_up;
// use smoothed value if above min and if smoothed is closer than raw
if (duty > min_speed_to_smooth && smoothed < duty) {
next_duty = smoothed;
}
}
return next_duty;
}