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