#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later
#
# /usr/libexec/pocketds-perf set <cpu|gpu|fan> <stop>
# /usr/libexec/pocketds-perf profile <tuned profile>
# /usr/libexec/pocketds-perf apply
#
# CPU and GPU clock caps and the fan curve, as a closed set of stops.
# `set` pins a stop in /etc/pocketds-perf/state (pkexec'd by the
# companion, see org.pocketds.perf.policy). `profile` runs from every
# tuned profile's script: pinned keys win, the rest take the profile's
# default stop. No state file means the tuned profiles alone decide.

set -eu

STATE_DIR="/etc/pocketds-perf"
STATE_FILE="${STATE_DIR}/state"
CPUFREQ="/sys/devices/system/cpu/cpufreq"
FAN_SETTER="/usr/libexec/pocketds-fancontrol-set-profile"

usage() {
    echo "usage: $0 set <cpu|gpu|fan> <stop> | profile <name> | apply" >&2
    exit 2
}

# little (policy0) / mid (policy3) / prime (policy7) caps in kHz
cpu_caps() {
    case "$1" in
        eco)    echo "1555200 1785600 1977600" ;;
        low)    echo "1785600 2054400 2342400" ;;
        normal) echo "2016000 2457600 2726400" ;;
        high)   echo "2016000 2803200 2956800" ;;
        max)    echo "2016000 2803200 3360000" ;;
        *) return 1 ;;
    esac
}

gpu_valid() {
    case "$1" in 475|615|746|860|1000) ;; *) return 1 ;; esac
}

fan_profile() {
    case "$1" in
        quiet) echo quiet ;;
        auto)  echo auto ;;
        cool)  echo aggressive ;;
        max)   echo max ;;
        *) return 1 ;;
    esac
}

# tuned profile → default cpu gpu fan stops
profile_defaults() {
    case "$1" in
        powersave)              echo "eco 615 quiet" ;;
        throughput-performance) echo "max 1000 cool" ;;
        *)                      echo "max 1000 auto" ;;
    esac
}

gpu_devfreq() {
    for d in /sys/class/devfreq/*.gpu; do
        [ -e "$d/max_freq" ] && { echo "$d"; return 0; }
    done
    return 1
}

apply_cpu() {
    set -- $(cpu_caps "$1")
    for p in "policy0:$1" "policy3:$2" "policy7:$3"; do
        f="${CPUFREQ}/${p%%:*}/scaling_max_freq"
        [ -w "$f" ] && echo "${p#*:}" > "$f"
    done
    return 0
}

apply_gpu() {
    d=$(gpu_devfreq) || return 0
    echo "$(( $1 * 1000000 ))" > "$d/max_freq"
}

# throughput-performance keeps its raised GPU floor, under the cap
apply_gpu_floor() {
    d=$(gpu_devfreq) || return 0
    lo=$(tr ' ' '\n' < "$d/available_frequencies" | sort -n | head -n1)
    if [ "$1" = throughput-performance ]; then
        echo 475000000 > "$d/min_freq"
    elif [ -n "$lo" ]; then
        echo "$lo" > "$d/min_freq"
    fi
}

apply_fan() {
    "$FAN_SETTER" "$(fan_profile "$1")"
}

pinned() {
    [ -r "$STATE_FILE" ] || return 1
    v=$(sed -n "s/^$1=//p" "$STATE_FILE" | tail -n1)
    [ -n "$v" ] && echo "$v"
}

pin() {
    mkdir -p "$STATE_DIR"
    tmp=$(mktemp "${STATE_FILE}.XXXXXX")
    { [ -r "$STATE_FILE" ] && grep -v "^$1=" "$STATE_FILE" || true; } > "$tmp"
    echo "$1=$2" >> "$tmp"
    chmod 0644 "$tmp"
    mv -f "$tmp" "$STATE_FILE"
}

active_profile() {
    tuned-adm active 2>/dev/null | sed -n 's/^Current active profile: //p'
}

apply_profile() {
    set -- "$1" $(profile_defaults "$1")
    cpu=$(pinned cpu) && cpu_caps "$cpu" >/dev/null || cpu=$2
    gpu=$(pinned gpu) && gpu_valid "$gpu" || gpu=$3
    fan=$(pinned fan) && fan_profile "$fan" >/dev/null || fan=$4
    apply_cpu "$cpu"
    apply_gpu_floor "$1"
    apply_gpu "$gpu"
    apply_fan "$fan"
}

[ "$#" -ge 1 ] || usage

case "$1" in
    set)
        [ "$#" -eq 3 ] || usage
        case "$2" in
            cpu) cpu_caps "$3" >/dev/null || usage; pin cpu "$3"; apply_cpu "$3" ;;
            gpu) gpu_valid "$3" || usage; pin gpu "$3"; apply_gpu "$3" ;;
            fan) fan_profile "$3" >/dev/null || usage; pin fan "$3"; apply_fan "$3" ;;
            *) usage ;;
        esac
        ;;
    profile)
        [ "$#" -eq 2 ] || usage
        apply_profile "$2"
        ;;
    apply)
        [ "$#" -eq 1 ] || usage
        apply_profile "$(active_profile)"
        ;;
    *)
        usage
        ;;
esac
