#include "types.h" #include "i2c.h" #include "eeprom.h" #include "board.h" #include "syscon.h" /* * The SFP section is placed somewhere inside FMC EEPROM and it really does not * matter where (can be a binary data inside the Board Info section but can be * placed also outside the FMC standardized EEPROM structure. The only requirement * is that it starts with 0xdeadbeef pattern. The structure of SFP section is: * * ---------------------------------------------- * | cal_ph_trans (4B) | SFP count (1B) | * -------------------------------------------------------------------------------------------- * | SFP(1) part number (16B) | alpha (4B) | deltaTx (4B) | deltaRx (4B) | chksum(1B) | * -------------------------------------------------------------------------------------------- * | SFP(2) part number (16B) | alpha (4B) | deltaTx (4B) | deltaRx (4B) | chksum(1B) | * -------------------------------------------------------------------------------------------- * | (....) | (....) | (....) | (....) | (...) | * -------------------------------------------------------------------------------------------- * | SFP(count) part number (16B) | alpha (4B) | deltaTx (4B) | deltaRx (4B) | chksum(1B) | * -------------------------------------------------------------------------------------------- * * Fields description: * cal_ph_trans - t2/t4 phase transition value (got from measure_t24p() ), contains * _valid_ bit (MSB) and 31 bits of cal_phase_transition value * count - how many SFPs are described in the list (binary) * SFP(n) part number - SFP PN as read from SFP's EEPROM (e.g. AXGE-1254-0531) * (16 ascii chars) * checksum - low order 8 bits of the sum of all bytes for the SFP(PN,alpha,dTx,dRx) * */ /* * The init script area consist of 2-byte size field and a set of shell commands * separated with '\n' character. * * ------------------- * | bytes used (2B) | * ------------------------------------------------ * | shell commands separated with '\n'..... | * | | * | | * ------------------------------------------------ */ uint8_t has_eeprom = 0; uint8_t eeprom_present(uint8_t i2cif, uint8_t i2c_addr) { has_eeprom = 1; if( !mi2c_devprobe(i2cif, i2c_addr) ) if( !mi2c_devprobe(i2cif, i2c_addr) ) has_eeprom = 0; return 0; } int eeprom_read(uint8_t i2cif, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size) { int i; unsigned char c; if(!has_eeprom) return -1; mi2c_start(i2cif); if(mi2c_put_byte(i2cif, i2c_addr << 1) < 0) { mi2c_stop(i2cif); return -1; } mi2c_put_byte(i2cif, (offset>>8) & 0xff); mi2c_put_byte(i2cif, offset & 0xff); mi2c_repeat_start(i2cif); mi2c_put_byte(i2cif, (i2c_addr << 1) | 1); for(i=0; i> 8) & 0xff); mi2c_put_byte(i2cif, offset & 0xff); mi2c_put_byte(i2cif, *buf++); offset++; mi2c_stop(i2cif); do /* wait until the chip becomes ready */ { mi2c_start(i2cif); busy = mi2c_put_byte(i2cif, i2c_addr << 1); mi2c_stop(i2cif); } while(busy); } return size; } int32_t eeprom_sfpdb_erase(uint8_t i2cif, uint8_t i2c_addr) { uint8_t sfpcount = 0; //just a dummy function that writes '0' to sfp count field of the SFP DB if( eeprom_write(i2cif, i2c_addr, EE_BASE_SFP, &sfpcount, sizeof(sfpcount)) != sizeof(sfpcount)) return EE_RET_I2CERR; else return sfpcount; } int32_t eeprom_get_sfp(uint8_t i2cif, uint8_t i2c_addr, struct s_sfpinfo* sfp, uint8_t add, uint8_t pos) { static uint8_t sfpcount = 0; uint8_t i, chksum=0; uint8_t* ptr; if( pos>=SFPS_MAX ) return EE_RET_POSERR; //position in database outside the range //read how many SFPs are in the database, but only in the first call (pos==0) if( !pos && eeprom_read(i2cif, i2c_addr, EE_BASE_SFP, &sfpcount, sizeof(sfpcount)) != sizeof(sfpcount) ) return EE_RET_I2CERR; if( add && sfpcount==SFPS_MAX ) //no more space in the database to add new SFPs return EE_RET_DBFULL; else if( !pos && !add && sfpcount==0 ) //there are no SFPs in the database to read return sfpcount; if(!add) { if( eeprom_read(i2cif, i2c_addr, EE_BASE_SFP + sizeof(sfpcount) + pos*sizeof(struct s_sfpinfo), sfp, sizeof(struct s_sfpinfo)) != sizeof(struct s_sfpinfo) ) return EE_RET_I2CERR; ptr = (uint8_t*)sfp; for(i=0; ichksum) EE_RET_CORRPT; } else { /*count checksum*/ ptr = (uint8_t*)sfp; for(i=0; ichksum = chksum; /*add SFP at the end of DB*/ eeprom_write(i2cif, i2c_addr, EE_BASE_SFP+sizeof(sfpcount) + sfpcount*sizeof(struct s_sfpinfo), sfp, sizeof(struct s_sfpinfo)); sfpcount++; eeprom_write(i2cif, i2c_addr, EE_BASE_SFP, &sfpcount, sizeof(sfpcount)); } return sfpcount; } int8_t eeprom_match_sfp(uint8_t i2cif, uint8_t i2c_addr, struct s_sfpinfo* sfp) { uint8_t sfpcount = 1; int8_t i, temp; struct s_sfpinfo dbsfp; for(i=0; ipn, 16) ) { sfp->dTx = dbsfp.dTx; sfp->dRx = dbsfp.dRx; sfp->alpha = dbsfp.alpha; return 1; } } return 0; } int8_t eeprom_phtrans(uint8_t i2cif, uint8_t i2c_addr, uint32_t *val, uint8_t write) { if(write) { *val |= (1<<31); if( eeprom_write(i2cif, i2c_addr, EE_BASE_CAL, val, sizeof(val) ) != sizeof(val) ) return EE_RET_I2CERR; else return 1; } else { if( eeprom_read(i2cif, i2c_addr, EE_BASE_CAL, val, sizeof(val) ) != sizeof(val) ) return EE_RET_I2CERR; if( !(*val&(1<<31)) ) return 0; *val &= 0x7fffffff; //return ph_trans value without validity bit return 1; } } int8_t eeprom_init_erase(uint8_t i2cif, uint8_t i2c_addr) { uint16_t used = 0; if( eeprom_write(i2cif, i2c_addr, EE_BASE_INIT, &used, sizeof(used)) != sizeof(used)) return EE_RET_I2CERR; else return used; } int8_t eeprom_init_purge(uint8_t i2cif, uint8_t i2c_addr) { uint16_t used = 0xffff, i; uint16_t pattern = 0xff; if( eeprom_read(i2cif, i2c_addr, EE_BASE_INIT, &used, sizeof(used)) != sizeof(used) ) return EE_RET_I2CERR; if(used==0xffff) used=0; for(i=0; i= used) return 0; do { if(ptr-sizeof(used) > bufsize) return EE_RET_CORRPT; if( eeprom_read(i2cif, i2c_addr, EE_BASE_INIT+(ptr++), &buf[i], sizeof(char)) != sizeof(char) ) return EE_RET_I2CERR; }while(buf[i++]!='\n'); return i; }