]>
Commit | Line | Data |
---|---|---|
aea1bd95 YW |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (C) 2023 StarFive Technology Co., Ltd. | |
4 | * Author: Yanhong Wang<[email protected]> | |
5 | */ | |
6 | ||
aea1bd95 YW |
7 | #include <command.h> |
8 | #include <env.h> | |
9 | #include <i2c.h> | |
10 | #include <init.h> | |
11 | #include <u-boot/crc.h> | |
12 | #include <linux/delay.h> | |
13 | ||
14 | #define FORMAT_VERSION 0x2 | |
15 | #define PCB_VERSION 0xB1 | |
16 | #define BOM_VERSION 'A' | |
17 | /* | |
18 | * BYTES_PER_EEPROM_PAGE: the 24FC04H datasheet says that data can | |
19 | * only be written in page mode, which means 16 bytes at a time: | |
20 | * 16-Byte Page Write Buffer | |
21 | */ | |
22 | #define BYTES_PER_EEPROM_PAGE 16 | |
23 | ||
24 | /* | |
25 | * EEPROM_WRITE_DELAY_MS: the 24FC04H datasheet says it takes up to | |
26 | * 5ms to complete a given write: | |
27 | * Write Cycle Time (byte or page) ro Page Write Time 5 ms, Maximum | |
28 | */ | |
29 | #define EEPROM_WRITE_DELAY_MS 5000 | |
30 | /* | |
31 | * StarFive OUI. Registration Date is 20xx-xx-xx | |
32 | */ | |
33 | #define STARFIVE_OUI_PREFIX "6C:CF:39:" | |
34 | #define STARFIVE_DEFAULT_MAC0 "6C:CF:39:6C:DE:AD" | |
35 | #define STARFIVE_DEFAULT_MAC1 "6C:CF:39:6C:DE:AE" | |
36 | ||
37 | /* Magic number at the first four bytes of EEPROM HATs */ | |
38 | #define STARFIVE_EEPROM_HATS_SIG "SFVF" /* StarFive VisionFive */ | |
39 | ||
40 | #define STARFIVE_EEPROM_HATS_SIZE_MAX 256 /* Header + Atom1&4(v1) */ | |
41 | #define STARFIVE_EEPROM_WP_OFFSET 0 /* Read only field */ | |
42 | #define STARFIVE_EEPROM_ATOM1_PSTR "VF7110A1-2228-D008E000-00000001\0" | |
43 | #define STARFIVE_EEPROM_ATOM1_PSTR_SIZE 32 | |
44 | #define STARFIVE_EEPROM_ATOM1_SN_OFFSET 23 | |
45 | #define STARFIVE_EEPROM_ATOM1_VSTR "StarFive Technology Co., Ltd.\0\0\0" | |
46 | #define STARFIVE_EEPROM_ATOM1_VSTR_SIZE 32 | |
47 | ||
48 | #define MAGIC_NUMBER_BYTES 4 | |
49 | #define MAC_ADDR_BYTES 6 | |
50 | #define MAC_ADDR_STRLEN 17 | |
51 | ||
52 | /* | |
53 | * Atom Types | |
54 | * 0x0000 = invalid | |
55 | * 0x0001 = vendor info | |
56 | * 0x0002 = GPIO map | |
57 | * 0x0003 = Linux device tree blob | |
58 | * 0x0004 = manufacturer custom data | |
59 | * 0x0005-0xfffe = reserved for future use | |
60 | * 0xffff = invalid | |
61 | */ | |
62 | ||
63 | #define HATS_ATOM_INVALID 0x0000 | |
64 | #define HATS_ATOM_VENDOR 0x0001 | |
65 | #define HATS_ATOM_GPIO 0x0002 | |
66 | #define HATS_ATOM_DTB 0x0003 | |
67 | #define HATS_ATOM_CUSTOM 0x0004 | |
68 | #define HATS_ATOM_INVALID_END 0xffff | |
69 | ||
70 | struct eeprom_header { | |
71 | char signature[MAGIC_NUMBER_BYTES]; /* ASCII table signature */ | |
72 | u8 version; /* EEPROM data format version */ | |
73 | /* (0x00 reserved, 0x01 = first version) */ | |
74 | u8 reversed; /* 0x00, Reserved field */ | |
75 | u16 numatoms; /* total atoms in EEPROM */ | |
76 | u32 eeplen; /* total length in bytes of all eeprom data */ | |
77 | /* (including this header) */ | |
78 | }; | |
79 | ||
80 | struct eeprom_atom_header { | |
81 | u16 type; | |
82 | u16 count; | |
83 | u32 dlen; | |
84 | }; | |
85 | ||
86 | struct eeprom_atom1_data { | |
87 | u8 uuid[16]; | |
88 | u16 pid; | |
89 | u16 pver; | |
90 | u8 vslen; | |
91 | u8 pslen; | |
92 | uchar vstr[STARFIVE_EEPROM_ATOM1_VSTR_SIZE]; | |
93 | uchar pstr[STARFIVE_EEPROM_ATOM1_PSTR_SIZE]; /* product SN */ | |
94 | }; | |
95 | ||
96 | struct starfive_eeprom_atom1 { | |
97 | struct eeprom_atom_header header; | |
98 | struct eeprom_atom1_data data; | |
99 | u16 crc; | |
100 | }; | |
101 | ||
102 | struct eeprom_atom4_data { | |
103 | u16 version; | |
104 | u8 pcb_revision; /* PCB version */ | |
105 | u8 bom_revision; /* BOM version */ | |
106 | u8 mac0_addr[MAC_ADDR_BYTES]; /* Ethernet0 MAC */ | |
107 | u8 mac1_addr[MAC_ADDR_BYTES]; /* Ethernet1 MAC */ | |
108 | u8 reserved[2]; | |
109 | }; | |
110 | ||
111 | struct starfive_eeprom_atom4 { | |
112 | struct eeprom_atom_header header; | |
113 | struct eeprom_atom4_data data; | |
114 | u16 crc; | |
115 | }; | |
116 | ||
117 | struct starfive_eeprom { | |
118 | struct eeprom_header header; | |
119 | struct starfive_eeprom_atom1 atom1; | |
120 | struct starfive_eeprom_atom4 atom4; | |
121 | }; | |
122 | ||
123 | static union { | |
124 | struct starfive_eeprom eeprom; | |
125 | uchar buf[STARFIVE_EEPROM_HATS_SIZE_MAX]; | |
126 | } pbuf __section(".data"); | |
127 | ||
128 | /* Set to 1 if we've read EEPROM into memory */ | |
129 | static int has_been_read __section(".data"); | |
130 | ||
131 | static inline int is_match_magic(void) | |
132 | { | |
133 | return strncmp(pbuf.eeprom.header.signature, STARFIVE_EEPROM_HATS_SIG, | |
134 | MAGIC_NUMBER_BYTES); | |
135 | } | |
136 | ||
137 | /* Calculate the current CRC */ | |
138 | static inline u32 calculate_crc16(struct eeprom_atom_header *head) | |
139 | { | |
140 | uint len = sizeof(struct eeprom_atom_header) + head->dlen - sizeof(u16); | |
141 | ||
142 | return crc16(0, (void *)head, len); | |
143 | } | |
144 | ||
145 | /* This function should be called after each update to the EEPROM structure */ | |
146 | static inline void update_crc(void) | |
147 | { | |
148 | pbuf.eeprom.atom1.crc = calculate_crc16(&pbuf.eeprom.atom1.header); | |
149 | pbuf.eeprom.atom4.crc = calculate_crc16(&pbuf.eeprom.atom4.header); | |
150 | } | |
151 | ||
152 | static void dump_raw_eeprom(void) | |
153 | { | |
154 | unsigned int i; | |
155 | u32 len; | |
156 | ||
157 | len = sizeof(struct starfive_eeprom); | |
158 | for (i = 0; i < len; i++) { | |
159 | if ((i % 16) == 0) | |
160 | printf("%02X: ", i); | |
161 | printf("%02X ", ((u8 *)pbuf.buf)[i]); | |
162 | if (((i % 16) == 15) || (i == len - 1)) | |
163 | printf("\n"); | |
164 | } | |
165 | } | |
166 | ||
167 | /** | |
168 | * show_eeprom - display the contents of the EEPROM | |
169 | */ | |
170 | static void show_eeprom(void) | |
171 | { | |
172 | if (has_been_read != 1) | |
173 | return; | |
174 | ||
175 | printf("\n--------EEPROM INFO--------\n"); | |
176 | printf("Vendor : %s\n", pbuf.eeprom.atom1.data.vstr); | |
177 | printf("Product full SN: %s\n", pbuf.eeprom.atom1.data.pstr); | |
178 | printf("data version: 0x%x\n", pbuf.eeprom.atom4.data.version); | |
179 | if (pbuf.eeprom.atom4.data.version == 2) { | |
180 | printf("PCB revision: 0x%x\n", pbuf.eeprom.atom4.data.pcb_revision); | |
181 | printf("BOM revision: %c\n", pbuf.eeprom.atom4.data.bom_revision); | |
182 | printf("Ethernet MAC0 address: %02x:%02x:%02x:%02x:%02x:%02x\n", | |
183 | pbuf.eeprom.atom4.data.mac0_addr[0], pbuf.eeprom.atom4.data.mac0_addr[1], | |
184 | pbuf.eeprom.atom4.data.mac0_addr[2], pbuf.eeprom.atom4.data.mac0_addr[3], | |
185 | pbuf.eeprom.atom4.data.mac0_addr[4], pbuf.eeprom.atom4.data.mac0_addr[5]); | |
186 | printf("Ethernet MAC1 address: %02x:%02x:%02x:%02x:%02x:%02x\n", | |
187 | pbuf.eeprom.atom4.data.mac1_addr[0], pbuf.eeprom.atom4.data.mac1_addr[1], | |
188 | pbuf.eeprom.atom4.data.mac1_addr[2], pbuf.eeprom.atom4.data.mac1_addr[3], | |
189 | pbuf.eeprom.atom4.data.mac1_addr[4], pbuf.eeprom.atom4.data.mac1_addr[5]); | |
190 | } else { | |
191 | printf("Custom data v%d is not Supported\n", pbuf.eeprom.atom4.data.version); | |
ede3234d | 192 | dump_raw_eeprom(); |
aea1bd95 YW |
193 | } |
194 | printf("--------EEPROM INFO--------\n\n"); | |
195 | } | |
196 | ||
197 | /** | |
198 | * set_mac_address() - stores a MAC address into the local EEPROM copy | |
199 | * | |
200 | * This function takes a pointer to MAC address string | |
201 | * (i.e."XX:XX:XX:XX:XX:XX", where "XX" is a two-digit hex number), | |
202 | * stores it in the MAC address field of the EEPROM local copy, and | |
203 | * updates the local copy of the CRC. | |
204 | */ | |
205 | static void set_mac_address(char *string, int index) | |
206 | { | |
207 | u8 i; | |
208 | u8 *mac; | |
209 | ||
210 | if (strncasecmp(STARFIVE_OUI_PREFIX, string, | |
211 | strlen(STARFIVE_OUI_PREFIX))) { | |
212 | printf("The MAC address doesn't match StarFive OUI %s\n", | |
213 | STARFIVE_OUI_PREFIX); | |
214 | return; | |
215 | } | |
216 | mac = (index == 0) ? pbuf.eeprom.atom4.data.mac0_addr : | |
217 | pbuf.eeprom.atom4.data.mac1_addr; | |
218 | ||
219 | for (i = 0; *string && (i < MAC_ADDR_BYTES); i++) { | |
220 | mac[i] = hextoul(string, &string); | |
221 | ||
222 | if (*string == ':') | |
223 | string++; | |
224 | } | |
225 | ||
226 | update_crc(); | |
227 | } | |
228 | ||
229 | /** | |
230 | * init_local_copy() - initialize the in-memory EEPROM copy | |
231 | * | |
232 | * Initialize the in-memory EEPROM copy with the magic number. Must | |
233 | * be done when preparing to initialize a blank EEPROM, or overwrite | |
234 | * one with a corrupted magic number. | |
235 | */ | |
236 | static void init_local_copy(void) | |
237 | { | |
238 | memset((void *)pbuf.buf, 0, sizeof(struct starfive_eeprom)); | |
239 | memcpy(pbuf.eeprom.header.signature, STARFIVE_EEPROM_HATS_SIG, | |
240 | strlen(STARFIVE_EEPROM_HATS_SIG)); | |
241 | pbuf.eeprom.header.version = FORMAT_VERSION; | |
242 | pbuf.eeprom.header.numatoms = 2; | |
243 | pbuf.eeprom.header.eeplen = sizeof(struct starfive_eeprom); | |
244 | ||
245 | pbuf.eeprom.atom1.header.type = HATS_ATOM_VENDOR; | |
246 | pbuf.eeprom.atom1.header.count = 1; | |
247 | pbuf.eeprom.atom1.header.dlen = sizeof(struct eeprom_atom1_data) + sizeof(u16); | |
248 | pbuf.eeprom.atom1.data.vslen = STARFIVE_EEPROM_ATOM1_VSTR_SIZE; | |
249 | pbuf.eeprom.atom1.data.pslen = STARFIVE_EEPROM_ATOM1_PSTR_SIZE; | |
250 | memcpy(pbuf.eeprom.atom1.data.vstr, STARFIVE_EEPROM_ATOM1_VSTR, | |
251 | strlen(STARFIVE_EEPROM_ATOM1_VSTR)); | |
252 | memcpy(pbuf.eeprom.atom1.data.pstr, STARFIVE_EEPROM_ATOM1_PSTR, | |
253 | strlen(STARFIVE_EEPROM_ATOM1_PSTR)); | |
254 | ||
255 | pbuf.eeprom.atom4.header.type = HATS_ATOM_CUSTOM; | |
256 | pbuf.eeprom.atom4.header.count = 2; | |
257 | pbuf.eeprom.atom4.header.dlen = sizeof(struct eeprom_atom4_data) + sizeof(u16); | |
258 | pbuf.eeprom.atom4.data.version = FORMAT_VERSION; | |
259 | pbuf.eeprom.atom4.data.pcb_revision = PCB_VERSION; | |
260 | pbuf.eeprom.atom4.data.bom_revision = BOM_VERSION; | |
261 | set_mac_address(STARFIVE_DEFAULT_MAC0, 0); | |
262 | set_mac_address(STARFIVE_DEFAULT_MAC1, 1); | |
263 | } | |
264 | ||
265 | /** | |
266 | * prog_eeprom() - write the EEPROM from memory | |
267 | */ | |
268 | static int prog_eeprom(unsigned int size) | |
269 | { | |
270 | unsigned int i; | |
271 | void *p; | |
272 | uchar tmp_buff[STARFIVE_EEPROM_HATS_SIZE_MAX]; | |
273 | struct udevice *dev; | |
274 | int ret; | |
275 | ||
276 | if (is_match_magic()) { | |
277 | printf("MAGIC ERROR, Please check the data@%p.\n", pbuf.buf); | |
278 | return -1; | |
279 | } | |
280 | ||
281 | ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM, | |
282 | CONFIG_SYS_I2C_EEPROM_ADDR, | |
283 | CONFIG_SYS_I2C_EEPROM_ADDR_LEN, | |
284 | &dev); | |
285 | if (ret) { | |
286 | printf("Get i2c bus:%d addr:%d fail.\n", CONFIG_SYS_EEPROM_BUS_NUM, | |
287 | CONFIG_SYS_I2C_EEPROM_ADDR); | |
288 | return ret; | |
289 | } | |
290 | ||
291 | for (i = 0, p = (u8 *)pbuf.buf; i < size; ) { | |
292 | if (!ret) | |
293 | ret = dm_i2c_write(dev, i, p, min((int)(size - i), | |
294 | BYTES_PER_EEPROM_PAGE)); | |
295 | if (ret) | |
296 | break; | |
297 | ||
298 | udelay(EEPROM_WRITE_DELAY_MS); | |
299 | i += BYTES_PER_EEPROM_PAGE; | |
300 | p += BYTES_PER_EEPROM_PAGE; | |
301 | } | |
302 | ||
303 | if (!ret) { | |
304 | /* Verify the write by reading back the EEPROM and comparing */ | |
305 | ret = dm_i2c_read(dev, | |
306 | STARFIVE_EEPROM_WP_OFFSET, | |
307 | tmp_buff, | |
308 | STARFIVE_EEPROM_HATS_SIZE_MAX); | |
309 | if (!ret && memcmp((void *)pbuf.buf, (void *)tmp_buff, | |
310 | STARFIVE_EEPROM_HATS_SIZE_MAX)) | |
311 | ret = -1; | |
312 | } | |
313 | ||
314 | if (ret) { | |
315 | has_been_read = -1; | |
316 | printf("Programming failed.\n"); | |
317 | return -1; | |
318 | } | |
319 | ||
320 | printf("Programming passed.\n"); | |
321 | return 0; | |
322 | } | |
323 | ||
324 | /** | |
325 | * read_eeprom() - read the EEPROM into memory, if it hasn't been read already | |
326 | */ | |
327 | static int read_eeprom(void) | |
328 | { | |
329 | int ret; | |
330 | struct udevice *dev; | |
331 | ||
332 | if (has_been_read == 1) | |
333 | return 0; | |
334 | ||
335 | ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM, | |
336 | CONFIG_SYS_I2C_EEPROM_ADDR, 1, &dev); | |
337 | if (!ret) | |
338 | ret = dm_i2c_read(dev, 0, (u8 *)pbuf.buf, | |
339 | STARFIVE_EEPROM_HATS_SIZE_MAX); | |
340 | ||
341 | has_been_read = (ret == 0) ? 1 : 0; | |
342 | ||
343 | return ret; | |
344 | } | |
345 | ||
346 | /** | |
347 | * set_pcb_revision() - stores a StarFive PCB revision into the local EEPROM copy | |
348 | * | |
349 | * Takes a pointer to a string representing the numeric PCB revision in | |
350 | * decimal ("0" - "255"), stores it in the pcb_revision field of the | |
351 | * EEPROM local copy, and updates the CRC of the local copy. | |
352 | */ | |
353 | static void set_pcb_revision(char *string) | |
354 | { | |
355 | u32 p; | |
356 | ||
357 | p = simple_strtoul(string, &string, 16); | |
358 | if (p > U8_MAX) { | |
359 | printf("%s must not be greater than %d\n", "PCB revision", | |
360 | U8_MAX); | |
361 | return; | |
362 | } | |
363 | ||
364 | pbuf.eeprom.atom4.data.pcb_revision = p; | |
365 | ||
366 | update_crc(); | |
367 | } | |
368 | ||
369 | /** | |
370 | * set_bom_revision() - stores a StarFive BOM revision into the local EEPROM copy | |
371 | * | |
372 | * Takes a pointer to a uppercase ASCII character representing the BOM | |
373 | * revision ("A" - "Z"), stores it in the bom_revision field of the | |
374 | * EEPROM local copy, and updates the CRC of the local copy. | |
375 | */ | |
376 | static void set_bom_revision(char *string) | |
377 | { | |
378 | if (string[0] < 'A' || string[0] > 'Z') { | |
379 | printf("BOM revision must be an uppercase letter between A and Z\n"); | |
380 | return; | |
381 | } | |
382 | ||
383 | pbuf.eeprom.atom4.data.bom_revision = string[0]; | |
384 | ||
385 | update_crc(); | |
386 | } | |
387 | ||
388 | /** | |
389 | * set_product_id() - stores a StarFive product ID into the local EEPROM copy | |
390 | * | |
391 | * Takes a pointer to a string representing the numeric product ID in | |
392 | * string ("VF7100A1-2150-D008E000-00000001\0"), stores it in the product string | |
393 | * field of the EEPROM local copy, and updates the CRC of the local copy. | |
394 | */ | |
395 | static void set_product_id(char *string) | |
396 | { | |
397 | u32 len; | |
398 | ||
399 | len = (strlen(string) > STARFIVE_EEPROM_ATOM1_PSTR_SIZE) ? | |
400 | STARFIVE_EEPROM_ATOM1_PSTR_SIZE : strlen(string); | |
401 | ||
402 | memcpy((void *)pbuf.eeprom.atom1.data.pstr, (void *)string, len); | |
403 | ||
404 | update_crc(); | |
405 | } | |
406 | ||
90e9dcd7 HS |
407 | const char *get_product_id_from_eeprom(void) |
408 | { | |
409 | if (read_eeprom()) | |
410 | return NULL; | |
411 | ||
412 | return pbuf.eeprom.atom1.data.pstr; | |
413 | } | |
414 | ||
aea1bd95 YW |
415 | int do_mac(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) |
416 | { | |
417 | char *cmd; | |
418 | ||
419 | if (argc == 1) { | |
420 | show_eeprom(); | |
421 | return 0; | |
422 | } | |
423 | ||
424 | if (argc > 3) | |
f54c7c53 | 425 | return CMD_RET_USAGE; |
aea1bd95 YW |
426 | |
427 | cmd = argv[1]; | |
428 | ||
429 | /* Commands with no argument */ | |
430 | if (!strcmp(cmd, "read_eeprom")) { | |
431 | has_been_read = 0; | |
432 | return read_eeprom(); | |
433 | } else if (!strcmp(cmd, "initialize")) { | |
434 | init_local_copy(); | |
435 | return 0; | |
436 | } else if (!strcmp(cmd, "write_eeprom")) { | |
437 | return prog_eeprom(STARFIVE_EEPROM_HATS_SIZE_MAX); | |
ef3ceb2c HS |
438 | } else if (!strcmp(cmd, "raw")) { |
439 | dump_raw_eeprom(); | |
440 | return 0; | |
aea1bd95 YW |
441 | } |
442 | ||
443 | if (argc != 3) | |
f54c7c53 | 444 | return CMD_RET_USAGE; |
aea1bd95 YW |
445 | |
446 | if (is_match_magic()) { | |
447 | printf("Please read the EEPROM ('read_eeprom') and/or initialize the EEPROM ('initialize') first.\n"); | |
448 | return 0; | |
449 | } | |
450 | ||
451 | if (!strcmp(cmd, "mac0_address")) { | |
452 | set_mac_address(argv[2], 0); | |
453 | return 0; | |
454 | } else if (!strcmp(cmd, "mac1_address")) { | |
455 | set_mac_address(argv[2], 1); | |
456 | return 0; | |
457 | } else if (!strcmp(cmd, "pcb_revision")) { | |
458 | set_pcb_revision(argv[2]); | |
459 | return 0; | |
460 | } else if (!strcmp(cmd, "bom_revision")) { | |
461 | set_bom_revision(argv[2]); | |
462 | return 0; | |
463 | } else if (!strcmp(cmd, "product_id")) { | |
464 | set_product_id(argv[2]); | |
465 | return 0; | |
466 | } | |
467 | ||
f54c7c53 | 468 | return CMD_RET_USAGE; |
aea1bd95 YW |
469 | } |
470 | ||
471 | /** | |
472 | * mac_read_from_eeprom() - read the MAC address & the serial number in EEPROM | |
473 | * | |
474 | * This function reads the MAC address and the serial number from EEPROM and | |
475 | * sets the appropriate environment variables for each one read. | |
476 | * | |
477 | * The environment variables are only set if they haven't been set already. | |
478 | * This ensures that any user-saved variables are never overwritten. | |
479 | * | |
480 | * If CONFIG_ID_EEPROM is enabled, this function will be called in | |
481 | * "static init_fnc_t init_sequence_r[]" of u-boot/common/board_r.c. | |
482 | */ | |
483 | int mac_read_from_eeprom(void) | |
484 | { | |
485 | /** | |
486 | * try to fill the buff from EEPROM, | |
487 | * always return SUCCESS, even some error happens. | |
488 | */ | |
489 | if (read_eeprom()) { | |
490 | dump_raw_eeprom(); | |
491 | return 0; | |
492 | } | |
493 | ||
494 | // 1, setup ethaddr env | |
71914337 | 495 | eth_env_set_enetaddr("ethaddr", pbuf.eeprom.atom4.data.mac0_addr); |
aea1bd95 YW |
496 | eth_env_set_enetaddr("eth1addr", pbuf.eeprom.atom4.data.mac1_addr); |
497 | ||
498 | /** | |
499 | * 2, setup serial# env, reference to hifive-platform-i2c-eeprom.c, | |
500 | * serial# can be a ASCII string, but not just a hex number, so we | |
501 | * setup serial# in the 32Byte format: | |
502 | * "VF7100A1-2201-D008E000-00000001;" | |
503 | * "<product>-<date>-<DDR&eMMC>-<serial_number>" | |
504 | * <date>: 4Byte, should be the output of `date +%y%W` | |
505 | * <DDR&eMMC>: 8Byte, "D008" means 8GB, "D01T" means 1TB; | |
506 | * "E000" means no eMMC,"E032" means 32GB, "E01T" means 1TB. | |
507 | * <serial_number>: 8Byte, the Unique Identifier of board in hex. | |
508 | */ | |
509 | if (!env_get("serial#")) | |
510 | env_set("serial#", pbuf.eeprom.atom1.data.pstr); | |
511 | ||
512 | printf("StarFive EEPROM format v%u\n", pbuf.eeprom.header.version); | |
513 | show_eeprom(); | |
514 | return 0; | |
515 | } | |
516 | ||
517 | /** | |
518 | * get_pcb_revision_from_eeprom - get the PCB revision | |
519 | * | |
520 | * 1.2A return 'A'/'a', 1.3B return 'B'/'b',other values are illegal | |
521 | */ | |
522 | u8 get_pcb_revision_from_eeprom(void) | |
523 | { | |
524 | u8 pv = 0xFF; | |
525 | ||
526 | if (read_eeprom()) | |
527 | return pv; | |
528 | ||
529 | return pbuf.eeprom.atom1.data.pstr[6]; | |
530 | } | |
531 | ||
532 | /** | |
533 | * get_ddr_size_from_eeprom - get the DDR size | |
534 | * pstr: VF7110A1-2228-D008E000-00000001 | |
535 | * VF7110A1/VF7110B1 : VisionFive JH7110A /VisionFive JH7110B | |
536 | * D008: 8GB LPDDR4 | |
537 | * E000: No emmc device, ECxx: include emmc device, xx: Capacity size[GB] | |
538 | * return: the field of 'D008E000' | |
539 | */ | |
540 | ||
541 | u32 get_ddr_size_from_eeprom(void) | |
542 | { | |
543 | u32 pv = 0xFFFFFFFF; | |
544 | ||
545 | if (read_eeprom()) | |
546 | return pv; | |
547 | ||
548 | return hextoul(&pbuf.eeprom.atom1.data.pstr[14], NULL); | |
549 | } | |
f54c7c53 | 550 | |
3616218b | 551 | U_BOOT_LONGHELP(mac, |
f54c7c53 HS |
552 | "\n" |
553 | " - display EEPROM content\n" | |
554 | "mac read_eeprom\n" | |
555 | " - read EEPROM content into memory data structure\n" | |
556 | "mac write_eeprom\n" | |
557 | " - save memory data structure to the EEPROM\n" | |
558 | "mac initialize\n" | |
559 | " - initialize the in-memory EEPROM copy with default data\n" | |
ef3ceb2c HS |
560 | "mac raw\n" |
561 | " - hexdump memory data structure\n" | |
f54c7c53 HS |
562 | "mac mac0_address <xx:xx:xx:xx:xx:xx>\n" |
563 | " - stores a MAC0 address into the local EEPROM copy\n" | |
564 | "mac mac1_address <xx:xx:xx:xx:xx:xx>\n" | |
565 | " - stores a MAC1 address into the local EEPROM copy\n" | |
566 | "mac pcb_revision <?>\n" | |
567 | " - stores a StarFive PCB revision into the local EEPROM copy\n" | |
568 | "mac bom_revision <A>\n" | |
569 | " - stores a StarFive BOM revision into the local EEPROM copy\n" | |
570 | "mac product_id <VF7110A1-2228-D008E000-xxxxxxxx>\n" | |
3616218b | 571 | " - stores a StarFive product ID into the local EEPROM copy\n"); |
f54c7c53 HS |
572 | |
573 | U_BOOT_CMD( | |
574 | mac, 3, 1, do_mac, | |
575 | "display and program the board revision and MAC address in EEPROM", | |
3616218b | 576 | mac_help_text); |