nixos-config/scripts/amd-fan-control

145 lines
3.1 KiB
Bash
Executable file

#!/usr/bin/env bash
set -e
bail() {
echo "Error: $@" >&2
echo "Exiting..." >&2
exit 1
}
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 ))
echo $(( ($VALUE - $MIN_INPUT) * $OUTPUT_RANGE / $INPUT_RANGE + $MIN_OUTPUT ))
}
clamp() {
VALUE="$1"
MIN="$2"
MAX="$3"
VALUE=$VALUE
if [ "$VALUE" -gt $MAX ]; then
VALUE=$MAX
elif [ "$VALUE" -lt $MIN ]; then
VALUE=$MIN
fi
echo $VALUE
}
cleanup() {
echo "Setting controll to auto" >&2
if test -f "$HWMON/pwm1_enable"; then
echo 2 > "$HWMON/pwm1_enable"
fi
}
trap cleanup EXIT INT
usage() {
echo "Usage: $0 <device> <min-temp> <max-temp> <min-fan> <max-fan>" >&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
}
main() {
parse_cli "$@"
validate_variables
setup
while true; do
main_loop
done
}
main "$@"