diff --git a/scripts/amd-fan-control b/scripts/amd-fan-control index 5b0d7a9..e014acf 100755 --- a/scripts/amd-fan-control +++ b/scripts/amd-fan-control @@ -2,85 +2,144 @@ set -e -DEVICE="$1" # eg: /sys/class/drm/card1/device -HWMON=$(echo "$DEVICE"/hwmon/hwmon*) - -exit() { - echo "Setting controll to auto" >&2 - echo 2 > "$HWMON/pwm1_enable" -} - -trap exit EXIT INT - bail() { echo "Error: $@" >&2 echo "Exiting..." >&2 exit 1 } -if ! [ -d "$HWMON" ]; then - bail "Invalid HWMON" -fi +map_range() { + VALUE="$1" + MIN_INPUT="$2" + MAX_INPUT="$3" + INPUT_RANGE=$(( $MAX_INPUT - $MIN_INPUT )) + MIN_OUTPUT="$4" + MAX_OUTPUT="$5" + OUTPUT_RANGE=$(( $MAX_OUTPUT - $MIN_OUTPUT )) -TEMP_INPUT="$HWMON/temp2_input" + echo $(( ($VALUE - $MIN_INPUT) * $OUTPUT_RANGE / $INPUT_RANGE + $MIN_OUTPUT )) +} -if ! [ -f $TEMP_INPUT ]; then - bail "Invalid TEMP_INPUT" -fi +clamp() { + VALUE="$1" -TEMP_MIN="$2" -TEMP_MAX="$3" + MIN="$2" + MAX="$3" -if [ -z "$TEMP_MIN" ];then - bail "No minimum temperature provided" -fi - -if [ -z "$TEMP_MAX" ];then - bail "No maximum temperature provided" -fi - -PWM_MIN_PCT="$4" -PWM_MAX_PCT="$5" - -if [ -z "$PWM_MIN_PCT" ];then - bail "No minimum fan speed % not provided" -fi - -if [ -z "$PWM_MAX_PCT" ];then - bail "No maximum fan speed % not provided" -fi - -PWM_MIN="$(( $PWM_MIN_PCT * 255 / 100))" -PWM_MAX="$(( $PWM_MAX_PCT * 255 / 100))" - -echo "Running..." >&2 - -echo "TEMP_MIN=$TEMP_MIN°C" -echo "TEMP_MAX=$TEMP_MAX°C" -echo "FAN_MIN=$PWM_MIN_PCT%" -echo "FAN_MAX=$PWM_MAX_PCT%" - -echo 1 > "$HWMON/pwm1_enable" - -PREV=0 - -while true; do - TEMPERATURE_RAW=$(cat "$TEMP_INPUT") - TEMPERATURE="$(( $TEMPERATURE_RAW / 1000 ))" - # Remap from a number between 60_000..90_000 to 0..255 - PWM=$(( ($TEMPERATURE - $TEMP_MIN) * $PWM_MAX / ($TEMP_MAX - $TEMP_MIN) )) - - if [ "$PWM" -gt $PWM_MAX ]; then - PWM=$PWM_MAX - elif [ "$PWM" -lt $PWM_MIN ]; then - PWM=$PWM_MIN + VALUE=$VALUE + if [ "$VALUE" -gt $MAX ]; then + VALUE=$MAX + elif [ "$VALUE" -lt $MIN ]; then + VALUE=$MIN fi - AVG="$(( ($PWM * 20 + $PREV * 80) / 100 ))" + echo $VALUE +} - echo "$AVG" +cleanup() { + echo "Setting controll to auto" >&2 + if test -f "$HWMON/pwm1_enable"; then + echo 2 > "$HWMON/pwm1_enable" + fi +} +trap cleanup EXIT INT - echo "$AVG" > "$HWMON/pwm1" - PREV="$AVG" +usage() { + echo "Usage: $0 " >&2 + echo "Example: $0 /sys/class/drm/card1/device 60 100 10 80" >&2 + exit 1 +} + +parse_cli() { + if test -n "$AMDGPU_FAN_CRONTROL_DEBUG"; then + echo parse_cli "$@" >&2 + fi + + DEVICE="$1" # eg: /sys/class/drm/card1/device + HWMON=$(echo "$DEVICE"/hwmon/hwmon*) + TEMP_INPUT="$HWMON/temp2_input" + + TEMP_MIN="$2" + TEMP_MAX="$3" + + PWM_MIN_PCT="$4" + PWM_MAX_PCT="$5" +} + +validate_variables() { + if ! [ -d "$HWMON" ]; then + bail "Invalid drm-device: '$HWMON' is not a directory" + fi + + if ! [ -f "$TEMP_INPUT" ]; then + bail "Error: Could not find hotspot temperature at '$TEMP_INPUT'" + fi + + if [ -z "$TEMP_MIN" -o -z "$TEMP_MAX" -o -z "$PWM_MIN_PCT" -o -z "$PWM_MAX_PCT" ];then + usage + fi +} + +setup() { + PWM_MIN=$(map_range $PWM_MIN_PCT 0 100 0 255) + PWM_MAX=$(map_range $PWM_MAX_PCT 0 100 0 255) + + echo "Running..." >&2 + + if test -n "$AMDGPU_FAN_CRONTROL_DEBUG"; then + echo "TEMP_MIN=$TEMP_MIN°C" >&2 + echo "TEMP_MAX=$TEMP_MAX°C" >&2 + echo "FAN_MIN=$PWM_MIN_PCT% (PWM=$PWM_MIN)" >&2 + echo "FAN_MAX=$PWM_MAX_PCT% (PWM=$PWM_MAX)" >&2 + fi + + # Set fan control mode to manual, this will be reverted in the cleanup trap + echo 1 > "$HWMON/pwm1_enable" + + PREV_PWM=0 +} + +main_loop() { + TEMPERATURE_RAW=$(cat "$TEMP_INPUT") + TEMPERATURE="$(( $TEMPERATURE_RAW / 1000 ))" # 60_000 = 60°C + + # Calculate the fan speed we would want to reach given infinite time + TARGET_PWM=$(map_range $TEMPERATURE $TEMP_MIN $TEMP_MAX $PWM_MIN $PWM_MAX) + + # Calculate an appropriate amount to "walk" in the direction of target fan speed + DIFFERENCE=$(( $TARGET_PWM - $PREV_PWM )) + ADJUSTMENT=$(( $DIFFERENCE * 20 / 100 )) + + NEXT_PWM=$(( $PREV_PWM + $ADJUSTMENT )) + + NEXT_PWM=$(clamp $NEXT_PWM $PWM_MIN $PWM_MAX) + NEXT_PWM_PCT=$(map_range $NEXT_PWM 0 255 0 100 ) + + if test -n "$AMDGPU_FAN_CRONTROL_DEBUG"; then + for var in \ + "Temperature=$TEMPERATURE°C" \ + "Fan speed=$NEXT_PWM_PCT%" \ + ; do + echo -en "$var\t" + done + echo + fi + + # Apply the new fan speed + echo "$NEXT_PWM" > "$HWMON/pwm1" + + # Wait for next iteratino + PREV_PWM="$NEXT_PWM" sleep .1s -done +} + +main() { + parse_cli "$@" + validate_variables + setup + while true; do + main_loop + done +} + +main "$@"