Home | History | Annotate | Download | only in common
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  *
      4  * Read FactorySet information from EEPROM into global structure.
      5  * (C) Copyright 2013 Siemens Schweiz AG
      6  */
      7 
      8 #if !defined(CONFIG_SPL_BUILD)
      9 
     10 #include <common.h>
     11 #include <environment.h>
     12 #include <i2c.h>
     13 #include <asm/io.h>
     14 #include <asm/arch/cpu.h>
     15 #include <asm/arch/sys_proto.h>
     16 #include <asm/unaligned.h>
     17 #include <net.h>
     18 #include <errno.h>
     19 #include <g_dnl.h>
     20 #include "factoryset.h"
     21 
     22 #define EEPR_PG_SZ		0x80
     23 #define EEPROM_FATORYSET_OFFSET	0x400
     24 #define OFF_PG            EEPROM_FATORYSET_OFFSET/EEPR_PG_SZ
     25 
     26 /* Global variable that contains necessary information from FactorySet */
     27 struct factorysetcontainer factory_dat;
     28 
     29 #define fact_get_char(i) *((char *)&eeprom_buf[i])
     30 
     31 static int fact_match(unsigned char *eeprom_buf, uchar *s1, int i2)
     32 {
     33 	if (s1 == NULL)
     34 		return -1;
     35 
     36 	while (*s1 == fact_get_char(i2++))
     37 		if (*s1++ == '=')
     38 			return i2;
     39 
     40 	if (*s1 == '\0' && fact_get_char(i2-1) == '=')
     41 		return i2;
     42 
     43 	return -1;
     44 }
     45 
     46 static int get_factory_val(unsigned char *eeprom_buf, int size, uchar *name,
     47 			uchar *buf, int len)
     48 {
     49 	int i, nxt = 0;
     50 
     51 	for (i = 0; fact_get_char(i) != '\0'; i = nxt + 1) {
     52 		int val, n;
     53 
     54 		for (nxt = i; fact_get_char(nxt) != '\0'; ++nxt) {
     55 			if (nxt >= size)
     56 				return -1;
     57 		}
     58 
     59 		val = fact_match(eeprom_buf, (uchar *)name, i);
     60 		if (val < 0)
     61 			continue;
     62 
     63 		/* found; copy out */
     64 		for (n = 0; n < len; ++n, ++buf) {
     65 			*buf = fact_get_char(val++);
     66 			if (*buf == '\0')
     67 				return n;
     68 		}
     69 
     70 		if (n)
     71 			*--buf = '\0';
     72 
     73 		printf("env_buf [%d bytes] too small for value of \"%s\"\n",
     74 		       len, name);
     75 
     76 		return n;
     77 	}
     78 	return -1;
     79 }
     80 
     81 static
     82 int get_factory_record_val(unsigned char *eeprom_buf, int size,	uchar *record,
     83 	uchar *name, uchar *buf, int len)
     84 {
     85 	int ret = -1;
     86 	int i, nxt = 0;
     87 	int c;
     88 	unsigned char end = 0xff;
     89 	unsigned char tmp;
     90 
     91 	for (i = 0; fact_get_char(i) != end; i = nxt) {
     92 		nxt = i + 1;
     93 		if (fact_get_char(i) == '>') {
     94 			int pos;
     95 			int endpos;
     96 			int z;
     97 			int level = 0;
     98 
     99 			c = strncmp((char *)&eeprom_buf[i + 1], (char *)record,
    100 				    strlen((char *)record));
    101 			if (c == 0) {
    102 				/* record found */
    103 				pos = i + strlen((char *)record) + 2;
    104 				nxt = pos;
    105 				/* search for "<" */
    106 				c = -1;
    107 				for (z = pos; fact_get_char(z) != end; z++) {
    108 					if (fact_get_char(z) == '<') {
    109 						if (level == 0) {
    110 							endpos = z;
    111 							nxt = endpos;
    112 							c = 0;
    113 							break;
    114 						} else {
    115 							level--;
    116 						}
    117 					}
    118 					if (fact_get_char(z) == '>')
    119 						level++;
    120 				}
    121 			} else {
    122 				continue;
    123 			}
    124 			if (c == 0) {
    125 				/* end found -> call get_factory_val */
    126 				tmp = eeprom_buf[endpos];
    127 				eeprom_buf[endpos] = end;
    128 				ret = get_factory_val(&eeprom_buf[pos],
    129 					endpos - pos, name, buf, len);
    130 				/* fix buffer */
    131 				eeprom_buf[endpos] = tmp;
    132 				debug("%s: %s.%s = %s\n",
    133 				      __func__, record, name, buf);
    134 				return ret;
    135 			}
    136 		}
    137 	}
    138 	return ret;
    139 }
    140 
    141 int factoryset_read_eeprom(int i2c_addr)
    142 {
    143 	int i, pages = 0, size = 0;
    144 	unsigned char eeprom_buf[0x3c00], hdr[4], buf[MAX_STRING_LENGTH];
    145 	unsigned char *cp, *cp1;
    146 
    147 #if defined(CONFIG_DFU_OVER_USB)
    148 	factory_dat.usb_vendor_id = CONFIG_USB_GADGET_VENDOR_NUM;
    149 	factory_dat.usb_product_id = CONFIG_USB_GADGET_PRODUCT_NUM;
    150 #endif
    151 	if (i2c_probe(i2c_addr))
    152 		goto err;
    153 
    154 	if (i2c_read(i2c_addr, EEPROM_FATORYSET_OFFSET, 2, hdr, sizeof(hdr)))
    155 		goto err;
    156 
    157 	if ((hdr[0] != 0x99) || (hdr[1] != 0x80)) {
    158 		printf("FactorySet is not right in eeprom.\n");
    159 		return 1;
    160 	}
    161 
    162 	/* get FactorySet size */
    163 	size = (hdr[2] << 8) + hdr[3] + sizeof(hdr);
    164 	if (size > 0x3bfa)
    165 		size = 0x3bfa;
    166 
    167 	pages = size / EEPR_PG_SZ;
    168 
    169 	/*
    170 	 * read the eeprom using i2c
    171 	 * I can not read entire eeprom in once, so separate into several
    172 	 * times. Furthermore, fetch eeprom take longer time, so we fetch
    173 	 * data after every time we got a record from eeprom
    174 	 */
    175 	debug("Read eeprom page :\n");
    176 	for (i = 0; i < pages; i++)
    177 		if (i2c_read(i2c_addr, (OFF_PG + i) * EEPR_PG_SZ, 2,
    178 			     eeprom_buf + (i * EEPR_PG_SZ), EEPR_PG_SZ))
    179 			goto err;
    180 
    181 	if (size % EEPR_PG_SZ)
    182 		if (i2c_read(i2c_addr, (OFF_PG + pages) * EEPR_PG_SZ, 2,
    183 			     eeprom_buf + (pages * EEPR_PG_SZ),
    184 			     (size % EEPR_PG_SZ)))
    185 			goto err;
    186 
    187 	/* we do below just for eeprom align */
    188 	for (i = 0; i < size; i++)
    189 		if (eeprom_buf[i] == '\n')
    190 			eeprom_buf[i] = 0;
    191 
    192 	/* skip header */
    193 	size -= sizeof(hdr);
    194 	cp = (uchar *)eeprom_buf + sizeof(hdr);
    195 
    196 	/* get mac address */
    197 	get_factory_record_val(cp, size, (uchar *)"ETH1", (uchar *)"mac",
    198 			       buf, MAX_STRING_LENGTH);
    199 	cp1 = buf;
    200 	for (i = 0; i < 6; i++) {
    201 		factory_dat.mac[i] = simple_strtoul((char *)cp1, NULL, 16);
    202 		cp1 += 3;
    203 	}
    204 
    205 #if defined(CONFIG_DFU_OVER_USB)
    206 	/* read vid and pid for dfu mode */
    207 	if (0 <= get_factory_record_val(cp, size, (uchar *)"USBD1",
    208 					(uchar *)"vid", buf,
    209 					MAX_STRING_LENGTH)) {
    210 		factory_dat.usb_vendor_id = simple_strtoul((char *)buf,
    211 							   NULL, 16);
    212 	}
    213 
    214 	if (0 <= get_factory_record_val(cp, size, (uchar *)"USBD1",
    215 					(uchar *)"pid", buf,
    216 					MAX_STRING_LENGTH)) {
    217 		factory_dat.usb_product_id = simple_strtoul((char *)buf,
    218 							    NULL, 16);
    219 	}
    220 	printf("DFU USB: VID = 0x%4x, PID = 0x%4x\n", factory_dat.usb_vendor_id,
    221 	       factory_dat.usb_product_id);
    222 #endif
    223 #if defined(CONFIG_VIDEO)
    224 	if (0 <= get_factory_record_val(cp, size, (uchar *)"DISP1",
    225 					(uchar *)"name", factory_dat.disp_name,
    226 					MAX_STRING_LENGTH)) {
    227 		debug("display name: %s\n", factory_dat.disp_name);
    228 	}
    229 #endif
    230 	if (0 <= get_factory_record_val(cp, size, (uchar *)"DEV",
    231 					(uchar *)"num", factory_dat.serial,
    232 					MAX_STRING_LENGTH)) {
    233 		debug("serial number: %s\n", factory_dat.serial);
    234 	}
    235 	if (0 <= get_factory_record_val(cp, size, (uchar *)"DEV",
    236 					(uchar *)"ver", buf,
    237 					MAX_STRING_LENGTH)) {
    238 		factory_dat.version = simple_strtoul((char *)buf,
    239 							    NULL, 16);
    240 		debug("version number: %d\n", factory_dat.version);
    241 	}
    242 	/* Get ASN from factory set if available */
    243 	if (0 <= get_factory_record_val(cp, size, (uchar *)"DEV",
    244 					(uchar *)"id", factory_dat.asn,
    245 					MAX_STRING_LENGTH)) {
    246 		debug("factoryset asn: %s\n", factory_dat.asn);
    247 	} else {
    248 		factory_dat.asn[0] = 0;
    249 	}
    250 	/* Get COMP/ver from factory set if available */
    251 	if (0 <= get_factory_record_val(cp, size, (uchar *)"COMP",
    252 					(uchar *)"ver",
    253 					factory_dat.comp_version,
    254 					MAX_STRING_LENGTH)) {
    255 		debug("factoryset COMP/ver: %s\n", factory_dat.comp_version);
    256 	} else {
    257 		strcpy((char *)factory_dat.comp_version, "1.0");
    258 	}
    259 
    260 	return 0;
    261 
    262 err:
    263 	printf("Could not read the EEPROM; something fundamentally wrong on the I2C bus.\n");
    264 	return 1;
    265 }
    266 
    267 static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE;
    268 
    269 static int factoryset_mac_env_set(void)
    270 {
    271 	uint8_t mac_addr[6];
    272 
    273 	debug("FactorySet: Set mac address\n");
    274 	if (is_valid_ethaddr(factory_dat.mac)) {
    275 		memcpy(mac_addr, factory_dat.mac, 6);
    276 	} else {
    277 		uint32_t mac_hi, mac_lo;
    278 
    279 		debug("Warning: FactorySet: <ethaddr> not set. Fallback to E-fuse\n");
    280 		mac_lo = readl(&cdev->macid0l);
    281 		mac_hi = readl(&cdev->macid0h);
    282 
    283 		mac_addr[0] = mac_hi & 0xFF;
    284 		mac_addr[1] = (mac_hi & 0xFF00) >> 8;
    285 		mac_addr[2] = (mac_hi & 0xFF0000) >> 16;
    286 		mac_addr[3] = (mac_hi & 0xFF000000) >> 24;
    287 		mac_addr[4] = mac_lo & 0xFF;
    288 		mac_addr[5] = (mac_lo & 0xFF00) >> 8;
    289 		if (!is_valid_ethaddr(mac_addr)) {
    290 			printf("Warning: ethaddr not set by FactorySet or E-fuse. Set <ethaddr> variable to overcome this.\n");
    291 			return -1;
    292 		}
    293 	}
    294 
    295 	eth_env_set_enetaddr("ethaddr", mac_addr);
    296 	return 0;
    297 }
    298 
    299 int factoryset_env_set(void)
    300 {
    301 	int ret = 0;
    302 
    303 	if (factoryset_mac_env_set() < 0)
    304 		ret = -1;
    305 
    306 	return ret;
    307 }
    308 
    309 int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
    310 {
    311 	put_unaligned(factory_dat.usb_vendor_id, &dev->idVendor);
    312 	put_unaligned(factory_dat.usb_product_id, &dev->idProduct);
    313 	g_dnl_set_serialnumber((char *)factory_dat.serial);
    314 
    315 	return 0;
    316 }
    317 
    318 int g_dnl_get_board_bcd_device_number(int gcnum)
    319 {
    320 	return factory_dat.version;
    321 }
    322 #endif /* defined(CONFIG_SPL_BUILD) */
    323