1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2020 SiFive, Inc.
4  *
5  * Based on board/freescale/common/sys_eeprom.c:
6  * Copyright 2006, 2008-2009, 2011 Freescale Semiconductor
7  * York Sun (yorksun@freescale.com)
8  * Haiying Wang (haiying.wang@freescale.com)
9  * Timur Tabi (timur@freescale.com)
10  */
11 
12 #include <common.h>
13 #include <command.h>
14 #include <env.h>
15 #include <i2c.h>
16 #include <init.h>
17 #include <linux/ctype.h>
18 #include <linux/delay.h>
19 #include <u-boot/crc.h>
20 
21 #ifndef CONFIG_SYS_EEPROM_BUS_NUM
22 #error Requires CONFIG_SYS_EEPROM_BUS_NUM to be defined
23 #endif
24 
25 #define FORMAT_VERSION				0x1
26 
27 /* Options for the manuf_test_status field */
28 #define SIFIVE_MANUF_TEST_STATUS_UNKNOWN	0
29 #define SIFIVE_MANUF_TEST_STATUS_PASS		1
30 #define SIFIVE_MANUF_TEST_STATUS_FAIL		2
31 
32 /*
33  * BYTES_PER_EEPROM_PAGE: the AT24C02 datasheet says that data can
34  * only be written in page mode, which means 8 bytes at a time
35  */
36 #define BYTES_PER_EEPROM_PAGE			8
37 
38 /*
39  * EEPROM_WRITE_DELAY_MS: the AT24C02 datasheet says it takes up to
40  * 5ms to complete a given write
41  */
42 #define EEPROM_WRITE_DELAY_MS			5000
43 
44 /*
45  * MAGIC_NUMBER_BYTES: number of bytes used by the magic number
46  */
47 #define MAGIC_NUMBER_BYTES			4
48 
49 /*
50  * SERIAL_NUMBER_BYTES: number of bytes used by the board serial
51  * number
52  */
53 #define SERIAL_NUMBER_BYTES			16
54 
55 /*
56  * MAC_ADDR_BYTES: number of bytes used by the Ethernet MAC address
57  */
58 #define MAC_ADDR_BYTES				6
59 
60 /*
61  * MAC_ADDR_STRLEN: length of mac address string
62  */
63 #define MAC_ADDR_STRLEN				17
64 
65 /*
66  * SiFive OUI. Registration Date is 2018-02-15
67  */
68 #define SIFIVE_OUI_PREFIX			"70:B3:D5:92:F"
69 
70 /**
71  * static eeprom: EEPROM layout for the SiFive platform I2C format
72  */
73 static struct __attribute__ ((__packed__)) sifive_eeprom {
74 	u8 magic[MAGIC_NUMBER_BYTES];
75 	u8 format_ver;
76 	u16 product_id;
77 	u8 pcb_revision;
78 	u8 bom_revision;
79 	u8 bom_variant;
80 	u8 serial[SERIAL_NUMBER_BYTES];
81 	u8 manuf_test_status;
82 	u8 mac_addr[MAC_ADDR_BYTES];
83 	u32 crc;
84 } e;
85 
86 struct sifive_product {
87 	u16 id;
88 	const char *name;
89 };
90 
91 /* Set to 1 if we've read EEPROM into memory */
92 static int has_been_read;
93 
94 /* Magic number at the first four bytes of EEPROM */
95 static const unsigned char magic[MAGIC_NUMBER_BYTES] = { 0xf1, 0x5e, 0x50, 0x45 };
96 
97 /* Does the magic number match that of a SiFive EEPROM? */
is_match_magic(void)98 static inline int is_match_magic(void)
99 {
100 	return (memcmp(&e.magic, &magic, MAGIC_NUMBER_BYTES) == 0);
101 }
102 
103 /* Calculate the current CRC */
calculate_crc32(void)104 static inline u32 calculate_crc32(void)
105 {
106 	return crc32(0, (void *)&e, sizeof(struct sifive_eeprom) - sizeof(e.crc));
107 }
108 
109 /* This function should be called after each update to the EEPROM structure */
update_crc(void)110 static inline void update_crc(void)
111 {
112 	e.crc = calculate_crc32();
113 }
114 
115 static struct sifive_product sifive_products[] = {
116 	{ 0, "Unknown"},
117 	{ 2, "HiFive Unmatched" },
118 };
119 
120 /**
121  * dump_raw_eeprom - display the raw contents of the EEPROM
122  */
dump_raw_eeprom(void)123 static void dump_raw_eeprom(void)
124 {
125 	unsigned int i;
126 
127 	printf("EEPROM dump: (0x%lx bytes)\n", sizeof(e));
128 	for (i = 0; i < sizeof(e); i++) {
129 		if ((i % 16) == 0)
130 			printf("%02X: ", i);
131 		printf("%02X ", ((u8 *)&e)[i]);
132 		if (((i % 16) == 15) || (i == sizeof(e) - 1))
133 			printf("\n");
134 	}
135 }
136 
137 /**
138  * show_eeprom - display the contents of the EEPROM
139  */
show_eeprom(void)140 static void show_eeprom(void)
141 {
142 	unsigned int i;
143 	u32 crc;
144 	const char *product_name = "Unknown";
145 	char board_serial[SERIAL_NUMBER_BYTES + 1] = { 0 };
146 
147 	if (!is_match_magic()) {
148 		printf("Not a SiFive HiFive EEPROM data format - magic bytes don't match\n");
149 		dump_raw_eeprom();
150 		return;
151 	};
152 
153 	snprintf(board_serial, sizeof(board_serial), "%s", e.serial);
154 
155 	for (i = 0; i < ARRAY_SIZE(sifive_products); i++) {
156 		if (sifive_products[i].id == e.product_id) {
157 			product_name = sifive_products[i].name;
158 			break;
159 		}
160 	};
161 
162 	printf("SiFive PCB EEPROM format v%u\n", e.format_ver);
163 	printf("Product ID: %04hx (%s)\n", e.product_id, product_name);
164 	printf("PCB revision: %x\n", e.pcb_revision);
165 	printf("BOM revision: %c\n", e.bom_revision);
166 	printf("BOM variant: %x\n", e.bom_variant);
167 	printf("Serial number: %s\n", board_serial);
168 	printf("Ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
169 	       e.mac_addr[0], e.mac_addr[1], e.mac_addr[2],
170 	       e.mac_addr[3], e.mac_addr[4], e.mac_addr[5]);
171 
172 	crc = calculate_crc32();
173 	if (crc == e.crc) {
174 		printf("CRC: %08x\n", e.crc);
175 	} else {
176 		printf("CRC: %08x (should be %08x)\n", e.crc, crc);
177 		dump_raw_eeprom();
178 	}
179 }
180 
181 /**
182  * read_eeprom() - read the EEPROM into memory, if it hasn't been read already
183  */
read_eeprom(void)184 static int read_eeprom(void)
185 {
186 	int ret;
187 	struct udevice *dev;
188 
189 	if (has_been_read)
190 		return 0;
191 
192 	ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM,
193 				      CONFIG_SYS_I2C_EEPROM_ADDR,
194 				      1,
195 				      &dev);
196 	if (!ret)
197 		dm_i2c_read(dev, 0, (void *)&e,
198 			    sizeof(struct sifive_eeprom));
199 
200 	show_eeprom();
201 
202 	has_been_read = (ret == 0) ? 1 : 0;
203 
204 	return ret;
205 }
206 
207 /**
208  * prog_eeprom() - write the EEPROM from memory
209  */
prog_eeprom(void)210 static int prog_eeprom(void)
211 {
212 	int ret = 0;
213 	unsigned int i;
214 	void *p;
215 
216 	if (!is_match_magic()) {
217 		printf("Please read the EEPROM ('read_eeprom') and/or initialize the EEPROM ('initialize') first.\n");
218 		return 0;
219 	}
220 
221 	for (i = 0, p = &e; i < sizeof(e);
222 	     i += BYTES_PER_EEPROM_PAGE, p += BYTES_PER_EEPROM_PAGE) {
223 		struct udevice *dev;
224 
225 		ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM,
226 					      CONFIG_SYS_I2C_EEPROM_ADDR,
227 					      CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
228 					      &dev);
229 		if (!ret)
230 			ret = dm_i2c_write(dev, i, p,
231 					   min((int)(sizeof(e) - i),
232 					       BYTES_PER_EEPROM_PAGE));
233 
234 		if (ret)
235 			break;
236 
237 		udelay(EEPROM_WRITE_DELAY_MS);
238 	}
239 
240 	if (!ret) {
241 		/* Verify the write by reading back the EEPROM and comparing */
242 		struct sifive_eeprom e2;
243 		struct udevice *dev;
244 
245 		ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM,
246 					      CONFIG_SYS_I2C_EEPROM_ADDR,
247 					      CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
248 					      &dev);
249 		if (!ret)
250 			ret = dm_i2c_read(dev, 0, (void *)&e2, sizeof(e2));
251 		if (!ret && memcmp(&e, &e2, sizeof(e)))
252 			ret = -1;
253 	}
254 
255 	if (ret) {
256 		printf("Programming failed.\n");
257 		has_been_read = 0;
258 		return -1;
259 	}
260 
261 	printf("Programming passed.\n");
262 	return 0;
263 }
264 
265 /**
266  * set_mac_address() - stores a MAC address into the local EEPROM copy
267  *
268  * This function takes a pointer to MAC address string
269  * (i.e."XX:XX:XX:XX:XX:XX", where "XX" is a two-digit hex number),
270  * stores it in the MAC address field of the EEPROM local copy, and
271  * updates the local copy of the CRC.
272  */
set_mac_address(char * string)273 static void set_mac_address(char *string)
274 {
275 	unsigned int i;
276 
277 	if (strncasecmp(SIFIVE_OUI_PREFIX, string, 13)) {
278 		printf("The MAC address doesn't match SiFive OUI %s\n",
279 		       SIFIVE_OUI_PREFIX);
280 		return;
281 	}
282 
283 	for (i = 0; *string && (i < MAC_ADDR_BYTES); i++) {
284 		e.mac_addr[i] = hextoul(string, &string);
285 		if (*string == ':')
286 			string++;
287 	}
288 
289 	update_crc();
290 }
291 
292 /**
293  * set_manuf_test_status() - stores a test status byte into the in-memory copy
294  *
295  * Takes a pointer to a manufacturing test status string ("unknown",
296  * "pass", "fail") and stores the corresponding numeric ID to the
297  * manuf_test_status field of the EEPROM local copy, and updates the
298  * CRC of the local copy.
299  */
set_manuf_test_status(char * string)300 static void set_manuf_test_status(char *string)
301 {
302 	if (!strcasecmp(string, "unknown")) {
303 		e.manuf_test_status = SIFIVE_MANUF_TEST_STATUS_UNKNOWN;
304 	} else if (!strcasecmp(string, "pass")) {
305 		e.manuf_test_status = SIFIVE_MANUF_TEST_STATUS_PASS;
306 	} else if (!strcasecmp(string, "fail")) {
307 		e.manuf_test_status = SIFIVE_MANUF_TEST_STATUS_FAIL;
308 	} else {
309 		printf("Usage: mac manuf_test_status (unknown|pass|fail)\n");
310 		return;
311 	}
312 
313 	update_crc();
314 }
315 
316 /**
317  * set_pcb_revision() - stores a SiFive PCB revision into the local EEPROM copy
318  *
319  * Takes a pointer to a string representing the numeric PCB revision in
320  * decimal ("0" - "255"), stores it in the pcb_revision field of the
321  * EEPROM local copy, and updates the CRC of the local copy.
322  */
set_pcb_revision(char * string)323 static void set_pcb_revision(char *string)
324 {
325 	unsigned long p;
326 
327 	p = dectoul(string, &string);
328 	if (p > U8_MAX) {
329 		printf("%s must not be greater than %d\n", "PCB revision",
330 		       U8_MAX);
331 		return;
332 	}
333 
334 	e.pcb_revision = p;
335 
336 	update_crc();
337 }
338 
339 /**
340  * set_bom_revision() - stores a SiFive BOM revision into the local EEPROM copy
341  *
342  * Takes a pointer to a uppercase ASCII character representing the BOM
343  * revision ("A" - "Z"), stores it in the bom_revision field of the
344  * EEPROM local copy, and updates the CRC of the local copy.
345  */
set_bom_revision(char * string)346 static void set_bom_revision(char *string)
347 {
348 	if (string[0] < 'A' || string[0] > 'Z') {
349 		printf("BOM revision must be an uppercase letter between A and Z\n");
350 		return;
351 	}
352 
353 	e.bom_revision = string[0];
354 
355 	update_crc();
356 }
357 
358 /**
359  * set_bom_variant() - stores a SiFive BOM variant into the local EEPROM copy
360  *
361  * Takes a pointer to a string representing the numeric BOM variant in
362  * decimal ("0" - "255"), stores it in the bom_variant field of the
363  * EEPROM local copy, and updates the CRC of the local copy.
364  */
set_bom_variant(char * string)365 static void set_bom_variant(char *string)
366 {
367 	unsigned long p;
368 
369 	p = dectoul(string, &string);
370 	if (p > U8_MAX) {
371 		printf("%s must not be greater than %d\n", "BOM variant",
372 		       U8_MAX);
373 		return;
374 	}
375 
376 	e.bom_variant = p;
377 
378 	update_crc();
379 }
380 
381 /**
382  * set_product_id() - stores a SiFive product ID into the local EEPROM copy
383  *
384  * Takes a pointer to a string representing the numeric product ID  in
385  * decimal ("0" - "65535"), stores it in the product ID field of the
386  * EEPROM local copy, and updates the CRC of the local copy.
387  */
set_product_id(char * string)388 static void set_product_id(char *string)
389 {
390 	unsigned long p;
391 
392 	p = dectoul(string, &string);
393 	if (p > U16_MAX) {
394 		printf("%s must not be greater than %d\n", "Product ID",
395 		       U16_MAX);
396 		return;
397 	}
398 
399 	e.product_id = p;
400 
401 	update_crc();
402 }
403 
404 /**
405  * init_local_copy() - initialize the in-memory EEPROM copy
406  *
407  * Initialize the in-memory EEPROM copy with the magic number.  Must
408  * be done when preparing to initialize a blank EEPROM, or overwrite
409  * one with a corrupted magic number.
410  */
init_local_copy(void)411 static void init_local_copy(void)
412 {
413 	memset(&e, 0, sizeof(e));
414 	memcpy(e.magic, magic, sizeof(e.magic));
415 	e.format_ver = FORMAT_VERSION;
416 	update_crc();
417 }
418 
do_mac(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])419 int do_mac(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
420 {
421 	char *cmd;
422 
423 	if (argc == 1) {
424 		show_eeprom();
425 		return 0;
426 	}
427 
428 	if (argc > 3)
429 		return cmd_usage(cmdtp);
430 
431 	cmd = argv[1];
432 
433 	/* Commands with no argument */
434 	if (!strcmp(cmd, "read_eeprom")) {
435 		read_eeprom();
436 		return 0;
437 	} else if (!strcmp(cmd, "initialize")) {
438 		init_local_copy();
439 		return 0;
440 	} else if (!strcmp(cmd, "write_eeprom")) {
441 		prog_eeprom();
442 		return 0;
443 	}
444 
445 	if (argc != 3)
446 		return cmd_usage(cmdtp);
447 
448 	if (!is_match_magic()) {
449 		printf("Please read the EEPROM ('read_eeprom') and/or initialize the EEPROM ('initialize') first.\n");
450 		return 0;
451 	}
452 
453 	if (!strcmp(cmd, "manuf_test_status")) {
454 		set_manuf_test_status(argv[2]);
455 		return 0;
456 	} else if (!strcmp(cmd, "mac_address")) {
457 		set_mac_address(argv[2]);
458 		return 0;
459 	} else if (!strcmp(cmd, "pcb_revision")) {
460 		set_pcb_revision(argv[2]);
461 		return 0;
462 	} else if (!strcmp(cmd, "bom_variant")) {
463 		set_bom_variant(argv[2]);
464 		return 0;
465 	} else if (!strcmp(cmd, "bom_revision")) {
466 		set_bom_revision(argv[2]);
467 		return 0;
468 	} else if (!strcmp(cmd, "product_id")) {
469 		set_product_id(argv[2]);
470 		return 0;
471 	}
472 
473 	return cmd_usage(cmdtp);
474 }
475 
476 /**
477  * mac_read_from_eeprom() - read the MAC address from EEPROM
478  *
479  * This function reads the MAC address from EEPROM and sets the
480  * appropriate environment variables for each one read.
481  *
482  * The environment variables are only set if they haven't been set already.
483  * This ensures that any user-saved variables are never overwritten.
484  *
485  * This function must be called after relocation.
486  */
mac_read_from_eeprom(void)487 int mac_read_from_eeprom(void)
488 {
489 	u32 crc;
490 	char board_serial[SERIAL_NUMBER_BYTES + 1] = { 0 };
491 
492 	puts("EEPROM: ");
493 
494 	if (read_eeprom()) {
495 		printf("Read failed.\n");
496 		return 0;
497 	}
498 
499 	if (!is_match_magic()) {
500 		printf("Invalid ID (%02x %02x %02x %02x)\n",
501 		       e.magic[0], e.magic[1], e.magic[2], e.magic[3]);
502 		dump_raw_eeprom();
503 		return 0;
504 	}
505 
506 	crc = calculate_crc32();
507 	if (crc != e.crc) {
508 		printf("CRC mismatch (%08x != %08x)\n", crc, e.crc);
509 		dump_raw_eeprom();
510 		return 0;
511 	}
512 
513 	eth_env_set_enetaddr("ethaddr", e.mac_addr);
514 
515 	if (!env_get("serial#")) {
516 		snprintf(board_serial, sizeof(board_serial), "%s", e.serial);
517 		env_set("serial#", board_serial);
518 	}
519 
520 	return 0;
521 }
522 
523 /**
524  * get_pcb_revision_from_eeprom - get the PCB revision
525  *
526  * Read the EEPROM to determine the board revision.
527  *
528  * This function is called before relocation, so we need to read a private
529  * copy of the EEPROM into a local variable on the stack.
530  */
get_pcb_revision_from_eeprom(void)531 u8 get_pcb_revision_from_eeprom(void)
532 {
533 	struct __attribute__ ((__packed__)) board_eeprom {
534 		u8 magic[MAGIC_NUMBER_BYTES];
535 		u8 format_ver;
536 		u16 product_id;
537 		u8 pcb_revision;
538 	} be;
539 
540 	int ret;
541 	struct udevice *dev;
542 
543 	ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM,
544 				      CONFIG_SYS_I2C_EEPROM_ADDR,
545 				      1,
546 				      &dev);
547 
548 	if (!ret)
549 		dm_i2c_read(dev, 0, (void *)&be,
550 			    sizeof(struct board_eeprom));
551 
552 	return be.pcb_revision;
553 }
554