jh7100-i2c-eeprom.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. /* SPDX-License-Identifier: GPL-2.0+ */
  2. /*
  3. * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
  4. * Written by Wei Fu (wefu@redhat.com)
  5. */
  6. #include <common.h>
  7. #include <command.h>
  8. #include <env.h>
  9. #include <i2c.h>
  10. #include <init.h>
  11. #include <linux/ctype.h>
  12. #include <linux/delay.h>
  13. //#include <u-boot/crc.h>
  14. /*
  15. * MAGIC_NUMBER_BYTES: number of bytes used by the magic number
  16. */
  17. #define MAGIC_NUMBER_BYTES 4
  18. /*
  19. * SERIAL_NUMBER_BYTES: number of bytes used by the board serial
  20. * number
  21. */
  22. //#define SERIAL_NUMBER_BYTES 16
  23. /*
  24. * MAC_ADDR_BYTES: number of bytes used by the Ethernet MAC address
  25. */
  26. #define MAC_ADDR_BYTES 6
  27. /*
  28. * MAC_ADDR_STRLEN: length of mac address string
  29. */
  30. #define MAC_ADDR_STRLEN 17
  31. /*
  32. * Atom Types
  33. * 0x0000 = invalid
  34. * 0x0001 = vendor info
  35. * 0x0002 = GPIO map
  36. * 0x0003 = Linux device tree blob
  37. * 0x0004 = manufacturer custom data
  38. * 0x0005-0xfffe = reserved for future use
  39. * 0xffff = invalid
  40. */
  41. #define HATS_ATOM_INVALID 0x0000
  42. #define HATS_ATOM_VENDOR 0x0001
  43. #define HATS_ATOM_GPIO 0x0002
  44. #define HATS_ATOM_DTB 0x0003
  45. #define HATS_ATOM_CUSTOM 0x0004
  46. #define HATS_ATOM_INVALID_END 0xffff
  47. struct eeprom_hats_header {
  48. char signature[MAGIC_NUMBER_BYTES]; /* ASCII table signature */
  49. u8 version; /* EEPROM data format version */
  50. /* (0x00 reserved, 0x01 = first version) */
  51. u8 reversed; /* 0x00, Reserved field */
  52. u16 numatoms; /* total atoms in EEPROM */
  53. u32 eeplen; /* total length in bytes of all eeprom data */
  54. /* (including this header) */
  55. };
  56. struct eeprom_hats_atom_header {
  57. u16 type;
  58. u16 count;
  59. u32 dlen;
  60. };
  61. /**
  62. * static eeprom: EEPROM layout for the StarFive platform I2C format
  63. */
  64. struct starfive_eeprom_atom1_data {
  65. u8 uuid[16];
  66. u16 pid;
  67. u16 pver;
  68. u8 vslen;
  69. u8 pslen;
  70. uchar vstr[CONFIG_STARFIVE_EEPROM_ATOM1_VSTR_SIZE];
  71. uchar pstr[CONFIG_STARFIVE_EEPROM_ATOM1_PSTR_SIZE]; /* product SN */
  72. };
  73. struct starfive_eeprom_atom1 {
  74. struct eeprom_hats_atom_header header;
  75. struct starfive_eeprom_atom1_data data;
  76. u16 crc16;
  77. };
  78. struct starfive_eeprom_atom4_v1_data {
  79. u16 version;
  80. u8 pcb_revision; /* PCB version */
  81. u8 bom_revision; /* BOM version */
  82. u8 mac_addr[MAC_ADDR_BYTES]; /* Ethernet0 MAC */
  83. };
  84. struct starfive_eeprom_atom4_v1 {
  85. struct eeprom_hats_atom_header header;
  86. struct starfive_eeprom_atom4_v1_data data;
  87. u16 crc16;
  88. };
  89. /* Set to 1 if we've read EEPROM into memory
  90. * Set to -1 if EEPROM data is wrong
  91. */
  92. static int has_been_read;
  93. /**
  94. * helper struct for getting info from the local EEPROM copy.
  95. * most of the items are pointers to the eeprom_wp_buff.
  96. * ONLY serialnum is the u32 from the last 8 Bytes of product string
  97. */
  98. struct starfive_eeprom_info {
  99. char *vstr; /* Vendor string in ATOM1 */
  100. char *pstr; /* product string in ATOM1 */
  101. u32 serialnum; /* serial number from in product string*/
  102. u16 *version; /* custom data version in ATOM4 */
  103. u8 *pcb_revision; /* PCB version in ATOM4 */
  104. u8 *bom_revision; /* BOM version in ATOM4 */
  105. u8 *mac_addr; /* Ethernet0 MAC in ATOM4 */
  106. };
  107. static struct starfive_eeprom_info einfo;
  108. static uchar eeprom_wp_buff[CONFIG_STARFIVE_EEPROM_HATS_SIZE_MAX];
  109. static struct eeprom_hats_header starfive_eeprom_hats_header_default = {
  110. .signature = STARFIVE_EEPROM_HATS_SIG,
  111. .version = FORMAT_VERSION,
  112. .numatoms = 2,
  113. .eeplen = sizeof(struct eeprom_hats_header) +
  114. sizeof(struct starfive_eeprom_atom1) +
  115. sizeof(struct starfive_eeprom_atom4_v1)
  116. };
  117. static struct starfive_eeprom_atom1 starfive_eeprom_atom1_default = {
  118. .header = {
  119. .type = HATS_ATOM_VENDOR,
  120. .count = 1,
  121. .dlen = sizeof(struct starfive_eeprom_atom1_data) + sizeof(u16)
  122. },
  123. .data = {
  124. .uuid = {0},
  125. .pid = 0,
  126. .pver = 0,
  127. .vslen = CONFIG_STARFIVE_EEPROM_ATOM1_VSTR_SIZE,
  128. .pslen = CONFIG_STARFIVE_EEPROM_ATOM1_PSTR_SIZE,
  129. .vstr = CONFIG_STARFIVE_EEPROM_ATOM1_VSTR,
  130. .pstr = CONFIG_STARFIVE_EEPROM_ATOM1_PSTR
  131. }
  132. };
  133. static struct starfive_eeprom_atom4_v1 starfive_eeprom_atom4_v1_default = {
  134. .header = {
  135. .type = HATS_ATOM_CUSTOM,
  136. .count = 2,
  137. .dlen = sizeof(struct starfive_eeprom_atom4_v1_data) + sizeof(u16)
  138. },
  139. .data = {
  140. .version = FORMAT_VERSION,
  141. .pcb_revision = PCB_VERSION,
  142. .bom_revision = BOM_VERSION,
  143. .mac_addr = STARFIVE_DEFAULT_MAC
  144. }
  145. };
  146. //static u8 starfive_default_mac[MAC_ADDR_BYTES] = STARFIVE_DEFAULT_MAC;
  147. /**
  148. * is_match_magic() - Does the magic number match that of a StarFive EEPROM?
  149. *
  150. * @hats: the pointer of eeprom_hats_header
  151. * Return: status code, 0: Yes, non-0: NO
  152. */
  153. static inline int is_match_magic(char *hats)
  154. {
  155. return strncmp(hats, STARFIVE_EEPROM_HATS_SIG, MAGIC_NUMBER_BYTES);
  156. }
  157. /**
  158. * calculate_crc16() - Calculate the current CRC for atom
  159. * Porting from https://github.com/raspberrypi/hats, getcrc
  160. * @data: the pointer of eeprom_hats_atom_header
  161. * @size: total length in bytes of the entire atom
  162. * (type, count, dlen, data)
  163. * Return: result: crc16 code
  164. */
  165. #define CRC16 0x8005
  166. static u16 calculate_crc16(uchar* data, unsigned int size)
  167. {
  168. int i, j = 0x0001;
  169. u16 out = 0, crc = 0;
  170. int bits_read = 0, bit_flag;
  171. /* Sanity check: */
  172. if((data == NULL) || size == 0)
  173. return 0;
  174. while(size > 0) {
  175. bit_flag = out >> 15;
  176. /* Get next bit: */
  177. out <<= 1;
  178. // item a) work from the least significant bits
  179. out |= (*data >> bits_read) & 1;
  180. /* Increment bit counter: */
  181. bits_read++;
  182. if(bits_read > 7) {
  183. bits_read = 0;
  184. data++;
  185. size--;
  186. }
  187. /* Cycle check: */
  188. if(bit_flag)
  189. out ^= CRC16;
  190. }
  191. // item b) "push out" the last 16 bits
  192. for (i = 0; i < 16; ++i) {
  193. bit_flag = out >> 15;
  194. out <<= 1;
  195. if(bit_flag)
  196. out ^= CRC16;
  197. }
  198. // item c) reverse the bits
  199. for (i = 0x8000; i != 0; i >>=1, j <<= 1) {
  200. if (i & out)
  201. crc |= j;
  202. }
  203. return crc;
  204. }
  205. /* This function should be called after each update to any EEPROM ATOM */
  206. static inline void update_crc(struct eeprom_hats_atom_header *atom)
  207. {
  208. uint atom_crc_offset = sizeof(struct eeprom_hats_atom_header) +
  209. atom->dlen - sizeof(u16);
  210. u16 *atom_crc_p = (void *) atom + atom_crc_offset;
  211. *atom_crc_p = calculate_crc16((uchar*) atom, atom_crc_offset);
  212. }
  213. /**
  214. * dump_raw_eeprom - display the raw contents of the EEPROM
  215. */
  216. static void dump_raw_eeprom(u8 *e, unsigned int size)
  217. {
  218. unsigned int i;
  219. printf("EEPROM dump: (0x%x bytes)\n", size);
  220. for (i = 0; i < size; i++) {
  221. if (!(i % 0x10))
  222. printf("%02X: ", i);
  223. printf("%02X ", e[i]);
  224. if (((i % 16) == 15) || (i == size - 1))
  225. printf("\n");
  226. }
  227. return;
  228. }
  229. static int hats_atom_crc_check(struct eeprom_hats_atom_header *atom)
  230. {
  231. u16 atom_crc, data_crc;
  232. uint atom_crc_offset = sizeof(struct eeprom_hats_atom_header) +
  233. atom->dlen - sizeof(atom_crc);
  234. u16 *atom_crc_p = (void *) atom + atom_crc_offset;
  235. atom_crc = *atom_crc_p;
  236. data_crc = calculate_crc16((uchar *) atom, atom_crc_offset);
  237. if (atom_crc == data_crc)
  238. return 0;
  239. printf("EEPROM HATs: CRC ERROR in atom %x type %x, (%x!=%x)\n",
  240. atom->count, atom->type, atom_crc, data_crc);
  241. return -1;
  242. }
  243. static void *hats_get_atom(struct eeprom_hats_header *header, u16 type)
  244. {
  245. struct eeprom_hats_atom_header *atom;
  246. void *hats_eeprom_max = (void *)header + header->eeplen;
  247. void *temp = (void *)header + sizeof(struct eeprom_hats_header);
  248. for (int numatoms = (int)header->numatoms; numatoms > 0; numatoms--) {
  249. atom = (struct eeprom_hats_atom_header *)temp;
  250. if (hats_atom_crc_check(atom))
  251. return NULL;
  252. if (atom->type == type)
  253. return (void *)atom;
  254. /* go to next atom */
  255. temp = (void *)atom + sizeof(struct eeprom_hats_atom_header) +
  256. atom->dlen;
  257. if (temp > hats_eeprom_max) {
  258. printf("EEPROM HATs: table overflow next@%p, max@%p\n",
  259. temp, hats_eeprom_max);
  260. break;
  261. }
  262. }
  263. /* fail to get atom */
  264. return NULL;
  265. }
  266. /**
  267. * show_eeprom - display the contents of the EEPROM
  268. */
  269. static void show_eeprom(struct starfive_eeprom_info *einfo)
  270. {
  271. printf("\n--------EEPROM INFO--------\n");
  272. printf("Vendor : %s\n", einfo->vstr);
  273. printf("Product full SN: %s\n", einfo->pstr);
  274. printf("data version: 0x%x\n", *einfo->version);
  275. if (1 == *einfo->version) {
  276. printf("PCB revision: 0x%x\n", *einfo->pcb_revision);
  277. printf("BOM revision: %c\n", *einfo->bom_revision);
  278. printf("Ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
  279. einfo->mac_addr[0], einfo->mac_addr[1],
  280. einfo->mac_addr[2], einfo->mac_addr[3],
  281. einfo->mac_addr[4], einfo->mac_addr[5]);
  282. } else {
  283. printf("Custom data v%d is not Supported\n", *einfo->version);
  284. }
  285. printf("--------EEPROM INFO--------\n\n");
  286. }
  287. /**
  288. * parse_eeprom_info - parse the contents of the EEPROM
  289. * If everthing gose right,
  290. * 1, set has_been_read to 1
  291. * 2, display info
  292. *
  293. * If anything goes wrong,
  294. * 1, set has_been_read to -1
  295. * 2, dump data by hex for debug
  296. *
  297. * @buf: the pointer of eeprom_hats_header in memory
  298. * Return: status code, 0: Success, non-0: Fail
  299. *
  300. */
  301. static int parse_eeprom_info(struct eeprom_hats_header *buf)
  302. {
  303. struct eeprom_hats_atom_header *atom;
  304. void *atom_data;
  305. struct starfive_eeprom_atom1_data *atom1 = NULL;
  306. struct starfive_eeprom_atom4_v1_data *atom4_v1 = NULL;
  307. if (is_match_magic((char *)buf)) {
  308. printf("Not a StarFive EEPROM data format - magic error\n");
  309. goto error;
  310. };
  311. printf("StarFive EEPROM format v%u\n", buf->version);
  312. // parse atom1(verdor)
  313. atom = (struct eeprom_hats_atom_header *)
  314. hats_get_atom(buf, HATS_ATOM_VENDOR);
  315. if (atom) {
  316. atom_data = (void *)atom +
  317. sizeof(struct eeprom_hats_atom_header);
  318. atom1 = (struct starfive_eeprom_atom1_data *)atom_data;
  319. einfo.vstr = atom1->vstr;
  320. einfo.pstr = atom1->pstr;
  321. einfo.serialnum = (u32)hextoul((void *)atom1->pstr +
  322. CONFIG_STARFIVE_EEPROM_ATOM1_SN_OFFSET,
  323. NULL);
  324. } else {
  325. printf("fail to get vendor atom\n");
  326. goto error;
  327. };
  328. // parse atom4(custom)
  329. atom = (struct eeprom_hats_atom_header *)
  330. hats_get_atom(buf, HATS_ATOM_CUSTOM);
  331. if (atom) {
  332. atom_data = (void *)atom +
  333. sizeof(struct eeprom_hats_atom_header);
  334. atom4_v1 = (struct starfive_eeprom_atom4_v1_data *)atom_data;
  335. einfo.version = &atom4_v1->version;
  336. if (*einfo.version == 1) {
  337. einfo.pcb_revision = &atom4_v1->pcb_revision;
  338. einfo.bom_revision = &atom4_v1->bom_revision;
  339. einfo.mac_addr = atom4_v1->mac_addr;
  340. }
  341. } else {
  342. printf("fail to get custom data atom\n");
  343. goto error;
  344. };
  345. // everthing gose right
  346. has_been_read = 1;
  347. show_eeprom(&einfo);
  348. return 0;
  349. error:
  350. has_been_read = -1;
  351. dump_raw_eeprom(eeprom_wp_buff,
  352. CONFIG_STARFIVE_EEPROM_HATS_SIZE_MAX);
  353. return -1;
  354. }
  355. /**
  356. * read_eeprom() - read the EEPROM into memory, if it hasn't been read yet
  357. * @buf: the pointer of eeprom data buff
  358. * Return: status code, 0: Success, non-0: Fail
  359. * Note: depend on CONFIG_SYS_EEPROM_BUS_NUM
  360. * CONFIG_SYS_I2C_EEPROM_ADDR
  361. * CONFIG_STARFIVE_EEPROM_WP_OFFSET
  362. * CONFIG_STARFIVE_EEPROM_HATS_SIZE_MAX
  363. */
  364. static int read_eeprom(uint8_t *buf)
  365. {
  366. int ret;
  367. struct udevice *dev;
  368. if (has_been_read == 1)
  369. return 0;
  370. ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM,
  371. CONFIG_SYS_I2C_EEPROM_ADDR,
  372. CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
  373. &dev);
  374. if (!ret) {
  375. ret = dm_i2c_read(dev, CONFIG_STARFIVE_EEPROM_WP_OFFSET,
  376. buf, CONFIG_STARFIVE_EEPROM_HATS_SIZE_MAX);
  377. }
  378. if (ret) {
  379. printf("fail to read EEPROM.\n");
  380. return ret;
  381. }
  382. return parse_eeprom_info((struct eeprom_hats_header *)buf);
  383. }
  384. /**
  385. * prog_eeprom() - write the EEPROM from memory
  386. */
  387. static int prog_eeprom(uint8_t *buf, unsigned int size)
  388. {
  389. unsigned int i;
  390. void *p;
  391. uchar tmp_buff[CONFIG_STARFIVE_EEPROM_HATS_SIZE_MAX];
  392. struct udevice *dev;
  393. int ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM,
  394. CONFIG_SYS_I2C_EEPROM_ADDR,
  395. CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
  396. &dev);
  397. if (is_match_magic(buf)) {
  398. printf("MAGIC ERROR, Please check the data@%p.\n", buf);
  399. return -1;
  400. }
  401. for (i = 0, p = buf; i < size;
  402. i += BYTES_PER_EEPROM_PAGE, p += BYTES_PER_EEPROM_PAGE) {
  403. if (!ret)
  404. ret = dm_i2c_write(dev,
  405. i + CONFIG_STARFIVE_EEPROM_WP_OFFSET,
  406. p, min((int)(size - i),
  407. BYTES_PER_EEPROM_PAGE));
  408. if (ret)
  409. break;
  410. udelay(EEPROM_WRITE_DELAY_MS);
  411. }
  412. if (!ret) {
  413. /* Verify the write by reading back the EEPROM and comparing */
  414. ret = dm_i2c_read(dev,
  415. CONFIG_STARFIVE_EEPROM_WP_OFFSET,
  416. tmp_buff,
  417. CONFIG_STARFIVE_EEPROM_HATS_SIZE_MAX);
  418. if (!ret && memcmp((void *)buf, (void *)tmp_buff,
  419. CONFIG_STARFIVE_EEPROM_HATS_SIZE_MAX))
  420. ret = -1;
  421. }
  422. if (ret) {
  423. has_been_read = -1;
  424. printf("Programming failed.Temp buff:\n");
  425. dump_raw_eeprom(tmp_buff,
  426. CONFIG_STARFIVE_EEPROM_HATS_SIZE_MAX);
  427. return -1;
  428. }
  429. printf("Programming passed.\n");
  430. return 0;
  431. }
  432. /**
  433. * set_mac_address() - stores a MAC address into the local EEPROM copy
  434. *
  435. * This function takes a pointer to MAC address string
  436. * (i.e."XX:XX:XX:XX:XX:XX", where "XX" is a two-digit hex number),
  437. * stores it in the MAC address field of the EEPROM local copy, and
  438. * updates the local copy of the CRC.
  439. */
  440. static void set_mac_address(char *string)
  441. {
  442. unsigned int i;
  443. struct eeprom_hats_atom_header *atom4;
  444. atom4 = (struct eeprom_hats_atom_header *)
  445. hats_get_atom((struct eeprom_hats_header *)eeprom_wp_buff,
  446. HATS_ATOM_CUSTOM);
  447. if (strncasecmp(STARFIVE_OUI_PREFIX, string,
  448. strlen(STARFIVE_OUI_PREFIX))) {
  449. printf("The MAC address doesn't match StarFive OUI %s\n",
  450. STARFIVE_OUI_PREFIX);
  451. return;
  452. }
  453. for (i = 0; *string && (i < MAC_ADDR_BYTES); i++) {
  454. einfo.mac_addr[i] = hextoul(string, &string);
  455. if (*string == ':')
  456. string++;
  457. }
  458. update_crc(atom4);
  459. }
  460. /**
  461. * set_pcb_revision() - stores a StarFive PCB revision into the local EEPROM copy
  462. *
  463. * Takes a pointer to a string representing the numeric PCB revision in
  464. * decimal ("0" - "255"), stores it in the pcb_revision field of the
  465. * EEPROM local copy, and updates the CRC of the local copy.
  466. */
  467. static void set_pcb_revision(char *string)
  468. {
  469. u8 p;
  470. uint base = 16;
  471. struct eeprom_hats_atom_header *atom4;
  472. atom4 = (struct eeprom_hats_atom_header *)
  473. hats_get_atom((struct eeprom_hats_header *)eeprom_wp_buff,
  474. HATS_ATOM_CUSTOM);
  475. p = (u8)simple_strtoul(string, NULL, base);
  476. if (p > U8_MAX) {
  477. printf("%s must not be greater than %d\n", "PCB revision",
  478. U8_MAX);
  479. return;
  480. }
  481. *einfo.pcb_revision = p;
  482. update_crc(atom4);
  483. }
  484. /**
  485. * set_bom_revision() - stores a StarFive BOM revision into the local EEPROM copy
  486. *
  487. * Takes a pointer to a uppercase ASCII character representing the BOM
  488. * revision ("A" - "Z"), stores it in the bom_revision field of the
  489. * EEPROM local copy, and updates the CRC of the local copy.
  490. */
  491. static void set_bom_revision(char *string)
  492. {
  493. struct eeprom_hats_atom_header *atom4;
  494. atom4 = (struct eeprom_hats_atom_header *)
  495. hats_get_atom((struct eeprom_hats_header *)eeprom_wp_buff,
  496. HATS_ATOM_CUSTOM);
  497. if (string[0] < 'A' || string[0] > 'Z') {
  498. printf("BOM revision must be an uppercase letter between A and Z\n");
  499. return;
  500. }
  501. *einfo.bom_revision = string[0];
  502. update_crc(atom4);
  503. }
  504. /**
  505. * set_product_id() - stores a StarFive product ID into the local EEPROM copy
  506. *
  507. * Takes a pointer to a string representing the numeric product ID in
  508. * string ("VF7100A1-2150-D008E000-00000001\0"), stores it in the product string
  509. * field of the EEPROM local copy, and updates the CRC of the local copy.
  510. */
  511. static void set_product_id(char *string)
  512. {
  513. struct eeprom_hats_atom_header *atom1;
  514. atom1 = (struct eeprom_hats_atom_header *)
  515. hats_get_atom((struct eeprom_hats_header *)eeprom_wp_buff,
  516. HATS_ATOM_VENDOR);
  517. memcpy((void *)einfo.pstr, (void *)string,
  518. CONFIG_STARFIVE_EEPROM_ATOM1_PSTR_SIZE);
  519. update_crc(atom1);
  520. }
  521. /**
  522. * init_local_copy() - initialize the in-memory EEPROM copy
  523. *
  524. * Initialize the in-memory EEPROM copy with the magic number. Must
  525. * be done when preparing to initialize a blank EEPROM, or overwrite
  526. * one with a corrupted magic number.
  527. */
  528. static void init_local_copy(uchar *buff)
  529. {
  530. struct eeprom_hats_header *hats = (struct eeprom_hats_header *)buff;
  531. struct eeprom_hats_atom_header *atom1 = (void *)hats +
  532. sizeof(struct eeprom_hats_header);
  533. struct eeprom_hats_atom_header *atom4_v1 = (void *)atom1 +
  534. sizeof(struct starfive_eeprom_atom1);
  535. memcpy((void *)hats, (void *)&starfive_eeprom_hats_header_default,
  536. sizeof(struct eeprom_hats_header));
  537. memcpy((void *)atom1, (void *)&starfive_eeprom_atom1_default,
  538. sizeof(struct starfive_eeprom_atom1));
  539. memcpy((void *)atom4_v1, (void *)&starfive_eeprom_atom4_v1_default,
  540. sizeof(struct starfive_eeprom_atom4_v1));
  541. update_crc(atom1);
  542. update_crc(atom4_v1);
  543. }
  544. static int print_usage(void)
  545. {
  546. printf("display and program the system ID and MAC addresses in EEPROM\n"
  547. "[read_eeprom|initialize|write_eeprom|mac_address|pcb_revision|bom_revision|product_id]\n"
  548. "mac read_eeprom\n"
  549. " - read EEPROM content into memory data structure\n"
  550. "mac write_eeprom\n"
  551. " - save memory data structure to the EEPROM\n"
  552. "mac initialize\n"
  553. " - initialize the in-memory EEPROM copy with default data\n"
  554. "mac mac_address <xx:xx:xx:xx:xx:xx>\n"
  555. " - stores a MAC address into the local EEPROM copy\n"
  556. "mac pcb_revision <?>\n"
  557. " - stores a StarFive PCB revision into the local EEPROM copy\n"
  558. "mac bom_revision <A>\n"
  559. " - stores a StarFive BOM revision into the local EEPROM copy\n"
  560. "mac product_id <VF7100A1-2150-D008E000-xxxxxxxx>\n"
  561. " - stores a StarFive product ID into the local EEPROM copy\n");
  562. return 0;
  563. }
  564. int do_mac(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
  565. {
  566. char *cmd;
  567. if (argc == 1) {
  568. show_eeprom(&einfo);
  569. return 0;
  570. }
  571. if (argc > 3)
  572. return print_usage();
  573. cmd = argv[1];
  574. /* Commands with no argument */
  575. if (!strcmp(cmd, "read_eeprom")) {
  576. has_been_read = 0;
  577. return read_eeprom(eeprom_wp_buff);
  578. } else if (!strcmp(cmd, "initialize")) {
  579. init_local_copy(eeprom_wp_buff);
  580. return 0;
  581. } else if (!strcmp(cmd, "write_eeprom")) {
  582. return prog_eeprom(eeprom_wp_buff,
  583. CONFIG_STARFIVE_EEPROM_HATS_SIZE_MAX);
  584. }
  585. if (argc != 3)
  586. return print_usage();
  587. if (is_match_magic(eeprom_wp_buff)) {
  588. printf("Please read the EEPROM ('read_eeprom') and/or initialize the EEPROM ('initialize') first.\n");
  589. return 0;
  590. }
  591. if (!strcmp(cmd, "mac_address")) {
  592. set_mac_address(argv[2]);
  593. return 0;
  594. } else if (!strcmp(cmd, "pcb_revision")) {
  595. set_pcb_revision(argv[2]);
  596. return 0;
  597. } else if (!strcmp(cmd, "bom_revision")) {
  598. set_bom_revision(argv[2]);
  599. return 0;
  600. } else if (!strcmp(cmd, "product_id")) {
  601. set_product_id(argv[2]);
  602. return 0;
  603. }
  604. return print_usage();
  605. }
  606. /**
  607. * mac_read_from_eeprom() - read the MAC address & the serial number in EEPROM
  608. *
  609. * This function reads the MAC address and the serial number from EEPROM and
  610. * sets the appropriate environment variables for each one read.
  611. *
  612. * The environment variables are only set if they haven't been set already.
  613. * This ensures that any user-saved variables are never overwritten.
  614. *
  615. * If CONFIG_ID_EEPROM is enabled, this function will be called in
  616. * "static init_fnc_t init_sequence_r[]" of u-boot/common/board_r.c.
  617. */
  618. int mac_read_from_eeprom(void)
  619. {
  620. /**
  621. * try to fill the buff from EEPROM,
  622. * always return SUCCESS, even some error happens.
  623. */
  624. if (read_eeprom(eeprom_wp_buff))
  625. return 0;
  626. // 1, setup ethaddr env
  627. eth_env_set_enetaddr("ethaddr", einfo.mac_addr);
  628. /**
  629. * 2, setup serial# env, reference to hifive-platform-i2c-eeprom.c,
  630. * serial# can be a ASCII string, but not just a hex number, so we
  631. * setup serial# in the 32Byte format:
  632. * "VF7100A1-2201-D008E000-00000001;"
  633. * "<product>-<date>-<DDR&eMMC>-<serial_number>"
  634. * <date>: 4Byte, should be the output of `date +%y%W`
  635. * <DDR&eMMC>: 8Byte, "D008" means 8GB, "D01T" means 1TB;
  636. * "E000" means no eMMC,"E032" means 32GB, "E01T" means 1TB.
  637. * <serial_number>: 8Byte, the Unique Identifier of board in hex.
  638. */
  639. if (!env_get("serial#"))
  640. env_set("serial#", einfo.pstr);
  641. return 0;
  642. }