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
109 lines
3.4 KiB
Python
109 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Find the exact EEPROM address where PLL config starts.
|
|
|
|
The stock firmware's FUN_CODE_10F2 presumably finds the PLL data by
|
|
computing an offset from the C2 boot firmware structure. This script
|
|
parses the C2 records to find where the firmware ends, then checks
|
|
if PLL data immediately follows.
|
|
"""
|
|
import sys
|
|
sys.path.insert(0, 'tools')
|
|
from skywalker_lib import SkyWalker1
|
|
|
|
CMD_EEPROM_READ = 0xC0
|
|
|
|
sw = SkyWalker1()
|
|
sw.open()
|
|
|
|
|
|
def eeprom_read(addr, length):
|
|
return sw._vendor_in(CMD_EEPROM_READ, value=addr, index=length, length=length)
|
|
|
|
|
|
print('=== C2 Firmware Structure Analysis ===')
|
|
print()
|
|
|
|
# Read C2 header (8 bytes)
|
|
header = eeprom_read(0x0000, 8)
|
|
print(f'Header: {header.hex(" ")}')
|
|
assert header[0] == 0xC2, 'Not a C2 EEPROM!'
|
|
vid = header[2] << 8 | header[1]
|
|
pid = header[4] << 8 | header[3]
|
|
print(f' VID: 0x{vid:04X} PID: 0x{pid:04X}')
|
|
print()
|
|
|
|
# Parse C2 load records
|
|
offset = 8
|
|
records = []
|
|
print('C2 Load Records:')
|
|
while offset < 0x8000:
|
|
hdr = eeprom_read(offset, 4)
|
|
rec_len = (hdr[0] << 8) | hdr[1]
|
|
rec_addr = (hdr[2] << 8) | hdr[3]
|
|
|
|
if rec_len == 0x8001:
|
|
print(f' [{len(records)}] END MARKER at EEPROM 0x{offset:04X} → entry=0x{rec_addr:04X}')
|
|
records.append({'type': 'end', 'offset': offset, 'entry': rec_addr})
|
|
offset += 4
|
|
break
|
|
elif rec_len == 0 or rec_len > 0x4000:
|
|
print(f' [{len(records)}] INVALID at EEPROM 0x{offset:04X}: len=0x{rec_len:04X}')
|
|
records.append({'type': 'invalid', 'offset': offset})
|
|
offset += 4
|
|
break
|
|
|
|
end_addr = rec_addr + rec_len - 1
|
|
print(f' [{len(records)}] {rec_len:5d} bytes at EEPROM 0x{offset:04X} → RAM 0x{rec_addr:04X}-0x{end_addr:04X}')
|
|
records.append({'type': 'data', 'offset': offset, 'len': rec_len, 'addr': rec_addr})
|
|
offset += 4 + rec_len
|
|
|
|
print(f'\nFirmware ends at EEPROM offset: 0x{offset:04X}')
|
|
print()
|
|
|
|
# Check what's right after the firmware
|
|
print(f'--- Data immediately after firmware (0x{offset:04X}) ---')
|
|
for addr in range(offset, offset + 128, 16):
|
|
data = eeprom_read(addr, 16)
|
|
hex_str = ' '.join(f'{b:02X}' for b in data)
|
|
print(f' {addr:04X}: {hex_str}')
|
|
|
|
print()
|
|
|
|
# Now check: does PLL data start right after the C2 firmware?
|
|
print(f'--- PLL block check starting at 0x{offset:04X} ---')
|
|
for addr in range(offset, offset + 200, 20):
|
|
block = eeprom_read(addr, 20)
|
|
count = block[0]
|
|
if count == 0:
|
|
print(f' 0x{addr:04X}: [sentinel count=0]')
|
|
break
|
|
elif 1 <= count <= 16:
|
|
ab = block[4:4 + count]
|
|
print(f' 0x{addr:04X}: count={count} A9=0x{block[1]:02X} AA=0x{block[2]:02X} '
|
|
f'unused=0x{block[3]:02X} AB=[{ab.hex(" ")}]')
|
|
else:
|
|
print(f' 0x{addr:04X}: count=0x{count:02X} (invalid, not PLL data)')
|
|
break
|
|
|
|
print()
|
|
|
|
# Also check the known PLL location from the scan
|
|
print('--- Confirmed PLL data at 0x125C (from EEPROM scan) ---')
|
|
for addr in range(0x125C, 0x12C0, 20):
|
|
block = eeprom_read(addr, 20)
|
|
count = block[0]
|
|
if count == 0:
|
|
print(f' 0x{addr:04X}: [sentinel count=0]')
|
|
break
|
|
elif 1 <= count <= 16:
|
|
ab = block[4:4 + count]
|
|
print(f' 0x{addr:04X}: count={count} A9=0x{block[1]:02X} AA=0x{block[2]:02X} '
|
|
f'unused=0x{block[3]:02X} AB=[{ab.hex(" ")}]')
|
|
else:
|
|
print(f' 0x{addr:04X}: NOT PLL (count=0x{count:02X})')
|
|
break
|
|
|
|
sw.close()
|
|
print()
|
|
print('=== Done ===')
|