#!/bin/sh
# SkillFishOS — enable/disable ACPI CPU frequency scaling on the BC-250.
#
# The board's firmware ships no _PSS objects, so Linux gets no cpufreq interface at
# all: the CPU runs at whatever the hardware picks and the OS has no say. Injecting
# an SSDT with P-states through GRUB's early initrd gives us acpi-cpufreq with 8
# steps (800–3200 MHz) and the usual governors, schedutil included.
#
# The frequencies in the table are labels — the real clock comes from the hardware
# P-state registers, so an SMU overclock above 3200 is NOT capped by this (measured:
# the board still peaks at ~3500 with the table loaded). What it buys is idle: the
# cores drop to 800 MHz instead of sitting near 1400, which frees thermal budget.
#
# Tables from mendesrr/bc250-acpi-fix-updated-8c (they cover P000..P00F = 16 threads).
# Both are installed: SSDT-PST gives the P-states, SSDT-CST the idle C-states — tested
# without CST and cpuidle came up empty, so it does real work here. The
# "Could not resolve symbol \_PR.C000" messages in dmesg are NOT from these tables:
# they still appear with CST removed, so they come from the board's own firmware.
#
#   skillfish-acpi-pstates auto     <- attiva sulla BC-250, TOGLIE altrove
#   skillfish-acpi-pstates enable   (default)
#   skillfish-acpi-pstates disable
#   skillfish-acpi-pstates status
#
# PERCHE' ESISTE "auto"
# "enable" su una macchina che non e' una BC-250 si limita a non fare nulla. Non
# basta: la ISO e' un'istantanea della scheda di sviluppo, dove la tabella E'
# attiva, quindi arriva gia' installata e gia' scritta in /etc/default/grub. Su
# un PC normale la guardia non entra mai in gioco perche' non c'e' niente da
# attivare — c'e' da TOGLIERE. Misurato installando la Generic in macchina
# virtuale: 32 righe di
#   ACPI BIOS Error (bug): Could not resolve symbol [\_PR.P000], AE_NOT_FOUND
# a ogni avvio, perche' la tabella si aggancia a P000..P00F che li' non esistono.
set -e
AMLDIR=/usr/share/skillfish/acpi
AML="$AMLDIR/SSDT-PST.aml"
CPIO=/boot/SkillFishOS-acpi.cpio
GRUBDEF=/etc/default/grub
ACTION="${1:-enable}"

need_root() { [ "$(id -u)" = 0 ] || { echo "serve root" >&2; exit 1; }; }

# The table hard-codes this board's P-state ladder and attaches to \_PR.P000..P00F.
# On any other machine that is at best useless and at worst a conflict with the
# firmware's own _PSS, so refuse unless we really are on a BC-250.
is_bc250() { grep -q 'AMD BC-250' /proc/cpuinfo 2>/dev/null; }

case "$ACTION" in
  auto)
    need_root
    if is_bc250; then
      exec "$0" enable
    fi
    # Non e' una BC-250. Se la tabella non c'e', non c'e' niente da fare e usciamo
    # in silenzio; se c'e' (arrivata con l'immagine), va tolta.
    if [ -f "$CPIO" ] || grep -q '^GRUB_EARLY_INITRD_LINUX_CUSTOM=' "$GRUBDEF" 2>/dev/null; then
      echo "non e' una BC-250: tolgo la tabella ACPI arrivata con l'immagine"
      exec "$0" disable
    fi
    exit 0
    ;;

  status)
    if [ -d /sys/devices/system/cpu/cpu0/cpufreq ]; then
      echo "cpufreq: $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver) / $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)"
      echo "P-states: $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies 2>/dev/null)"
    else
      echo "cpufreq: assente (tabella non attiva o non ancora riavviato)"
    fi
    [ -f "$CPIO" ] && echo "tabella installata: $CPIO" || echo "tabella non installata"
    ;;

  enable)
    need_root
    if ! is_bc250 && [ "${2:-}" != "--force" ]; then
      echo "non è una BC-250: non tocco l'ACPI (usa --force se sai cosa stai facendo)."
      exit 0
    fi
    [ -f "$AML" ] || { echo "manca $AML" >&2; exit 1; }
    # the kernel looks for the tables at this exact path inside the early cpio
    tmp=$(mktemp -d)
    mkdir -p "$tmp/kernel/firmware/acpi"
    cp "$AMLDIR"/SSDT-*.aml "$tmp/kernel/firmware/acpi/"
    (cd "$tmp" && find kernel | cpio -H newc --create --quiet) > "$CPIO"
    rm -rf "$tmp"
    sed -i '/^GRUB_EARLY_INITRD_LINUX_CUSTOM=/d' "$GRUBDEF"
    echo "GRUB_EARLY_INITRD_LINUX_CUSTOM=\"$(basename "$CPIO")\"" >> "$GRUBDEF"
    update-grub >/dev/null 2>&1 || update-grub2 >/dev/null 2>&1 || true
    echo "P-states ACPI attivati — hanno effetto al prossimo riavvio."
    ;;

  disable)
    need_root
    sed -i '/^GRUB_EARLY_INITRD_LINUX_CUSTOM=/d' "$GRUBDEF"
    rm -f "$CPIO"
    update-grub >/dev/null 2>&1 || update-grub2 >/dev/null 2>&1 || true
    echo "P-states ACPI disattivati — al prossimo riavvio si torna al comportamento del firmware."
    ;;

  *) echo "uso: $0 [auto|enable|disable|status]" >&2; exit 2 ;;
esac
