1
2
3
4
5
6
7
8
9
10
11
12#include <common.h>
13#include <command.h>
14#include <dm.h>
15#include <i2c.h>
16#include <i2c_eeprom.h>
17#include <env.h>
18#include <init.h>
19#include <net.h>
20#include <asm/global_data.h>
21#include <linux/ctype.h>
22#include <u-boot/crc.h>
23
24#include "tlv_eeprom.h"
25
26DECLARE_GLOBAL_DATA_PTR;
27
28#define MAX_TLV_DEVICES 2
29
30
31static bool is_checksum_valid(u8 *eeprom);
32static int read_eeprom(u8 *eeprom);
33static void show_eeprom(u8 *eeprom);
34static void decode_tlv(struct tlvinfo_tlv *tlv);
35static void update_crc(u8 *eeprom);
36static int prog_eeprom(u8 *eeprom);
37static bool tlvinfo_find_tlv(u8 *eeprom, u8 tcode, int *eeprom_index);
38static bool tlvinfo_delete_tlv(u8 *eeprom, u8 code);
39static bool tlvinfo_add_tlv(u8 *eeprom, int tcode, char *strval);
40static int set_mac(char *buf, const char *string);
41static int set_date(char *buf, const char *string);
42static int set_bytes(char *buf, const char *string, int *converted_accum);
43static void show_tlv_devices(void);
44
45
46static int has_been_read;
47
48static u8 eeprom[TLV_INFO_MAX_LEN];
49
50static struct udevice *tlv_devices[MAX_TLV_DEVICES];
51static unsigned int current_dev;
52
53#define to_header(p) ((struct tlvinfo_header *)p)
54#define to_entry(p) ((struct tlvinfo_tlv *)p)
55
56#define HDR_SIZE sizeof(struct tlvinfo_header)
57#define ENT_SIZE sizeof(struct tlvinfo_tlv)
58
59static inline bool is_digit(char c)
60{
61 return (c >= '0' && c <= '9');
62}
63
64
65
66
67
68
69
70
71static inline bool is_valid_tlv(struct tlvinfo_tlv *tlv)
72{
73 return((tlv->type != 0x00) && (tlv->type != 0xFF));
74}
75
76
77
78
79
80
81static inline u8 is_hex(char p)
82{
83 return (((p >= '0') && (p <= '9')) ||
84 ((p >= 'A') && (p <= 'F')) ||
85 ((p >= 'a') && (p <= 'f')));
86}
87
88
89
90
91
92
93
94
95
96static bool is_checksum_valid(u8 *eeprom)
97{
98 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
99 struct tlvinfo_tlv *eeprom_crc;
100 unsigned int calc_crc;
101 unsigned int stored_crc;
102
103
104 if (!is_valid_tlvinfo_header(eeprom_hdr))
105 return false;
106
107
108 eeprom_crc = to_entry(&eeprom[HDR_SIZE +
109 be16_to_cpu(eeprom_hdr->totallen) - (ENT_SIZE + 4)]);
110 if (eeprom_crc->type != TLV_CODE_CRC_32 || eeprom_crc->length != 4)
111 return false;
112
113
114 calc_crc = crc32(0, (void *)eeprom,
115 HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen) - 4);
116 stored_crc = (eeprom_crc->value[0] << 24) |
117 (eeprom_crc->value[1] << 16) |
118 (eeprom_crc->value[2] << 8) |
119 eeprom_crc->value[3];
120 return calc_crc == stored_crc;
121}
122
123
124
125
126
127
128static int read_eeprom(u8 *eeprom)
129{
130 int ret;
131 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
132 struct tlvinfo_tlv *eeprom_tlv = to_entry(&eeprom[HDR_SIZE]);
133
134 if (has_been_read)
135 return 0;
136
137
138 ret = read_tlv_eeprom((void *)eeprom_hdr, 0, HDR_SIZE, current_dev);
139
140 if (ret == 0 && is_valid_tlvinfo_header(eeprom_hdr))
141 ret = read_tlv_eeprom((void *)eeprom_tlv, HDR_SIZE,
142 be16_to_cpu(eeprom_hdr->totallen),
143 current_dev);
144
145
146 if (!is_valid_tlvinfo_header(eeprom_hdr) ||
147 !is_checksum_valid(eeprom)) {
148 strcpy(eeprom_hdr->signature, TLV_INFO_ID_STRING);
149 eeprom_hdr->version = TLV_INFO_VERSION;
150 eeprom_hdr->totallen = cpu_to_be16(0);
151 update_crc(eeprom);
152 }
153
154 has_been_read = 1;
155
156#ifdef DEBUG
157 show_eeprom(eeprom);
158#endif
159
160 return ret;
161}
162
163
164
165
166
167
168static void show_eeprom(u8 *eeprom)
169{
170 int tlv_end;
171 int curr_tlv;
172#ifdef DEBUG
173 int i;
174#endif
175 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
176 struct tlvinfo_tlv *eeprom_tlv;
177
178 if (!is_valid_tlvinfo_header(eeprom_hdr)) {
179 printf("EEPROM does not contain data in a valid TlvInfo format.\n");
180 return;
181 }
182
183 printf("TLV: %u\n", current_dev);
184 printf("TlvInfo Header:\n");
185 printf(" Id String: %s\n", eeprom_hdr->signature);
186 printf(" Version: %d\n", eeprom_hdr->version);
187 printf(" Total Length: %d\n", be16_to_cpu(eeprom_hdr->totallen));
188
189 printf("TLV Name Code Len Value\n");
190 printf("-------------------- ---- --- -----\n");
191 curr_tlv = HDR_SIZE;
192 tlv_end = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
193 while (curr_tlv < tlv_end) {
194 eeprom_tlv = to_entry(&eeprom[curr_tlv]);
195 if (!is_valid_tlv(eeprom_tlv)) {
196 printf("Invalid TLV field starting at EEPROM offset %d\n",
197 curr_tlv);
198 return;
199 }
200 decode_tlv(eeprom_tlv);
201 curr_tlv += ENT_SIZE + eeprom_tlv->length;
202 }
203
204 printf("Checksum is %s.\n",
205 is_checksum_valid(eeprom) ? "valid" : "invalid");
206
207#ifdef DEBUG
208 printf("EEPROM dump: (0x%x bytes)", TLV_INFO_MAX_LEN);
209 for (i = 0; i < TLV_INFO_MAX_LEN; i++) {
210 if ((i % 16) == 0)
211 printf("\n%02X: ", i);
212 printf("%02X ", eeprom[i]);
213 }
214 printf("\n");
215#endif
216}
217
218
219
220
221struct tlv_code_desc {
222 u8 m_code;
223 char *m_name;
224};
225
226
227
228
229static struct tlv_code_desc tlv_code_list[] = {
230 { TLV_CODE_PRODUCT_NAME, "Product Name"},
231 { TLV_CODE_PART_NUMBER, "Part Number"},
232 { TLV_CODE_SERIAL_NUMBER, "Serial Number"},
233 { TLV_CODE_MAC_BASE, "Base MAC Address"},
234 { TLV_CODE_MANUF_DATE, "Manufacture Date"},
235 { TLV_CODE_DEVICE_VERSION, "Device Version"},
236 { TLV_CODE_LABEL_REVISION, "Label Revision"},
237 { TLV_CODE_PLATFORM_NAME, "Platform Name"},
238 { TLV_CODE_ONIE_VERSION, "ONIE Version"},
239 { TLV_CODE_MAC_SIZE, "MAC Addresses"},
240 { TLV_CODE_MANUF_NAME, "Manufacturer"},
241 { TLV_CODE_MANUF_COUNTRY, "Country Code"},
242 { TLV_CODE_VENDOR_NAME, "Vendor Name"},
243 { TLV_CODE_DIAG_VERSION, "Diag Version"},
244 { TLV_CODE_SERVICE_TAG, "Service Tag"},
245 { TLV_CODE_VENDOR_EXT, "Vendor Extension"},
246 { TLV_CODE_CRC_32, "CRC-32"},
247};
248
249
250
251
252static inline const char *tlv_type2name(u8 type)
253{
254 char *name = "Unknown";
255 int i;
256
257 for (i = 0; i < ARRAY_SIZE(tlv_code_list); i++) {
258 if (tlv_code_list[i].m_code == type) {
259 name = tlv_code_list[i].m_name;
260 break;
261 }
262 }
263
264 return name;
265}
266
267
268
269
270
271
272
273
274
275
276
277
278
279#define DECODE_NAME_MAX 20
280
281
282
283
284
285
286
287
288
289#define DECODE_VALUE_MAX ((5 * TLV_VALUE_MAX_LEN) + 1)
290
291static void decode_tlv(struct tlvinfo_tlv *tlv)
292{
293 char name[DECODE_NAME_MAX];
294 char value[DECODE_VALUE_MAX];
295 int i;
296
297 strncpy(name, tlv_type2name(tlv->type), DECODE_NAME_MAX);
298
299 switch (tlv->type) {
300 case TLV_CODE_PRODUCT_NAME:
301 case TLV_CODE_PART_NUMBER:
302 case TLV_CODE_SERIAL_NUMBER:
303 case TLV_CODE_MANUF_DATE:
304 case TLV_CODE_LABEL_REVISION:
305 case TLV_CODE_PLATFORM_NAME:
306 case TLV_CODE_ONIE_VERSION:
307 case TLV_CODE_MANUF_NAME:
308 case TLV_CODE_MANUF_COUNTRY:
309 case TLV_CODE_VENDOR_NAME:
310 case TLV_CODE_DIAG_VERSION:
311 case TLV_CODE_SERVICE_TAG:
312 memcpy(value, tlv->value, tlv->length);
313 value[tlv->length] = 0;
314 break;
315 case TLV_CODE_MAC_BASE:
316 sprintf(value, "%02X:%02X:%02X:%02X:%02X:%02X",
317 tlv->value[0], tlv->value[1], tlv->value[2],
318 tlv->value[3], tlv->value[4], tlv->value[5]);
319 break;
320 case TLV_CODE_DEVICE_VERSION:
321 sprintf(value, "%u", tlv->value[0]);
322 break;
323 case TLV_CODE_MAC_SIZE:
324 sprintf(value, "%u", (tlv->value[0] << 8) | tlv->value[1]);
325 break;
326 case TLV_CODE_VENDOR_EXT:
327 value[0] = 0;
328 for (i = 0; (i < (DECODE_VALUE_MAX / 5)) && (i < tlv->length);
329 i++) {
330 sprintf(value, "%s 0x%02X", value, tlv->value[i]);
331 }
332 break;
333 case TLV_CODE_CRC_32:
334 sprintf(value, "0x%02X%02X%02X%02X",
335 tlv->value[0], tlv->value[1],
336 tlv->value[2], tlv->value[3]);
337 break;
338 default:
339 value[0] = 0;
340 for (i = 0; (i < (DECODE_VALUE_MAX / 5)) && (i < tlv->length);
341 i++) {
342 sprintf(value, "%s 0x%02X", value, tlv->value[i]);
343 }
344 break;
345 }
346
347 name[DECODE_NAME_MAX - 1] = 0;
348 printf("%-20s 0x%02X %3d %s\n", name, tlv->type, tlv->length, value);
349}
350
351
352
353
354
355
356
357
358static void update_crc(u8 *eeprom)
359{
360 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
361 struct tlvinfo_tlv *eeprom_crc;
362 unsigned int calc_crc;
363 int eeprom_index;
364
365
366 if (!tlvinfo_find_tlv(eeprom, TLV_CODE_CRC_32, &eeprom_index)) {
367 unsigned int totallen = be16_to_cpu(eeprom_hdr->totallen);
368
369 if ((totallen + ENT_SIZE + 4) > TLV_TOTAL_LEN_MAX)
370 return;
371 eeprom_index = HDR_SIZE + totallen;
372 eeprom_hdr->totallen = cpu_to_be16(totallen + ENT_SIZE + 4);
373 }
374 eeprom_crc = to_entry(&eeprom[eeprom_index]);
375 eeprom_crc->type = TLV_CODE_CRC_32;
376 eeprom_crc->length = 4;
377
378
379 calc_crc = crc32(0, (void *)eeprom,
380 HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen) - 4);
381 eeprom_crc->value[0] = (calc_crc >> 24) & 0xFF;
382 eeprom_crc->value[1] = (calc_crc >> 16) & 0xFF;
383 eeprom_crc->value[2] = (calc_crc >> 8) & 0xFF;
384 eeprom_crc->value[3] = (calc_crc >> 0) & 0xFF;
385}
386
387
388
389
390
391
392static int prog_eeprom(u8 *eeprom)
393{
394 int ret = 0;
395 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
396 int eeprom_len;
397
398 update_crc(eeprom);
399
400 eeprom_len = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
401 ret = write_tlv_eeprom(eeprom, eeprom_len);
402 if (ret) {
403 printf("Programming failed.\n");
404 return -1;
405 }
406
407 printf("Programming passed.\n");
408 return 0;
409}
410
411
412
413
414void show_tlv_code_list(void)
415{
416 int i;
417
418 printf("TLV Code TLV Name\n");
419 printf("======== =================\n");
420 for (i = 0; i < ARRAY_SIZE(tlv_code_list); i++) {
421 printf("0x%02X %s\n",
422 tlv_code_list[i].m_code,
423 tlv_code_list[i].m_name);
424 }
425}
426
427
428
429
430
431
432int do_tlv_eeprom(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
433{
434 char cmd;
435 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
436
437
438 if (argc == 1) {
439 read_eeprom(eeprom);
440 show_eeprom(eeprom);
441 return 0;
442 }
443
444
445
446 cmd = argv[1][0];
447
448
449 if (cmd == 'r') {
450 has_been_read = 0;
451 if (!read_eeprom(eeprom))
452 printf("EEPROM data loaded from device to memory.\n");
453 return 0;
454 }
455
456
457 if (!has_been_read) {
458 printf("Please read the EEPROM data first, using the 'tlv_eeprom read' command.\n");
459 return 0;
460 }
461
462
463 if (argc == 2) {
464 switch (cmd) {
465 case 'w':
466 prog_eeprom(eeprom);
467 break;
468 case 'e':
469 strcpy(eeprom_hdr->signature, TLV_INFO_ID_STRING);
470 eeprom_hdr->version = TLV_INFO_VERSION;
471 eeprom_hdr->totallen = cpu_to_be16(0);
472 update_crc(eeprom);
473 printf("EEPROM data in memory reset.\n");
474 break;
475 case 'l':
476 show_tlv_code_list();
477 break;
478 case 'd':
479 show_tlv_devices();
480 break;
481 default:
482 cmd_usage(cmdtp);
483 break;
484 }
485 return 0;
486 }
487
488
489 if (argc > 4) {
490 cmd_usage(cmdtp);
491 return 0;
492 }
493
494
495
496
497 if (cmd == 's') {
498 int tcode;
499
500 tcode = simple_strtoul(argv[2], NULL, 0);
501 tlvinfo_delete_tlv(eeprom, tcode);
502 if (argc == 4)
503 tlvinfo_add_tlv(eeprom, tcode, argv[3]);
504 } else if (cmd == 'd') {
505 unsigned int devnum;
506
507 devnum = simple_strtoul(argv[2], NULL, 0);
508 if (devnum > MAX_TLV_DEVICES || !tlv_devices[devnum]) {
509 printf("Invalid device number\n");
510 return 0;
511 }
512 current_dev = devnum;
513 has_been_read = 0;
514 } else {
515 cmd_usage(cmdtp);
516 }
517
518 return 0;
519}
520
521
522
523
524U_BOOT_CMD(tlv_eeprom, 4, 1, do_tlv_eeprom,
525 "Display and program the system EEPROM data block.",
526 "[read|write|set <type_code> <string_value>|erase|list]\n"
527 "tlv_eeprom\n"
528 " - With no arguments display the current contents.\n"
529 "tlv_eeprom dev [dev]\n"
530 " - List devices or set current EEPROM device.\n"
531 "tlv_eeprom read\n"
532 " - Load EEPROM data from device to memory.\n"
533 "tlv_eeprom write\n"
534 " - Write the EEPROM data to persistent storage.\n"
535 "tlv_eeprom set <type_code> <string_value>\n"
536 " - Set a field to a value.\n"
537 " - If no string_value, field is deleted.\n"
538 " - Use 'tlv_eeprom write' to make changes permanent.\n"
539 "tlv_eeprom erase\n"
540 " - Reset the in memory EEPROM data.\n"
541 " - Use 'tlv_eeprom read' to refresh the in memory EEPROM data.\n"
542 " - Use 'tlv_eeprom write' to make changes permanent.\n"
543 "tlv_eeprom list\n"
544 " - List the understood TLV codes and names.\n"
545 );
546
547
548
549
550
551
552
553
554static bool tlvinfo_find_tlv(u8 *eeprom, u8 tcode, int *eeprom_index)
555{
556 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
557 struct tlvinfo_tlv *eeprom_tlv;
558 int eeprom_end;
559
560
561
562 *eeprom_index = HDR_SIZE;
563 eeprom_end = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
564 while (*eeprom_index < eeprom_end) {
565 eeprom_tlv = to_entry(&eeprom[*eeprom_index]);
566 if (!is_valid_tlv(eeprom_tlv))
567 return false;
568 if (eeprom_tlv->type == tcode)
569 return true;
570 *eeprom_index += ENT_SIZE + eeprom_tlv->length;
571 }
572 return(false);
573}
574
575
576
577
578
579
580
581static bool tlvinfo_delete_tlv(u8 *eeprom, u8 code)
582{
583 int eeprom_index;
584 int tlength;
585 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
586 struct tlvinfo_tlv *eeprom_tlv;
587
588
589 if (tlvinfo_find_tlv(eeprom, code, &eeprom_index)) {
590 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
591 tlength = ENT_SIZE + eeprom_tlv->length;
592 memcpy(&eeprom[eeprom_index], &eeprom[eeprom_index + tlength],
593 HDR_SIZE +
594 be16_to_cpu(eeprom_hdr->totallen) - eeprom_index -
595 tlength);
596 eeprom_hdr->totallen =
597 cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) -
598 tlength);
599 update_crc(eeprom);
600 return true;
601 }
602 return false;
603}
604
605
606
607
608
609
610
611#define MAX_TLV_VALUE_LEN 256
612static bool tlvinfo_add_tlv(u8 *eeprom, int tcode, char *strval)
613{
614 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
615 struct tlvinfo_tlv *eeprom_tlv;
616 int new_tlv_len = 0;
617 u32 value;
618 char data[MAX_TLV_VALUE_LEN];
619 int eeprom_index;
620
621
622 switch (tcode) {
623 case TLV_CODE_PRODUCT_NAME:
624 case TLV_CODE_PART_NUMBER:
625 case TLV_CODE_SERIAL_NUMBER:
626 case TLV_CODE_LABEL_REVISION:
627 case TLV_CODE_PLATFORM_NAME:
628 case TLV_CODE_ONIE_VERSION:
629 case TLV_CODE_MANUF_NAME:
630 case TLV_CODE_MANUF_COUNTRY:
631 case TLV_CODE_VENDOR_NAME:
632 case TLV_CODE_DIAG_VERSION:
633 case TLV_CODE_SERVICE_TAG:
634 strncpy(data, strval, MAX_TLV_VALUE_LEN);
635 new_tlv_len = min_t(size_t, MAX_TLV_VALUE_LEN, strlen(strval));
636 break;
637 case TLV_CODE_DEVICE_VERSION:
638 value = simple_strtoul(strval, NULL, 0);
639 if (value >= 256) {
640 printf("ERROR: Device version must be 255 or less. Value supplied: %u",
641 value);
642 return false;
643 }
644 data[0] = value & 0xFF;
645 new_tlv_len = 1;
646 break;
647 case TLV_CODE_MAC_SIZE:
648 value = simple_strtoul(strval, NULL, 0);
649 if (value >= 65536) {
650 printf("ERROR: MAC Size must be 65535 or less. Value supplied: %u",
651 value);
652 return false;
653 }
654 data[0] = (value >> 8) & 0xFF;
655 data[1] = value & 0xFF;
656 new_tlv_len = 2;
657 break;
658 case TLV_CODE_MANUF_DATE:
659 if (set_date(data, strval) != 0)
660 return false;
661 new_tlv_len = 19;
662 break;
663 case TLV_CODE_MAC_BASE:
664 if (set_mac(data, strval) != 0)
665 return false;
666 new_tlv_len = 6;
667 break;
668 case TLV_CODE_CRC_32:
669 printf("WARNING: The CRC TLV is set automatically and cannot be set manually.\n");
670 return false;
671 case TLV_CODE_VENDOR_EXT:
672 default:
673 if (set_bytes(data, strval, &new_tlv_len) != 0)
674 return false;
675 break;
676 }
677
678
679 if ((be16_to_cpu(eeprom_hdr->totallen) + ENT_SIZE + new_tlv_len) >
680 TLV_TOTAL_LEN_MAX) {
681 printf("ERROR: There is not enough room in the EERPOM to save data.\n");
682 return false;
683 }
684
685
686 if (tlvinfo_find_tlv(eeprom, TLV_CODE_CRC_32, &eeprom_index))
687 eeprom_hdr->totallen =
688 cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) -
689 ENT_SIZE - 4);
690 else
691 eeprom_index = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
692 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
693 eeprom_tlv->type = tcode;
694 eeprom_tlv->length = new_tlv_len;
695 memcpy(eeprom_tlv->value, data, new_tlv_len);
696
697
698 eeprom_hdr->totallen = cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) +
699 ENT_SIZE + new_tlv_len);
700 update_crc(eeprom);
701
702 return true;
703}
704
705
706
707
708
709
710
711
712
713
714
715static int set_mac(char *buf, const char *string)
716{
717 char *p = (char *)string;
718 int i;
719 int err = 0;
720 char *end;
721
722 if (!p) {
723 printf("ERROR: NULL mac addr string passed in.\n");
724 return -1;
725 }
726
727 if (strlen(p) != 17) {
728 printf("ERROR: MAC address strlen() != 17 -- %zu\n", strlen(p));
729 printf("ERROR: Bad MAC address format: %s\n", string);
730 return -1;
731 }
732
733 for (i = 0; i < 17; i++) {
734 if ((i % 3) == 2) {
735 if (p[i] != ':') {
736 err++;
737 printf("ERROR: mac: p[%i] != :, found: `%c'\n",
738 i, p[i]);
739 break;
740 }
741 continue;
742 } else if (!is_hex(p[i])) {
743 err++;
744 printf("ERROR: mac: p[%i] != hex digit, found: `%c'\n",
745 i, p[i]);
746 break;
747 }
748 }
749
750 if (err != 0) {
751 printf("ERROR: Bad MAC address format: %s\n", string);
752 return -1;
753 }
754
755
756 for (i = 0, p = (char *)string; i < 6; i++) {
757 buf[i] = p ? hextoul(p, &end) : 0;
758 if (p)
759 p = (*end) ? end + 1 : end;
760 }
761
762 if (!is_valid_ethaddr((u8 *)buf)) {
763 printf("ERROR: MAC address must not be 00:00:00:00:00:00, a multicast address or FF:FF:FF:FF:FF:FF.\n");
764 printf("ERROR: Bad MAC address format: %s\n", string);
765 return -1;
766 }
767
768 return 0;
769}
770
771
772
773
774
775
776
777
778
779
780static int set_date(char *buf, const char *string)
781{
782 int i;
783
784 if (!string) {
785 printf("ERROR: NULL date string passed in.\n");
786 return -1;
787 }
788
789 if (strlen(string) != 19) {
790 printf("ERROR: Date strlen() != 19 -- %zu\n", strlen(string));
791 printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
792 string);
793 return -1;
794 }
795
796 for (i = 0; string[i] != 0; i++) {
797 switch (i) {
798 case 2:
799 case 5:
800 if (string[i] != '/') {
801 printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
802 string);
803 return -1;
804 }
805 break;
806 case 10:
807 if (string[i] != ' ') {
808 printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
809 string);
810 return -1;
811 }
812 break;
813 case 13:
814 case 16:
815 if (string[i] != ':') {
816 printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
817 string);
818 return -1;
819 }
820 break;
821 default:
822 if (!is_digit(string[i])) {
823 printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
824 string);
825 return -1;
826 }
827 break;
828 }
829 }
830
831 strcpy(buf, string);
832 return 0;
833}
834
835
836
837
838
839
840
841
842
843
844
845static int set_bytes(char *buf, const char *string, int *converted_accum)
846{
847 char *p = (char *)string;
848 int i;
849 uint byte;
850
851 if (!p) {
852 printf("ERROR: NULL string passed in.\n");
853 return -1;
854 }
855
856
857 for (i = 0, p = (char *)string; (i < TLV_VALUE_MAX_LEN) && (*p != 0);
858 i++) {
859 while ((*p == ' ') || (*p == '\t') || (*p == ',') ||
860 (*p == ';')) {
861 p++;
862 }
863 if (*p != 0) {
864 if (!is_digit(*p)) {
865 printf("ERROR: Non-digit found in byte string: (%s)\n",
866 string);
867 return -1;
868 }
869 byte = simple_strtoul(p, &p, 0);
870 if (byte >= 256) {
871 printf("ERROR: The value specified is greater than 255: (%u) in string: %s\n",
872 byte, string);
873 return -1;
874 }
875 buf[i] = byte & 0xFF;
876 }
877 }
878
879 if (i == TLV_VALUE_MAX_LEN && (*p != 0)) {
880 printf("ERROR: Trying to assign too many bytes (max: %d) in string: %s\n",
881 TLV_VALUE_MAX_LEN, string);
882 return -1;
883 }
884
885 *converted_accum = i;
886 return 0;
887}
888
889static void show_tlv_devices(void)
890{
891 unsigned int dev;
892
893 for (dev = 0; dev < MAX_TLV_DEVICES; dev++)
894 if (tlv_devices[dev])
895 printf("TLV: %u%s\n", dev,
896 (dev == current_dev) ? " (*)" : "");
897}
898
899static int find_tlv_devices(struct udevice **tlv_devices_p)
900{
901 int ret;
902 int count_dev = 0;
903 struct udevice *dev;
904
905 for (ret = uclass_first_device_check(UCLASS_I2C_EEPROM, &dev);
906 dev;
907 ret = uclass_next_device_check(&dev)) {
908 if (ret == 0)
909 tlv_devices_p[count_dev++] = dev;
910 if (count_dev >= MAX_TLV_DEVICES)
911 break;
912 }
913
914 return (count_dev == 0) ? -ENODEV : 0;
915}
916
917static struct udevice *find_tlv_device_by_index(int dev_num)
918{
919 struct udevice *local_tlv_devices[MAX_TLV_DEVICES] = {};
920 struct udevice **tlv_devices_p;
921 int ret;
922
923 if (gd->flags & (GD_FLG_RELOC | GD_FLG_SPL_INIT)) {
924
925 if (tlv_devices[dev_num])
926 return tlv_devices[dev_num];
927 tlv_devices_p = tlv_devices;
928 } else {
929 tlv_devices_p = local_tlv_devices;
930 }
931
932 ret = find_tlv_devices(tlv_devices_p);
933 if (ret == 0 && tlv_devices_p[dev_num])
934 return tlv_devices_p[dev_num];
935
936 return NULL;
937}
938
939
940
941
942int read_tlv_eeprom(void *eeprom, int offset, int len, int dev_num)
943{
944 struct udevice *dev;
945
946 if (dev_num >= MAX_TLV_DEVICES)
947 return -EINVAL;
948
949 dev = find_tlv_device_by_index(dev_num);
950 if (!dev)
951 return -ENODEV;
952
953 return i2c_eeprom_read(dev, offset, eeprom, len);
954}
955
956
957
958
959int write_tlv_eeprom(void *eeprom, int len)
960{
961 if (!(gd->flags & GD_FLG_RELOC))
962 return -ENODEV;
963 if (!tlv_devices[current_dev])
964 return -ENODEV;
965
966 return i2c_eeprom_write(tlv_devices[current_dev], 0, eeprom, len);
967}
968
969int read_tlvinfo_tlv_eeprom(void *eeprom, struct tlvinfo_header **hdr,
970 struct tlvinfo_tlv **first_entry, int dev_num)
971{
972 int ret;
973 struct tlvinfo_header *tlv_hdr;
974 struct tlvinfo_tlv *tlv_ent;
975
976
977 ret = read_tlv_eeprom(eeprom, 0, HDR_SIZE, dev_num);
978 if (ret < 0)
979 return ret;
980
981 tlv_hdr = eeprom;
982 if (!is_valid_tlvinfo_header(tlv_hdr))
983 return -EINVAL;
984
985
986 tlv_ent = to_entry(&tlv_hdr[1]);
987 ret = read_tlv_eeprom(tlv_ent, HDR_SIZE,
988 be16_to_cpu(tlv_hdr->totallen), dev_num);
989 if (ret < 0)
990 return ret;
991 if (!is_checksum_valid(eeprom))
992 return -EINVAL;
993
994 *hdr = tlv_hdr;
995 *first_entry = tlv_ent;
996
997 return 0;
998}
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013int mac_read_from_eeprom(void)
1014{
1015 unsigned int i;
1016 int eeprom_index;
1017 struct tlvinfo_tlv *eeprom_tlv;
1018 int maccount;
1019 u8 macbase[6];
1020 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
1021
1022 puts("EEPROM: ");
1023
1024 if (read_eeprom(eeprom)) {
1025 printf("Read failed.\n");
1026 return -1;
1027 }
1028
1029 maccount = 1;
1030 if (tlvinfo_find_tlv(eeprom, TLV_CODE_MAC_SIZE, &eeprom_index)) {
1031 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
1032 maccount = (eeprom_tlv->value[0] << 8) | eeprom_tlv->value[1];
1033 }
1034
1035 memcpy(macbase, "\0\0\0\0\0\0", 6);
1036 if (tlvinfo_find_tlv(eeprom, TLV_CODE_MAC_BASE, &eeprom_index)) {
1037 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
1038 memcpy(macbase, eeprom_tlv->value, 6);
1039 }
1040
1041 for (i = 0; i < maccount; i++) {
1042 if (is_valid_ethaddr(macbase)) {
1043 char ethaddr[18];
1044 char enetvar[11];
1045
1046 sprintf(ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
1047 macbase[0], macbase[1], macbase[2],
1048 macbase[3], macbase[4], macbase[5]);
1049 sprintf(enetvar, i ? "eth%daddr" : "ethaddr", i);
1050
1051
1052
1053 if (!env_get(enetvar))
1054 env_set(enetvar, ethaddr);
1055
1056 macbase[5]++;
1057 if (macbase[5] == 0) {
1058 macbase[4]++;
1059 if (macbase[4] == 0) {
1060 macbase[3]++;
1061 if (macbase[3] == 0) {
1062 macbase[0] = 0;
1063 macbase[1] = 0;
1064 macbase[2] = 0;
1065 }
1066 }
1067 }
1068 }
1069 }
1070
1071 printf("%s v%u len=%u\n", eeprom_hdr->signature, eeprom_hdr->version,
1072 be16_to_cpu(eeprom_hdr->totallen));
1073
1074 return 0;
1075}
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089int populate_serial_number(void)
1090{
1091 char serialstr[257];
1092 int eeprom_index;
1093 struct tlvinfo_tlv *eeprom_tlv;
1094
1095 if (env_get("serial#"))
1096 return 0;
1097
1098 if (read_eeprom(eeprom)) {
1099 printf("Read failed.\n");
1100 return -1;
1101 }
1102
1103 if (tlvinfo_find_tlv(eeprom, TLV_CODE_SERIAL_NUMBER, &eeprom_index)) {
1104 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
1105 memcpy(serialstr, eeprom_tlv->value, eeprom_tlv->length);
1106 serialstr[eeprom_tlv->length] = 0;
1107 env_set("serial#", serialstr);
1108 }
1109
1110 return 0;
1111}
1112