board: siemens: extend factoryset reading for giedi and deneb boards
[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 <dm.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 #if CONFIG_IS_ENABLED(DM_I2C)
148         struct udevice *bus, *dev;
149         int ret;
150 #endif
151
152 #if defined(CONFIG_DFU_OVER_USB)
153         factory_dat.usb_vendor_id = CONFIG_USB_GADGET_VENDOR_NUM;
154         factory_dat.usb_product_id = CONFIG_USB_GADGET_PRODUCT_NUM;
155 #endif
156
157 #if CONFIG_IS_ENABLED(DM_I2C)
158         ret = uclass_get_device_by_seq(UCLASS_I2C, EEPROM_I2C_BUS, &bus);
159         if (ret)
160                 goto err;
161
162         ret = dm_i2c_probe(bus, i2c_addr, 0, &dev);
163         if (ret)
164                 goto err;
165
166         ret = i2c_set_chip_offset_len(dev, 2);
167         if (ret)
168                 goto err;
169
170         ret = dm_i2c_read(dev, EEPROM_FATORYSET_OFFSET, hdr, sizeof(hdr));
171         if (ret)
172                 goto err;
173 #else
174         if (i2c_probe(i2c_addr))
175                 goto err;
176
177         if (i2c_read(i2c_addr, EEPROM_FATORYSET_OFFSET, 2, hdr, sizeof(hdr)))
178                 goto err;
179 #endif
180
181         if ((hdr[0] != 0x99) || (hdr[1] != 0x80)) {
182                 printf("FactorySet is not right in eeprom.\n");
183                 return 1;
184         }
185
186         /* get FactorySet size */
187         size = (hdr[2] << 8) + hdr[3] + sizeof(hdr);
188         if (size > 0x3bfa)
189                 size = 0x3bfa;
190
191         pages = size / EEPR_PG_SZ;
192
193         /*
194          * read the eeprom using i2c
195          * I can not read entire eeprom in once, so separate into several
196          * times. Furthermore, fetch eeprom take longer time, so we fetch
197          * data after every time we got a record from eeprom
198          */
199         debug("Read eeprom page :\n");
200         for (i = 0; i < pages; i++) {
201 #if CONFIG_IS_ENABLED(DM_I2C)
202                 ret = dm_i2c_read(dev, (OFF_PG + i) * EEPR_PG_SZ,
203                                   eeprom_buf + (i * EEPR_PG_SZ), EEPR_PG_SZ);
204                 if (ret)
205                         goto err;
206 #else
207                 if (i2c_read(i2c_addr, (OFF_PG + i) * EEPR_PG_SZ, 2,
208                              eeprom_buf + (i * EEPR_PG_SZ), EEPR_PG_SZ))
209                         goto err;
210 #endif
211         }
212
213         if (size % EEPR_PG_SZ) {
214 #if CONFIG_IS_ENABLED(DM_I2C)
215                 ret = dm_i2c_read(dev, (OFF_PG + pages) * EEPR_PG_SZ,
216                                   eeprom_buf + (pages * EEPR_PG_SZ),
217                                   size % EEPR_PG_SZ);
218                 if (ret)
219                         goto err;
220 #else
221                 if (i2c_read(i2c_addr, (OFF_PG + pages) * EEPR_PG_SZ, 2,
222                              eeprom_buf + (pages * EEPR_PG_SZ),
223                              (size % EEPR_PG_SZ)))
224                         goto err;
225 #endif
226         }
227
228         /* we do below just for eeprom align */
229         for (i = 0; i < size; i++)
230                 if (eeprom_buf[i] == '\n')
231                         eeprom_buf[i] = 0;
232
233         /* skip header */
234         size -= sizeof(hdr);
235         cp = (uchar *)eeprom_buf + sizeof(hdr);
236
237         /* get mac address */
238         get_factory_record_val(cp, size, (uchar *)"ETH1", (uchar *)"mac",
239                                buf, MAX_STRING_LENGTH);
240         cp1 = buf;
241         for (i = 0; i < 6; i++) {
242                 factory_dat.mac[i] = simple_strtoul((char *)cp1, NULL, 16);
243                 cp1 += 3;
244         }
245
246 #if CONFIG_IS_ENABLED(TARGET_GIEDI) || CONFIG_IS_ENABLED(TARGET_DENEB)
247         /* get mac address for WLAN */
248         ret = get_factory_record_val(cp, size, (uchar *)"WLAN1", (uchar *)"mac",
249                                      buf, MAX_STRING_LENGTH);
250         if (ret > 0) {
251                 cp1 = buf;
252                 for (i = 0; i < 6; i++) {
253                         factory_dat.mac_wlan[i] = simple_strtoul((char *)cp1,
254                                                                  NULL, 16);
255                         cp1 += 3;
256                 }
257         }
258 #endif
259
260 #if defined(CONFIG_DFU_OVER_USB)
261         /* read vid and pid for dfu mode */
262         if (0 <= get_factory_record_val(cp, size, (uchar *)"USBD1",
263                                         (uchar *)"vid", buf,
264                                         MAX_STRING_LENGTH)) {
265                 factory_dat.usb_vendor_id = simple_strtoul((char *)buf,
266                                                            NULL, 16);
267         }
268
269         if (0 <= get_factory_record_val(cp, size, (uchar *)"USBD1",
270                                         (uchar *)"pid", buf,
271                                         MAX_STRING_LENGTH)) {
272                 factory_dat.usb_product_id = simple_strtoul((char *)buf,
273                                                             NULL, 16);
274         }
275         printf("DFU USB: VID = 0x%4x, PID = 0x%4x\n", factory_dat.usb_vendor_id,
276                factory_dat.usb_product_id);
277 #endif
278 #if defined(CONFIG_VIDEO)
279         if (0 <= get_factory_record_val(cp, size, (uchar *)"DISP1",
280                                         (uchar *)"name", factory_dat.disp_name,
281                                         MAX_STRING_LENGTH)) {
282                 debug("display name: %s\n", factory_dat.disp_name);
283         }
284 #endif
285         if (0 <= get_factory_record_val(cp, size, (uchar *)"DEV",
286                                         (uchar *)"num", factory_dat.serial,
287                                         MAX_STRING_LENGTH)) {
288                 debug("serial number: %s\n", factory_dat.serial);
289         }
290         if (0 <= get_factory_record_val(cp, size, (uchar *)"DEV",
291                                         (uchar *)"ver", buf,
292                                         MAX_STRING_LENGTH)) {
293                 factory_dat.version = simple_strtoul((char *)buf,
294                                                             NULL, 16);
295                 debug("version number: %d\n", factory_dat.version);
296         }
297         /* Get ASN from factory set if available */
298         if (0 <= get_factory_record_val(cp, size, (uchar *)"DEV",
299                                         (uchar *)"id", factory_dat.asn,
300                                         MAX_STRING_LENGTH)) {
301                 debug("factoryset asn: %s\n", factory_dat.asn);
302         } else {
303                 factory_dat.asn[0] = 0;
304         }
305         /* Get COMP/ver from factory set if available */
306         if (0 <= get_factory_record_val(cp, size, (uchar *)"COMP",
307                                         (uchar *)"ver",
308                                         factory_dat.comp_version,
309                                         MAX_STRING_LENGTH)) {
310                 debug("factoryset COMP/ver: %s\n", factory_dat.comp_version);
311         } else {
312                 strcpy((char *)factory_dat.comp_version, "1.0");
313         }
314
315         return 0;
316
317 err:
318         printf("Could not read the EEPROM; something fundamentally wrong on the I2C bus.\n");
319         return 1;
320 }
321
322 static int get_mac_from_efuse(uint8_t mac[6])
323 {
324 #ifdef CONFIG_AM33XX
325         struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE;
326         uint32_t mac_hi, mac_lo;
327
328         mac_lo = readl(&cdev->macid0l);
329         mac_hi = readl(&cdev->macid0h);
330
331         mac[0] = mac_hi & 0xFF;
332         mac[1] = (mac_hi & 0xFF00) >> 8;
333         mac[2] = (mac_hi & 0xFF0000) >> 16;
334         mac[3] = (mac_hi & 0xFF000000) >> 24;
335         mac[4] = mac_lo & 0xFF;
336         mac[5] = (mac_lo & 0xFF00) >> 8;
337 #else
338         /* unhandled */
339         memset(mac, 0, 6);
340 #endif
341         if (!is_valid_ethaddr(mac)) {
342                 puts("Warning: ethaddr not set by FactorySet or E-fuse. ");
343                 puts("Set <ethaddr> variable to overcome this.\n");
344                 return -1;
345         }
346         return 0;
347 }
348
349 static int factoryset_mac_env_set(void)
350 {
351         uint8_t mac_addr[6];
352
353         /* Set mac from factoryset or try reading E-fuse */
354         debug("FactorySet: Set mac address\n");
355         if (is_valid_ethaddr(factory_dat.mac)) {
356                 memcpy(mac_addr, factory_dat.mac, 6);
357         } else {
358                 debug("Warning: FactorySet: <ethaddr> not set. Fallback to E-fuse\n");
359                 if (get_mac_from_efuse(mac_addr) < 0)
360                         return -1;
361         }
362
363         eth_env_set_enetaddr("ethaddr", mac_addr);
364
365 #if CONFIG_IS_ENABLED(TARGET_GIEDI) || CONFIG_IS_ENABLED(TARGET_DENEB)
366         eth_env_set_enetaddr("eth1addr", mac_addr);
367
368         /* wlan mac */
369         if (is_valid_ethaddr(factory_dat.mac_wlan))
370                 eth_env_set_enetaddr("eth2addr", factory_dat.mac_wlan);
371 #endif
372         return 0;
373 }
374
375 static void factoryset_dtb_env_set(void)
376 {
377         /* Set ASN in environment*/
378         if (factory_dat.asn[0] != 0) {
379                 env_set("dtb_name", (char *)factory_dat.asn);
380         } else {
381                 /* dtb suffix gets added in load script */
382                 env_set("dtb_name", "default");
383         }
384 }
385
386 int factoryset_env_set(void)
387 {
388         int ret = 0;
389
390         factoryset_dtb_env_set();
391
392         if (factoryset_mac_env_set() < 0)
393                 ret = -1;
394
395         return ret;
396 }
397
398 int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
399 {
400         put_unaligned(factory_dat.usb_vendor_id, &dev->idVendor);
401         put_unaligned(factory_dat.usb_product_id, &dev->idProduct);
402         g_dnl_set_serialnumber((char *)factory_dat.serial);
403
404         return 0;
405 }
406
407 int g_dnl_get_board_bcd_device_number(int gcnum)
408 {
409         return factory_dat.version;
410 }
411 #endif /* defined(CONFIG_SPL_BUILD) */