skywalker-1/tools/boot_test.py
Ryan Malloy 0d6facb321 Add experimental I2C debugging and EEPROM analysis tools
One-off diagnostic scripts from experiments 0xD7-0xDB investigating
the I2C BERR deadlock. Documents the systematic elimination of
software-only recovery approaches:

- i2c_host_test.py: Proved 0xA0 register writes cannot drive I2C bus
- i2c_register_test.py: Tested I2C register writability from host
- i2c_recovery_boot.py: Attempted I2C state machine recovery via boot
- eeprom_flash_a0.py: Host-side EEPROM flash attempt (failed)
- boot_ab_test.py / boot_test.py: EEPROM boot reliability testing
- a8_autoclear_test.py: BCM4500 command register auto-clear behavior
- addr_gateway_test.py: BCM3440 gateway address routing analysis
- stock_fw_compare.py / stock_fw_test.py: Stock vs custom fw analysis
2026-02-20 10:57:10 -07:00

178 lines
5.8 KiB
Python

#!/usr/bin/env python3
"""Quick boot test for PLL config firmware."""
import sys
sys.path.insert(0, 'tools')
from skywalker_lib import SkyWalker1
CMD_RAW_DEMOD_READ = 0xB1
CMD_I2C_SCAN = 0xB4
CMD_GET_PLL_DIAG = 0xBF
sw = SkyWalker1()
sw.open()
print('=== SkyWalker-1 Custom Firmware Boot Test ===')
print()
# Check firmware version
ver = sw.get_fw_version()
print(f'Firmware version: {ver}')
# Check config status
cfg = sw.get_config()
print(f'Config status: 0x{cfg:02X}')
bits = []
if cfg & 0x01: bits.append('Started')
if cfg & 0x02: bits.append('FW_Loaded')
if cfg & 0x04: bits.append('Intersil')
if cfg & 0x08: bits.append('DVBmode')
if cfg & 0x10: bits.append('22kHz')
if cfg & 0x20: bits.append('18V')
if cfg & 0x40: bits.append('DCtuned')
if cfg & 0x80: bits.append('Armed')
print(f' Flags: {" | ".join(bits) if bits else "(none)"}')
print()
# Check last error before boot
err = sw.get_last_error()
print(f'Last error (pre-boot): 0x{err:02X}')
print()
# Boot the BCM4500
print('--- Booting BCM4500 ---')
boot_result = sw.boot()
print(f'Boot result: {boot_result}')
cfg = sw.get_config()
print(f'Config after boot: 0x{cfg:02X}')
bits = []
if cfg & 0x01: bits.append('Started')
if cfg & 0x02: bits.append('FW_Loaded')
if cfg & 0x04: bits.append('Intersil')
if cfg & 0x08: bits.append('DVBmode')
if cfg & 0x10: bits.append('22kHz')
if cfg & 0x20: bits.append('18V')
if cfg & 0x40: bits.append('DCtuned')
if cfg & 0x80: bits.append('Armed')
print(f' Flags: {" | ".join(bits) if bits else "(none)"}')
err = sw.get_last_error()
ERR_NAMES = {
0x00: 'ERR_OK',
0x01: 'ERR_I2C_TIMEOUT',
0x02: 'ERR_I2C_NAK',
0x03: 'ERR_I2C_ARB_LOST',
0x04: 'ERR_BCM_NOT_READY (PLL config failed)',
0x05: 'ERR_BCM_TIMEOUT',
}
print(f'Last error after boot: 0x{err:02X} = {ERR_NAMES.get(err, "unknown")}')
print()
# PLL config diagnostics
print('--- PLL Config Diagnostics ---')
try:
pd = sw._vendor_in(CMD_GET_PLL_DIAG, value=0, index=0, length=10)
print(f' EEPROM present: {"YES" if pd[0] else "NO"}')
print(f' First block count: 0x{pd[1]:02X}' + (' (sentinel=0, no PLL data!)' if pd[1] == 0 else
(' (not reached)' if pd[1] == 0xFF else f' ({pd[1]} AB bytes)')))
print(f' Blocks written: {pd[2]}')
print(f' Last A9 value: 0x{pd[3]:02X}' + (' (none)' if pd[3] == 0xFF else ''))
print(f' Last AA value: 0x{pd[4]:02X}' + (' (none)' if pd[4] == 0xFF else ''))
print(f' Last AB count: 0x{pd[5]:02X}' + (' (none)' if pd[5] == 0xFF else ''))
print(f' Config mode exit: {"OK" if pd[6] == 1 else ("FAIL" if pd[6] == 0 else "not reached")}')
print(f' Overall PLL result: {"SUCCESS" if pd[7] == 1 else "FAILED"}')
print(f' Boot stage: 0x{pd[8]:02X}' + (' (all complete)' if pd[8] == 0xFF else f' (stopped at stage {pd[8]})'))
print(f' Last error: 0x{pd[9]:02X}')
except Exception as e:
print(f' PLL diag failed: {e}')
print()
# I2C bus scan
print('--- I2C Bus Scan ---')
try:
bitmap = sw._vendor_in(CMD_I2C_SCAN, value=0, index=0, length=16)
found = []
for byte_idx in range(16):
for bit_idx in range(8):
if bitmap[byte_idx] & (1 << bit_idx):
addr = byte_idx * 8 + bit_idx
found.append(addr)
labels = {0x08: 'BCM4500', 0x10: 'BCM3440', 0x51: 'EEPROM'}
for addr in found:
label = labels.get(addr, '')
print(f' 0x{addr:02X} {label}')
if not found:
print(' (no devices found!)')
except Exception as e:
print(f' Scan failed: {e}')
print()
# Try reading signal
print('--- Signal Check ---')
try:
sig = sw.signal_monitor()
print(f'Signal monitor: {sig}')
except Exception as e:
print(f'Signal monitor failed: {e}')
# Read BCM4500 direct registers via 0xB1 vendor command
# wValue=register address, wIndex=1 for direct read mode
print()
print('--- BCM4500 Direct Register Reads ---')
key_regs = [
(0xA0, 'CFG_MODE'),
(0xA2, 'STATUS'),
(0xA4, 'LOCK'),
(0xA9, 'PLL_A9'),
(0xAA, 'PLL_AA'),
(0xAB, 'PLL_AB'),
]
for reg, label in key_regs:
try:
data = sw._vendor_in(CMD_RAW_DEMOD_READ, value=reg, index=1, length=1)
val = data[0]
print(f' 0x{reg:02X} ({label:8s}): 0x{val:02X}')
except Exception as e:
print(f' 0x{reg:02X} ({label:8s}): FAILED ({e})')
# Indirect register reads via 0xB1 with wIndex=0 (indirect mode)
# wValue=page, wIndex=0. Only meaningful if the DSP core is running.
print()
print('--- BCM4500 Indirect Register Reads (DSP core test) ---')
for page in [0x06, 0x07, 0x0F]:
try:
data = sw._vendor_in(CMD_RAW_DEMOD_READ, value=page, index=0, length=1)
val = data[0]
alive = ' << DSP responding' if val != 0 else ''
print(f' Page 0x{page:02X}: 0x{val:02X}{alive}')
except Exception as e:
print(f' Page 0x{page:02X}: FAILED ({e})')
# Cross-check: read key registers via 0xB5 (raw I2C, writes into EP0BUF directly)
# This bypasses the 0xB1 handler's val variable entirely
CMD_I2C_RAW_READ = 0xB5
BCM4500_ADDR = 0x08
print()
print('--- Cross-check via 0xB5 Raw I2C Read (BCM4500 @ 0x08) ---')
for reg, label in key_regs:
try:
data = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR, index=reg, length=1)
val = data[0]
tag = ' ** I2C FAIL (0xFF) **' if val == 0xFF else ''
print(f' 0x{reg:02X} ({label:8s}): 0x{val:02X}{tag}')
except Exception as e:
print(f' 0x{reg:02X} ({label:8s}): FAILED ({e})')
# Full register dump 0xA0-0xBF via 0xB5 raw I2C (ground truth)
print()
print('--- Full Direct Register Dump 0xA0-0xBF (via 0xB5 raw I2C) ---')
for reg in range(0xA0, 0xC0):
try:
data = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR, index=reg, length=1)
val = data[0]
print(f' 0x{reg:02X}: 0x{val:02X}')
except Exception as e:
print(f' 0x{reg:02X}: FAIL')
sw.close()
print()
print('=== Test Complete ===')