PageRenderTime 55ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/cmd/eeprom.c

https://gitlab.com/jiangming1399/u-boot
C | 444 lines | 308 code | 79 blank | 57 comment | 53 complexity | 4b1c2695438fd41cf8b183bb96b803da MD5 | raw file
  1. /*
  2. * (C) Copyright 2000, 2001
  3. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  4. *
  5. * SPDX-License-Identifier: GPL-2.0+
  6. */
  7. /*
  8. * Support for read and write access to EEPROM like memory devices. This
  9. * includes regular EEPROM as well as FRAM (ferroelectic nonvolaile RAM).
  10. * FRAM devices read and write data at bus speed. In particular, there is no
  11. * write delay. Also, there is no limit imposed on the number of bytes that can
  12. * be transferred with a single read or write.
  13. *
  14. * Use the following configuration options to ensure no unneeded performance
  15. * degradation (typical for EEPROM) is incured for FRAM memory:
  16. *
  17. * #define CONFIG_SYS_I2C_FRAM
  18. * #undef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
  19. *
  20. */
  21. #include <common.h>
  22. #include <config.h>
  23. #include <command.h>
  24. #include <i2c.h>
  25. #include <eeprom_layout.h>
  26. #ifndef CONFIG_SYS_I2C_SPEED
  27. #define CONFIG_SYS_I2C_SPEED 50000
  28. #endif
  29. #ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
  30. #define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 0
  31. #endif
  32. #ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS
  33. #define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 8
  34. #endif
  35. #ifndef I2C_RXTX_LEN
  36. #define I2C_RXTX_LEN 128
  37. #endif
  38. #define EEPROM_PAGE_SIZE (1 << CONFIG_SYS_EEPROM_PAGE_WRITE_BITS)
  39. #define EEPROM_PAGE_OFFSET(x) ((x) & (EEPROM_PAGE_SIZE - 1))
  40. /*
  41. * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is
  42. * 0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM.
  43. *
  44. * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is
  45. * 0x00000nxx for EEPROM address selectors and page number at n.
  46. */
  47. #if !defined(CONFIG_SPI) || defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
  48. #if !defined(CONFIG_SYS_I2C_EEPROM_ADDR_LEN) || \
  49. (CONFIG_SYS_I2C_EEPROM_ADDR_LEN < 1) || \
  50. (CONFIG_SYS_I2C_EEPROM_ADDR_LEN > 2)
  51. #error CONFIG_SYS_I2C_EEPROM_ADDR_LEN must be 1 or 2
  52. #endif
  53. #endif
  54. __weak int eeprom_write_enable(unsigned dev_addr, int state)
  55. {
  56. return 0;
  57. }
  58. void eeprom_init(int bus)
  59. {
  60. /* SPI EEPROM */
  61. #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
  62. spi_init_f();
  63. #endif
  64. /* I2C EEPROM */
  65. #if defined(CONFIG_SYS_I2C)
  66. if (bus >= 0)
  67. i2c_set_bus_num(bus);
  68. i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
  69. #endif
  70. }
  71. static int eeprom_addr(unsigned dev_addr, unsigned offset, uchar *addr)
  72. {
  73. unsigned blk_off;
  74. int alen;
  75. blk_off = offset & 0xff; /* block offset */
  76. #if CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1
  77. addr[0] = offset >> 8; /* block number */
  78. addr[1] = blk_off; /* block offset */
  79. alen = 2;
  80. #else
  81. addr[0] = offset >> 16; /* block number */
  82. addr[1] = offset >> 8; /* upper address octet */
  83. addr[2] = blk_off; /* lower address octet */
  84. alen = 3;
  85. #endif /* CONFIG_SYS_I2C_EEPROM_ADDR_LEN */
  86. addr[0] |= dev_addr; /* insert device address */
  87. return alen;
  88. }
  89. static int eeprom_len(unsigned offset, unsigned end)
  90. {
  91. unsigned len = end - offset;
  92. /*
  93. * For a FRAM device there is no limit on the number of the
  94. * bytes that can be ccessed with the single read or write
  95. * operation.
  96. */
  97. #if !defined(CONFIG_SYS_I2C_FRAM)
  98. unsigned blk_off = offset & 0xff;
  99. unsigned maxlen = EEPROM_PAGE_SIZE - EEPROM_PAGE_OFFSET(blk_off);
  100. if (maxlen > I2C_RXTX_LEN)
  101. maxlen = I2C_RXTX_LEN;
  102. if (len > maxlen)
  103. len = maxlen;
  104. #endif
  105. return len;
  106. }
  107. static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen,
  108. uchar *buffer, unsigned len, bool read)
  109. {
  110. int ret = 0;
  111. /* SPI */
  112. #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
  113. if (read)
  114. spi_read(addr, alen, buffer, len);
  115. else
  116. spi_write(addr, alen, buffer, len);
  117. #else /* I2C */
  118. #if defined(CONFIG_SYS_I2C_EEPROM_BUS)
  119. i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS);
  120. #endif
  121. if (read)
  122. ret = i2c_read(addr[0], offset, alen - 1, buffer, len);
  123. else
  124. ret = i2c_write(addr[0], offset, alen - 1, buffer, len);
  125. if (ret)
  126. ret = 1;
  127. #endif
  128. return ret;
  129. }
  130. static int eeprom_rw(unsigned dev_addr, unsigned offset, uchar *buffer,
  131. unsigned cnt, bool read)
  132. {
  133. unsigned end = offset + cnt;
  134. unsigned alen, len;
  135. int rcode = 0;
  136. uchar addr[3];
  137. while (offset < end) {
  138. alen = eeprom_addr(dev_addr, offset, addr);
  139. len = eeprom_len(offset, end);
  140. rcode = eeprom_rw_block(offset, addr, alen, buffer, len, read);
  141. buffer += len;
  142. offset += len;
  143. if (!read)
  144. udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
  145. }
  146. return rcode;
  147. }
  148. int eeprom_read(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt)
  149. {
  150. /*
  151. * Read data until done or would cross a page boundary.
  152. * We must write the address again when changing pages
  153. * because the next page may be in a different device.
  154. */
  155. return eeprom_rw(dev_addr, offset, buffer, cnt, 1);
  156. }
  157. int eeprom_write(unsigned dev_addr, unsigned offset,
  158. uchar *buffer, unsigned cnt)
  159. {
  160. int ret;
  161. eeprom_write_enable(dev_addr, 1);
  162. /*
  163. * Write data until done or would cross a write page boundary.
  164. * We must write the address again when changing pages
  165. * because the address counter only increments within a page.
  166. */
  167. ret = eeprom_rw(dev_addr, offset, buffer, cnt, 0);
  168. eeprom_write_enable(dev_addr, 0);
  169. return ret;
  170. }
  171. static int parse_numeric_param(char *str)
  172. {
  173. char *endptr;
  174. int value = simple_strtol(str, &endptr, 16);
  175. return (*endptr != '\0') ? -1 : value;
  176. }
  177. /**
  178. * parse_i2c_bus_addr - parse the i2c bus and i2c devaddr parameters
  179. *
  180. * @i2c_bus: address to store the i2c bus
  181. * @i2c_addr: address to store the device i2c address
  182. * @argc: count of command line arguments left to parse
  183. * @argv: command line arguments left to parse
  184. * @argc_no_bus_addr: argc value we expect to see when bus & addr aren't given
  185. *
  186. * @returns: number of arguments parsed or CMD_RET_USAGE if error
  187. */
  188. static int parse_i2c_bus_addr(int *i2c_bus, ulong *i2c_addr, int argc,
  189. char * const argv[], int argc_no_bus_addr)
  190. {
  191. int argc_no_bus = argc_no_bus_addr + 1;
  192. int argc_bus_addr = argc_no_bus_addr + 2;
  193. #ifdef CONFIG_SYS_DEF_EEPROM_ADDR
  194. if (argc == argc_no_bus_addr) {
  195. *i2c_bus = -1;
  196. *i2c_addr = CONFIG_SYS_DEF_EEPROM_ADDR;
  197. return 0;
  198. }
  199. #endif
  200. if (argc == argc_no_bus) {
  201. *i2c_bus = -1;
  202. *i2c_addr = parse_numeric_param(argv[0]);
  203. return 1;
  204. }
  205. if (argc == argc_bus_addr) {
  206. *i2c_bus = parse_numeric_param(argv[0]);
  207. *i2c_addr = parse_numeric_param(argv[1]);
  208. return 2;
  209. }
  210. return CMD_RET_USAGE;
  211. }
  212. #ifdef CONFIG_CMD_EEPROM_LAYOUT
  213. __weak int eeprom_parse_layout_version(char *str)
  214. {
  215. return LAYOUT_VERSION_UNRECOGNIZED;
  216. }
  217. static unsigned char eeprom_buf[CONFIG_SYS_EEPROM_SIZE];
  218. #endif
  219. enum eeprom_action {
  220. EEPROM_READ,
  221. EEPROM_WRITE,
  222. EEPROM_PRINT,
  223. EEPROM_UPDATE,
  224. EEPROM_ACTION_INVALID,
  225. };
  226. static enum eeprom_action parse_action(char *cmd)
  227. {
  228. if (!strncmp(cmd, "read", 4))
  229. return EEPROM_READ;
  230. if (!strncmp(cmd, "write", 5))
  231. return EEPROM_WRITE;
  232. #ifdef CONFIG_CMD_EEPROM_LAYOUT
  233. if (!strncmp(cmd, "print", 5))
  234. return EEPROM_PRINT;
  235. if (!strncmp(cmd, "update", 6))
  236. return EEPROM_UPDATE;
  237. #endif
  238. return EEPROM_ACTION_INVALID;
  239. }
  240. static int eeprom_execute_command(enum eeprom_action action, int i2c_bus,
  241. ulong i2c_addr, int layout_ver, char *key,
  242. char *value, ulong addr, ulong off, ulong cnt)
  243. {
  244. int rcode = 0;
  245. const char *const fmt =
  246. "\nEEPROM @0x%lX %s: addr %08lx off %04lx count %ld ... ";
  247. #ifdef CONFIG_CMD_EEPROM_LAYOUT
  248. struct eeprom_layout layout;
  249. #endif
  250. if (action == EEPROM_ACTION_INVALID)
  251. return CMD_RET_USAGE;
  252. eeprom_init(i2c_bus);
  253. if (action == EEPROM_READ) {
  254. printf(fmt, i2c_addr, "read", addr, off, cnt);
  255. rcode = eeprom_read(i2c_addr, off, (uchar *)addr, cnt);
  256. puts("done\n");
  257. return rcode;
  258. } else if (action == EEPROM_WRITE) {
  259. printf(fmt, i2c_addr, "write", addr, off, cnt);
  260. rcode = eeprom_write(i2c_addr, off, (uchar *)addr, cnt);
  261. puts("done\n");
  262. return rcode;
  263. }
  264. #ifdef CONFIG_CMD_EEPROM_LAYOUT
  265. rcode = eeprom_read(i2c_addr, 0, eeprom_buf, CONFIG_SYS_EEPROM_SIZE);
  266. if (rcode < 0)
  267. return rcode;
  268. eeprom_layout_setup(&layout, eeprom_buf, CONFIG_SYS_EEPROM_SIZE,
  269. layout_ver);
  270. if (action == EEPROM_PRINT) {
  271. layout.print(&layout);
  272. return 0;
  273. }
  274. layout.update(&layout, key, value);
  275. rcode = eeprom_write(i2c_addr, 0, layout.data, CONFIG_SYS_EEPROM_SIZE);
  276. #endif
  277. return rcode;
  278. }
  279. #define NEXT_PARAM(argc, index) { (argc)--; (index)++; }
  280. int do_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  281. {
  282. int layout_ver = LAYOUT_VERSION_AUTODETECT;
  283. enum eeprom_action action = EEPROM_ACTION_INVALID;
  284. int i2c_bus = -1, index = 0;
  285. ulong i2c_addr = -1, addr = 0, cnt = 0, off = 0;
  286. int ret;
  287. char *field_name = "";
  288. char *field_value = "";
  289. if (argc <= 1)
  290. return CMD_RET_USAGE;
  291. NEXT_PARAM(argc, index); /* Skip program name */
  292. action = parse_action(argv[index]);
  293. NEXT_PARAM(argc, index);
  294. if (action == EEPROM_ACTION_INVALID)
  295. return CMD_RET_USAGE;
  296. #ifdef CONFIG_CMD_EEPROM_LAYOUT
  297. if (action == EEPROM_PRINT || action == EEPROM_UPDATE) {
  298. if (!strcmp(argv[index], "-l")) {
  299. NEXT_PARAM(argc, index);
  300. layout_ver = eeprom_parse_layout_version(argv[index]);
  301. NEXT_PARAM(argc, index);
  302. }
  303. }
  304. #endif
  305. switch (action) {
  306. case EEPROM_READ:
  307. case EEPROM_WRITE:
  308. ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc,
  309. argv + index, 3);
  310. break;
  311. case EEPROM_PRINT:
  312. ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc,
  313. argv + index, 0);
  314. break;
  315. case EEPROM_UPDATE:
  316. ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc,
  317. argv + index, 2);
  318. break;
  319. default:
  320. /* Get compiler to stop whining */
  321. return CMD_RET_USAGE;
  322. }
  323. if (ret == CMD_RET_USAGE)
  324. return ret;
  325. while (ret--)
  326. NEXT_PARAM(argc, index);
  327. if (action == EEPROM_READ || action == EEPROM_WRITE) {
  328. addr = parse_numeric_param(argv[index]);
  329. NEXT_PARAM(argc, index);
  330. off = parse_numeric_param(argv[index]);
  331. NEXT_PARAM(argc, index);
  332. cnt = parse_numeric_param(argv[index]);
  333. }
  334. #ifdef CONFIG_CMD_EEPROM_LAYOUT
  335. if (action == EEPROM_UPDATE) {
  336. field_name = argv[index];
  337. NEXT_PARAM(argc, index);
  338. field_value = argv[index];
  339. NEXT_PARAM(argc, index);
  340. }
  341. #endif
  342. return eeprom_execute_command(action, i2c_bus, i2c_addr, layout_ver,
  343. field_name, field_value, addr, off, cnt);
  344. }
  345. U_BOOT_CMD(
  346. eeprom, 8, 1, do_eeprom,
  347. "EEPROM sub-system",
  348. "read <bus> <devaddr> addr off cnt\n"
  349. "eeprom write <bus> <devaddr> addr off cnt\n"
  350. " - read/write `cnt' bytes from `devaddr` EEPROM at offset `off'"
  351. #ifdef CONFIG_CMD_EEPROM_LAYOUT
  352. "\n"
  353. "eeprom print [-l <layout_version>] <bus> <devaddr>\n"
  354. " - Print layout fields and their data in human readable format\n"
  355. "eeprom update [-l <layout_version>] <bus> <devaddr> field_name field_value\n"
  356. " - Update a specific eeprom field with new data.\n"
  357. " The new data must be written in the same human readable format as shown by the print command.\n"
  358. "\n"
  359. "LAYOUT VERSIONS\n"
  360. "The -l option can be used to force the command to interpret the EEPROM data using the chosen layout.\n"
  361. "If the -l option is omitted, the command will auto detect the layout based on the data in the EEPROM.\n"
  362. "The values which can be provided with the -l option are:\n"
  363. CONFIG_EEPROM_LAYOUT_HELP_STRING"\n"
  364. #endif
  365. )