Files
bouwhuim.nikhef.nl dee2668a61 newest version WRPC
2013-09-10 08:08:59 +00:00

357 lines
9.9 KiB
C

/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Grzegorz Daniluk <grzegorz.daniluk@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#include <string.h>
#include <wrc.h>
#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;
}
static 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 < size - 1; ++i) {
mi2c_get_byte(i2cif, &c, 0);
*buf++ = c;
}
mi2c_get_byte(i2cif, &c, 1);
*buf++ = c;
mi2c_stop(i2cif);
return size;
}
static int eeprom_write(uint8_t i2cif, uint8_t i2c_addr, uint32_t offset,
uint8_t * buf, size_t size)
{
int i, busy;
if (!has_eeprom)
return -1;
for (i = 0; i < size; i++) {
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_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),
(uint8_t*)sfp, sizeof(struct s_sfpinfo))
!= sizeof(struct s_sfpinfo) )
return EE_RET_I2CERR;
ptr = (uint8_t *) sfp;
for (i = 0; i < sizeof(struct s_sfpinfo) - 1; ++i) //'-1' because we do not include chksum in computation
chksum =
(uint8_t) ((uint16_t) chksum + *(ptr++)) & 0xff;
if (chksum != sfp->chksum)
return EE_RET_CORRPT;
} else {
/*count checksum */
ptr = (uint8_t *) sfp;
for (i = 0; i < sizeof(struct s_sfpinfo) - 1; ++i) //'-1' because we do not include chksum in computation
chksum =
(uint8_t) ((uint16_t) chksum + *(ptr++)) & 0xff;
sfp->chksum = chksum;
/*add SFP at the end of DB */
eeprom_write(i2cif, i2c_addr,
EE_BASE_SFP + sizeof(sfpcount)
+ sfpcount * sizeof(struct s_sfpinfo),
(uint8_t *) 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; i < sfpcount; ++i) {
temp = eeprom_get_sfp(WRPC_FMC_I2C, FMC_EEPROM_ADR,
&dbsfp, 0, i);
if (!i) {
sfpcount = temp; //only in first round valid sfpcount is returned from eeprom_get_sfp
if (sfpcount == 0 || sfpcount == 0xFF)
return 0;
else if (sfpcount < 0)
return sfpcount;
}
if (!strncmp(dbsfp.pn, sfp->pn, 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, (uint8_t *) val,
sizeof(*val)) != sizeof(*val))
return EE_RET_I2CERR;
else
return 1;
} else {
if (eeprom_read(i2cif, i2c_addr, EE_BASE_CAL, (uint8_t *) 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, (uint8_t *) & used,
sizeof(used)) != sizeof(used))
return EE_RET_I2CERR;
else
return used;
}
/*
* Appends a new shell command at the end of boot script
*/
int8_t eeprom_init_add(uint8_t i2cif, uint8_t i2c_addr, const char *args[])
{
uint8_t i = 1;
uint8_t separator = ' ';
uint16_t used, readback;
if (eeprom_read(i2cif, i2c_addr, EE_BASE_INIT, (uint8_t *) & used,
sizeof(used)) != sizeof(used))
return EE_RET_I2CERR;
if (used == 0xffff)
used = 0; //this means the memory is blank
while (args[i] != '\0') {
if (eeprom_write(i2cif, i2c_addr, EE_BASE_INIT + sizeof(used)
+ used, (uint8_t *) args[i], strlen(args[i]))
!= strlen(args[i]))
return EE_RET_I2CERR;
used += strlen(args[i]);
if (eeprom_write(i2cif, i2c_addr, EE_BASE_INIT + sizeof(used)
+ used, &separator, sizeof(separator))
!= sizeof(separator))
return EE_RET_I2CERR;
++used;
++i;
}
//the end of the command, replace last separator with '\n'
separator = '\n';
if (eeprom_write(i2cif, i2c_addr, EE_BASE_INIT + sizeof(used) + used-1,
&separator, sizeof(separator)) != sizeof(separator))
return EE_RET_I2CERR;
//and finally update the size of the script
if (eeprom_write(i2cif, i2c_addr, EE_BASE_INIT, (uint8_t *) & used,
sizeof(used)) != sizeof(used))
return EE_RET_I2CERR;
if (eeprom_read(i2cif, i2c_addr, EE_BASE_INIT, (uint8_t *) & readback,
sizeof(readback)) != sizeof(readback))
return EE_RET_I2CERR;
return 0;
}
int32_t eeprom_init_show(uint8_t i2cif, uint8_t i2c_addr)
{
uint16_t used, i;
uint8_t byte;
if (eeprom_read(i2cif, i2c_addr, EE_BASE_INIT, (uint8_t *) & used,
sizeof(used)) != sizeof(used))
return EE_RET_I2CERR;
if (used == 0 || used == 0xffff) {
used = 0; //this means the memory is blank
mprintf("Empty init script...\n");
}
//just read and print to the screen char after char
for (i = 0; i < used; ++i) {
if (eeprom_read(i2cif, i2c_addr, EE_BASE_INIT + sizeof(used)
+ i, &byte, sizeof(byte)) != sizeof(byte))
return EE_RET_I2CERR;
mprintf("%c", byte);
}
return 0;
}
int8_t eeprom_init_readcmd(uint8_t i2cif, uint8_t i2c_addr, uint8_t *buf,
uint8_t bufsize, uint8_t next)
{
static uint16_t ptr;
static uint16_t used = 0;
uint8_t i = 0;
if (next == 0) {
if (eeprom_read(i2cif, i2c_addr, EE_BASE_INIT,
(uint8_t *) & used, sizeof(used))
!= sizeof(used))
return EE_RET_I2CERR;
ptr = sizeof(used);
}
if (ptr - sizeof(used) >= 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;
}