Site Tools


projects:homelab:sfp_gpon_onu:eeprom_editing

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
projects:homelab:sfp_gpon_onu:eeprom_editing [2025/03/29 07:31] – [Steps] i2cset param note Andrew Yongprojects:homelab:sfp_gpon_onu:eeprom_editing [2026/03/21 17:21] (current) – clarification on 1000BASE-X linux limitation Andrew Yong
Line 10: Line 10:
     * SFP port(s) (any speed) with I2C bus     * SFP port(s) (any speed) with I2C bus
     * Packages ''ethtool-full'' ''i2c-tools''     * Packages ''ethtool-full'' ''i2c-tools''
-  * [[https://sfptotal.io/software|SFPTotal Wizard]] (Windows software, only used to calculate checksum at 0x3f) 
  
 ==== Steps ==== ==== Steps ====
  
-  - On OpenWrt +  - SSH into OpenWrt 
-    Dump EEPROM:\\ ''ethtool -m //**[ethX]**// raw on > /tmp/sfp.bin'' +  Run one of the following commands to determine which I2C bus your SFP is on 
-  On Windows desktop +    * If your router has **a single SFP**: 
-    - Copy EEPROM to Windows desktop (run in Windows Terminal):\\ ''scp -O root@192.168.1.1:/tmp/sfp.bin .'+      - ''%%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)%%'' 
-    - Open sfp.bin in SFPTotal Wizard +      ''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) 
-    - Set the bits in SFPTotal Wizard according to the EEPROM Bits table below +    * If your router has **multiple SFPs**: 
-    Take note of the checksum in 0x3F (first green byte+      <code>for bus in /sys/bus/i2c/devices/i2c-*; do 
-  - On OpenWrt +    b=${bus##*-} 
-    - Set the SFP EEPROM bits in OpenWrt according to the EEPROM Bits table below (you will need to adjust ''-y 5'' to match the i2c bus on your system) +    if i2cdetect -y -r $b 2>/dev/null | grep -q " 50 " && i2cdetect -y -r $b 2>/dev/null | grep -q " 51 "; then 
-      * ''i2cset -y 0x50 0x06 0x00'' +        vendor="" 
-      ''i2cset -y 0x50 0x0a 0x05'' +        for reg in $(seq 20 35); do 
-      ''i2cset -y 0x50 0x0c 0x1f'' +            vendor="$vendor$(printf "\\x$(i2cget -y $b 0x50 $reg | sed 's/0x//')")" 
-      ''i2cset -y 0x50 0x3f 0x//**[Refer to SFPTotal Wizard]**//'' +        done 
-    - Physically re-seat the SFP +        serial="" 
-    - Verify the new speeds are detected:\\ ''ethtool -m //**[ethX]**//''\\ <code>+        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</code> 
 +      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]**//''\\ <code>
         Supported link modes:   2500baseX/Full         Supported link modes:   2500baseX/Full
                                 1000baseX/Full                                 1000baseX/Full
Line 35: Line 51:
 ==== EEPROM Bits ==== ==== EEPROM Bits ====
  
-^ Address ^ Old Setting ^ New Setting + Address   Field  ^  Old Value   New Value  ^  Reason  
-| ''0x06'' | ''0x02'' | ''0x00''+ ''0x06''   Ethernet Compliance  |  ''0x02''   ''0x00''   Clear 1000BASE-LX to avoid advertising conflicting speeds alongside 2500BASE-X  
-| ''0x0A'' | ''0x00'' | ''0x05''+ ''0x0A''   Extended Compliance  |  ''0x00''   ''0x05''   Declare 2500BASE-X support  
-| ''0x0C'' | ''0x0D'' | ''0x1F''+ ''0x0C''   Nominal Bit Rate  |  ''0x0D''   ''0x1F''   Set to 3100MBd (correct value for 2500BASE-X)  
-| ''0x3F'' (Checksum) | :!: Use SFPTotal to calculate! :!: ||+ ''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'' ||||
projects/homelab/sfp_gpon_onu/eeprom_editing.1743233472.txt.gz · Last modified: by Andrew Yong