#!/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 " >&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 "$@"