visionfive2-i2c-eeprom.c 22 KB

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