From: wdenk Date: Sun, 10 Mar 2002 22:52:58 +0000 (+0000) Subject: * Patch by Erik Theisen, 9 Mar 2002: X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=5d5ac3c84b001e52aedf86082d0c5387282915fc;p=users%2Frw%2Fppcboot.git * Patch by Erik Theisen, 9 Mar 2002: VPD patch for W7O boards --- diff --git a/board/w7o/cmd_vpd.c b/board/w7o/cmd_vpd.c new file mode 100644 index 0000000..f8b49c1 --- /dev/null +++ b/board/w7o/cmd_vpd.c @@ -0,0 +1,60 @@ +/* + * (C) Copyright 2001 + * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#if (CONFIG_COMMANDS & CFG_CMD_BSP) + +#include "vpd.h" +#include "cmd_bsp.h" + +/* ====================================================================== + * Interpreter command to retrieve board specific Vital Product Data, "VPD" + * ====================================================================== + */ +int do_vpd( cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[] ) +{ + VPD vpd; /* Board specific data struct */ + uchar dev_addr = CFG_DEF_EEPROM_ADDR; + + /* Validate usage */ + if (argc > 2) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* Passed in EEPROM address */ + if (argc == 2) + dev_addr = (uchar)simple_strtoul(argv[1], NULL, 16); + + /* Read VPD and output it */ + if (!vpd_get_data(dev_addr, &vpd)) { + vpd_print(&vpd); + return 0; + } + + return 1; +} + +#endif /* (CONFIG_COMMANDS & CFG_CMD_BSP) */ diff --git a/board/w7o/vpd.c b/board/w7o/vpd.c new file mode 100644 index 0000000..598360a --- /dev/null +++ b/board/w7o/vpd.c @@ -0,0 +1,408 @@ +/* + * (C) Copyright 2001 + * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#if defined(VXWORKS) +# include +# include +# define CFG_DEF_EEPROM_ADDR 0xa0 +extern char iicReadByte( char, char ); +extern ulong_t crc32( unsigned char *, unsigned long ); +#else +#include +#endif + +#include "vpd.h" + +/* + * vpd_reader() - reads VPD data from I2C EEPROMS. + * returns pointer to buffer or NULL. + */ +static unsigned char * +vpd_reader(unsigned char *buf, unsigned dev_addr, unsigned off, unsigned count) +{ + unsigned offset = off; /* Calculated offset */ + + /* + * The main board EEPROM contains + * SDRAM SPD in the first 128 bytes, + * so skew the offset. + */ + if (dev_addr == CFG_DEF_EEPROM_ADDR) + offset += SDRAM_SPD_DATA_SIZE; + + /* Try to read the I2C EEPROM */ +#if defined(VXWORKS) + { + int i; + for( i = 0; i < count; ++i ) { + buf[ i ] = iicReadByte( dev_addr, offset+i ); + } + } +#else + if (eeprom_read(dev_addr, offset, buf, count)) { + printf("Failed to read %d bytes from VPD EEPROM 0x%x @ 0x%x\n", + count, dev_addr, offset); + return NULL; + } +#endif + + return buf; +} /* vpd_reader() */ + + +/* + * vpd_get_packet() - returns next VPD packet or NULL. + */ +static vpd_packet_t *vpd_get_packet(vpd_packet_t *vpd_packet) +{ + vpd_packet_t *packet = vpd_packet; + + if (packet != NULL) { + if (packet->identifier == VPD_PID_TERM) + return NULL; + else + packet = (vpd_packet_t *)((char *)packet + packet->size + 2); + } + + return packet; +} /* vpd_get_packet() */ + + +/* + * vpd_find_packet() - Locates and returns the specified + * VPD packet or NULL on error. + */ +static vpd_packet_t *vpd_find_packet(vpd_t *vpd, unsigned char ident) +{ + vpd_packet_t *packet = (vpd_packet_t *)&vpd->packets; + + /* Guaranteed illegal */ + if (ident == VPD_PID_GI) + return NULL; + + /* Scan tuples looking for a match */ + while ((packet->identifier != ident) && + (packet->identifier != VPD_PID_TERM)) + packet = vpd_get_packet(packet); + + /* Did we find it? */ + if ((packet->identifier) && (packet->identifier != ident)) + return NULL; + return packet; +} + + +/* + * vpd_is_valid() - Validates contents of VPD data + * in I2C EEPROM. Returns 1 for + * success or 0 for failure. + */ +static int vpd_is_valid(unsigned dev_addr, unsigned char *buf) +{ + unsigned num_bytes; + vpd_packet_t *packet; + vpd_t *vpd = (vpd_t *)buf; + unsigned short stored_crc16, calc_crc16 = 0xffff; + + /* Check Eyecatcher */ + if (strncmp(vpd->header.eyecatcher, VPD_EYECATCHER, VPD_EYE_SIZE) != 0) { + unsigned offset = 0; + if (dev_addr == CFG_DEF_EEPROM_ADDR) + offset += SDRAM_SPD_DATA_SIZE; + printf("Error: VPD EEPROM 0x%x corrupt @ 0x%x\n", dev_addr, offset); + + return 0; + } + + /* Check Length */ + if (vpd->header.size> VPD_MAX_EEPROM_SIZE) { + printf("Error: VPD EEPROM 0x%x contains bad size 0x%x\n", + dev_addr, vpd->header.size); + return 0; + } + + /* Now find the termination packet */ + if ((packet = vpd_find_packet(vpd, VPD_PID_TERM)) == NULL) { + printf("Error: VPD EEPROM 0x%x missing termination packet\n", + dev_addr); + return 0; + } + + /* Calculate data size */ + num_bytes = (unsigned long)((unsigned char *)packet - + (unsigned char *)vpd + sizeof(vpd_packet_t)); + + /* Find stored CRC and clear it */ + if ((packet = vpd_find_packet(vpd, VPD_PID_CRC)) == NULL) { + printf("Error: VPD EEPROM 0x%x missing CRC\n", dev_addr); + return 0; + } + stored_crc16 = *((ushort *)packet->data); + *(ushort *)packet->data = 0; + + /* OK, lets calculate the CRC and check it */ +#if defined(VXWORKS) + calc_crc16 = (0xffff & crc32(buf, num_bytes)); +#else + calc_crc16 = (0xffff & crc32(0, buf, num_bytes)); +#endif + *(ushort *)packet->data = stored_crc16; /* Now restore the CRC */ + if (stored_crc16 != calc_crc16) { + printf("Error: VPD EEPROM 0x%x has bad CRC 0x%x\n", + dev_addr, stored_crc16); + return 0; + } + + return 1; +} /* vpd_is_valid() */ + + +/* + * size_ok() - Check to see if packet size matches + * size of data we want. Returns 1 for + * good match or 0 for failure. + */ +static int size_ok(vpd_packet_t *packet, unsigned long size) +{ + if (packet->size != size) { + printf("VPD Packet 0x%x corrupt.\n", packet->identifier); + return 0; + } + return 1; +} /* size_ok() */ + + +/* + * strlen_ok() - Check to see if packet size matches + * strlen of the string we want to populate. + * Returns 1 for valid length or 0 for failure. + */ +static int strlen_ok(vpd_packet_t *packet, unsigned long length) +{ + if (packet->size >= length) { + printf("VPD Packet 0x%x corrupt.\n", packet->identifier); + return 0; + } + return 1; +} /* strlen_ok() */ + + +/* + * get_vpd_data() - populates the passed VPD structure 'vpdInfo' + * with data obtained from the specified + * I2C EEPROM 'dev_addr'. Returns 0 for + * success or 1 for failure. + */ +int vpd_get_data(unsigned char dev_addr, VPD *vpdInfo) +{ + unsigned char buf[VPD_EEPROM_SIZE]; + vpd_t *vpd = (vpd_t *)buf; + vpd_packet_t *packet; + + if (vpdInfo == NULL) + return 1; + + /* + * Fill vpdInfo with 0s to blank out + * unused fields, fill vpdInfo->ethAddrs + * with all 0xffs so that other's code can + * determine how many real Ethernet addresses + * there are. OUIs starting with 0xff are + * broadcast addresses, and would never be + * permantely stored. + */ + memset((void *)vpdInfo, 0, sizeof(VPD)); + memset((void *)&vpdInfo->ethAddrs, 0xff, sizeof(vpdInfo->ethAddrs)); + vpdInfo->_devAddr = dev_addr; + + /* Read the minimum size first */ + if (vpd_reader(buf, dev_addr, 0, VPD_EEPROM_SIZE) == NULL) { + return 1; + } + + /* Check validity of VPD data */ + if (!vpd_is_valid(dev_addr, buf)) { + printf("VPD Data is INVALID!\n"); + return 1; + } + + /* + * Walk all the packets and populate + * the VPD info structure. + */ + packet = (vpd_packet_t *)&vpd->packets; + do { + switch (packet->identifier) { + case VPD_PID_GI: + printf("Error: Illegal VPD value\n"); + break; + case VPD_PID_PID: + if (strlen_ok(packet, MAX_PROD_ID)) { + strncpy(vpdInfo->productId, + packet->data, packet->size); + } + break; + case VPD_PID_REV: + if (size_ok(packet, sizeof(char))) + vpdInfo->revisionId = *packet->data; + break; + case VPD_PID_SN: + if (size_ok(packet, sizeof(unsigned long))) { + vpdInfo->serialNum = + *(unsigned long *)packet->data; + } + break; + case VPD_PID_MANID: + if (size_ok(packet, sizeof(unsigned char))) + vpdInfo->manuID = *packet->data; + break; + case VPD_PID_PCO: + if (size_ok(packet, sizeof(unsigned long))) { + vpdInfo->configOpt = + *(unsigned long *)packet->data; + } + break; + case VPD_PID_SYSCLK: + if (size_ok(packet, sizeof(unsigned long))) + vpdInfo->sysClk = *(unsigned long *)packet->data; + break; + case VPD_PID_SERCLK: + if (size_ok(packet, sizeof(unsigned long))) + vpdInfo->serClk = *(unsigned long *)packet->data; + break; + case VPD_PID_FLASH: + if (size_ok(packet, 9)) { /* XXX - hardcoded, + padding in struct */ + memcpy(&vpdInfo->flashCfg, packet->data, 9); + } + break; + case VPD_PID_ETHADDR: + memcpy(vpdInfo->ethAddrs, packet->data, packet->size); + break; + case VPD_PID_POTS: + if (size_ok(packet, sizeof(char))) + vpdInfo->numPOTS = (unsigned)*packet->data; + break; + case VPD_PID_DS1: + if (size_ok(packet, sizeof(char))) + vpdInfo->numDS1 = (unsigned)*packet->data; + case VPD_PID_GAL: + case VPD_PID_CRC: + case VPD_PID_TERM: + break; + default: + printf("Warning: Found unknown VPD packet ID 0x%x\n", + packet->identifier); + break; + } + } while ((packet = vpd_get_packet(packet))); + + return 0; +} /* end get_vpd_data() */ + + +/* + * vpd_init() - Initialize default VPD environment + */ +int vpd_init(unsigned char dev_addr) +{ + return (0); +} /* vpd_init() */ + + +/* + * vpd_print() - Pretty print the VPD data. + */ +void vpd_print(VPD *vpdInfo) +{ + const char *const sp = ""; + const char *const sfmt = "%4s%-20s: \"%s\"\n"; + const char *const cfmt = "%4s%-20s: '%c'\n"; + const char *const dfmt = "%4s%-20s: %ld\n"; + const char *const hfmt = "%4s%-20s: %08lX\n"; + const char *const dsfmt = "%4s%-20s: %d\n"; + const char *const hsfmt = "%4s%-20s: %04X\n"; + const char *const dhfmt = "%4s%-20s: %ld (%lX)\n"; + + printf("VPD read from I2C device: %02X\n", vpdInfo->_devAddr); + + if (vpdInfo->productId[0]) + printf(sfmt, sp, "Product ID", vpdInfo->productId); + else + printf(sfmt, sp, "Product ID", "UNKNOWN"); + + if (vpdInfo->revisionId) + printf(cfmt, sp, "Revision ID", vpdInfo->revisionId); + + if (vpdInfo->serialNum) + printf(dfmt, sp, "Serial Number", vpdInfo->serialNum); + + if (vpdInfo->manuID) + printf(dfmt, sp, "Manufacture ID", (long)vpdInfo->manuID); + + if (vpdInfo->configOpt) + printf(hfmt, sp, "Configuration", vpdInfo->configOpt); + + if (vpdInfo->sysClk) + printf(dhfmt, sp, "System Clock", vpdInfo->sysClk, vpdInfo->sysClk); + + if (vpdInfo->serClk) + printf(dhfmt, sp, "Serial Clock", vpdInfo->serClk, vpdInfo->serClk); + + if (vpdInfo->numPOTS) + printf(dfmt, sp, "Number of POTS lines", vpdInfo->numPOTS); + + if (vpdInfo->numDS1) + printf(dfmt, sp, "Number of DS1s", vpdInfo->numDS1); + + /* Print Ethernet Addresses */ + if (vpdInfo->ethAddrs[0][0] != 0xff) { + int i, j; + printf("%4sEtherNet Address(es): ", sp); + for (i = 0; i < MAX_ETH_ADDRS; i++) { + if (vpdInfo->ethAddrs[i][0] != 0xff) { + for (j = 0; j < 6; j++) { + printf("%02X", vpdInfo->ethAddrs[i][j]); + if (((j + 1) % 6) != 0) + printf(":"); + else + printf(" "); + } + if (((i + 1) % 3) == 0) printf("\n%24s: ", sp); + } + } + printf("\n"); + } + + if (vpdInfo->flashCfg.mfg && vpdInfo->flashCfg.dev) { + printf("Main Flash Configuration:\n"); + printf(hsfmt, sp, "Manufacture ID", vpdInfo->flashCfg.mfg); + printf(hsfmt, sp, "Device ID", vpdInfo->flashCfg.dev); + printf(dsfmt, sp, "Device Width", vpdInfo->flashCfg.devWidth); + printf(dsfmt, sp, "Num. Devices", vpdInfo->flashCfg.numDevs); + printf(dsfmt, sp, "Num. Columns", vpdInfo->flashCfg.numCols); + printf(dsfmt, sp, "Column Width", vpdInfo->flashCfg.colWidth); + printf(dsfmt, sp, "WE Data Width", vpdInfo->flashCfg.weDataWidth); + } +} /* vpd_print() */ + diff --git a/board/w7o/vpd.h b/board/w7o/vpd.h new file mode 100644 index 0000000..6f7d10a --- /dev/null +++ b/board/w7o/vpd.h @@ -0,0 +1,135 @@ +/* + * (C) Copyright 2001 + * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _VPD_H_ +#define _VPD_H_ + +/* + * Main Flash Configuration. + */ +typedef struct flashCfg_s { + unsigned short mfg; /* Manufacture ID */ + unsigned short dev; /* Device ID */ + unsigned char devWidth; /* Device Width */ + unsigned char numDevs; /* Number of devices */ + unsigned char numCols; /* Number of columns */ + unsigned char colWidth; /* Width of a column */ + unsigned char weDataWidth; /* Write/Erase Data Width */ +} flashCfg_t; + +/* + * Vital Product Data - VPD + */ +#define MAX_PROD_ID 15 +#define MAX_ETH_ADDRS 10 +typedef unsigned char EthAddr[6]; +typedef struct vpd { + unsigned char _devAddr; /* Device address during read */ + char productId[MAX_PROD_ID]; /* Product ID */ + char revisionId; /* Revision ID as a char */ + unsigned long serialNum; /* Serial number */ + unsigned char manuID; /* Manufact ID - byte int */ + unsigned long configOpt; /* Config Option - bit field */ + unsigned long sysClk; /* System clock in Hertz */ + unsigned long serClk; /* Ext. clock in Hertz */ + flashCfg_t flashCfg; /* Flash configuration */ + unsigned long numPOTS; /* Number of POTS lines */ + unsigned long numDS1; /* Number of DS1 circuits */ + EthAddr ethAddrs[MAX_ETH_ADDRS]; /* Ethernet MAC, 1st = craft */ +} VPD; + + +#define VPD_MAX_EEPROM_SIZE 512 /* Max size VPD EEPROM */ +#define SDRAM_SPD_DATA_SIZE 128 /* Size SPD in VPD EEPROM */ + +/* + * PIDs - Packet Identifiers + */ +#define VPD_PID_GI 0x0 /* Guaranted Illegal */ +#define VPD_PID_PID 0x1 /* Product Identifier */ +#define VPD_PID_REV 0x2 /* Product Revision */ +#define VPD_PID_SN 0x3 /* Serial Number */ +#define VPD_PID_MANID 0x4 /* Manufacture ID */ +#define VPD_PID_PCO 0x5 /* Product configuration */ +#define VPD_PID_SYSCLK 0x6 /* System Clock */ +#define VPD_PID_SERCLK 0x7 /* Ser. Clk. Speed in Hertz */ +#define VPD_PID_CRC 0x8 /* VPD CRC */ +#define VPD_PID_FLASH 0x9 /* Flash Configuration */ +#define VPD_PID_ETHADDR 0xA /* Ethernet Address(es) */ +#define VPD_PID_GAL 0xB /* Galileo Switch Config */ +#define VPD_PID_POTS 0xC /* Number of POTS Lines */ +#define VPD_PID_DS1 0xD /* Number of DS1s */ +#define VPD_PID_TERM 0xFF /* Termination packet */ + +/* + * VPD - Eyecatcher/Magic + */ +#define VPD_EYECATCHER "W7O" +#define VPD_EYE_SIZE 3 +typedef struct vpd_header { + unsigned char eyecatcher[VPD_EYE_SIZE]; /* eyecatcher - "W7O" */ + unsigned short size __attribute__((packed)); /* size of EEPROM */ +} vpd_header_t; + + +#define VPD_DATA_SIZE (VPD_MAX_EEPROM_SIZE - SDRAM_SPD_DATA_SIZE - \ + sizeof(vpd_header_t)) +typedef struct vpd_s { + vpd_header_t header; + unsigned char packets[VPD_DATA_SIZE]; +} vpd_t; + +typedef struct vpd_packet { + unsigned char identifier; + unsigned char size; + unsigned char data[1]; +} vpd_packet_t; + +/* + * VPD configOpt bit mask + */ +#define VPD_HAS_BBRAM 0x1 /* Battery backed SRAM */ +#define VPD_HAS_RTC 0x2 /* Battery backed RTC */ +#define VPD_HAS_EXT_SER_CLK 0x4 /* External serial clock */ +#define VPD_HAS_SER_TRANS_1 0x8 /* COM1 transceiver */ +#define VPD_HAS_SER_TRANS_2 0x10 /* COM2 transceiver */ +#define VPD_HAS_CRAFT_PHY 0x20 /* CRAFT Ethernet */ +#define VPD_HAS_DTT_1 0x40 /* I2C Digital therm. #1 */ +#define VPD_HAS_DTT_2 0x80 /* I2C Digital therm. #2 */ +#define VPD_HAS_1000_UP_LASER 0x100 /* GMM - 1000Mbit Uplink */ +#define VPD_HAS_70KM_UP_LASER 0x200 /* CMM - 70KM Uplink laser */ +#define VPD_HAS_2_UPLINKS 0x400 /* CMM - 2 uplink lasers */ +#define VPD_HAS_FPGA 0x800 /* Has 1 or more FPGAs */ +#define VPD_HAS_DFA 0x1000 /* CLM - Has 2 Fiber Inter. */ +#define VPD_HAS_GAL_SWITCH 0x2000 /* GMM - Has a Gal switch */ +#define VPD_HAS_POTS_LINES 0x4000 /* GMM - Has POTS lines */ +#define VPD_HAS_DS1_CHANNELS 0x8000 /* GMM - Has DS1 channels */ +#define VPD_HAS_CABLE_RETURN 0x10000 /* GBM/GBR - Cable ret. path */ + +#define VPD_EEPROM_SIZE (256 - SDRAM_SPD_DATA_SIZE) /* Size EEPROM */ + +extern int vpd_get_data(unsigned char dev_addr, VPD *vpd); +extern void vpd_print(VPD *vpdInfo); + +#endif /* _VPD_H_ */ +