blob: 636c1fe32ef77fc827918d103fdf50ea3187d533 [file] [log] [blame]
Baruch Siach1c79f2f2020-01-21 15:44:54 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * See file CREDITS for list of people who contributed to this
4 * project.
5 *
6 * Copyright (C) 2013 Curt Brune <curt@cumulusnetworks.com>
7 * Copyright (C) 2014 Srideep <srideep_devireddy@dell.com>
8 * Copyright (C) 2013 Miles Tseng <miles_tseng@accton.com>
9 * Copyright (C) 2014,2016 david_yang <david_yang@accton.com>
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>
Simon Glass691d7192020-05-10 11:40:02 -060018#include <init.h>
Simon Glass90526e92020-05-10 11:39:56 -060019#include <net.h>
Simon Glass401d1c42020-10-30 21:38:53 -060020#include <asm/global_data.h>
Baruch Siach1c79f2f2020-01-21 15:44:54 +020021#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/* File scope function prototypes */
31static bool is_checksum_valid(u8 *eeprom);
Josua Mayerdfda0c02023-05-05 11:20:46 +030032static int read_eeprom(int devnum, u8 *eeprom);
33static void show_eeprom(int devnum, u8 *eeprom);
Baruch Siach1c79f2f2020-01-21 15:44:54 +020034static void decode_tlv(struct tlvinfo_tlv *tlv);
35static void update_crc(u8 *eeprom);
Josua Mayerdfda0c02023-05-05 11:20:46 +030036static int prog_eeprom(int devnum, u8 *eeprom);
Baruch Siach1c79f2f2020-01-21 15:44:54 +020037static 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);
Josua Mayerdfda0c02023-05-05 11:20:46 +030043static void show_tlv_devices(int current_dev);
Baruch Siach1c79f2f2020-01-21 15:44:54 +020044
Baruch Siach1c79f2f2020-01-21 15:44:54 +020045/* The EERPOM contents after being read into memory */
46static u8 eeprom[TLV_INFO_MAX_LEN];
47
48static struct udevice *tlv_devices[MAX_TLV_DEVICES];
Baruch Siach1c79f2f2020-01-21 15:44:54 +020049
50#define to_header(p) ((struct tlvinfo_header *)p)
51#define to_entry(p) ((struct tlvinfo_tlv *)p)
52
53#define HDR_SIZE sizeof(struct tlvinfo_header)
54#define ENT_SIZE sizeof(struct tlvinfo_tlv)
55
56static inline bool is_digit(char c)
57{
58 return (c >= '0' && c <= '9');
59}
60
61/**
62 * is_valid_tlv
63 *
64 * Perform basic sanity checks on a TLV field. The TLV is pointed to
65 * by the parameter provided.
66 * 1. The type code is not reserved (0x00 or 0xFF)
67 */
68static inline bool is_valid_tlv(struct tlvinfo_tlv *tlv)
69{
70 return((tlv->type != 0x00) && (tlv->type != 0xFF));
71}
72
73/**
74 * is_hex
75 *
76 * Tests if character is an ASCII hex digit
77 */
78static inline u8 is_hex(char p)
79{
80 return (((p >= '0') && (p <= '9')) ||
81 ((p >= 'A') && (p <= 'F')) ||
82 ((p >= 'a') && (p <= 'f')));
83}
84
85/**
86 * is_checksum_valid
87 *
88 * Validate the checksum in the provided TlvInfo EEPROM data. First,
89 * verify that the TlvInfo header is valid, then make sure the last
90 * TLV is a CRC-32 TLV. Then calculate the CRC over the EEPROM data
91 * and compare it to the value stored in the EEPROM CRC-32 TLV.
92 */
93static bool is_checksum_valid(u8 *eeprom)
94{
95 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
96 struct tlvinfo_tlv *eeprom_crc;
97 unsigned int calc_crc;
98 unsigned int stored_crc;
99
100 // Is the eeprom header valid?
101 if (!is_valid_tlvinfo_header(eeprom_hdr))
102 return false;
103
104 // Is the last TLV a CRC?
105 eeprom_crc = to_entry(&eeprom[HDR_SIZE +
106 be16_to_cpu(eeprom_hdr->totallen) - (ENT_SIZE + 4)]);
107 if (eeprom_crc->type != TLV_CODE_CRC_32 || eeprom_crc->length != 4)
108 return false;
109
110 // Calculate the checksum
111 calc_crc = crc32(0, (void *)eeprom,
112 HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen) - 4);
113 stored_crc = (eeprom_crc->value[0] << 24) |
114 (eeprom_crc->value[1] << 16) |
115 (eeprom_crc->value[2] << 8) |
116 eeprom_crc->value[3];
117 return calc_crc == stored_crc;
118}
119
120/**
121 * read_eeprom
122 *
123 * Read the EEPROM into memory, if it hasn't already been read.
124 */
Josua Mayerdfda0c02023-05-05 11:20:46 +0300125static int read_eeprom(int devnum, u8 *eeprom)
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200126{
127 int ret;
128 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
129 struct tlvinfo_tlv *eeprom_tlv = to_entry(&eeprom[HDR_SIZE]);
130
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200131 /* Read the header */
Josua Mayerdfda0c02023-05-05 11:20:46 +0300132 ret = read_tlv_eeprom((void *)eeprom_hdr, 0, HDR_SIZE, devnum);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200133 /* If the header was successfully read, read the TLVs */
134 if (ret == 0 && is_valid_tlvinfo_header(eeprom_hdr))
135 ret = read_tlv_eeprom((void *)eeprom_tlv, HDR_SIZE,
Josua Mayerdfda0c02023-05-05 11:20:46 +0300136 be16_to_cpu(eeprom_hdr->totallen), devnum);
Josua Mayerf6eff352023-05-05 11:20:48 +0300137 else if (ret == -ENODEV)
138 return ret;
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200139
140 // If the contents are invalid, start over with default contents
141 if (!is_valid_tlvinfo_header(eeprom_hdr) ||
142 !is_checksum_valid(eeprom)) {
143 strcpy(eeprom_hdr->signature, TLV_INFO_ID_STRING);
144 eeprom_hdr->version = TLV_INFO_VERSION;
145 eeprom_hdr->totallen = cpu_to_be16(0);
146 update_crc(eeprom);
147 }
148
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200149#ifdef DEBUG
Josua Mayer425d9632023-05-05 11:20:47 +0300150 show_eeprom(devnum, eeprom);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200151#endif
152
153 return ret;
154}
155
156/**
157 * show_eeprom
158 *
159 * Display the contents of the EEPROM
160 */
Josua Mayerdfda0c02023-05-05 11:20:46 +0300161static void show_eeprom(int devnum, u8 *eeprom)
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200162{
163 int tlv_end;
164 int curr_tlv;
Sven Auhagenee8ce382021-09-12 09:25:44 +0200165#ifdef DEBUG
166 int i;
167#endif
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200168 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
169 struct tlvinfo_tlv *eeprom_tlv;
170
171 if (!is_valid_tlvinfo_header(eeprom_hdr)) {
172 printf("EEPROM does not contain data in a valid TlvInfo format.\n");
173 return;
174 }
175
Josua Mayerdfda0c02023-05-05 11:20:46 +0300176 printf("TLV: %u\n", devnum);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200177 printf("TlvInfo Header:\n");
178 printf(" Id String: %s\n", eeprom_hdr->signature);
179 printf(" Version: %d\n", eeprom_hdr->version);
180 printf(" Total Length: %d\n", be16_to_cpu(eeprom_hdr->totallen));
181
182 printf("TLV Name Code Len Value\n");
183 printf("-------------------- ---- --- -----\n");
184 curr_tlv = HDR_SIZE;
185 tlv_end = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
186 while (curr_tlv < tlv_end) {
187 eeprom_tlv = to_entry(&eeprom[curr_tlv]);
188 if (!is_valid_tlv(eeprom_tlv)) {
189 printf("Invalid TLV field starting at EEPROM offset %d\n",
190 curr_tlv);
191 return;
192 }
193 decode_tlv(eeprom_tlv);
194 curr_tlv += ENT_SIZE + eeprom_tlv->length;
195 }
196
197 printf("Checksum is %s.\n",
198 is_checksum_valid(eeprom) ? "valid" : "invalid");
199
200#ifdef DEBUG
201 printf("EEPROM dump: (0x%x bytes)", TLV_INFO_MAX_LEN);
202 for (i = 0; i < TLV_INFO_MAX_LEN; i++) {
203 if ((i % 16) == 0)
204 printf("\n%02X: ", i);
205 printf("%02X ", eeprom[i]);
206 }
207 printf("\n");
208#endif
209}
210
211/**
212 * Struct for displaying the TLV codes and names.
213 */
214struct tlv_code_desc {
215 u8 m_code;
216 char *m_name;
217};
218
219/**
220 * List of TLV codes and names.
221 */
222static struct tlv_code_desc tlv_code_list[] = {
223 { TLV_CODE_PRODUCT_NAME, "Product Name"},
224 { TLV_CODE_PART_NUMBER, "Part Number"},
225 { TLV_CODE_SERIAL_NUMBER, "Serial Number"},
226 { TLV_CODE_MAC_BASE, "Base MAC Address"},
227 { TLV_CODE_MANUF_DATE, "Manufacture Date"},
228 { TLV_CODE_DEVICE_VERSION, "Device Version"},
229 { TLV_CODE_LABEL_REVISION, "Label Revision"},
230 { TLV_CODE_PLATFORM_NAME, "Platform Name"},
231 { TLV_CODE_ONIE_VERSION, "ONIE Version"},
232 { TLV_CODE_MAC_SIZE, "MAC Addresses"},
233 { TLV_CODE_MANUF_NAME, "Manufacturer"},
234 { TLV_CODE_MANUF_COUNTRY, "Country Code"},
235 { TLV_CODE_VENDOR_NAME, "Vendor Name"},
236 { TLV_CODE_DIAG_VERSION, "Diag Version"},
237 { TLV_CODE_SERVICE_TAG, "Service Tag"},
238 { TLV_CODE_VENDOR_EXT, "Vendor Extension"},
239 { TLV_CODE_CRC_32, "CRC-32"},
240};
241
242/**
243 * Look up a TLV name by its type.
244 */
245static inline const char *tlv_type2name(u8 type)
246{
247 char *name = "Unknown";
248 int i;
249
250 for (i = 0; i < ARRAY_SIZE(tlv_code_list); i++) {
251 if (tlv_code_list[i].m_code == type) {
252 name = tlv_code_list[i].m_name;
253 break;
254 }
255 }
256
257 return name;
258}
259
260/*
261 * decode_tlv
262 *
263 * Print a string representing the contents of the TLV field. The format of
264 * the string is:
265 * 1. The name of the field left justified in 20 characters
266 * 2. The type code in hex right justified in 5 characters
267 * 3. The length in decimal right justified in 4 characters
268 * 4. The value, left justified in however many characters it takes
269 * The validity of EEPROM contents and the TLV field have been verified
270 * prior to calling this function.
271 */
272#define DECODE_NAME_MAX 20
273
274/*
275 * The max decode value is currently for the 'raw' type or the 'vendor
276 * extension' type, both of which have the same decode format. The
277 * max decode string size is computed as follows:
278 *
279 * strlen(" 0xFF") * TLV_VALUE_MAX_LEN + 1
280 *
281 */
282#define DECODE_VALUE_MAX ((5 * TLV_VALUE_MAX_LEN) + 1)
283
284static void decode_tlv(struct tlvinfo_tlv *tlv)
285{
286 char name[DECODE_NAME_MAX];
287 char value[DECODE_VALUE_MAX];
288 int i;
289
290 strncpy(name, tlv_type2name(tlv->type), DECODE_NAME_MAX);
291
292 switch (tlv->type) {
293 case TLV_CODE_PRODUCT_NAME:
294 case TLV_CODE_PART_NUMBER:
295 case TLV_CODE_SERIAL_NUMBER:
296 case TLV_CODE_MANUF_DATE:
297 case TLV_CODE_LABEL_REVISION:
298 case TLV_CODE_PLATFORM_NAME:
299 case TLV_CODE_ONIE_VERSION:
300 case TLV_CODE_MANUF_NAME:
301 case TLV_CODE_MANUF_COUNTRY:
302 case TLV_CODE_VENDOR_NAME:
303 case TLV_CODE_DIAG_VERSION:
304 case TLV_CODE_SERVICE_TAG:
305 memcpy(value, tlv->value, tlv->length);
306 value[tlv->length] = 0;
307 break;
308 case TLV_CODE_MAC_BASE:
309 sprintf(value, "%02X:%02X:%02X:%02X:%02X:%02X",
310 tlv->value[0], tlv->value[1], tlv->value[2],
311 tlv->value[3], tlv->value[4], tlv->value[5]);
312 break;
313 case TLV_CODE_DEVICE_VERSION:
314 sprintf(value, "%u", tlv->value[0]);
315 break;
316 case TLV_CODE_MAC_SIZE:
317 sprintf(value, "%u", (tlv->value[0] << 8) | tlv->value[1]);
318 break;
319 case TLV_CODE_VENDOR_EXT:
320 value[0] = 0;
321 for (i = 0; (i < (DECODE_VALUE_MAX / 5)) && (i < tlv->length);
322 i++) {
323 sprintf(value, "%s 0x%02X", value, tlv->value[i]);
324 }
325 break;
326 case TLV_CODE_CRC_32:
327 sprintf(value, "0x%02X%02X%02X%02X",
328 tlv->value[0], tlv->value[1],
329 tlv->value[2], tlv->value[3]);
330 break;
331 default:
332 value[0] = 0;
333 for (i = 0; (i < (DECODE_VALUE_MAX / 5)) && (i < tlv->length);
334 i++) {
335 sprintf(value, "%s 0x%02X", value, tlv->value[i]);
336 }
337 break;
338 }
339
340 name[DECODE_NAME_MAX - 1] = 0;
341 printf("%-20s 0x%02X %3d %s\n", name, tlv->type, tlv->length, value);
342}
343
344/**
345 * update_crc
346 *
347 * This function updates the CRC-32 TLV. If there is no CRC-32 TLV, then
348 * one is added. This function should be called after each update to the
349 * EEPROM structure, to make sure the CRC is always correct.
350 */
351static void update_crc(u8 *eeprom)
352{
353 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
354 struct tlvinfo_tlv *eeprom_crc;
355 unsigned int calc_crc;
356 int eeprom_index;
357
358 // Discover the CRC TLV
359 if (!tlvinfo_find_tlv(eeprom, TLV_CODE_CRC_32, &eeprom_index)) {
360 unsigned int totallen = be16_to_cpu(eeprom_hdr->totallen);
361
362 if ((totallen + ENT_SIZE + 4) > TLV_TOTAL_LEN_MAX)
363 return;
364 eeprom_index = HDR_SIZE + totallen;
365 eeprom_hdr->totallen = cpu_to_be16(totallen + ENT_SIZE + 4);
366 }
367 eeprom_crc = to_entry(&eeprom[eeprom_index]);
368 eeprom_crc->type = TLV_CODE_CRC_32;
369 eeprom_crc->length = 4;
370
371 // Calculate the checksum
372 calc_crc = crc32(0, (void *)eeprom,
373 HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen) - 4);
374 eeprom_crc->value[0] = (calc_crc >> 24) & 0xFF;
375 eeprom_crc->value[1] = (calc_crc >> 16) & 0xFF;
376 eeprom_crc->value[2] = (calc_crc >> 8) & 0xFF;
377 eeprom_crc->value[3] = (calc_crc >> 0) & 0xFF;
378}
379
380/**
381 * prog_eeprom
382 *
383 * Write the EEPROM data from CPU memory to the hardware.
384 */
Josua Mayerdfda0c02023-05-05 11:20:46 +0300385static int prog_eeprom(int devnum, u8 *eeprom)
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200386{
387 int ret = 0;
388 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
389 int eeprom_len;
390
391 update_crc(eeprom);
392
393 eeprom_len = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
Josua Mayerdfda0c02023-05-05 11:20:46 +0300394 ret = write_tlv_eeprom(eeprom, eeprom_len, devnum);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200395 if (ret) {
396 printf("Programming failed.\n");
397 return -1;
398 }
399
400 printf("Programming passed.\n");
401 return 0;
402}
403
404/**
405 * show_tlv_code_list - Display the list of TLV codes and names
406 */
407void show_tlv_code_list(void)
408{
409 int i;
410
411 printf("TLV Code TLV Name\n");
412 printf("======== =================\n");
413 for (i = 0; i < ARRAY_SIZE(tlv_code_list); i++) {
414 printf("0x%02X %s\n",
415 tlv_code_list[i].m_code,
416 tlv_code_list[i].m_name);
417 }
418}
419
420/**
421 * do_tlv_eeprom
422 *
423 * This function implements the tlv_eeprom command.
424 */
Simon Glass09140112020-05-10 11:40:03 -0600425int do_tlv_eeprom(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200426{
427 char cmd;
428 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
Josua Mayerdfda0c02023-05-05 11:20:46 +0300429 static unsigned int current_dev;
Josua Mayer425d9632023-05-05 11:20:47 +0300430 /* Set to 1 if we've read EEPROM into memory */
431 static int has_been_read;
432 int ret;
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200433
434 // If no arguments, read the EERPOM and display its contents
435 if (argc == 1) {
Josua Mayer425d9632023-05-05 11:20:47 +0300436 if (!has_been_read) {
Josua Mayerf6eff352023-05-05 11:20:48 +0300437 ret = read_eeprom(current_dev, eeprom);
438 if (ret) {
439 printf("Failed to read EEPROM data from device.\n");
440 return 0;
441 }
442
443 has_been_read = 1;
Josua Mayer425d9632023-05-05 11:20:47 +0300444 }
Josua Mayerdfda0c02023-05-05 11:20:46 +0300445 show_eeprom(current_dev, eeprom);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200446 return 0;
447 }
448
449 // We only look at the first character to the command, so "read" and
450 // "reset" will both be treated as "read".
451 cmd = argv[1][0];
452
453 // Read the EEPROM contents
454 if (cmd == 'r') {
455 has_been_read = 0;
Josua Mayerf6eff352023-05-05 11:20:48 +0300456 ret = read_eeprom(current_dev, eeprom);
457 if (ret) {
458 printf("Failed to read EEPROM data from device.\n");
459 return 0;
Josua Mayer425d9632023-05-05 11:20:47 +0300460 }
Josua Mayerf6eff352023-05-05 11:20:48 +0300461
462 printf("EEPROM data loaded from device to memory.\n");
463 has_been_read = 1;
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200464 }
465
466 // Subsequent commands require that the EEPROM has already been read.
467 if (!has_been_read) {
468 printf("Please read the EEPROM data first, using the 'tlv_eeprom read' command.\n");
469 return 0;
470 }
471
472 // Handle the commands that don't take parameters
473 if (argc == 2) {
474 switch (cmd) {
475 case 'w': /* write */
Josua Mayerdfda0c02023-05-05 11:20:46 +0300476 prog_eeprom(current_dev, eeprom);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200477 break;
478 case 'e': /* erase */
479 strcpy(eeprom_hdr->signature, TLV_INFO_ID_STRING);
480 eeprom_hdr->version = TLV_INFO_VERSION;
481 eeprom_hdr->totallen = cpu_to_be16(0);
482 update_crc(eeprom);
483 printf("EEPROM data in memory reset.\n");
484 break;
485 case 'l': /* list */
486 show_tlv_code_list();
487 break;
488 case 'd': /* dev */
Josua Mayerdfda0c02023-05-05 11:20:46 +0300489 show_tlv_devices(current_dev);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200490 break;
491 default:
Heinrich Schuchardt93a80c12023-01-27 22:49:10 +0100492 return CMD_RET_USAGE;
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200493 }
494 return 0;
495 }
496
497 // The set command takes one or two args.
Heinrich Schuchardt93a80c12023-01-27 22:49:10 +0100498 if (argc > 4)
499 return CMD_RET_USAGE;
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200500
501 // Set command. If the TLV exists in the EEPROM, delete it. Then if
502 // data was supplied for this TLV add the TLV with the new contents at
503 // the end.
504 if (cmd == 's') {
505 int tcode;
506
507 tcode = simple_strtoul(argv[2], NULL, 0);
508 tlvinfo_delete_tlv(eeprom, tcode);
509 if (argc == 4)
510 tlvinfo_add_tlv(eeprom, tcode, argv[3]);
511 } else if (cmd == 'd') { /* 'dev' command */
512 unsigned int devnum;
513
514 devnum = simple_strtoul(argv[2], NULL, 0);
515 if (devnum > MAX_TLV_DEVICES || !tlv_devices[devnum]) {
516 printf("Invalid device number\n");
517 return 0;
518 }
519 current_dev = devnum;
520 has_been_read = 0;
521 } else {
Heinrich Schuchardt93a80c12023-01-27 22:49:10 +0100522 return CMD_RET_USAGE;
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200523 }
524
525 return 0;
526}
527
528/**
529 * This macro defines the tlv_eeprom command line command.
530 */
531U_BOOT_CMD(tlv_eeprom, 4, 1, do_tlv_eeprom,
532 "Display and program the system EEPROM data block.",
533 "[read|write|set <type_code> <string_value>|erase|list]\n"
534 "tlv_eeprom\n"
535 " - With no arguments display the current contents.\n"
536 "tlv_eeprom dev [dev]\n"
537 " - List devices or set current EEPROM device.\n"
538 "tlv_eeprom read\n"
539 " - Load EEPROM data from device to memory.\n"
540 "tlv_eeprom write\n"
541 " - Write the EEPROM data to persistent storage.\n"
542 "tlv_eeprom set <type_code> <string_value>\n"
543 " - Set a field to a value.\n"
544 " - If no string_value, field is deleted.\n"
545 " - Use 'tlv_eeprom write' to make changes permanent.\n"
546 "tlv_eeprom erase\n"
547 " - Reset the in memory EEPROM data.\n"
548 " - Use 'tlv_eeprom read' to refresh the in memory EEPROM data.\n"
549 " - Use 'tlv_eeprom write' to make changes permanent.\n"
550 "tlv_eeprom list\n"
551 " - List the understood TLV codes and names.\n"
552 );
553
554/**
555 * tlvinfo_find_tlv
556 *
557 * This function finds the TLV with the supplied code in the EERPOM.
558 * An offset from the beginning of the EEPROM is returned in the
559 * eeprom_index parameter if the TLV is found.
560 */
561static bool tlvinfo_find_tlv(u8 *eeprom, u8 tcode, int *eeprom_index)
562{
563 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
564 struct tlvinfo_tlv *eeprom_tlv;
565 int eeprom_end;
566
567 // Search through the TLVs, looking for the first one which matches the
568 // supplied type code.
569 *eeprom_index = HDR_SIZE;
570 eeprom_end = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
571 while (*eeprom_index < eeprom_end) {
572 eeprom_tlv = to_entry(&eeprom[*eeprom_index]);
573 if (!is_valid_tlv(eeprom_tlv))
574 return false;
575 if (eeprom_tlv->type == tcode)
576 return true;
577 *eeprom_index += ENT_SIZE + eeprom_tlv->length;
578 }
579 return(false);
580}
581
582/**
583 * tlvinfo_delete_tlv
584 *
585 * This function deletes the TLV with the specified type code from the
586 * EEPROM.
587 */
588static bool tlvinfo_delete_tlv(u8 *eeprom, u8 code)
589{
590 int eeprom_index;
591 int tlength;
592 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
593 struct tlvinfo_tlv *eeprom_tlv;
594
595 // Find the TLV and then move all following TLVs "forward"
596 if (tlvinfo_find_tlv(eeprom, code, &eeprom_index)) {
597 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
598 tlength = ENT_SIZE + eeprom_tlv->length;
599 memcpy(&eeprom[eeprom_index], &eeprom[eeprom_index + tlength],
600 HDR_SIZE +
601 be16_to_cpu(eeprom_hdr->totallen) - eeprom_index -
602 tlength);
603 eeprom_hdr->totallen =
604 cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) -
605 tlength);
606 update_crc(eeprom);
607 return true;
608 }
609 return false;
610}
611
612/**
613 * tlvinfo_add_tlv
614 *
615 * This function adds a TLV to the EEPROM, converting the value (a string) to
616 * the format in which it will be stored in the EEPROM.
617 */
618#define MAX_TLV_VALUE_LEN 256
619static bool tlvinfo_add_tlv(u8 *eeprom, int tcode, char *strval)
620{
621 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
622 struct tlvinfo_tlv *eeprom_tlv;
623 int new_tlv_len = 0;
624 u32 value;
625 char data[MAX_TLV_VALUE_LEN];
626 int eeprom_index;
627
628 // Encode each TLV type into the format to be stored in the EERPOM
629 switch (tcode) {
630 case TLV_CODE_PRODUCT_NAME:
631 case TLV_CODE_PART_NUMBER:
632 case TLV_CODE_SERIAL_NUMBER:
633 case TLV_CODE_LABEL_REVISION:
634 case TLV_CODE_PLATFORM_NAME:
635 case TLV_CODE_ONIE_VERSION:
636 case TLV_CODE_MANUF_NAME:
637 case TLV_CODE_MANUF_COUNTRY:
638 case TLV_CODE_VENDOR_NAME:
639 case TLV_CODE_DIAG_VERSION:
640 case TLV_CODE_SERVICE_TAG:
641 strncpy(data, strval, MAX_TLV_VALUE_LEN);
642 new_tlv_len = min_t(size_t, MAX_TLV_VALUE_LEN, strlen(strval));
643 break;
644 case TLV_CODE_DEVICE_VERSION:
645 value = simple_strtoul(strval, NULL, 0);
646 if (value >= 256) {
647 printf("ERROR: Device version must be 255 or less. Value supplied: %u",
648 value);
649 return false;
650 }
651 data[0] = value & 0xFF;
652 new_tlv_len = 1;
653 break;
654 case TLV_CODE_MAC_SIZE:
655 value = simple_strtoul(strval, NULL, 0);
656 if (value >= 65536) {
657 printf("ERROR: MAC Size must be 65535 or less. Value supplied: %u",
658 value);
659 return false;
660 }
661 data[0] = (value >> 8) & 0xFF;
662 data[1] = value & 0xFF;
663 new_tlv_len = 2;
664 break;
665 case TLV_CODE_MANUF_DATE:
666 if (set_date(data, strval) != 0)
667 return false;
668 new_tlv_len = 19;
669 break;
670 case TLV_CODE_MAC_BASE:
671 if (set_mac(data, strval) != 0)
672 return false;
673 new_tlv_len = 6;
674 break;
675 case TLV_CODE_CRC_32:
676 printf("WARNING: The CRC TLV is set automatically and cannot be set manually.\n");
677 return false;
678 case TLV_CODE_VENDOR_EXT:
679 default:
680 if (set_bytes(data, strval, &new_tlv_len) != 0)
681 return false;
682 break;
683 }
684
685 // Is there room for this TLV?
686 if ((be16_to_cpu(eeprom_hdr->totallen) + ENT_SIZE + new_tlv_len) >
687 TLV_TOTAL_LEN_MAX) {
688 printf("ERROR: There is not enough room in the EERPOM to save data.\n");
689 return false;
690 }
691
692 // Add TLV at the end, overwriting CRC TLV if it exists
693 if (tlvinfo_find_tlv(eeprom, TLV_CODE_CRC_32, &eeprom_index))
694 eeprom_hdr->totallen =
695 cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) -
696 ENT_SIZE - 4);
697 else
698 eeprom_index = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
699 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
700 eeprom_tlv->type = tcode;
701 eeprom_tlv->length = new_tlv_len;
702 memcpy(eeprom_tlv->value, data, new_tlv_len);
703
704 // Update the total length and calculate (add) a new CRC-32 TLV
705 eeprom_hdr->totallen = cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) +
706 ENT_SIZE + new_tlv_len);
707 update_crc(eeprom);
708
709 return true;
710}
711
712/**
713 * set_mac
714 *
715 * Converts a string MAC address into a binary buffer.
716 *
717 * This function takes a pointer to a MAC address string
718 * (i.e."XX:XX:XX:XX:XX:XX", where "XX" is a two-digit hex number).
719 * The string format is verified and then converted to binary and
720 * stored in a buffer.
721 */
722static int set_mac(char *buf, const char *string)
723{
724 char *p = (char *)string;
725 int i;
726 int err = 0;
727 char *end;
728
729 if (!p) {
730 printf("ERROR: NULL mac addr string passed in.\n");
731 return -1;
732 }
733
734 if (strlen(p) != 17) {
735 printf("ERROR: MAC address strlen() != 17 -- %zu\n", strlen(p));
736 printf("ERROR: Bad MAC address format: %s\n", string);
737 return -1;
738 }
739
740 for (i = 0; i < 17; i++) {
741 if ((i % 3) == 2) {
742 if (p[i] != ':') {
743 err++;
744 printf("ERROR: mac: p[%i] != :, found: `%c'\n",
745 i, p[i]);
746 break;
747 }
748 continue;
749 } else if (!is_hex(p[i])) {
750 err++;
751 printf("ERROR: mac: p[%i] != hex digit, found: `%c'\n",
752 i, p[i]);
753 break;
754 }
755 }
756
757 if (err != 0) {
758 printf("ERROR: Bad MAC address format: %s\n", string);
759 return -1;
760 }
761
762 /* Convert string to binary */
763 for (i = 0, p = (char *)string; i < 6; i++) {
Simon Glass7e5f4602021-07-24 09:03:29 -0600764 buf[i] = p ? hextoul(p, &end) : 0;
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200765 if (p)
766 p = (*end) ? end + 1 : end;
767 }
768
769 if (!is_valid_ethaddr((u8 *)buf)) {
770 printf("ERROR: MAC address must not be 00:00:00:00:00:00, a multicast address or FF:FF:FF:FF:FF:FF.\n");
771 printf("ERROR: Bad MAC address format: %s\n", string);
772 return -1;
773 }
774
775 return 0;
776}
777
778/**
779 * set_date
780 *
781 * Validates the format of the data string
782 *
783 * This function takes a pointer to a date string (i.e. MM/DD/YYYY hh:mm:ss)
784 * and validates that the format is correct. If so the string is copied
785 * to the supplied buffer.
786 */
787static int set_date(char *buf, const char *string)
788{
789 int i;
790
791 if (!string) {
792 printf("ERROR: NULL date string passed in.\n");
793 return -1;
794 }
795
796 if (strlen(string) != 19) {
797 printf("ERROR: Date strlen() != 19 -- %zu\n", strlen(string));
798 printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
799 string);
800 return -1;
801 }
802
803 for (i = 0; string[i] != 0; i++) {
804 switch (i) {
805 case 2:
806 case 5:
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 10:
814 if (string[i] != ' ') {
815 printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
816 string);
817 return -1;
818 }
819 break;
820 case 13:
821 case 16:
822 if (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 default:
829 if (!is_digit(string[i])) {
830 printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
831 string);
832 return -1;
833 }
834 break;
835 }
836 }
837
838 strcpy(buf, string);
839 return 0;
840}
841
842/**
843 * set_bytes
844 *
845 * Converts a space-separated string of decimal numbers into a
846 * buffer of bytes.
847 *
848 * This function takes a pointer to a space-separated string of decimal
849 * numbers (i.e. "128 0x55 0321") with "C" standard radix specifiers
850 * and converts them to an array of bytes.
851 */
852static int set_bytes(char *buf, const char *string, int *converted_accum)
853{
854 char *p = (char *)string;
855 int i;
856 uint byte;
857
858 if (!p) {
859 printf("ERROR: NULL string passed in.\n");
860 return -1;
861 }
862
863 /* Convert string to bytes */
864 for (i = 0, p = (char *)string; (i < TLV_VALUE_MAX_LEN) && (*p != 0);
865 i++) {
866 while ((*p == ' ') || (*p == '\t') || (*p == ',') ||
867 (*p == ';')) {
868 p++;
869 }
870 if (*p != 0) {
871 if (!is_digit(*p)) {
872 printf("ERROR: Non-digit found in byte string: (%s)\n",
873 string);
874 return -1;
875 }
876 byte = simple_strtoul(p, &p, 0);
877 if (byte >= 256) {
878 printf("ERROR: The value specified is greater than 255: (%u) in string: %s\n",
879 byte, string);
880 return -1;
881 }
882 buf[i] = byte & 0xFF;
883 }
884 }
885
886 if (i == TLV_VALUE_MAX_LEN && (*p != 0)) {
887 printf("ERROR: Trying to assign too many bytes (max: %d) in string: %s\n",
888 TLV_VALUE_MAX_LEN, string);
889 return -1;
890 }
891
892 *converted_accum = i;
893 return 0;
894}
895
Josua Mayerdfda0c02023-05-05 11:20:46 +0300896static void show_tlv_devices(int current_dev)
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200897{
898 unsigned int dev;
899
900 for (dev = 0; dev < MAX_TLV_DEVICES; dev++)
901 if (tlv_devices[dev])
902 printf("TLV: %u%s\n", dev,
903 (dev == current_dev) ? " (*)" : "");
904}
905
906static int find_tlv_devices(struct udevice **tlv_devices_p)
907{
908 int ret;
909 int count_dev = 0;
910 struct udevice *dev;
911
912 for (ret = uclass_first_device_check(UCLASS_I2C_EEPROM, &dev);
913 dev;
914 ret = uclass_next_device_check(&dev)) {
915 if (ret == 0)
916 tlv_devices_p[count_dev++] = dev;
917 if (count_dev >= MAX_TLV_DEVICES)
918 break;
919 }
920
921 return (count_dev == 0) ? -ENODEV : 0;
922}
923
924static struct udevice *find_tlv_device_by_index(int dev_num)
925{
926 struct udevice *local_tlv_devices[MAX_TLV_DEVICES] = {};
927 struct udevice **tlv_devices_p;
928 int ret;
929
930 if (gd->flags & (GD_FLG_RELOC | GD_FLG_SPL_INIT)) {
931 /* Assume BSS is initialized; use static data */
932 if (tlv_devices[dev_num])
933 return tlv_devices[dev_num];
934 tlv_devices_p = tlv_devices;
935 } else {
936 tlv_devices_p = local_tlv_devices;
937 }
938
939 ret = find_tlv_devices(tlv_devices_p);
940 if (ret == 0 && tlv_devices_p[dev_num])
941 return tlv_devices_p[dev_num];
942
943 return NULL;
944}
945
946/**
947 * read_tlv_eeprom - read the hwinfo from i2c EEPROM
948 */
949int read_tlv_eeprom(void *eeprom, int offset, int len, int dev_num)
950{
951 struct udevice *dev;
952
953 if (dev_num >= MAX_TLV_DEVICES)
954 return -EINVAL;
955
956 dev = find_tlv_device_by_index(dev_num);
957 if (!dev)
958 return -ENODEV;
959
960 return i2c_eeprom_read(dev, offset, eeprom, len);
961}
962
963/**
964 * write_tlv_eeprom - write the hwinfo to i2c EEPROM
965 */
Josua Mayerdfda0c02023-05-05 11:20:46 +0300966int write_tlv_eeprom(void *eeprom, int len, int dev)
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200967{
968 if (!(gd->flags & GD_FLG_RELOC))
969 return -ENODEV;
Josua Mayerdfda0c02023-05-05 11:20:46 +0300970 if (!tlv_devices[dev])
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200971 return -ENODEV;
972
Josua Mayerdfda0c02023-05-05 11:20:46 +0300973 return i2c_eeprom_write(tlv_devices[dev], 0, eeprom, len);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200974}
975
976int read_tlvinfo_tlv_eeprom(void *eeprom, struct tlvinfo_header **hdr,
977 struct tlvinfo_tlv **first_entry, int dev_num)
978{
979 int ret;
980 struct tlvinfo_header *tlv_hdr;
981 struct tlvinfo_tlv *tlv_ent;
982
983 /* Read TLV header */
984 ret = read_tlv_eeprom(eeprom, 0, HDR_SIZE, dev_num);
985 if (ret < 0)
986 return ret;
987
988 tlv_hdr = eeprom;
989 if (!is_valid_tlvinfo_header(tlv_hdr))
990 return -EINVAL;
991
992 /* Read TLV entries */
993 tlv_ent = to_entry(&tlv_hdr[1]);
994 ret = read_tlv_eeprom(tlv_ent, HDR_SIZE,
995 be16_to_cpu(tlv_hdr->totallen), dev_num);
996 if (ret < 0)
997 return ret;
998 if (!is_checksum_valid(eeprom))
999 return -EINVAL;
1000
1001 *hdr = tlv_hdr;
1002 *first_entry = tlv_ent;
1003
1004 return 0;
1005}
1006
1007/**
1008 * mac_read_from_eeprom
1009 *
1010 * Read the MAC addresses from EEPROM
1011 *
1012 * This function reads the MAC addresses from EEPROM and sets the
1013 * appropriate environment variables for each one read.
1014 *
1015 * The environment variables are only set if they haven't been set already.
1016 * This ensures that any user-saved variables are never overwritten.
1017 *
1018 * This function must be called after relocation.
1019 */
1020int mac_read_from_eeprom(void)
1021{
1022 unsigned int i;
1023 int eeprom_index;
1024 struct tlvinfo_tlv *eeprom_tlv;
1025 int maccount;
1026 u8 macbase[6];
1027 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
Josua Mayerdfda0c02023-05-05 11:20:46 +03001028 int devnum = 0; // TODO: support multiple EEPROMs
Baruch Siach1c79f2f2020-01-21 15:44:54 +02001029
1030 puts("EEPROM: ");
1031
Josua Mayerdfda0c02023-05-05 11:20:46 +03001032 if (read_eeprom(devnum, eeprom)) {
Baruch Siach1c79f2f2020-01-21 15:44:54 +02001033 printf("Read failed.\n");
1034 return -1;
1035 }
1036
1037 maccount = 1;
1038 if (tlvinfo_find_tlv(eeprom, TLV_CODE_MAC_SIZE, &eeprom_index)) {
1039 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
1040 maccount = (eeprom_tlv->value[0] << 8) | eeprom_tlv->value[1];
1041 }
1042
1043 memcpy(macbase, "\0\0\0\0\0\0", 6);
1044 if (tlvinfo_find_tlv(eeprom, TLV_CODE_MAC_BASE, &eeprom_index)) {
1045 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
1046 memcpy(macbase, eeprom_tlv->value, 6);
1047 }
1048
1049 for (i = 0; i < maccount; i++) {
1050 if (is_valid_ethaddr(macbase)) {
1051 char ethaddr[18];
1052 char enetvar[11];
1053
1054 sprintf(ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
1055 macbase[0], macbase[1], macbase[2],
1056 macbase[3], macbase[4], macbase[5]);
1057 sprintf(enetvar, i ? "eth%daddr" : "ethaddr", i);
1058 /* Only initialize environment variables that are blank
1059 * (i.e. have not yet been set)
1060 */
1061 if (!env_get(enetvar))
1062 env_set(enetvar, ethaddr);
1063
1064 macbase[5]++;
1065 if (macbase[5] == 0) {
1066 macbase[4]++;
1067 if (macbase[4] == 0) {
1068 macbase[3]++;
1069 if (macbase[3] == 0) {
1070 macbase[0] = 0;
1071 macbase[1] = 0;
1072 macbase[2] = 0;
1073 }
1074 }
1075 }
1076 }
1077 }
1078
1079 printf("%s v%u len=%u\n", eeprom_hdr->signature, eeprom_hdr->version,
1080 be16_to_cpu(eeprom_hdr->totallen));
1081
1082 return 0;
1083}
1084
1085/**
1086 * populate_serial_number - read the serial number from EEPROM
1087 *
1088 * This function reads the serial number from the EEPROM and sets the
1089 * appropriate environment variable.
1090 *
1091 * The environment variable is only set if it has not been set
1092 * already. This ensures that any user-saved variables are never
1093 * overwritten.
1094 *
1095 * This function must be called after relocation.
1096 */
Josua Mayerdfda0c02023-05-05 11:20:46 +03001097int populate_serial_number(int devnum)
Baruch Siach1c79f2f2020-01-21 15:44:54 +02001098{
1099 char serialstr[257];
1100 int eeprom_index;
1101 struct tlvinfo_tlv *eeprom_tlv;
1102
1103 if (env_get("serial#"))
1104 return 0;
1105
Josua Mayerdfda0c02023-05-05 11:20:46 +03001106 if (read_eeprom(devnum, eeprom)) {
Baruch Siach1c79f2f2020-01-21 15:44:54 +02001107 printf("Read failed.\n");
1108 return -1;
1109 }
1110
1111 if (tlvinfo_find_tlv(eeprom, TLV_CODE_SERIAL_NUMBER, &eeprom_index)) {
1112 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
1113 memcpy(serialstr, eeprom_tlv->value, eeprom_tlv->length);
1114 serialstr[eeprom_tlv->length] = 0;
1115 env_set("serial#", serialstr);
1116 }
1117
1118 return 0;
1119}