diff options
Diffstat (limited to 'board/siemens/common/factoryset.c')
-rw-r--r-- | board/siemens/common/factoryset.c | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/board/siemens/common/factoryset.c b/board/siemens/common/factoryset.c new file mode 100644 index 00000000000..eda9141c546 --- /dev/null +++ b/board/siemens/common/factoryset.c @@ -0,0 +1,284 @@ +/* + * + * Read FactorySet information from EEPROM into global structure. + * (C) Copyright 2013 Siemens Schweiz AG + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#if !defined(CONFIG_SPL_BUILD) + +#include <common.h> +#include <i2c.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/sys_proto.h> +#include <asm/unaligned.h> +#include <net.h> +#include <usbdescriptors.h> +#include "factoryset.h" + +#define EEPR_PG_SZ 0x80 +#define EEPROM_FATORYSET_OFFSET 0x400 +#define OFF_PG EEPROM_FATORYSET_OFFSET/EEPR_PG_SZ + +/* Global variable that contains necessary information from FactorySet */ +struct factorysetcontainer factory_dat; + +#define fact_get_char(i) *((char *)&eeprom_buf[i]) + +static int fact_match(unsigned char *eeprom_buf, uchar *s1, int i2) +{ + if (s1 == NULL) + return -1; + + while (*s1 == fact_get_char(i2++)) + if (*s1++ == '=') + return i2; + + if (*s1 == '\0' && fact_get_char(i2-1) == '=') + return i2; + + return -1; +} + +static int get_factory_val(unsigned char *eeprom_buf, int size, uchar *name, + uchar *buf, int len) +{ + int i, nxt = 0; + + for (i = 0; fact_get_char(i) != '\0'; i = nxt + 1) { + int val, n; + + for (nxt = i; fact_get_char(nxt) != '\0'; ++nxt) { + if (nxt >= size) + return -1; + } + + val = fact_match(eeprom_buf, (uchar *)name, i); + if (val < 0) + continue; + + /* found; copy out */ + for (n = 0; n < len; ++n, ++buf) { + *buf = fact_get_char(val++); + if (*buf == '\0') + return n; + } + + if (n) + *--buf = '\0'; + + printf("env_buf [%d bytes] too small for value of \"%s\"\n", + len, name); + + return n; + } + return -1; +} + +static +int get_factory_record_val(unsigned char *eeprom_buf, int size, uchar *record, + uchar *name, uchar *buf, int len) +{ + int ret = -1; + int i, nxt = 0; + int c; + unsigned char end = 0xff; + + for (i = 0; fact_get_char(i) != end; i = nxt) { + nxt = i + 1; + if (fact_get_char(i) == '>') { + int pos; + int endpos; + int z; + + c = strncmp((char *)&eeprom_buf[i + 1], (char *)record, + strlen((char *)record)); + if (c == 0) { + /* record found */ + pos = i + strlen((char *)record) + 2; + nxt = pos; + /* search for "<" */ + c = -1; + for (z = pos; fact_get_char(z) != end; z++) { + if ((fact_get_char(z) == '<') || + (fact_get_char(z) == '>')) { + endpos = z; + nxt = endpos; + c = 0; + break; + } + } + } + if (c == 0) { + /* end found -> call get_factory_val */ + eeprom_buf[endpos] = end; + ret = get_factory_val(&eeprom_buf[pos], + size - pos, name, buf, len); + /* fix buffer */ + eeprom_buf[endpos] = '<'; + debug("%s: %s.%s = %s\n", + __func__, record, name, buf); + return ret; + } + } + } + return ret; +} + +int factoryset_read_eeprom(int i2c_addr) +{ + int i, pages = 0, size = 0; + unsigned char eeprom_buf[0x3c00], hdr[4], buf[MAX_STRING_LENGTH]; + unsigned char *cp, *cp1; + +#if defined(CONFIG_DFU_FUNCTION) + factory_dat.usb_vendor_id = CONFIG_G_DNL_VENDOR_NUM; + factory_dat.usb_product_id = CONFIG_G_DNL_PRODUCT_NUM; +#endif + if (i2c_probe(i2c_addr)) + goto err; + + if (i2c_read(i2c_addr, EEPROM_FATORYSET_OFFSET, 2, hdr, sizeof(hdr))) + goto err; + + if ((hdr[0] != 0x99) || (hdr[1] != 0x80)) { + printf("FactorySet is not right in eeprom.\n"); + return 1; + } + + /* get FactorySet size */ + size = (hdr[2] << 8) + hdr[3] + sizeof(hdr); + if (size > 0x3bfa) + size = 0x3bfa; + + pages = size / EEPR_PG_SZ; + + /* + * read the eeprom using i2c + * I can not read entire eeprom in once, so separate into several + * times. Furthermore, fetch eeprom take longer time, so we fetch + * data after every time we got a record from eeprom + */ + debug("Read eeprom page :\n"); + for (i = 0; i < pages; i++) + if (i2c_read(i2c_addr, (OFF_PG + i) * EEPR_PG_SZ, 2, + eeprom_buf + (i * EEPR_PG_SZ), EEPR_PG_SZ)) + goto err; + + if (size % EEPR_PG_SZ) + if (i2c_read(i2c_addr, (OFF_PG + pages) * EEPR_PG_SZ, 2, + eeprom_buf + (pages * EEPR_PG_SZ), + (size % EEPR_PG_SZ))) + goto err; + + /* we do below just for eeprom align */ + for (i = 0; i < size; i++) + if (eeprom_buf[i] == '\n') + eeprom_buf[i] = 0; + + /* skip header */ + size -= sizeof(hdr); + cp = (uchar *)eeprom_buf + sizeof(hdr); + + /* get mac address */ + get_factory_record_val(cp, size, (uchar *)"ETH1", (uchar *)"mac", + buf, MAX_STRING_LENGTH); + cp1 = buf; + for (i = 0; i < 6; i++) { + factory_dat.mac[i] = simple_strtoul((char *)cp1, NULL, 16); + cp1 += 3; + } + +#if defined(CONFIG_DFU_FUNCTION) + /* read vid and pid for dfu mode */ + if (0 <= get_factory_record_val(cp, size, (uchar *)"USBD1", + (uchar *)"vid", buf, + MAX_STRING_LENGTH)) { + factory_dat.usb_vendor_id = simple_strtoul((char *)buf, + NULL, 16); + } + + if (0 <= get_factory_record_val(cp, size, (uchar *)"USBD1", + (uchar *)"pid", buf, + MAX_STRING_LENGTH)) { + factory_dat.usb_product_id = simple_strtoul((char *)buf, + NULL, 16); + } + printf("DFU USB: VID = 0x%4x, PID = 0x%4x\n", factory_dat.usb_vendor_id, + factory_dat.usb_product_id); +#endif + if (0 <= get_factory_record_val(cp, size, (uchar *)"DEV", + (uchar *)"id", buf, + MAX_STRING_LENGTH)) { + if (strncmp((const char *)buf, "PXM50", 5) == 0) + factory_dat.pxm50 = 1; + else + factory_dat.pxm50 = 0; + } + debug("PXM50: %d\n", factory_dat.pxm50); +#if defined(CONFIG_VIDEO) + if (0 <= get_factory_record_val(cp, size, (uchar *)"DISP1", + (uchar *)"name", factory_dat.disp_name, + MAX_STRING_LENGTH)) { + debug("display name: %s\n", factory_dat.disp_name); + } + +#endif + return 0; + +err: + printf("Could not read the EEPROM; something fundamentally wrong on the I2C bus.\n"); + return 1; +} + +static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE; + +static int factoryset_mac_setenv(void) +{ + uint8_t mac_addr[6]; + + debug("FactorySet: Set mac address\n"); + if (is_valid_ether_addr(factory_dat.mac)) { + memcpy(mac_addr, factory_dat.mac, 6); + } else { + uint32_t mac_hi, mac_lo; + + debug("Warning: FactorySet: <ethaddr> not set. Fallback to E-fuse\n"); + mac_lo = readl(&cdev->macid0l); + mac_hi = readl(&cdev->macid0h); + + mac_addr[0] = mac_hi & 0xFF; + mac_addr[1] = (mac_hi & 0xFF00) >> 8; + mac_addr[2] = (mac_hi & 0xFF0000) >> 16; + mac_addr[3] = (mac_hi & 0xFF000000) >> 24; + mac_addr[4] = mac_lo & 0xFF; + mac_addr[5] = (mac_lo & 0xFF00) >> 8; + if (!is_valid_ether_addr(mac_addr)) { + printf("Warning: ethaddr not set by FactorySet or E-fuse. Set <ethaddr> variable to overcome this.\n"); + return -1; + } + } + + eth_setenv_enetaddr("ethaddr", mac_addr); + return 0; +} + +int factoryset_setenv(void) +{ + int ret = 0; + + if (factoryset_mac_setenv() < 0) + ret = -1; + + return ret; +} + +int g_dnl_bind_fixup(struct usb_device_descriptor *dev) +{ + put_unaligned(factory_dat.usb_vendor_id, &dev->idVendor); + put_unaligned(factory_dat.usb_product_id, &dev->idProduct); + return 0; +} +#endif /* defined(CONFIG_SPL_BUILD) */ |