devkits-i2c-eeprom.c 20 KB

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