Friday 16 May 2014

Raspberry Pi and Programming EEPROMs on SFP/SFP+ modules


Connecting to the I2C pins on an SFP can be difficult, the easiest way I have found is to use old Cisco TwinGig module to house the SFP or SFP+. These can be purchased at a very reasonable price from ebay if you don't have one lying around.

The pins we are interested in on the SFP/SFP+ are:
Pin1: All VeeT or VeeR pins are ground, you only need to connect to one as they are connected internally in the SFP.
Pin 15 and Pin 16 both require +3.3V.
Pin 4: MOD-Def(2) - data line of i2c serial interface
Pin 5: MOD-Def(1) - clock line of i2c serial interface
Pin 6: MOD-Def(0) is connected to ground internally on any of the SFPs I have played with. So no need to connect.





The easiest place I found to make a solder was on the ends of resistors R57 (SDA) and R54(SCL) on the back of the PCB. For the 3.3V and 0V I used the large PCB edge card connectors.











On the Raspberry Pi you just need to connect the 4 wires to the GPIO pins:
GPIO Pin 1: 3.3V
GPIO Pin 6: 0V
GPIO Pin 3: SDA
GPIO Pin 5: SCL

Here is what the final version should look like:
















How to test that everything is working:
1) Install i2c-tools. ie apt-get install i2c-tools
2) Make sure the module is being loaded and not blacklisted.
pi@raspberrypi ~ $ cat /etc/modprobe.d/raspi-blacklist.conf
# blacklist spi and i2c by default (many users don't need them)
blacklist spi-bcm2708
#blacklist i2c-bcm2708

3) Test your wiring. Make sure you can see the SFP address (0x50) on the I2C bus. If you cannot see the address something is wrong with your wiring.


pi@raspberrypi ~ $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --                      
pi@raspberrypi ~ $

If you also see address 0x51, your SFP supports DOM(Digital Optical Monitoring).

4) Read the EEPROM details from address 0x50 using i2cdump.


pi@raspberrypi ~ $ i2cdump -y 1 0x50
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 03 04 07 00 00 00 01 00 00 00 00 01 0d 00 00 00    ???...?....??...
10: 37 1b 00 00 52 61 73 70 62 65 72 72 79 20 50 69    7?..Raspberry Pi
20: 20 20 20 20 00 00 30 d3 51 46 42 52 2d 35 37 36        ..0?QFBR-576
30: 36 4c 50 20 20 20 20 20 20 20 20 20 03 52 00 c6    6LP         ?R.?
40: 00 1a 00 00 31 32 33 34 35 36 37 38 39 4a 4b 20    .?..123456789JK
50: 20 20 20 20 30 35 30 33 31 30 20 20 00 00 00 95        050310  ...?
60: 00 00 02 ab 89 12 ea 3e 00 04 1c 5f 6a 0a de 10    ..?????>.??_j???
70: 74 11 3b 00 00 00 00 00 00 00 00 00 ef 19 f8 08    t?;.........????
80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
pi@raspberrypi ~ $

To understand the details of the EEPROM refer to the latest SFP MSA.
ftp://ftp.seagate.com/sff/SFF-8472.PDF
Note the addresses in the SFP MSA are in decimal while the addresses above in the dump are in hex.

5) How to read/write to the EEPROM on your SFP or SFP+

The easiest way I have come across for the Pi is using a library called wiringPi by Gordon Henderson. Check out  http://wiringpi.com/ for details.

To read all the bytes on the EEPROM and store them in an array called A50.

int xio;
int fd1;
unsigned char A50[128];
printf ("Read SFP EEPROM\n");

        xio = wiringPiI2CSetup (0x50);
        if (xio < 0){
                fprintf (stderr, "xio: Unable to initialise I2C: %s\n", strerror (errno));
                return 1;
        }
        /*Read in the first 128 bytes 0 to 127*/
        for(i=0; i <128; i++){
                fd1 = wiringPiI2CReadReg8 (xio,i);
                A50[i] = fd1;
        }

//print vendor id bytes 20 to 35
        memcpy(&vendor, &A50[20],16);
        vendor[16] = '\0';
        printf("\nVendor = %s",vendor);

You can write a byte or an array containing your bytes using a loop for  wiringPiI2CWriteReg8.
unsigned char mybytes[] = {0xff};
   wiringPiI2CWriteReg8(xio, counter, mybytes[0]);

To check to see if your checksum agrees with the value on the EEPROM.
        sum = 0;
        for (counter = 0; counter <0x3f; counter++)
        sum = (A50[counter] + sum);
        sum = sum & 0xff;
        cc_base = A50[0x3f]; //sum stored in address 63.
        printf("value of cc_base = %x and sum= %x\n",cc_base,sum);
        printf ("\n");

To read the transceiver wavelength:
int wave; //3 bytes. 60 high order, 61 low order. 62 is the mantissa             
        wave = ((int) A50[60]<<8) | ((int) A50[61]);
        printf("\nWavelength = %d.%d",wave,A50[62]);


The dump of the EEPROM from the SFP above has a vendor id of Raspberry Pi. It's easy enough to read in and print out more values.
Transceiver is 1000Base SX
Wavelength = 850.0
Vendor = Raspberry Pi  
Serial = 123456789JK
cc_base = c6 and cc_ext = 95

The SFP EEPROM above is Cisco compliant without using service unsupported. To make an SFP Cisco compliant you need to make the two checksums valid(cc_base and cc_ext), you also need to compute the vendor specific bytes 60 to 0x7f. 
Details can be found here: http://forum.nag.ru/

My code can be found here: https://github.com/sonicepk/sfppi