feat(pwr): Add blanton_multiphase_read.sh to read back the SWB VRMs
Reads the controllers blanton_multiphase_margin.sh writes (native i2c, SWB0 = i2c-13/15, SWB1 = i2c-14/16) and prints one row per chip in the pu_show.sh layout - VOUT/VOUT2, IOUT/IOUT2, POUT (V x I), TEMP - with the raw PMBus word in hex after every voltage and current, plus the total power per board. PAGE is read back after each page and the page is re-read if something else moved it. Not run on the bench yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0131orciRKrejchsuDk6UpXk
This commit is contained in:
@@ -0,0 +1,202 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# blanton_multiphase_read.sh -- read back the SWB multiphase VRMs (V / I / P / T)
|
||||||
|
# =============================================================================
|
||||||
|
# Version History:
|
||||||
|
# V1.0.0 2026-11-04 First version. Reads the same controllers that
|
||||||
|
# blanton_multiphase_margin.sh writes (native i2c,
|
||||||
|
# SWB0 = i2c-13/15, SWB1 = i2c-14/16) and prints one row
|
||||||
|
# per chip in the pu_show.sh layout, with the raw PMBus
|
||||||
|
# word in hex after every voltage and current.
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# Per chip, per PAGE (page 0 -> VOUT/IOUT, page 1 -> VOUT2/IOUT2):
|
||||||
|
# PAGE 0x00 i2cset <page>
|
||||||
|
# READ_VOUT 0x8B MP29816 : bits[11:0] x LSB from MFR_VOUT_SCALE_LOOP
|
||||||
|
# (0x29) bits[12:10], read from the chip
|
||||||
|
# MP2985B : bits[11:0] x 1 mV
|
||||||
|
# READ_IOUT 0x8C SLINEAR11
|
||||||
|
# READ_TEMP1 0x8D page 0 only. MP29816 SLINEAR11, MP2985B bits[10:0]
|
||||||
|
# two's complement degC
|
||||||
|
# POUT computed V x I (not READ_POUT) -- same as pu_show.sh
|
||||||
|
# Conversions are the ones verified in blanton_pwr_data.sh V1.0.0.
|
||||||
|
#
|
||||||
|
# The kernel / platform daemons may talk to the same chips and move PAGE
|
||||||
|
# between our page select and our read. After every page's reads the PAGE
|
||||||
|
# register is read back; if it moved, that page is re-read (MP_RETRY times)
|
||||||
|
# and printed NA if it never holds still. 0xFFFF is also treated as NA.
|
||||||
|
#
|
||||||
|
# Read only -- nothing but PAGE is written. PAGE is put back to 0 afterwards.
|
||||||
|
# ⚠️ Do not run while blanton_multiphase_margin.sh is writing: both select
|
||||||
|
# PAGE on the same chips and neither one knows about the other.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./blanton_multiphase_read.sh # both boards
|
||||||
|
# ./blanton_multiphase_read.sh -u 0 # SWB0 only
|
||||||
|
# ./blanton_multiphase_read.sh -n # print the i2c commands only
|
||||||
|
#
|
||||||
|
# Options:
|
||||||
|
# -u|--unit <0|1|all> which switch board (default: both)
|
||||||
|
# -d|--debug print every i2c command and the word it returned
|
||||||
|
# -n|--dry-run print the commands only, do not touch the DUT
|
||||||
|
# -h|--help help
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
MP_UNITS="${MP_UNITS:-0 1}"
|
||||||
|
MP_RETRY="${MP_RETRY:-3}"
|
||||||
|
MP_DRY_RUN=${MP_DRY_RUN:-0}
|
||||||
|
DEBUG_MODE=${DEBUG_MODE:-0}
|
||||||
|
MP_NA="NA"
|
||||||
|
|
||||||
|
# --- Chip map ----------------------------------------------------------------
|
||||||
|
# "name:part:bus_swb0:addr:pages" SWB1 = same addr on bus + 1 (13->14, 15->16)
|
||||||
|
# PU numbers are from PWR_Data.xlsx (blanton_pwr_data.sh PWR_RAILS).
|
||||||
|
MP_CHIPS=(
|
||||||
|
"PU2:MP29816:13:0x20:0"
|
||||||
|
"PU105:MP2985B:13:0x21:0 1"
|
||||||
|
"PU102:MP2985B:13:0x22:0 1"
|
||||||
|
"PU114:MP2985B:13:0x25:0 1"
|
||||||
|
"PU122:MP2985B:13:0x27:0 1"
|
||||||
|
"PU142:MP2985B:13:0x29:0 1"
|
||||||
|
"PU108:MP2985B:15:0x23:0 1"
|
||||||
|
"PU111:MP2985B:15:0x24:0 1"
|
||||||
|
"PU118:MP2985B:15:0x26:0 1"
|
||||||
|
"PU127:MP2985B:15:0x28:0 1"
|
||||||
|
)
|
||||||
|
|
||||||
|
_mp_err() { echo -e "[\033[31mERR \033[0m] $*" >&2; }
|
||||||
|
_mp_dbg() { [ "$DEBUG_MODE" = "1" ] && echo -e "\033[90m[DEBG] $*\033[0m" >&2; return 0; }
|
||||||
|
|
||||||
|
# --- i2c ---------------------------------------------------------------------
|
||||||
|
_mp_setpage() { # <bus> <addr> <page>
|
||||||
|
if [ "$MP_DRY_RUN" = "1" ]; then echo "i2cset -f -y $1 $2 0x00 $3"; return 0; fi
|
||||||
|
_mp_dbg "i2cset -f -y $1 $2 0x00 $3"
|
||||||
|
i2cset -f -y "$1" "$2" 0x00 "$3" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
_mp_rd() { # <bus> <addr> <reg> <b|w> -> decimal on stdout
|
||||||
|
local out
|
||||||
|
if [ "$MP_DRY_RUN" = "1" ]; then echo "i2cget -f -y $1 $2 $3 $4" >&2; echo 0; return 0; fi
|
||||||
|
out=$(i2cget -f -y "$1" "$2" "$3" "$4" 2>/dev/null) || { _mp_dbg "i2cget -f -y $1 $2 $3 $4 -> fail"; return 1; }
|
||||||
|
_mp_dbg "i2cget -f -y $1 $2 $3 $4 -> $out"
|
||||||
|
case "$out" in 0x[0-9a-fA-F]*) echo $(( out )) ;; *) return 1 ;; esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- decoders ----------------------------------------------------------------
|
||||||
|
_mp_l11() { # SLINEAR11 word -> value
|
||||||
|
local w=$(( $1 & 0xFFFF )) e m
|
||||||
|
e=$(( (w >> 11) & 0x1F )); (( e > 15 )) && e=$(( e - 32 ))
|
||||||
|
m=$(( w & 0x7FF )); (( m > 1023 )) && m=$(( m - 2048 ))
|
||||||
|
awk -v m="$m" -v e="$e" 'BEGIN { printf "%.3f", m * (2.0 ^ e) }'
|
||||||
|
}
|
||||||
|
|
||||||
|
_mp_res() { # MP29816 Vout LSB (V) from MFR_VOUT_SCALE_LOOP bits[12:10]
|
||||||
|
case $(( ($1 >> 10) & 0x7 )) in
|
||||||
|
0) echo 0.00625 ;; 1) echo 0.005 ;; 2) echo 0.0025 ;; 3) echo 0.002 ;;
|
||||||
|
4) echo 0.001 ;; 5) echo 0.00390625 ;; 6) echo 0.001953125 ;; 7) echo 0.0009765625 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- one page: sets V_STR / I_STR / V_VAL / I_VAL ----------------------------
|
||||||
|
_mp_read_page() { # <part> <bus> <addr> <page> <res>
|
||||||
|
local part="$1" bus="$2" addr="$3" pg="$4" res="$5" try wv wi wp
|
||||||
|
V_STR="$MP_NA"; I_STR="$MP_NA"; V_VAL=""; I_VAL=""
|
||||||
|
for (( try=0; try<MP_RETRY; try++ )); do
|
||||||
|
_mp_setpage "$bus" "$addr" "$pg" || continue
|
||||||
|
wv=$(_mp_rd "$bus" "$addr" 0x8B w) || wv=""
|
||||||
|
wi=$(_mp_rd "$bus" "$addr" 0x8C w) || wi=""
|
||||||
|
[ "$MP_DRY_RUN" = "1" ] && { _mp_rd "$bus" "$addr" 0x00 b >/dev/null; return 0; }
|
||||||
|
wp=$(_mp_rd "$bus" "$addr" 0x00 b) || continue
|
||||||
|
(( wp == pg )) || { _mp_dbg "$bus/$addr: PAGE moved to $wp, re-reading page $pg"; continue; }
|
||||||
|
break
|
||||||
|
done
|
||||||
|
(( try == MP_RETRY )) && return 1
|
||||||
|
if [ -n "$wv" ] && (( wv != 0xFFFF )); then
|
||||||
|
if [ "$part" = "MP29816" ]; then
|
||||||
|
V_VAL=$(awk -v c=$(( wv & 0xFFF )) -v r="$res" 'BEGIN { printf "%.3f", c * r }')
|
||||||
|
else
|
||||||
|
V_VAL=$(awk -v c=$(( wv & 0xFFF )) 'BEGIN { printf "%.3f", c / 1000 }')
|
||||||
|
fi
|
||||||
|
V_STR=$(printf '%s(0x%04X)' "$V_VAL" "$wv")
|
||||||
|
fi
|
||||||
|
if [ -n "$wi" ] && (( wi != 0xFFFF )); then
|
||||||
|
I_VAL=$(_mp_l11 "$wi")
|
||||||
|
I_STR=$(printf '%s(0x%04X)' "$I_VAL" "$wi")
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_mp_pout() { [ -n "$1" ] && [ -n "$2" ] && awk -v v="$1" -v i="$2" 'BEGIN { printf "%.3f", v * i }' || echo "$MP_NA"; }
|
||||||
|
|
||||||
|
# --- main --------------------------------------------------------------------
|
||||||
|
blanton_multiphase_read() {
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
-u|--unit)
|
||||||
|
case "$2" in
|
||||||
|
all|ALL) MP_UNITS="0 1" ;;
|
||||||
|
0|1) MP_UNITS="$2" ;;
|
||||||
|
*) _mp_err "invalid unit '$2' (use 0, 1 or all)"; return 2 ;;
|
||||||
|
esac
|
||||||
|
shift 2 ;;
|
||||||
|
-d|--debug) DEBUG_MODE=1; shift ;;
|
||||||
|
-n|--dry-run) MP_DRY_RUN=1; shift ;;
|
||||||
|
-h|--help) sed -n '/^# Usage:/,/^# =====/p' "${BASH_SOURCE[0]}" | sed '$d; s/^# \{0,1\}//'; return 0 ;;
|
||||||
|
*) _mp_err "unknown option '$1'"; return 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
command -v i2cget >/dev/null 2>&1 || [ "$MP_DRY_RUN" = "1" ] || { _mp_err "i2cget not found"; return 1; }
|
||||||
|
|
||||||
|
local fmt='%-16s| %-17s| %-17s| %-18s| %-18s| %-9s| %-9s| %s\n'
|
||||||
|
local rule='--------------------------------------------------------------------------------------------------------------------------'
|
||||||
|
local u e name part bus0 addr pages bus res w temp tot sums=""
|
||||||
|
local V1 I1 V1v I1v V2 I2 V2v I2v P1 P2 m
|
||||||
|
|
||||||
|
printf "$fmt" NAME "VOUT" "VOUT2" "IOUT" "IOUT2" "POUT" "POUT2" "TEMP"
|
||||||
|
echo "$rule"
|
||||||
|
for u in $MP_UNITS; do
|
||||||
|
tot=0
|
||||||
|
for e in "${MP_CHIPS[@]}"; do
|
||||||
|
IFS=: read -r name part bus0 addr pages <<< "$e"
|
||||||
|
bus=$(( bus0 + u ))
|
||||||
|
res=""; temp="$MP_NA"
|
||||||
|
V1="$MP_NA"; I1="$MP_NA"; V1v=""; I1v=""
|
||||||
|
V2="$MP_NA"; I2="$MP_NA"; V2v=""; I2v=""
|
||||||
|
|
||||||
|
# page 0: scale (MP29816), temperature, VOUT/IOUT
|
||||||
|
_mp_setpage "$bus" "$addr" 0
|
||||||
|
if [ "$part" = "MP29816" ]; then
|
||||||
|
w=$(_mp_rd "$bus" "$addr" 0x29 w) && res=$(_mp_res "$w")
|
||||||
|
[ -n "$res" ] || res=0.0025
|
||||||
|
fi
|
||||||
|
if w=$(_mp_rd "$bus" "$addr" 0x8D w) && (( w != 0xFFFF )); then
|
||||||
|
if [ "$part" = "MP29816" ]; then temp=$(printf '%.2f' "$(_mp_l11 "$w")")
|
||||||
|
else m=$(( w & 0x7FF )); (( m > 1023 )) && m=$(( m - 2048 )); temp=$(printf '%.2f' "$m"); fi
|
||||||
|
fi
|
||||||
|
if _mp_read_page "$part" "$bus" "$addr" 0 "$res"; then
|
||||||
|
V1="$V_STR"; I1="$I_STR"; V1v="$V_VAL"; I1v="$I_VAL"
|
||||||
|
fi
|
||||||
|
if [[ " $pages " == *" 1 "* ]] && _mp_read_page "$part" "$bus" "$addr" 1 "$res"; then
|
||||||
|
V2="$V_STR"; I2="$I_STR"; V2v="$V_VAL"; I2v="$I_VAL"
|
||||||
|
fi
|
||||||
|
_mp_setpage "$bus" "$addr" 0 >/dev/null
|
||||||
|
|
||||||
|
P1=$(_mp_pout "$V1v" "$I1v")
|
||||||
|
if [[ " $pages " == *" 1 "* ]]; then P2=$(_mp_pout "$V2v" "$I2v"); else P2="$MP_NA"; fi
|
||||||
|
[ "$P1" != "$MP_NA" ] && tot=$(awk -v a="$tot" -v b="$P1" 'BEGIN { printf "%.3f", a + b }')
|
||||||
|
[ "$P2" != "$MP_NA" ] && tot=$(awk -v a="$tot" -v b="$P2" 'BEGIN { printf "%.3f", a + b }')
|
||||||
|
|
||||||
|
[ "$MP_DRY_RUN" = "1" ] && continue
|
||||||
|
printf "$fmt" "SWB${u}-MP_${name}" "$V1" "$V2" "$I1" "$I2" "$P1" "$P2" "$temp"
|
||||||
|
done
|
||||||
|
sums="${sums}SWB${u} Total Power: ${tot} W"$'\n'
|
||||||
|
done
|
||||||
|
[ "$MP_DRY_RUN" = "1" ] && return 0
|
||||||
|
echo "$rule"
|
||||||
|
printf '%s' "$sums"
|
||||||
|
echo "(hex = raw PMBus word; POUT = VOUT x IOUT; an NA row means the chip did not answer or PAGE kept moving)"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
|
||||||
|
blanton_multiphase_read "$@"
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user