Replaces speculative "corrupted boot data" with confirmed I2C bus latch diagnosis from 100+ failed power cycle attempts. Mark Option D (wait + watch) as exhausted. Add pending firmware fixes table for post-recovery testing.
187 lines
6.0 KiB
Markdown
187 lines
6.0 KiB
Markdown
# SkyWalker-1 EEPROM Recovery Guide
|
|
|
|
The device is soft-bricked: the FX2 boot ROM hangs trying to load
|
|
corrupted firmware from EEPROM, preventing USB enumeration.
|
|
|
|
## Symptoms
|
|
|
|
- Hub shows `0101 power connect []` (D+ pull-up active, no enumeration)
|
|
- dmesg: `device descriptor read/8, error -110` (timeout)
|
|
- Does not enumerate as bare FX2 (04B4:8613) either
|
|
- NanoVNA on same hub works fine (hub hardware is OK)
|
|
|
|
## Root Cause
|
|
|
|
The FX2LP boot ROM reads EEPROM (24C128 at I2C 0x51) at power-up.
|
|
The I2C bus is shared with the BCM3440 tuner and BCM4500 demod. Two
|
|
failure modes cause the hang:
|
|
|
|
1. **I2C bus latch** (confirmed): The BCM4500 or BCM3440 holds SDA
|
|
LOW from a prior incomplete transaction. I2C is open-drain — any
|
|
device sinking SDA prevents all communication. The boot ROM loops
|
|
waiting for ACK from the EEPROM, which can never respond because
|
|
SDA is stuck.
|
|
|
|
2. **Corrupted C2 image** (possible): If the EEPROM's C2 header is
|
|
intact but load records have invalid lengths or addresses, the boot
|
|
ROM hangs mid-load.
|
|
|
|
Either way, the boot ROM occupies the 8051 core and never reaches
|
|
the USB enumeration handler. The D+ pull-up activates (hub sees the
|
|
device as "present") but descriptor reads time out.
|
|
|
|
**Tested and failed (2025-02-19/20):**
|
|
- 100+ USB power cycles via uhubctl (varied off-times: 0.2s to 30s)
|
|
- Host-side I2C manipulation via 0xA0 vendor commands
|
|
- xHCI controller reset, port deauthorization
|
|
- Ultra-rapid cycling (0.2-1.0s off)
|
|
- Historically ~3-6% success rate on power cycles, now 0%
|
|
|
|
The I2C bus state degrades with each failed attempt. Software-only
|
|
recovery is not viable. Physical intervention (Options A or B) is
|
|
required.
|
|
|
|
## Recovery Options (pick one)
|
|
|
|
### Option A: SOIC Clip + External Programmer (Recommended)
|
|
|
|
Blank the first byte of the EEPROM so the boot ROM falls back to
|
|
bare FX2 enumeration. Then reload via USB.
|
|
|
|
**Hardware needed:**
|
|
- SOIC-8 test clip (Pomona 5250 or similar, ~$5)
|
|
- CH341A USB programmer (~$3) or Bus Pirate or any I2C-capable tool
|
|
- OR: Raspberry Pi / Arduino with I2C
|
|
|
|
**Steps:**
|
|
1. Power OFF the SkyWalker-1 (unplug USB)
|
|
2. Locate the 24C128 EEPROM on the PCB (SOIC-8 package near the FX2)
|
|
3. Clip the SOIC clip onto the EEPROM
|
|
4. Connect to your I2C programmer (SDA, SCL, VCC, GND)
|
|
5. Read and save the EEPROM contents (16KB backup!)
|
|
6. Write 0xFF to address 0x0000 (corrupts the C2 magic byte)
|
|
7. Remove clip, plug in SkyWalker-1
|
|
8. Device should enumerate as bare FX2 (04B4:8613)
|
|
9. Load custom firmware via `fw_load.py`
|
|
10. Use the custom firmware to write good C2 image back to EEPROM
|
|
|
|
**With CH341A:**
|
|
```bash
|
|
# Read backup
|
|
flashrom -p ch341a_spi -c "AT24C128" -r eeprom_backup.bin
|
|
|
|
# Or use i2c-tools if CH341A is in I2C mode:
|
|
# i2cdetect -l (find the CH341A bus)
|
|
# i2cdump -y <bus> 0x51 b > dump.txt
|
|
```
|
|
|
|
**With Raspberry Pi (I2C):**
|
|
```bash
|
|
# Enable I2C: raspi-config -> Interfaces -> I2C
|
|
# Connect EEPROM: SDA->GPIO2, SCL->GPIO3, VCC->3.3V, GND->GND
|
|
i2cdetect -y 1 # Should show 0x51
|
|
# Read first byte
|
|
i2cget -y 1 0x51 0x00
|
|
# Write 0xFF to byte 0 (corrupts C2 header)
|
|
i2cset -y 1 0x51 0x00 0xFF
|
|
```
|
|
|
|
### Option B: Hold SDA HIGH During Boot
|
|
|
|
Prevent the EEPROM from responding by holding SDA HIGH, forcing
|
|
the boot ROM to see "no EEPROM" and enumerate as bare FX2.
|
|
|
|
**Steps:**
|
|
1. Locate the SDA test point or EEPROM pin 5 (SDA)
|
|
2. Connect a 1kΩ pull-up to 3.3V on SDA
|
|
3. Power on the SkyWalker-1
|
|
4. If it enumerates as bare FX2 (04B4:8613), load firmware:
|
|
```bash
|
|
python3 tools/fw_load.py load firmware/build/skywalker1.ihx
|
|
```
|
|
5. Remove the pull-up
|
|
6. Use the loaded firmware to reprogram the EEPROM
|
|
|
|
**Note:** This only works if the SDA pull-up is strong enough to
|
|
override the EEPROM's SDA output. May need to experiment with
|
|
pull-up values (470Ω to 4.7kΩ).
|
|
|
|
### Option C: Desolder EEPROM Pin
|
|
|
|
Most reliable but requires soldering skill.
|
|
|
|
1. Lift EEPROM pin 5 (SDA) from the PCB pad
|
|
2. Power on → enumerates as bare FX2
|
|
3. Load firmware via USB
|
|
4. Resolder pin 5
|
|
5. Use firmware to reprogram EEPROM with good C2 image
|
|
|
|
### Option D: Wait + Watch (Exhausted — Do Not Use)
|
|
|
|
Tested extensively (100+ attempts, 2025-02-19/20) with no success.
|
|
The I2C bus latch does not clear on its own.
|
|
|
|
```bash
|
|
# Watch for bare FX2 enumeration
|
|
sudo dmesg -w | grep -E "04b4|8613|New USB"
|
|
|
|
# In another terminal, keep power cycling every 5 minutes
|
|
while true; do
|
|
sudo uhubctl -l 1-5.4.4 -p 3 -a off
|
|
sleep 5
|
|
sudo uhubctl -l 1-5.4.4 -p 3 -a on
|
|
sleep 300 # wait 5 minutes
|
|
done
|
|
```
|
|
|
|
If it appears even briefly:
|
|
```bash
|
|
python3 tools/fw_load.py load firmware/build/skywalker1.ihx --force
|
|
```
|
|
|
|
## After Recovery
|
|
|
|
Once the device enumerates (as bare FX2 or with loaded firmware):
|
|
|
|
1. **Load custom firmware to RAM:**
|
|
```bash
|
|
python3 tools/fw_load.py load firmware/build/skywalker1.ihx
|
|
```
|
|
|
|
2. **Reprogram EEPROM with good C2 image:**
|
|
```bash
|
|
# The custom firmware needs EEPROM write support first
|
|
# (vendor command to relay I2C writes to EEPROM)
|
|
python3 tools/eeprom_write.py flash firmware/build/skywalker1_eeprom.bin
|
|
```
|
|
|
|
3. **Or restore stock firmware:**
|
|
If you have a backup of the original EEPROM contents, flash that
|
|
instead of the custom firmware.
|
|
|
|
## Firmware Fixes Pending Hardware Test
|
|
|
|
The custom firmware at `firmware/build/skywalker1.ihx` (15,171 bytes)
|
|
includes three fixes discovered from stock firmware analysis:
|
|
|
|
| Commit | Fix | Stock Reference |
|
|
|-----------|------------------------------|--------------------|
|
|
| `e9e5ab8` | Init block readback verify | 0x0DDD readback |
|
|
| `dffef75` | `bcm_wait_ready()` 3-check | 0x2000 pre-write |
|
|
| `0259950` | GPIF stop before boot | 0x1D6A GPIF abort |
|
|
|
|
Load immediately after recovery:
|
|
```bash
|
|
python3 tools/fw_load.py load firmware/build/skywalker1.ihx
|
|
```
|
|
|
|
Then test: `BOOT_8PSK` (wValue=1), read signal, verify lock.
|
|
|
|
## Prevention
|
|
|
|
- Never send `BOOT_8PSK (0x89)` with mode 0x84 ("firmware load")
|
|
unless you know what data the firmware expects
|
|
- Always backup EEPROM before experiments that touch vendor commands
|
|
- The stock firmware's I2C proxy (0x83/0x84) may have side effects
|
|
on the EEPROM that aren't documented
|