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