LAN7800 EEPROM programming on Linux — mechanism reference

Source: CONDUCTOR research scout, verified against Linux kernel source, LAN7800 datasheet DS00001992G, and u-boot. LAN7800 only (USB VID 0x0424 / PID 0x7800).

Two backends

drivers/net/usb/lan78xx.c implements ethtool EEPROM ops.

  • Constants: LAN78XX_EEPROM_MAGIC 0x78A5, OTP_MAGIC 0x78F3, MAX_EEPROM_SIZE 512, EEPROM_INDICATOR 0xA5, EEPROM_MAC_OFFSET 0x01, OTP indicators 0xF3/0xF7.
  • Read: ethtool -e <iface> [raw on] [offset N length M]. Reading a blank/unsigned EEPROM returns -ENODATA (offset 0 != 0xA5) — not zeros.
  • Write: ethtool -E <iface> magic 0x78A5 offset <o> value <v> — one byte per call. The driver issues EWEN internally; you do NOT manage EWEN/EWDS on this path.
  • Quirks: 512-byte max; 9-bit address (0–511); no signature check on write (you own writing 0xA5); reset/replug to reload the image (avoid raw RELOAD).

B. libusb vendor commands (only if driver-independence / blank-chip needed)

Unbind the kernel driver first. Two vendor control transfers:

  • Read reg: bmRequestType 0xC0, bRequest 0xA1, wValue 0, wIndex=reg offset, 4-byte LE.
  • Write reg: bmRequestType 0x40, bRequest 0xA0, wValue 0, wIndex=reg offset, 4-byte LE. Registers: HW_CFG 0x010, E2P_CMD 0x040, E2P_DATA 0x044. E2P_CMD bits: BUSY 0x80000000, cmd field bits 30:28 — READ 0x0, EWDS 0x1<<28, EWEN 0x2<<28, WRITE 0x3<<28, WRAL 0x4<<28, ERASE 0x5<<28, ERAL 0x6<<28, RELOAD 0x7<<28; TIMEOUT 0x400, DL 0x200, ADDR_MASK 0x1FF.
  • Read byte A: write E2P_CMD = BUSY|READ|A; poll BUSY clear; read E2P_DATA[7:0].
  • Write byte D@A: EWEN once (BUSY|EWEN, poll); write E2P_DATA=D; write E2P_CMD=BUSY|WRITE|A (poll); repeat; EWDS when done. You must issue EWEN yourself on this path.

EEPROM binary layout (datasheet Table 10-2, byte offsets)

  • 0x00: 0xA5 signature (device ignores EEPROM if != 0xA5 → falls back to OTP/defaults)
  • 0x01–0x06: MAC, LE octet order — MAC AA:BB:CC:DD:EE:FF → bytes FF EE DD CC BB AA (VERIFY direction against a real dump + datasheet §15.1.54 before trusting.)
  • 0x07: GPIO wakeup enables; 0x09–0x0A GPIO PME flags; 0x0B–0x0D LED config 0/1/2
  • 0x0E: GPIO wakeup polarity; 0x10–0x12 interrupt-EP polling (FS/HS/SS)
  • 0x13–0x22: Config Flags 0–3 (4 bytes each, LE)
  • 0x23–0x24: Language ID; 0x25–0x2E string desc len+word-offset pairs (Mfr, Product, Serial, Config, Interface). VID/PID live INSIDE the SS/HS/FS device-descriptor blocks (pointed to by 0x31/0x35/0x39), idVendor at desc bytes 8–9, idProduct 10–11, LE.
  • Pointer fields are in 16-bit WORD units; length 0 = field absent → hardware default.

Boot precedence

valid EEPROM → configured OTP → CSR defaults. USB reset reloads MAC only; full load on POR/RESET/SRST.

Safe procedure (ethtool path)

  1. Back up full EEPROM first: sudo ethtool -e <iface> raw on > eeprom-backup.bin
  2. Confirm byte 0 == A5; MAC at 0x01–0x06.
  3. Edit only the 6 MAC bytes on a COPY.
  4. Write per-byte with magic 0x78A5.
  5. Replug / usb reset to reload.
  6. Verify: re-read, diff against intended image; ip link shows new MAC.

Anti-brick: never touch 0x00 unless deliberately writing 0xA5; stay 0–511; change the minimum bytes; keep the backup; a cleared/!=A5 signature is recoverable (falls back).

References

  • linux drivers/net/usb/lan78xx.c + lan78xx.h (authoritative register map)
  • LAN7800 Data Sheet DS00001992G §10.0–10.4, Table 10-2, §15.1.54
  • u-boot drivers/usb/eth/lan78xx.c ; microchip-ung/lan78xx_linux
  • Template libusb scaffolding (different chip, reuse structure only): karosium/asix_eepromtool, jglim/ASIXFlash