12e192b24SSimon Glass /* 22e192b24SSimon Glass * (C) Copyright 2000, 2001 32e192b24SSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 42e192b24SSimon Glass * 52e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 62e192b24SSimon Glass */ 72e192b24SSimon Glass 82e192b24SSimon Glass /* 92e192b24SSimon Glass * Support for read and write access to EEPROM like memory devices. This 102e192b24SSimon Glass * includes regular EEPROM as well as FRAM (ferroelectic nonvolaile RAM). 112e192b24SSimon Glass * FRAM devices read and write data at bus speed. In particular, there is no 122e192b24SSimon Glass * write delay. Also, there is no limit imposed on the number of bytes that can 132e192b24SSimon Glass * be transferred with a single read or write. 142e192b24SSimon Glass * 152e192b24SSimon Glass * Use the following configuration options to ensure no unneeded performance 162e192b24SSimon Glass * degradation (typical for EEPROM) is incured for FRAM memory: 172e192b24SSimon Glass * 182e192b24SSimon Glass * #define CONFIG_SYS_I2C_FRAM 192e192b24SSimon Glass * #undef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 202e192b24SSimon Glass * 212e192b24SSimon Glass */ 222e192b24SSimon Glass 232e192b24SSimon Glass #include <common.h> 242e192b24SSimon Glass #include <config.h> 252e192b24SSimon Glass #include <command.h> 262e192b24SSimon Glass #include <i2c.h> 27*e7c2729bSNikita Kiryanov #include <eeprom_layout.h> 282e192b24SSimon Glass 292e192b24SSimon Glass #ifndef CONFIG_SYS_I2C_SPEED 302e192b24SSimon Glass #define CONFIG_SYS_I2C_SPEED 50000 312e192b24SSimon Glass #endif 322e192b24SSimon Glass 332e192b24SSimon Glass #ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 342e192b24SSimon Glass #define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 0 352e192b24SSimon Glass #endif 362e192b24SSimon Glass 372e192b24SSimon Glass #ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 382e192b24SSimon Glass #define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 8 392e192b24SSimon Glass #endif 402e192b24SSimon Glass 41a6e7b774SMario Six #ifndef I2C_RXTX_LEN 42a6e7b774SMario Six #define I2C_RXTX_LEN 128 43a6e7b774SMario Six #endif 44a6e7b774SMario Six 452e192b24SSimon Glass #define EEPROM_PAGE_SIZE (1 << CONFIG_SYS_EEPROM_PAGE_WRITE_BITS) 462e192b24SSimon Glass #define EEPROM_PAGE_OFFSET(x) ((x) & (EEPROM_PAGE_SIZE - 1)) 472e192b24SSimon Glass 482e192b24SSimon Glass /* 492e192b24SSimon Glass * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is 502e192b24SSimon Glass * 0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM. 512e192b24SSimon Glass * 522e192b24SSimon Glass * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is 532e192b24SSimon Glass * 0x00000nxx for EEPROM address selectors and page number at n. 542e192b24SSimon Glass */ 552e192b24SSimon Glass #if !defined(CONFIG_SPI) || defined(CONFIG_ENV_EEPROM_IS_ON_I2C) 562e192b24SSimon Glass #if !defined(CONFIG_SYS_I2C_EEPROM_ADDR_LEN) || \ 572e192b24SSimon Glass (CONFIG_SYS_I2C_EEPROM_ADDR_LEN < 1) || \ 582e192b24SSimon Glass (CONFIG_SYS_I2C_EEPROM_ADDR_LEN > 2) 592e192b24SSimon Glass #error CONFIG_SYS_I2C_EEPROM_ADDR_LEN must be 1 or 2 602e192b24SSimon Glass #endif 612e192b24SSimon Glass #endif 622e192b24SSimon Glass 632e192b24SSimon Glass __weak int eeprom_write_enable(unsigned dev_addr, int state) 642e192b24SSimon Glass { 652e192b24SSimon Glass return 0; 662e192b24SSimon Glass } 672e192b24SSimon Glass 682e192b24SSimon Glass void eeprom_init(int bus) 692e192b24SSimon Glass { 702e192b24SSimon Glass /* SPI EEPROM */ 712e192b24SSimon Glass #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C) 722e192b24SSimon Glass spi_init_f(); 732e192b24SSimon Glass #endif 742e192b24SSimon Glass 752e192b24SSimon Glass /* I2C EEPROM */ 762636ac65SNikita Kiryanov #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C) 772e192b24SSimon Glass #if defined(CONFIG_SYS_I2C) 782e192b24SSimon Glass if (bus >= 0) 792e192b24SSimon Glass i2c_set_bus_num(bus); 802e192b24SSimon Glass #endif 812e192b24SSimon Glass i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); 822e192b24SSimon Glass #endif 832e192b24SSimon Glass } 842e192b24SSimon Glass 852e192b24SSimon Glass static int eeprom_addr(unsigned dev_addr, unsigned offset, uchar *addr) 862e192b24SSimon Glass { 872e192b24SSimon Glass unsigned blk_off; 882e192b24SSimon Glass int alen; 892e192b24SSimon Glass 902e192b24SSimon Glass blk_off = offset & 0xff; /* block offset */ 912e192b24SSimon Glass #if CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 922e192b24SSimon Glass addr[0] = offset >> 8; /* block number */ 932e192b24SSimon Glass addr[1] = blk_off; /* block offset */ 942e192b24SSimon Glass alen = 2; 952e192b24SSimon Glass #else 962e192b24SSimon Glass addr[0] = offset >> 16; /* block number */ 972e192b24SSimon Glass addr[1] = offset >> 8; /* upper address octet */ 982e192b24SSimon Glass addr[2] = blk_off; /* lower address octet */ 992e192b24SSimon Glass alen = 3; 1002e192b24SSimon Glass #endif /* CONFIG_SYS_I2C_EEPROM_ADDR_LEN */ 1012e192b24SSimon Glass 1022e192b24SSimon Glass addr[0] |= dev_addr; /* insert device address */ 1032e192b24SSimon Glass 1042e192b24SSimon Glass return alen; 1052e192b24SSimon Glass } 1062e192b24SSimon Glass 1072e192b24SSimon Glass static int eeprom_len(unsigned offset, unsigned end) 1082e192b24SSimon Glass { 1092e192b24SSimon Glass unsigned len = end - offset; 1102e192b24SSimon Glass 1112e192b24SSimon Glass /* 1122e192b24SSimon Glass * For a FRAM device there is no limit on the number of the 1132e192b24SSimon Glass * bytes that can be ccessed with the single read or write 1142e192b24SSimon Glass * operation. 1152e192b24SSimon Glass */ 1162e192b24SSimon Glass #if !defined(CONFIG_SYS_I2C_FRAM) 1172e192b24SSimon Glass unsigned blk_off = offset & 0xff; 1182e192b24SSimon Glass unsigned maxlen = EEPROM_PAGE_SIZE - EEPROM_PAGE_OFFSET(blk_off); 1192e192b24SSimon Glass 1202e192b24SSimon Glass if (maxlen > I2C_RXTX_LEN) 1212e192b24SSimon Glass maxlen = I2C_RXTX_LEN; 1222e192b24SSimon Glass 1232e192b24SSimon Glass if (len > maxlen) 1242e192b24SSimon Glass len = maxlen; 1252e192b24SSimon Glass #endif 1262e192b24SSimon Glass 1272e192b24SSimon Glass return len; 1282e192b24SSimon Glass } 1292e192b24SSimon Glass 1302e192b24SSimon Glass static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen, 1312e192b24SSimon Glass uchar *buffer, unsigned len, bool read) 1322e192b24SSimon Glass { 1332e192b24SSimon Glass int ret = 0; 1342e192b24SSimon Glass 1352e192b24SSimon Glass /* SPI */ 1362e192b24SSimon Glass #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C) 1372e192b24SSimon Glass if (read) 1382e192b24SSimon Glass spi_read(addr, alen, buffer, len); 1392e192b24SSimon Glass else 1402e192b24SSimon Glass spi_write(addr, alen, buffer, len); 1412e192b24SSimon Glass #else /* I2C */ 1422e192b24SSimon Glass 1432e192b24SSimon Glass #if defined(CONFIG_SYS_I2C_EEPROM_BUS) 1442e192b24SSimon Glass i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS); 1452e192b24SSimon Glass #endif 1462e192b24SSimon Glass 1472e192b24SSimon Glass if (read) 1482e192b24SSimon Glass ret = i2c_read(addr[0], offset, alen - 1, buffer, len); 1492e192b24SSimon Glass else 1502e192b24SSimon Glass ret = i2c_write(addr[0], offset, alen - 1, buffer, len); 1512e192b24SSimon Glass 1522e192b24SSimon Glass if (ret) 1532e192b24SSimon Glass ret = 1; 1542e192b24SSimon Glass #endif 1552e192b24SSimon Glass return ret; 1562e192b24SSimon Glass } 1572e192b24SSimon Glass 1582e192b24SSimon Glass static int eeprom_rw(unsigned dev_addr, unsigned offset, uchar *buffer, 1592e192b24SSimon Glass unsigned cnt, bool read) 1602e192b24SSimon Glass { 1612e192b24SSimon Glass unsigned end = offset + cnt; 1622e192b24SSimon Glass unsigned alen, len; 1632e192b24SSimon Glass int rcode = 0; 1642e192b24SSimon Glass uchar addr[3]; 1652e192b24SSimon Glass 1662e192b24SSimon Glass while (offset < end) { 1672e192b24SSimon Glass alen = eeprom_addr(dev_addr, offset, addr); 1682e192b24SSimon Glass 1692e192b24SSimon Glass len = eeprom_len(offset, end); 1702e192b24SSimon Glass 1712e192b24SSimon Glass rcode = eeprom_rw_block(offset, addr, alen, buffer, len, read); 1722e192b24SSimon Glass 1732e192b24SSimon Glass buffer += len; 1742e192b24SSimon Glass offset += len; 1752e192b24SSimon Glass 1762e192b24SSimon Glass if (!read) 1772e192b24SSimon Glass udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000); 1782e192b24SSimon Glass } 1792e192b24SSimon Glass 1802e192b24SSimon Glass return rcode; 1812e192b24SSimon Glass } 1822e192b24SSimon Glass 1832e192b24SSimon Glass int eeprom_read(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt) 1842e192b24SSimon Glass { 1852e192b24SSimon Glass /* 1862e192b24SSimon Glass * Read data until done or would cross a page boundary. 1872e192b24SSimon Glass * We must write the address again when changing pages 1882e192b24SSimon Glass * because the next page may be in a different device. 1892e192b24SSimon Glass */ 1902e192b24SSimon Glass return eeprom_rw(dev_addr, offset, buffer, cnt, 1); 1912e192b24SSimon Glass } 1922e192b24SSimon Glass 1932e192b24SSimon Glass int eeprom_write(unsigned dev_addr, unsigned offset, 1942e192b24SSimon Glass uchar *buffer, unsigned cnt) 1952e192b24SSimon Glass { 1962e192b24SSimon Glass int ret; 1972e192b24SSimon Glass 1982e192b24SSimon Glass eeprom_write_enable(dev_addr, 1); 1992e192b24SSimon Glass 2002e192b24SSimon Glass /* 2012e192b24SSimon Glass * Write data until done or would cross a write page boundary. 2022e192b24SSimon Glass * We must write the address again when changing pages 2032e192b24SSimon Glass * because the address counter only increments within a page. 2042e192b24SSimon Glass */ 2052e192b24SSimon Glass ret = eeprom_rw(dev_addr, offset, buffer, cnt, 0); 2062e192b24SSimon Glass 2072e192b24SSimon Glass eeprom_write_enable(dev_addr, 0); 2082e192b24SSimon Glass return ret; 2092e192b24SSimon Glass } 2102e192b24SSimon Glass 211c40f0372SNikita Kiryanov static int parse_numeric_param(char *str) 212c40f0372SNikita Kiryanov { 213c40f0372SNikita Kiryanov char *endptr; 214c40f0372SNikita Kiryanov int value = simple_strtol(str, &endptr, 16); 215c40f0372SNikita Kiryanov 216c40f0372SNikita Kiryanov return (*endptr != '\0') ? -1 : value; 217c40f0372SNikita Kiryanov } 218c40f0372SNikita Kiryanov 219c40f0372SNikita Kiryanov /** 220c40f0372SNikita Kiryanov * parse_i2c_bus_addr - parse the i2c bus and i2c devaddr parameters 221c40f0372SNikita Kiryanov * 222c40f0372SNikita Kiryanov * @i2c_bus: address to store the i2c bus 223c40f0372SNikita Kiryanov * @i2c_addr: address to store the device i2c address 224c40f0372SNikita Kiryanov * @argc: count of command line arguments left to parse 225c40f0372SNikita Kiryanov * @argv: command line arguments left to parse 226c40f0372SNikita Kiryanov * @argc_no_bus_addr: argc value we expect to see when bus & addr aren't given 227c40f0372SNikita Kiryanov * 228c40f0372SNikita Kiryanov * @returns: number of arguments parsed or CMD_RET_USAGE if error 229c40f0372SNikita Kiryanov */ 230c40f0372SNikita Kiryanov static int parse_i2c_bus_addr(int *i2c_bus, ulong *i2c_addr, int argc, 231c40f0372SNikita Kiryanov char * const argv[], int argc_no_bus_addr) 232c40f0372SNikita Kiryanov { 233c40f0372SNikita Kiryanov int argc_no_bus = argc_no_bus_addr + 1; 234c40f0372SNikita Kiryanov int argc_bus_addr = argc_no_bus_addr + 2; 235c40f0372SNikita Kiryanov 236c40f0372SNikita Kiryanov #ifdef CONFIG_SYS_DEF_EEPROM_ADDR 237c40f0372SNikita Kiryanov if (argc == argc_no_bus_addr) { 238c40f0372SNikita Kiryanov *i2c_bus = -1; 239c40f0372SNikita Kiryanov *i2c_addr = CONFIG_SYS_DEF_EEPROM_ADDR; 240c40f0372SNikita Kiryanov 241c40f0372SNikita Kiryanov return 0; 242c40f0372SNikita Kiryanov } 243c40f0372SNikita Kiryanov #endif 244c40f0372SNikita Kiryanov if (argc == argc_no_bus) { 245c40f0372SNikita Kiryanov *i2c_bus = -1; 246c40f0372SNikita Kiryanov *i2c_addr = parse_numeric_param(argv[0]); 247c40f0372SNikita Kiryanov 248c40f0372SNikita Kiryanov return 1; 249c40f0372SNikita Kiryanov } 250c40f0372SNikita Kiryanov 251c40f0372SNikita Kiryanov if (argc == argc_bus_addr) { 252c40f0372SNikita Kiryanov *i2c_bus = parse_numeric_param(argv[0]); 253c40f0372SNikita Kiryanov *i2c_addr = parse_numeric_param(argv[1]); 254c40f0372SNikita Kiryanov 255c40f0372SNikita Kiryanov return 2; 256c40f0372SNikita Kiryanov } 257c40f0372SNikita Kiryanov 258c40f0372SNikita Kiryanov return CMD_RET_USAGE; 259c40f0372SNikita Kiryanov } 260c40f0372SNikita Kiryanov 261aa9e6044SNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 262aa9e6044SNikita Kiryanov 263aa9e6044SNikita Kiryanov __weak int eeprom_parse_layout_version(char *str) 264aa9e6044SNikita Kiryanov { 265aa9e6044SNikita Kiryanov return LAYOUT_VERSION_UNRECOGNIZED; 266aa9e6044SNikita Kiryanov } 267aa9e6044SNikita Kiryanov 268aa9e6044SNikita Kiryanov static unsigned char eeprom_buf[CONFIG_SYS_EEPROM_SIZE]; 269aa9e6044SNikita Kiryanov 270aa9e6044SNikita Kiryanov #ifndef CONFIG_EEPROM_LAYOUT_HELP_STRING 271aa9e6044SNikita Kiryanov #define CONFIG_EEPROM_LAYOUT_HELP_STRING "<not defined>" 272aa9e6044SNikita Kiryanov #endif 273aa9e6044SNikita Kiryanov 274*e7c2729bSNikita Kiryanov #endif 275*e7c2729bSNikita Kiryanov 276aa9e6044SNikita Kiryanov enum eeprom_action { 277*e7c2729bSNikita Kiryanov EEPROM_READ, 278*e7c2729bSNikita Kiryanov EEPROM_WRITE, 279aa9e6044SNikita Kiryanov EEPROM_PRINT, 280aa9e6044SNikita Kiryanov EEPROM_UPDATE, 281aa9e6044SNikita Kiryanov EEPROM_ACTION_INVALID, 282aa9e6044SNikita Kiryanov }; 283aa9e6044SNikita Kiryanov 284*e7c2729bSNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 285aa9e6044SNikita Kiryanov static enum eeprom_action parse_action(char *cmd) 286aa9e6044SNikita Kiryanov { 287aa9e6044SNikita Kiryanov if (!strncmp(cmd, "print", 5)) 288aa9e6044SNikita Kiryanov return EEPROM_PRINT; 289aa9e6044SNikita Kiryanov if (!strncmp(cmd, "update", 6)) 290aa9e6044SNikita Kiryanov return EEPROM_UPDATE; 291aa9e6044SNikita Kiryanov 292aa9e6044SNikita Kiryanov return EEPROM_ACTION_INVALID; 293aa9e6044SNikita Kiryanov } 294*e7c2729bSNikita Kiryanov #endif 295aa9e6044SNikita Kiryanov 296aa9e6044SNikita Kiryanov static int eeprom_execute_command(enum eeprom_action action, int i2c_bus, 297*e7c2729bSNikita Kiryanov ulong i2c_addr, int layout_ver, char *key, 298*e7c2729bSNikita Kiryanov char *value, ulong addr, ulong off, ulong cnt) 299aa9e6044SNikita Kiryanov { 300*e7c2729bSNikita Kiryanov int rcode = 0; 301*e7c2729bSNikita Kiryanov const char *const fmt = 302*e7c2729bSNikita Kiryanov "\nEEPROM @0x%lX %s: addr %08lx off %04lx count %ld ... "; 303*e7c2729bSNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 304aa9e6044SNikita Kiryanov struct eeprom_layout layout; 305*e7c2729bSNikita Kiryanov #endif 306aa9e6044SNikita Kiryanov 307aa9e6044SNikita Kiryanov if (action == EEPROM_ACTION_INVALID) 308aa9e6044SNikita Kiryanov return CMD_RET_USAGE; 309aa9e6044SNikita Kiryanov 310aa9e6044SNikita Kiryanov eeprom_init(i2c_bus); 311*e7c2729bSNikita Kiryanov if (action == EEPROM_READ) { 312*e7c2729bSNikita Kiryanov printf(fmt, i2c_addr, "read", addr, off, cnt); 313*e7c2729bSNikita Kiryanov 314*e7c2729bSNikita Kiryanov rcode = eeprom_read(i2c_addr, off, (uchar *)addr, cnt); 315*e7c2729bSNikita Kiryanov 316*e7c2729bSNikita Kiryanov puts("done\n"); 317*e7c2729bSNikita Kiryanov return rcode; 318*e7c2729bSNikita Kiryanov } else if (action == EEPROM_WRITE) { 319*e7c2729bSNikita Kiryanov printf(fmt, i2c_addr, "write", addr, off, cnt); 320*e7c2729bSNikita Kiryanov 321*e7c2729bSNikita Kiryanov rcode = eeprom_write(i2c_addr, off, (uchar *)addr, cnt); 322*e7c2729bSNikita Kiryanov 323*e7c2729bSNikita Kiryanov puts("done\n"); 324*e7c2729bSNikita Kiryanov return rcode; 325*e7c2729bSNikita Kiryanov } 326*e7c2729bSNikita Kiryanov 327*e7c2729bSNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 328aa9e6044SNikita Kiryanov rcode = eeprom_read(i2c_addr, 0, eeprom_buf, CONFIG_SYS_EEPROM_SIZE); 329aa9e6044SNikita Kiryanov if (rcode < 0) 330aa9e6044SNikita Kiryanov return rcode; 331aa9e6044SNikita Kiryanov 332aa9e6044SNikita Kiryanov eeprom_layout_setup(&layout, eeprom_buf, CONFIG_SYS_EEPROM_SIZE, 333aa9e6044SNikita Kiryanov layout_ver); 334aa9e6044SNikita Kiryanov 335aa9e6044SNikita Kiryanov if (action == EEPROM_PRINT) { 336aa9e6044SNikita Kiryanov layout.print(&layout); 337aa9e6044SNikita Kiryanov return 0; 338aa9e6044SNikita Kiryanov } 339aa9e6044SNikita Kiryanov 340aa9e6044SNikita Kiryanov layout.update(&layout, key, value); 341aa9e6044SNikita Kiryanov 342aa9e6044SNikita Kiryanov rcode = eeprom_write(i2c_addr, 0, layout.data, CONFIG_SYS_EEPROM_SIZE); 343*e7c2729bSNikita Kiryanov #endif 344aa9e6044SNikita Kiryanov 345aa9e6044SNikita Kiryanov return rcode; 346aa9e6044SNikita Kiryanov } 347aa9e6044SNikita Kiryanov 348*e7c2729bSNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 349aa9e6044SNikita Kiryanov #define NEXT_PARAM(argc, index) { (argc)--; (index)++; } 350aa9e6044SNikita Kiryanov static int do_eeprom_layout(cmd_tbl_t *cmdtp, int flag, int argc, 351aa9e6044SNikita Kiryanov char * const argv[]) 352aa9e6044SNikita Kiryanov { 353aa9e6044SNikita Kiryanov int layout_ver = LAYOUT_VERSION_AUTODETECT; 354aa9e6044SNikita Kiryanov enum eeprom_action action = EEPROM_ACTION_INVALID; 355aa9e6044SNikita Kiryanov int i2c_bus = -1, i2c_addr = -1, index = 0; 356aa9e6044SNikita Kiryanov char *field_name = ""; 357aa9e6044SNikita Kiryanov char *field_value = ""; 358aa9e6044SNikita Kiryanov 359aa9e6044SNikita Kiryanov if (argc <= 1) 360aa9e6044SNikita Kiryanov return CMD_RET_USAGE; 361aa9e6044SNikita Kiryanov 362aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); /* Skip program name */ 363aa9e6044SNikita Kiryanov 364aa9e6044SNikita Kiryanov action = parse_action(argv[index]); 365aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 366aa9e6044SNikita Kiryanov 367aa9e6044SNikita Kiryanov if (argc <= 1) 368aa9e6044SNikita Kiryanov return CMD_RET_USAGE; 369aa9e6044SNikita Kiryanov 370aa9e6044SNikita Kiryanov if (!strcmp(argv[index], "-l")) { 371aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 372aa9e6044SNikita Kiryanov 373aa9e6044SNikita Kiryanov layout_ver = eeprom_parse_layout_version(argv[index]); 374aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 375aa9e6044SNikita Kiryanov } 376aa9e6044SNikita Kiryanov 377aa9e6044SNikita Kiryanov if (argc <= 1) 378aa9e6044SNikita Kiryanov return CMD_RET_USAGE; 379aa9e6044SNikita Kiryanov 380aa9e6044SNikita Kiryanov i2c_bus = parse_numeric_param(argv[index]); 381aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 382aa9e6044SNikita Kiryanov 383aa9e6044SNikita Kiryanov i2c_addr = parse_numeric_param(argv[index]); 384aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 385aa9e6044SNikita Kiryanov 386aa9e6044SNikita Kiryanov if (action == EEPROM_PRINT) 387aa9e6044SNikita Kiryanov goto done; 388aa9e6044SNikita Kiryanov 389aa9e6044SNikita Kiryanov if (argc) { 390aa9e6044SNikita Kiryanov field_name = argv[index]; 391aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 392aa9e6044SNikita Kiryanov } 393aa9e6044SNikita Kiryanov 394aa9e6044SNikita Kiryanov if (argc) { 395aa9e6044SNikita Kiryanov field_value = argv[index]; 396aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 397aa9e6044SNikita Kiryanov } 398aa9e6044SNikita Kiryanov 399aa9e6044SNikita Kiryanov done: 400aa9e6044SNikita Kiryanov return eeprom_execute_command(action, i2c_bus, i2c_addr, layout_ver, 401*e7c2729bSNikita Kiryanov field_name, field_value, 0, 0, 0); 402aa9e6044SNikita Kiryanov } 403aa9e6044SNikita Kiryanov 404aa9e6044SNikita Kiryanov #endif 405aa9e6044SNikita Kiryanov 4062e192b24SSimon Glass static int do_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 4072e192b24SSimon Glass { 4082e192b24SSimon Glass char * const *args = &argv[2]; 4092e192b24SSimon Glass int rcode; 4102e192b24SSimon Glass ulong dev_addr, addr, off, cnt; 4112e192b24SSimon Glass int bus_addr; 4122e192b24SSimon Glass 413aa9e6044SNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 414aa9e6044SNikita Kiryanov if (argc >= 2) { 415aa9e6044SNikita Kiryanov if (!strcmp(argv[1], "update") || !strcmp(argv[1], "print")) 416aa9e6044SNikita Kiryanov return do_eeprom_layout(cmdtp, flag, argc, argv); 417aa9e6044SNikita Kiryanov } 418aa9e6044SNikita Kiryanov #endif 419aa9e6044SNikita Kiryanov 420c40f0372SNikita Kiryanov rcode = parse_i2c_bus_addr(&bus_addr, &dev_addr, argc - 2, argv + 2, 3); 421c40f0372SNikita Kiryanov if (rcode == CMD_RET_USAGE) 422c40f0372SNikita Kiryanov return rcode; 4232e192b24SSimon Glass 4242e192b24SSimon Glass addr = simple_strtoul(*args++, NULL, 16); 4252e192b24SSimon Glass off = simple_strtoul(*args++, NULL, 16); 4262e192b24SSimon Glass cnt = simple_strtoul(*args++, NULL, 16); 4272e192b24SSimon Glass 4282e192b24SSimon Glass if (strcmp(argv[1], "read") == 0) { 429*e7c2729bSNikita Kiryanov return eeprom_execute_command(EEPROM_READ, bus_addr, dev_addr, 430*e7c2729bSNikita Kiryanov LAYOUT_VERSION_UNRECOGNIZED, 431*e7c2729bSNikita Kiryanov NULL, NULL, addr, off, cnt); 4322e192b24SSimon Glass } else if (strcmp(argv[1], "write") == 0) { 433*e7c2729bSNikita Kiryanov return eeprom_execute_command(EEPROM_WRITE, bus_addr, dev_addr, 434*e7c2729bSNikita Kiryanov LAYOUT_VERSION_UNRECOGNIZED, 435*e7c2729bSNikita Kiryanov NULL, NULL, addr, off, cnt); 4362e192b24SSimon Glass } 4372e192b24SSimon Glass 4382e192b24SSimon Glass return CMD_RET_USAGE; 4392e192b24SSimon Glass } 4402e192b24SSimon Glass 4412e192b24SSimon Glass U_BOOT_CMD( 442aa9e6044SNikita Kiryanov eeprom, 8, 1, do_eeprom, 4432e192b24SSimon Glass "EEPROM sub-system", 4442e192b24SSimon Glass "read <bus> <devaddr> addr off cnt\n" 4452e192b24SSimon Glass "eeprom write <bus> <devaddr> addr off cnt\n" 4462e192b24SSimon Glass " - read/write `cnt' bytes from `devaddr` EEPROM at offset `off'" 447aa9e6044SNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 448aa9e6044SNikita Kiryanov "\n" 449aa9e6044SNikita Kiryanov "eeprom print [-l <layout_version>] bus devaddr\n" 450aa9e6044SNikita Kiryanov " - Print layout fields and their data in human readable format\n" 451aa9e6044SNikita Kiryanov "eeprom update [-l <layout_version>] bus devaddr <field_name> <field_value>\n" 452aa9e6044SNikita Kiryanov " - Update a specific eeprom field with new data.\n" 453aa9e6044SNikita Kiryanov " The new data must be written in the same human readable format as shown by the print command.\n" 454aa9e6044SNikita Kiryanov "\n" 455aa9e6044SNikita Kiryanov "LAYOUT VERSIONS\n" 456aa9e6044SNikita Kiryanov "The -l option can be used to force the command to interpret the EEPROM data using the chosen layout.\n" 457aa9e6044SNikita Kiryanov "If the -l option is omitted, the command will auto detect the layout based on the data in the EEPROM.\n" 458aa9e6044SNikita Kiryanov "The values which can be provided with the -l option are:\n" 459aa9e6044SNikita Kiryanov CONFIG_EEPROM_LAYOUT_HELP_STRING"\n" 460aa9e6044SNikita Kiryanov #endif 4612e192b24SSimon Glass ) 462