1
2
3
4
5
6
7
8
9
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
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
34
35
36#define BYTES_PER_EEPROM_PAGE 8
37
38
39
40
41
42#define EEPROM_WRITE_DELAY_MS 5000
43
44
45
46
47#define MAGIC_NUMBER_BYTES 4
48
49
50
51
52
53#define SERIAL_NUMBER_BYTES 16
54
55
56
57
58#define MAC_ADDR_BYTES 6
59
60
61
62
63#define MAC_ADDR_STRLEN 17
64
65
66
67
68#define SIFIVE_OUI_PREFIX "70:B3:D5:92:F"
69
70
71
72
73static 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
86struct sifive_product {
87 u16 id;
88 const char *name;
89};
90
91
92static int has_been_read;
93
94
95static const unsigned char magic[MAGIC_NUMBER_BYTES] = { 0xf1, 0x5e, 0x50, 0x45 };
96
97
98static inline int is_match_magic(void)
99{
100 return (memcmp(&e.magic, &magic, MAGIC_NUMBER_BYTES) == 0);
101}
102
103
104static inline u32 calculate_crc32(void)
105{
106 return crc32(0, (void *)&e, sizeof(struct sifive_eeprom) - sizeof(e.crc));
107}
108
109
110static inline void update_crc(void)
111{
112 e.crc = calculate_crc32();
113}
114
115static struct sifive_product sifive_products[] = {
116 { 0, "Unknown"},
117 { 2, "HiFive Unmatched" },
118};
119
120
121
122
123static 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
139
140static 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
183
184static 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
209
210static 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
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
267
268
269
270
271
272
273static 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
294
295
296
297
298
299
300static 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
318
319
320
321
322
323static 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
341
342
343
344
345
346static 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
360
361
362
363
364
365static 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
383
384
385
386
387
388static 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
406
407
408
409
410
411static 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
419int 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
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
478
479
480
481
482
483
484
485
486
487int 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
525
526
527
528
529
530
531u8 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