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