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 000000000..eda9141c5 --- /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) */ |