====== SFP GPON ONU EEPROM Editing ======
===== Add 2500Base-X =====
Credit: https://github.com/Anime4000/RTL960x/discussions/250#discussion-6288339
==== Prerequisites ====
* OpenWrt router with:
* SFP port(s) (any speed) with I2C bus
* Packages ''ethtool-full'' ''i2c-tools''
==== Steps ====
- SSH into OpenWrt
- Run one of the following commands to determine which I2C bus your SFP is on
* If your router has **a single SFP**:
- ''%%BUS=$(for bus in /sys/bus/i2c/devices/i2c-*; do b=${bus##*-}; i2cdetect -y -r $b 2>/dev/null | grep -q " 50 " && i2cdetect -y -r $b 2>/dev/null | grep -q " 51 " && echo $b; done)%%''
- ''echo $BUS'' and check there is a value before proceeding (you can also run the multiple SFP script below to verify the SFP vendor and S/N)
* If your router has **multiple SFPs**:
- for bus in /sys/bus/i2c/devices/i2c-*; do
b=${bus##*-}
if i2cdetect -y -r $b 2>/dev/null | grep -q " 50 " && i2cdetect -y -r $b 2>/dev/null | grep -q " 51 "; then
vendor=""
for reg in $(seq 20 35); do
vendor="$vendor$(printf "\\x$(i2cget -y $b 0x50 $reg | sed 's/0x//')")"
done
serial=""
for reg in $(seq 68 83); do
serial="$serial$(printf "\\x$(i2cget -y $b 0x50 $reg | sed 's/0x//')")"
done
echo ""
echo "Bus: $b"
echo "├─▶ Vendor: $vendor"
echo "└─▶ S/N: $serial"
fi
done
- Determine the correct bus number, e.g. 5
- ''BUS=5'' (replace 5 with the respective bus number)
- Run the following commands to set the SFP EEPROM bits in OpenWrt according to the EEPROM Bits table below
- ''i2cset -y $BUS 0x50 0x06 0x00''
- ''i2cset -y $BUS 0x50 0x0a 0x05''
- ''i2cset -y $BUS 0x50 0x0c 0x1f''
- ''%%i2cset -y $BUS 0x50 0x3f $(i2cdump -y -r 0-62 $BUS 0x50 b | awk 'NR>1 {for(i=2;i<=NF;i++) if($i~/^[0-9a-f]{2}$/) {cmd="printf \"%d\" 0x"$i; cmd|getline d; close(cmd); sum+=d}} END {printf "0x%02x", sum % 256}')%%''
- Physically re-seat the SFP
- Verify the new speeds are detected:\\ ''ethtool -m //**[ethX]**//''\\
Supported link modes: 2500baseX/Full
1000baseX/Full
==== EEPROM Bits ====
^ Address ^ Field ^ Old Value ^ New Value ^ Reason ^
| ''0x06'' | Ethernet Compliance | ''0x02'' | ''0x00'' | Clear 1000BASE-LX to avoid advertising conflicting speeds alongside 2500BASE-X |
| ''0x0A'' | Extended Compliance | ''0x00'' | ''0x05'' | Declare 2500BASE-X support |
| ''0x0C'' | Nominal Bit Rate | ''0x0D'' | ''0x1F'' | Set to 3100MBd (correct value for 2500BASE-X) |
| ''0x3F'' | CC_BASE Checksum | (varies) | (recalculated by ''awk'') | Sum of bytes 0x00–0x3E mod 256 |
| ''0x5F'' | CC_EXT Checksum | (varies) | (unchanged) | Not affected by these changes |
==== EEPROM Bits (XG-PON/XGS-PON) ====
> ⚠️ **Warning:** These settings are untested. Proceed with caution.
Notes:
* Due to Linux kernel limitations, only a single speed can be advertised via EEPROM for XG-PON/XGS-PON. Multi-rate combinations (e.g. 2.5/5Gbps, 5/10Gbps, 2.5/5/10Gbps) are not achievable through EEPROM editing alone((Linux's SFP bus driver derives supported speeds solely from EEPROM compliance codes, which only allows a single speed to be declared via the compliance code bytes. Multi-rate support requires either a kernel quirk (hardcoded per vendor/part number in ''sfp.c''), a PHY-emulating module that negotiates speeds independently, or a NIC driver that bypasses the generic SFP bus logic entirely.))
* You do not have to update the 0x5F checksum (CC_EXT) unless you edit addresses ''0x40''–''0x5E'', which are out of scope of this guide; but in case you need it, this command will update CC_EXT:\\ ''%%i2cset -y $BUS 0x50 0x5f $(i2cdump -y -r 64-94 $BUS 0x50 b | awk 'NR>1 {for(i=2;i<=NF;i++) if($i~/^[0-9a-f]{2}$/) {cmd="printf \"%d\" 0x"$i; cmd|getline d; close(cmd); sum+=d}} END {printf "0x%02x", sum % 256}')%%''
=== Fiber Rates (No PHY) ===
^ Address ^ Field ^ Choose only ONE column of values ^^^^^^
^ ::: ^ ::: ^ 1000BASE-X ^ 2500BASE-X ^ 10GBASE-LR ^ 10GBASE-SR ^ 10GBASE-LRM ^ 10GBASE-ER ^
| ''0x03'' | 10G Ethernet Compliance | ''0x00'' | ''0x00'' | ''0x20'' | ''0x10'' | ''0x40'' | ''0x80'' |
| ''0x06'' | Ethernet Compliance | ''0x02'' | ''0x00'' | ''0x00'' | ''0x00'' | ''0x00'' | ''0x00'' |
| ''0x0A'' | Extended Compliance | ''0x00'' | ''0x05'' | ''0x00'' | ''0x00'' | ''0x00'' | ''0x00'' |
| ''0x0C'' | Nominal Bit Rate | ''0x0D'' (1300MBd) | ''0x1F'' (3100MBd) | ''0x67'' (10300MBd) | ''0x67'' (10300MBd) | ''0x67'' (10300MBd) | ''0x67'' (10300MBd) |
| ''0x3F'' | CC_BASE Checksum | (recalculated by ''awk'') ||||||
Notes:
* Set ''0x06'' to ''0x00'' (clear 1000BASE-LX) for all configurations above except 1000BASE-X, to avoid advertising conflicting speeds alongside the selected rate
=== Copper Rates (PHY Emulation Required) ===
^ Address ^ Field ^ Choose only ONE column of values ^^^^
^ ::: ^ ::: ^ 2500BASE-T ^ 5GBASE-T ^ 10GBASE-T (SFI) ^ 10GBASE-T (SR, 30m) ^
| ''0x03'' | 10G Ethernet Compliance | ''0x00'' | ''0x00'' | ''0x00'' | ''0x00'' |
| ''0x06'' | Ethernet Compliance | ''0x00'' | ''0x00'' | ''0x00'' | ''0x00'' |
| ''0x0A'' | Extended Compliance | ''0x1E'' | ''0x1D'' | ''0x16'' | ''0x1C'' |
| ''0x0C'' | Nominal Bit Rate | ''0x1F'' (3100MBd) | ''0x32'' (5000MBd) | ''0x67'' (10300MBd) | ''0x67'' (10300MBd) |
| ''0x3F'' | CC_BASE Checksum | (recalculated by ''awk'') ||||