blob: d36401e91389b723b344d208f939aa8ceab576e0 [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);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200137
138 // If the contents are invalid, start over with default contents
139 if (!is_valid_tlvinfo_header(eeprom_hdr) ||
140 !is_checksum_valid(eeprom)) {
141 strcpy(eeprom_hdr->signature, TLV_INFO_ID_STRING);
142 eeprom_hdr->version = TLV_INFO_VERSION;
143 eeprom_hdr->totallen = cpu_to_be16(0);
144 update_crc(eeprom);
145 }
146
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200147#ifdef DEBUG
Josua Mayer425d9632023-05-05 11:20:47 +0300148 show_eeprom(devnum, eeprom);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200149#endif
150
151 return ret;
152}
153
154/**
155 * show_eeprom
156 *
157 * Display the contents of the EEPROM
158 */
Josua Mayerdfda0c02023-05-05 11:20:46 +0300159static void show_eeprom(int devnum, u8 *eeprom)
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200160{
161 int tlv_end;
162 int curr_tlv;
Sven Auhagenee8ce382021-09-12 09:25:44 +0200163#ifdef DEBUG
164 int i;
165#endif
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200166 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
167 struct tlvinfo_tlv *eeprom_tlv;
168
169 if (!is_valid_tlvinfo_header(eeprom_hdr)) {
170 printf("EEPROM does not contain data in a valid TlvInfo format.\n");
171 return;
172 }
173
Josua Mayerdfda0c02023-05-05 11:20:46 +0300174 printf("TLV: %u\n", devnum);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200175 printf("TlvInfo Header:\n");
176 printf(" Id String: %s\n", eeprom_hdr->signature);
177 printf(" Version: %d\n", eeprom_hdr->version);
178 printf(" Total Length: %d\n", be16_to_cpu(eeprom_hdr->totallen));
179
180 printf("TLV Name Code Len Value\n");
181 printf("-------------------- ---- --- -----\n");
182 curr_tlv = HDR_SIZE;
183 tlv_end = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
184 while (curr_tlv < tlv_end) {
185 eeprom_tlv = to_entry(&eeprom[curr_tlv]);
186 if (!is_valid_tlv(eeprom_tlv)) {
187 printf("Invalid TLV field starting at EEPROM offset %d\n",
188 curr_tlv);
189 return;
190 }
191 decode_tlv(eeprom_tlv);
192 curr_tlv += ENT_SIZE + eeprom_tlv->length;
193 }
194
195 printf("Checksum is %s.\n",
196 is_checksum_valid(eeprom) ? "valid" : "invalid");
197
198#ifdef DEBUG
199 printf("EEPROM dump: (0x%x bytes)", TLV_INFO_MAX_LEN);
200 for (i = 0; i < TLV_INFO_MAX_LEN; i++) {
201 if ((i % 16) == 0)
202 printf("\n%02X: ", i);
203 printf("%02X ", eeprom[i]);
204 }
205 printf("\n");
206#endif
207}
208
209/**
210 * Struct for displaying the TLV codes and names.
211 */
212struct tlv_code_desc {
213 u8 m_code;
214 char *m_name;
215};
216
217/**
218 * List of TLV codes and names.
219 */
220static struct tlv_code_desc tlv_code_list[] = {
221 { TLV_CODE_PRODUCT_NAME, "Product Name"},
222 { TLV_CODE_PART_NUMBER, "Part Number"},
223 { TLV_CODE_SERIAL_NUMBER, "Serial Number"},
224 { TLV_CODE_MAC_BASE, "Base MAC Address"},
225 { TLV_CODE_MANUF_DATE, "Manufacture Date"},
226 { TLV_CODE_DEVICE_VERSION, "Device Version"},
227 { TLV_CODE_LABEL_REVISION, "Label Revision"},
228 { TLV_CODE_PLATFORM_NAME, "Platform Name"},
229 { TLV_CODE_ONIE_VERSION, "ONIE Version"},
230 { TLV_CODE_MAC_SIZE, "MAC Addresses"},
231 { TLV_CODE_MANUF_NAME, "Manufacturer"},
232 { TLV_CODE_MANUF_COUNTRY, "Country Code"},
233 { TLV_CODE_VENDOR_NAME, "Vendor Name"},
234 { TLV_CODE_DIAG_VERSION, "Diag Version"},
235 { TLV_CODE_SERVICE_TAG, "Service Tag"},
236 { TLV_CODE_VENDOR_EXT, "Vendor Extension"},
237 { TLV_CODE_CRC_32, "CRC-32"},
238};
239
240/**
241 * Look up a TLV name by its type.
242 */
243static inline const char *tlv_type2name(u8 type)
244{
245 char *name = "Unknown";
246 int i;
247
248 for (i = 0; i < ARRAY_SIZE(tlv_code_list); i++) {
249 if (tlv_code_list[i].m_code == type) {
250 name = tlv_code_list[i].m_name;
251 break;
252 }
253 }
254
255 return name;
256}
257
258/*
259 * decode_tlv
260 *
261 * Print a string representing the contents of the TLV field. The format of
262 * the string is:
263 * 1. The name of the field left justified in 20 characters
264 * 2. The type code in hex right justified in 5 characters
265 * 3. The length in decimal right justified in 4 characters
266 * 4. The value, left justified in however many characters it takes
267 * The validity of EEPROM contents and the TLV field have been verified
268 * prior to calling this function.
269 */
270#define DECODE_NAME_MAX 20
271
272/*
273 * The max decode value is currently for the 'raw' type or the 'vendor
274 * extension' type, both of which have the same decode format. The
275 * max decode string size is computed as follows:
276 *
277 * strlen(" 0xFF") * TLV_VALUE_MAX_LEN + 1
278 *
279 */
280#define DECODE_VALUE_MAX ((5 * TLV_VALUE_MAX_LEN) + 1)
281
282static void decode_tlv(struct tlvinfo_tlv *tlv)
283{
284 char name[DECODE_NAME_MAX];
285 char value[DECODE_VALUE_MAX];
286 int i;
287
288 strncpy(name, tlv_type2name(tlv->type), DECODE_NAME_MAX);
289
290 switch (tlv->type) {
291 case TLV_CODE_PRODUCT_NAME:
292 case TLV_CODE_PART_NUMBER:
293 case TLV_CODE_SERIAL_NUMBER:
294 case TLV_CODE_MANUF_DATE:
295 case TLV_CODE_LABEL_REVISION:
296 case TLV_CODE_PLATFORM_NAME:
297 case TLV_CODE_ONIE_VERSION:
298 case TLV_CODE_MANUF_NAME:
299 case TLV_CODE_MANUF_COUNTRY:
300 case TLV_CODE_VENDOR_NAME:
301 case TLV_CODE_DIAG_VERSION:
302 case TLV_CODE_SERVICE_TAG:
303 memcpy(value, tlv->value, tlv->length);
304 value[tlv->length] = 0;
305 break;
306 case TLV_CODE_MAC_BASE:
307 sprintf(value, "%02X:%02X:%02X:%02X:%02X:%02X",
308 tlv->value[0], tlv->value[1], tlv->value[2],
309 tlv->value[3], tlv->value[4], tlv->value[5]);
310 break;
311 case TLV_CODE_DEVICE_VERSION:
312 sprintf(value, "%u", tlv->value[0]);
313 break;
314 case TLV_CODE_MAC_SIZE:
315 sprintf(value, "%u", (tlv->value[0] << 8) | tlv->value[1]);
316 break;
317 case TLV_CODE_VENDOR_EXT:
318 value[0] = 0;
319 for (i = 0; (i < (DECODE_VALUE_MAX / 5)) && (i < tlv->length);
320 i++) {
321 sprintf(value, "%s 0x%02X", value, tlv->value[i]);
322 }
323 break;
324 case TLV_CODE_CRC_32:
325 sprintf(value, "0x%02X%02X%02X%02X",
326 tlv->value[0], tlv->value[1],
327 tlv->value[2], tlv->value[3]);
328 break;
329 default:
330 value[0] = 0;
331 for (i = 0; (i < (DECODE_VALUE_MAX / 5)) && (i < tlv->length);
332 i++) {
333 sprintf(value, "%s 0x%02X", value, tlv->value[i]);
334 }
335 break;
336 }
337
338 name[DECODE_NAME_MAX - 1] = 0;
339 printf("%-20s 0x%02X %3d %s\n", name, tlv->type, tlv->length, value);
340}
341
342/**
343 * update_crc
344 *
345 * This function updates the CRC-32 TLV. If there is no CRC-32 TLV, then
346 * one is added. This function should be called after each update to the
347 * EEPROM structure, to make sure the CRC is always correct.
348 */
349static void update_crc(u8 *eeprom)
350{
351 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
352 struct tlvinfo_tlv *eeprom_crc;
353 unsigned int calc_crc;
354 int eeprom_index;
355
356 // Discover the CRC TLV
357 if (!tlvinfo_find_tlv(eeprom, TLV_CODE_CRC_32, &eeprom_index)) {
358 unsigned int totallen = be16_to_cpu(eeprom_hdr->totallen);
359
360 if ((totallen + ENT_SIZE + 4) > TLV_TOTAL_LEN_MAX)
361 return;
362 eeprom_index = HDR_SIZE + totallen;
363 eeprom_hdr->totallen = cpu_to_be16(totallen + ENT_SIZE + 4);
364 }
365 eeprom_crc = to_entry(&eeprom[eeprom_index]);
366 eeprom_crc->type = TLV_CODE_CRC_32;
367 eeprom_crc->length = 4;
368
369 // Calculate the checksum
370 calc_crc = crc32(0, (void *)eeprom,
371 HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen) - 4);
372 eeprom_crc->value[0] = (calc_crc >> 24) & 0xFF;
373 eeprom_crc->value[1] = (calc_crc >> 16) & 0xFF;
374 eeprom_crc->value[2] = (calc_crc >> 8) & 0xFF;
375 eeprom_crc->value[3] = (calc_crc >> 0) & 0xFF;
376}
377
378/**
379 * prog_eeprom
380 *
381 * Write the EEPROM data from CPU memory to the hardware.
382 */
Josua Mayerdfda0c02023-05-05 11:20:46 +0300383static int prog_eeprom(int devnum, u8 *eeprom)
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200384{
385 int ret = 0;
386 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
387 int eeprom_len;
388
389 update_crc(eeprom);
390
391 eeprom_len = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
Josua Mayerdfda0c02023-05-05 11:20:46 +0300392 ret = write_tlv_eeprom(eeprom, eeprom_len, devnum);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200393 if (ret) {
394 printf("Programming failed.\n");
395 return -1;
396 }
397
398 printf("Programming passed.\n");
399 return 0;
400}
401
402/**
403 * show_tlv_code_list - Display the list of TLV codes and names
404 */
405void show_tlv_code_list(void)
406{
407 int i;
408
409 printf("TLV Code TLV Name\n");
410 printf("======== =================\n");
411 for (i = 0; i < ARRAY_SIZE(tlv_code_list); i++) {
412 printf("0x%02X %s\n",
413 tlv_code_list[i].m_code,
414 tlv_code_list[i].m_name);
415 }
416}
417
418/**
419 * do_tlv_eeprom
420 *
421 * This function implements the tlv_eeprom command.
422 */
Simon Glass09140112020-05-10 11:40:03 -0600423int do_tlv_eeprom(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200424{
425 char cmd;
426 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
Josua Mayerdfda0c02023-05-05 11:20:46 +0300427 static unsigned int current_dev;
Josua Mayer425d9632023-05-05 11:20:47 +0300428 /* Set to 1 if we've read EEPROM into memory */
429 static int has_been_read;
430 int ret;
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200431
432 // If no arguments, read the EERPOM and display its contents
433 if (argc == 1) {
Josua Mayer425d9632023-05-05 11:20:47 +0300434 if (!has_been_read) {
435 if (read_eeprom(current_dev, eeprom) == 0)
436 has_been_read = 1;
437 }
Josua Mayerdfda0c02023-05-05 11:20:46 +0300438 show_eeprom(current_dev, eeprom);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200439 return 0;
440 }
441
442 // We only look at the first character to the command, so "read" and
443 // "reset" will both be treated as "read".
444 cmd = argv[1][0];
445
446 // Read the EEPROM contents
447 if (cmd == 'r') {
448 has_been_read = 0;
Josua Mayer425d9632023-05-05 11:20:47 +0300449 if (read_eeprom(current_dev, eeprom) == 0) {
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200450 printf("EEPROM data loaded from device to memory.\n");
Josua Mayer425d9632023-05-05 11:20:47 +0300451 has_been_read = 1;
452 }
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200453 return 0;
454 }
455
456 // Subsequent commands require that the EEPROM has already been read.
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 // Handle the commands that don't take parameters
463 if (argc == 2) {
464 switch (cmd) {
465 case 'w': /* write */
Josua Mayerdfda0c02023-05-05 11:20:46 +0300466 prog_eeprom(current_dev, eeprom);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200467 break;
468 case 'e': /* erase */
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': /* list */
476 show_tlv_code_list();
477 break;
478 case 'd': /* dev */
Josua Mayerdfda0c02023-05-05 11:20:46 +0300479 show_tlv_devices(current_dev);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200480 break;
481 default:
Heinrich Schuchardt93a80c12023-01-27 22:49:10 +0100482 return CMD_RET_USAGE;
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200483 }
484 return 0;
485 }
486
487 // The set command takes one or two args.
Heinrich Schuchardt93a80c12023-01-27 22:49:10 +0100488 if (argc > 4)
489 return CMD_RET_USAGE;
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200490
491 // Set command. If the TLV exists in the EEPROM, delete it. Then if
492 // data was supplied for this TLV add the TLV with the new contents at
493 // the end.
494 if (cmd == 's') {
495 int tcode;
496
497 tcode = simple_strtoul(argv[2], NULL, 0);
498 tlvinfo_delete_tlv(eeprom, tcode);
499 if (argc == 4)
500 tlvinfo_add_tlv(eeprom, tcode, argv[3]);
501 } else if (cmd == 'd') { /* 'dev' command */
502 unsigned int devnum;
503
504 devnum = simple_strtoul(argv[2], NULL, 0);
505 if (devnum > MAX_TLV_DEVICES || !tlv_devices[devnum]) {
506 printf("Invalid device number\n");
507 return 0;
508 }
509 current_dev = devnum;
510 has_been_read = 0;
511 } else {
Heinrich Schuchardt93a80c12023-01-27 22:49:10 +0100512 return CMD_RET_USAGE;
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200513 }
514
515 return 0;
516}
517
518/**
519 * This macro defines the tlv_eeprom command line command.
520 */
521U_BOOT_CMD(tlv_eeprom, 4, 1, do_tlv_eeprom,
522 "Display and program the system EEPROM data block.",
523 "[read|write|set <type_code> <string_value>|erase|list]\n"
524 "tlv_eeprom\n"
525 " - With no arguments display the current contents.\n"
526 "tlv_eeprom dev [dev]\n"
527 " - List devices or set current EEPROM device.\n"
528 "tlv_eeprom read\n"
529 " - Load EEPROM data from device to memory.\n"
530 "tlv_eeprom write\n"
531 " - Write the EEPROM data to persistent storage.\n"
532 "tlv_eeprom set <type_code> <string_value>\n"
533 " - Set a field to a value.\n"
534 " - If no string_value, field is deleted.\n"
535 " - Use 'tlv_eeprom write' to make changes permanent.\n"
536 "tlv_eeprom erase\n"
537 " - Reset the in memory EEPROM data.\n"
538 " - Use 'tlv_eeprom read' to refresh the in memory EEPROM data.\n"
539 " - Use 'tlv_eeprom write' to make changes permanent.\n"
540 "tlv_eeprom list\n"
541 " - List the understood TLV codes and names.\n"
542 );
543
544/**
545 * tlvinfo_find_tlv
546 *
547 * This function finds the TLV with the supplied code in the EERPOM.
548 * An offset from the beginning of the EEPROM is returned in the
549 * eeprom_index parameter if the TLV is found.
550 */
551static bool tlvinfo_find_tlv(u8 *eeprom, u8 tcode, int *eeprom_index)
552{
553 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
554 struct tlvinfo_tlv *eeprom_tlv;
555 int eeprom_end;
556
557 // Search through the TLVs, looking for the first one which matches the
558 // supplied type code.
559 *eeprom_index = HDR_SIZE;
560 eeprom_end = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
561 while (*eeprom_index < eeprom_end) {
562 eeprom_tlv = to_entry(&eeprom[*eeprom_index]);
563 if (!is_valid_tlv(eeprom_tlv))
564 return false;
565 if (eeprom_tlv->type == tcode)
566 return true;
567 *eeprom_index += ENT_SIZE + eeprom_tlv->length;
568 }
569 return(false);
570}
571
572/**
573 * tlvinfo_delete_tlv
574 *
575 * This function deletes the TLV with the specified type code from the
576 * EEPROM.
577 */
578static bool tlvinfo_delete_tlv(u8 *eeprom, u8 code)
579{
580 int eeprom_index;
581 int tlength;
582 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
583 struct tlvinfo_tlv *eeprom_tlv;
584
585 // Find the TLV and then move all following TLVs "forward"
586 if (tlvinfo_find_tlv(eeprom, code, &eeprom_index)) {
587 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
588 tlength = ENT_SIZE + eeprom_tlv->length;
589 memcpy(&eeprom[eeprom_index], &eeprom[eeprom_index + tlength],
590 HDR_SIZE +
591 be16_to_cpu(eeprom_hdr->totallen) - eeprom_index -
592 tlength);
593 eeprom_hdr->totallen =
594 cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) -
595 tlength);
596 update_crc(eeprom);
597 return true;
598 }
599 return false;
600}
601
602/**
603 * tlvinfo_add_tlv
604 *
605 * This function adds a TLV to the EEPROM, converting the value (a string) to
606 * the format in which it will be stored in the EEPROM.
607 */
608#define MAX_TLV_VALUE_LEN 256
609static bool tlvinfo_add_tlv(u8 *eeprom, int tcode, char *strval)
610{
611 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
612 struct tlvinfo_tlv *eeprom_tlv;
613 int new_tlv_len = 0;
614 u32 value;
615 char data[MAX_TLV_VALUE_LEN];
616 int eeprom_index;
617
618 // Encode each TLV type into the format to be stored in the EERPOM
619 switch (tcode) {
620 case TLV_CODE_PRODUCT_NAME:
621 case TLV_CODE_PART_NUMBER:
622 case TLV_CODE_SERIAL_NUMBER:
623 case TLV_CODE_LABEL_REVISION:
624 case TLV_CODE_PLATFORM_NAME:
625 case TLV_CODE_ONIE_VERSION:
626 case TLV_CODE_MANUF_NAME:
627 case TLV_CODE_MANUF_COUNTRY:
628 case TLV_CODE_VENDOR_NAME:
629 case TLV_CODE_DIAG_VERSION:
630 case TLV_CODE_SERVICE_TAG:
631 strncpy(data, strval, MAX_TLV_VALUE_LEN);
632 new_tlv_len = min_t(size_t, MAX_TLV_VALUE_LEN, strlen(strval));
633 break;
634 case TLV_CODE_DEVICE_VERSION:
635 value = simple_strtoul(strval, NULL, 0);
636 if (value >= 256) {
637 printf("ERROR: Device version must be 255 or less. Value supplied: %u",
638 value);
639 return false;
640 }
641 data[0] = value & 0xFF;
642 new_tlv_len = 1;
643 break;
644 case TLV_CODE_MAC_SIZE:
645 value = simple_strtoul(strval, NULL, 0);
646 if (value >= 65536) {
647 printf("ERROR: MAC Size must be 65535 or less. Value supplied: %u",
648 value);
649 return false;
650 }
651 data[0] = (value >> 8) & 0xFF;
652 data[1] = value & 0xFF;
653 new_tlv_len = 2;
654 break;
655 case TLV_CODE_MANUF_DATE:
656 if (set_date(data, strval) != 0)
657 return false;
658 new_tlv_len = 19;
659 break;
660 case TLV_CODE_MAC_BASE:
661 if (set_mac(data, strval) != 0)
662 return false;
663 new_tlv_len = 6;
664 break;
665 case TLV_CODE_CRC_32:
666 printf("WARNING: The CRC TLV is set automatically and cannot be set manually.\n");
667 return false;
668 case TLV_CODE_VENDOR_EXT:
669 default:
670 if (set_bytes(data, strval, &new_tlv_len) != 0)
671 return false;
672 break;
673 }
674
675 // Is there room for this TLV?
676 if ((be16_to_cpu(eeprom_hdr->totallen) + ENT_SIZE + new_tlv_len) >
677 TLV_TOTAL_LEN_MAX) {
678 printf("ERROR: There is not enough room in the EERPOM to save data.\n");
679 return false;
680 }
681
682 // Add TLV at the end, overwriting CRC TLV if it exists
683 if (tlvinfo_find_tlv(eeprom, TLV_CODE_CRC_32, &eeprom_index))
684 eeprom_hdr->totallen =
685 cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) -
686 ENT_SIZE - 4);
687 else
688 eeprom_index = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
689 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
690 eeprom_tlv->type = tcode;
691 eeprom_tlv->length = new_tlv_len;
692 memcpy(eeprom_tlv->value, data, new_tlv_len);
693
694 // Update the total length and calculate (add) a new CRC-32 TLV
695 eeprom_hdr->totallen = cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) +
696 ENT_SIZE + new_tlv_len);
697 update_crc(eeprom);
698
699 return true;
700}
701
702/**
703 * set_mac
704 *
705 * Converts a string MAC address into a binary buffer.
706 *
707 * This function takes a pointer to a MAC address string
708 * (i.e."XX:XX:XX:XX:XX:XX", where "XX" is a two-digit hex number).
709 * The string format is verified and then converted to binary and
710 * stored in a buffer.
711 */
712static int set_mac(char *buf, const char *string)
713{
714 char *p = (char *)string;
715 int i;
716 int err = 0;
717 char *end;
718
719 if (!p) {
720 printf("ERROR: NULL mac addr string passed in.\n");
721 return -1;
722 }
723
724 if (strlen(p) != 17) {
725 printf("ERROR: MAC address strlen() != 17 -- %zu\n", strlen(p));
726 printf("ERROR: Bad MAC address format: %s\n", string);
727 return -1;
728 }
729
730 for (i = 0; i < 17; i++) {
731 if ((i % 3) == 2) {
732 if (p[i] != ':') {
733 err++;
734 printf("ERROR: mac: p[%i] != :, found: `%c'\n",
735 i, p[i]);
736 break;
737 }
738 continue;
739 } else if (!is_hex(p[i])) {
740 err++;
741 printf("ERROR: mac: p[%i] != hex digit, found: `%c'\n",
742 i, p[i]);
743 break;
744 }
745 }
746
747 if (err != 0) {
748 printf("ERROR: Bad MAC address format: %s\n", string);
749 return -1;
750 }
751
752 /* Convert string to binary */
753 for (i = 0, p = (char *)string; i < 6; i++) {
Simon Glass7e5f4602021-07-24 09:03:29 -0600754 buf[i] = p ? hextoul(p, &end) : 0;
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200755 if (p)
756 p = (*end) ? end + 1 : end;
757 }
758
759 if (!is_valid_ethaddr((u8 *)buf)) {
760 printf("ERROR: MAC address must not be 00:00:00:00:00:00, a multicast address or FF:FF:FF:FF:FF:FF.\n");
761 printf("ERROR: Bad MAC address format: %s\n", string);
762 return -1;
763 }
764
765 return 0;
766}
767
768/**
769 * set_date
770 *
771 * Validates the format of the data string
772 *
773 * This function takes a pointer to a date string (i.e. MM/DD/YYYY hh:mm:ss)
774 * and validates that the format is correct. If so the string is copied
775 * to the supplied buffer.
776 */
777static int set_date(char *buf, const char *string)
778{
779 int i;
780
781 if (!string) {
782 printf("ERROR: NULL date string passed in.\n");
783 return -1;
784 }
785
786 if (strlen(string) != 19) {
787 printf("ERROR: Date strlen() != 19 -- %zu\n", strlen(string));
788 printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
789 string);
790 return -1;
791 }
792
793 for (i = 0; string[i] != 0; i++) {
794 switch (i) {
795 case 2:
796 case 5:
797 if (string[i] != '/') {
798 printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
799 string);
800 return -1;
801 }
802 break;
803 case 10:
804 if (string[i] != ' ') {
805 printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
806 string);
807 return -1;
808 }
809 break;
810 case 13:
811 case 16:
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 default:
819 if (!is_digit(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 }
826 }
827
828 strcpy(buf, string);
829 return 0;
830}
831
832/**
833 * set_bytes
834 *
835 * Converts a space-separated string of decimal numbers into a
836 * buffer of bytes.
837 *
838 * This function takes a pointer to a space-separated string of decimal
839 * numbers (i.e. "128 0x55 0321") with "C" standard radix specifiers
840 * and converts them to an array of bytes.
841 */
842static int set_bytes(char *buf, const char *string, int *converted_accum)
843{
844 char *p = (char *)string;
845 int i;
846 uint byte;
847
848 if (!p) {
849 printf("ERROR: NULL string passed in.\n");
850 return -1;
851 }
852
853 /* Convert string to bytes */
854 for (i = 0, p = (char *)string; (i < TLV_VALUE_MAX_LEN) && (*p != 0);
855 i++) {
856 while ((*p == ' ') || (*p == '\t') || (*p == ',') ||
857 (*p == ';')) {
858 p++;
859 }
860 if (*p != 0) {
861 if (!is_digit(*p)) {
862 printf("ERROR: Non-digit found in byte string: (%s)\n",
863 string);
864 return -1;
865 }
866 byte = simple_strtoul(p, &p, 0);
867 if (byte >= 256) {
868 printf("ERROR: The value specified is greater than 255: (%u) in string: %s\n",
869 byte, string);
870 return -1;
871 }
872 buf[i] = byte & 0xFF;
873 }
874 }
875
876 if (i == TLV_VALUE_MAX_LEN && (*p != 0)) {
877 printf("ERROR: Trying to assign too many bytes (max: %d) in string: %s\n",
878 TLV_VALUE_MAX_LEN, string);
879 return -1;
880 }
881
882 *converted_accum = i;
883 return 0;
884}
885
Josua Mayerdfda0c02023-05-05 11:20:46 +0300886static void show_tlv_devices(int current_dev)
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200887{
888 unsigned int dev;
889
890 for (dev = 0; dev < MAX_TLV_DEVICES; dev++)
891 if (tlv_devices[dev])
892 printf("TLV: %u%s\n", dev,
893 (dev == current_dev) ? " (*)" : "");
894}
895
896static int find_tlv_devices(struct udevice **tlv_devices_p)
897{
898 int ret;
899 int count_dev = 0;
900 struct udevice *dev;
901
902 for (ret = uclass_first_device_check(UCLASS_I2C_EEPROM, &dev);
903 dev;
904 ret = uclass_next_device_check(&dev)) {
905 if (ret == 0)
906 tlv_devices_p[count_dev++] = dev;
907 if (count_dev >= MAX_TLV_DEVICES)
908 break;
909 }
910
911 return (count_dev == 0) ? -ENODEV : 0;
912}
913
914static struct udevice *find_tlv_device_by_index(int dev_num)
915{
916 struct udevice *local_tlv_devices[MAX_TLV_DEVICES] = {};
917 struct udevice **tlv_devices_p;
918 int ret;
919
920 if (gd->flags & (GD_FLG_RELOC | GD_FLG_SPL_INIT)) {
921 /* Assume BSS is initialized; use static data */
922 if (tlv_devices[dev_num])
923 return tlv_devices[dev_num];
924 tlv_devices_p = tlv_devices;
925 } else {
926 tlv_devices_p = local_tlv_devices;
927 }
928
929 ret = find_tlv_devices(tlv_devices_p);
930 if (ret == 0 && tlv_devices_p[dev_num])
931 return tlv_devices_p[dev_num];
932
933 return NULL;
934}
935
936/**
937 * read_tlv_eeprom - read the hwinfo from i2c EEPROM
938 */
939int read_tlv_eeprom(void *eeprom, int offset, int len, int dev_num)
940{
941 struct udevice *dev;
942
943 if (dev_num >= MAX_TLV_DEVICES)
944 return -EINVAL;
945
946 dev = find_tlv_device_by_index(dev_num);
947 if (!dev)
948 return -ENODEV;
949
950 return i2c_eeprom_read(dev, offset, eeprom, len);
951}
952
953/**
954 * write_tlv_eeprom - write the hwinfo to i2c EEPROM
955 */
Josua Mayerdfda0c02023-05-05 11:20:46 +0300956int write_tlv_eeprom(void *eeprom, int len, int dev)
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200957{
958 if (!(gd->flags & GD_FLG_RELOC))
959 return -ENODEV;
Josua Mayerdfda0c02023-05-05 11:20:46 +0300960 if (!tlv_devices[dev])
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200961 return -ENODEV;
962
Josua Mayerdfda0c02023-05-05 11:20:46 +0300963 return i2c_eeprom_write(tlv_devices[dev], 0, eeprom, len);
Baruch Siach1c79f2f2020-01-21 15:44:54 +0200964}
965
966int read_tlvinfo_tlv_eeprom(void *eeprom, struct tlvinfo_header **hdr,
967 struct tlvinfo_tlv **first_entry, int dev_num)
968{
969 int ret;
970 struct tlvinfo_header *tlv_hdr;
971 struct tlvinfo_tlv *tlv_ent;
972
973 /* Read TLV header */
974 ret = read_tlv_eeprom(eeprom, 0, HDR_SIZE, dev_num);
975 if (ret < 0)
976 return ret;
977
978 tlv_hdr = eeprom;
979 if (!is_valid_tlvinfo_header(tlv_hdr))
980 return -EINVAL;
981
982 /* Read TLV entries */
983 tlv_ent = to_entry(&tlv_hdr[1]);
984 ret = read_tlv_eeprom(tlv_ent, HDR_SIZE,
985 be16_to_cpu(tlv_hdr->totallen), dev_num);
986 if (ret < 0)
987 return ret;
988 if (!is_checksum_valid(eeprom))
989 return -EINVAL;
990
991 *hdr = tlv_hdr;
992 *first_entry = tlv_ent;
993
994 return 0;
995}
996
997/**
998 * mac_read_from_eeprom
999 *
1000 * Read the MAC addresses from EEPROM
1001 *
1002 * This function reads the MAC addresses from EEPROM and sets the
1003 * appropriate environment variables for each one read.
1004 *
1005 * The environment variables are only set if they haven't been set already.
1006 * This ensures that any user-saved variables are never overwritten.
1007 *
1008 * This function must be called after relocation.
1009 */
1010int mac_read_from_eeprom(void)
1011{
1012 unsigned int i;
1013 int eeprom_index;
1014 struct tlvinfo_tlv *eeprom_tlv;
1015 int maccount;
1016 u8 macbase[6];
1017 struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
Josua Mayerdfda0c02023-05-05 11:20:46 +03001018 int devnum = 0; // TODO: support multiple EEPROMs
Baruch Siach1c79f2f2020-01-21 15:44:54 +02001019
1020 puts("EEPROM: ");
1021
Josua Mayerdfda0c02023-05-05 11:20:46 +03001022 if (read_eeprom(devnum, eeprom)) {
Baruch Siach1c79f2f2020-01-21 15:44:54 +02001023 printf("Read failed.\n");
1024 return -1;
1025 }
1026
1027 maccount = 1;
1028 if (tlvinfo_find_tlv(eeprom, TLV_CODE_MAC_SIZE, &eeprom_index)) {
1029 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
1030 maccount = (eeprom_tlv->value[0] << 8) | eeprom_tlv->value[1];
1031 }
1032
1033 memcpy(macbase, "\0\0\0\0\0\0", 6);
1034 if (tlvinfo_find_tlv(eeprom, TLV_CODE_MAC_BASE, &eeprom_index)) {
1035 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
1036 memcpy(macbase, eeprom_tlv->value, 6);
1037 }
1038
1039 for (i = 0; i < maccount; i++) {
1040 if (is_valid_ethaddr(macbase)) {
1041 char ethaddr[18];
1042 char enetvar[11];
1043
1044 sprintf(ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
1045 macbase[0], macbase[1], macbase[2],
1046 macbase[3], macbase[4], macbase[5]);
1047 sprintf(enetvar, i ? "eth%daddr" : "ethaddr", i);
1048 /* Only initialize environment variables that are blank
1049 * (i.e. have not yet been set)
1050 */
1051 if (!env_get(enetvar))
1052 env_set(enetvar, ethaddr);
1053
1054 macbase[5]++;
1055 if (macbase[5] == 0) {
1056 macbase[4]++;
1057 if (macbase[4] == 0) {
1058 macbase[3]++;
1059 if (macbase[3] == 0) {
1060 macbase[0] = 0;
1061 macbase[1] = 0;
1062 macbase[2] = 0;
1063 }
1064 }
1065 }
1066 }
1067 }
1068
1069 printf("%s v%u len=%u\n", eeprom_hdr->signature, eeprom_hdr->version,
1070 be16_to_cpu(eeprom_hdr->totallen));
1071
1072 return 0;
1073}
1074
1075/**
1076 * populate_serial_number - read the serial number from EEPROM
1077 *
1078 * This function reads the serial number from the EEPROM and sets the
1079 * appropriate environment variable.
1080 *
1081 * The environment variable is only set if it has not been set
1082 * already. This ensures that any user-saved variables are never
1083 * overwritten.
1084 *
1085 * This function must be called after relocation.
1086 */
Josua Mayerdfda0c02023-05-05 11:20:46 +03001087int populate_serial_number(int devnum)
Baruch Siach1c79f2f2020-01-21 15:44:54 +02001088{
1089 char serialstr[257];
1090 int eeprom_index;
1091 struct tlvinfo_tlv *eeprom_tlv;
1092
1093 if (env_get("serial#"))
1094 return 0;
1095
Josua Mayerdfda0c02023-05-05 11:20:46 +03001096 if (read_eeprom(devnum, eeprom)) {
Baruch Siach1c79f2f2020-01-21 15:44:54 +02001097 printf("Read failed.\n");
1098 return -1;
1099 }
1100
1101 if (tlvinfo_find_tlv(eeprom, TLV_CODE_SERIAL_NUMBER, &eeprom_index)) {
1102 eeprom_tlv = to_entry(&eeprom[eeprom_index]);
1103 memcpy(serialstr, eeprom_tlv->value, eeprom_tlv->length);
1104 serialstr[eeprom_tlv->length] = 0;
1105 env_set("serial#", serialstr);
1106 }
1107
1108 return 0;
1109}