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> 272e192b24SSimon Glass 282e192b24SSimon Glass #ifndef CONFIG_SYS_I2C_SPEED 292e192b24SSimon Glass #define CONFIG_SYS_I2C_SPEED 50000 302e192b24SSimon Glass #endif 312e192b24SSimon Glass 322e192b24SSimon Glass #ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 332e192b24SSimon Glass #define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 0 342e192b24SSimon Glass #endif 352e192b24SSimon Glass 362e192b24SSimon Glass #ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 372e192b24SSimon Glass #define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 8 382e192b24SSimon Glass #endif 392e192b24SSimon Glass 40a6e7b774SMario Six #ifndef I2C_RXTX_LEN 41a6e7b774SMario Six #define I2C_RXTX_LEN 128 42a6e7b774SMario Six #endif 43a6e7b774SMario Six 442e192b24SSimon Glass #define EEPROM_PAGE_SIZE (1 << CONFIG_SYS_EEPROM_PAGE_WRITE_BITS) 452e192b24SSimon Glass #define EEPROM_PAGE_OFFSET(x) ((x) & (EEPROM_PAGE_SIZE - 1)) 462e192b24SSimon Glass 472e192b24SSimon Glass /* 482e192b24SSimon Glass * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is 492e192b24SSimon Glass * 0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM. 502e192b24SSimon Glass * 512e192b24SSimon Glass * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is 522e192b24SSimon Glass * 0x00000nxx for EEPROM address selectors and page number at n. 532e192b24SSimon Glass */ 542e192b24SSimon Glass #if !defined(CONFIG_SPI) || defined(CONFIG_ENV_EEPROM_IS_ON_I2C) 552e192b24SSimon Glass #if !defined(CONFIG_SYS_I2C_EEPROM_ADDR_LEN) || \ 562e192b24SSimon Glass (CONFIG_SYS_I2C_EEPROM_ADDR_LEN < 1) || \ 572e192b24SSimon Glass (CONFIG_SYS_I2C_EEPROM_ADDR_LEN > 2) 582e192b24SSimon Glass #error CONFIG_SYS_I2C_EEPROM_ADDR_LEN must be 1 or 2 592e192b24SSimon Glass #endif 602e192b24SSimon Glass #endif 612e192b24SSimon Glass 622e192b24SSimon Glass __weak int eeprom_write_enable(unsigned dev_addr, int state) 632e192b24SSimon Glass { 642e192b24SSimon Glass return 0; 652e192b24SSimon Glass } 662e192b24SSimon Glass 672e192b24SSimon Glass void eeprom_init(int bus) 682e192b24SSimon Glass { 692e192b24SSimon Glass /* SPI EEPROM */ 702e192b24SSimon Glass #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C) 712e192b24SSimon Glass spi_init_f(); 722e192b24SSimon Glass #endif 732e192b24SSimon Glass 742e192b24SSimon Glass /* I2C EEPROM */ 752636ac65SNikita Kiryanov #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C) 762e192b24SSimon Glass #if defined(CONFIG_SYS_I2C) 772e192b24SSimon Glass if (bus >= 0) 782e192b24SSimon Glass i2c_set_bus_num(bus); 792e192b24SSimon Glass #endif 802e192b24SSimon Glass i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); 812e192b24SSimon Glass #endif 822e192b24SSimon Glass } 832e192b24SSimon Glass 842e192b24SSimon Glass static int eeprom_addr(unsigned dev_addr, unsigned offset, uchar *addr) 852e192b24SSimon Glass { 862e192b24SSimon Glass unsigned blk_off; 872e192b24SSimon Glass int alen; 882e192b24SSimon Glass 892e192b24SSimon Glass blk_off = offset & 0xff; /* block offset */ 902e192b24SSimon Glass #if CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 912e192b24SSimon Glass addr[0] = offset >> 8; /* block number */ 922e192b24SSimon Glass addr[1] = blk_off; /* block offset */ 932e192b24SSimon Glass alen = 2; 942e192b24SSimon Glass #else 952e192b24SSimon Glass addr[0] = offset >> 16; /* block number */ 962e192b24SSimon Glass addr[1] = offset >> 8; /* upper address octet */ 972e192b24SSimon Glass addr[2] = blk_off; /* lower address octet */ 982e192b24SSimon Glass alen = 3; 992e192b24SSimon Glass #endif /* CONFIG_SYS_I2C_EEPROM_ADDR_LEN */ 1002e192b24SSimon Glass 1012e192b24SSimon Glass addr[0] |= dev_addr; /* insert device address */ 1022e192b24SSimon Glass 1032e192b24SSimon Glass return alen; 1042e192b24SSimon Glass } 1052e192b24SSimon Glass 1062e192b24SSimon Glass static int eeprom_len(unsigned offset, unsigned end) 1072e192b24SSimon Glass { 1082e192b24SSimon Glass unsigned len = end - offset; 1092e192b24SSimon Glass 1102e192b24SSimon Glass /* 1112e192b24SSimon Glass * For a FRAM device there is no limit on the number of the 1122e192b24SSimon Glass * bytes that can be ccessed with the single read or write 1132e192b24SSimon Glass * operation. 1142e192b24SSimon Glass */ 1152e192b24SSimon Glass #if !defined(CONFIG_SYS_I2C_FRAM) 1162e192b24SSimon Glass unsigned blk_off = offset & 0xff; 1172e192b24SSimon Glass unsigned maxlen = EEPROM_PAGE_SIZE - EEPROM_PAGE_OFFSET(blk_off); 1182e192b24SSimon Glass 1192e192b24SSimon Glass if (maxlen > I2C_RXTX_LEN) 1202e192b24SSimon Glass maxlen = I2C_RXTX_LEN; 1212e192b24SSimon Glass 1222e192b24SSimon Glass if (len > maxlen) 1232e192b24SSimon Glass len = maxlen; 1242e192b24SSimon Glass #endif 1252e192b24SSimon Glass 1262e192b24SSimon Glass return len; 1272e192b24SSimon Glass } 1282e192b24SSimon Glass 1292e192b24SSimon Glass static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen, 1302e192b24SSimon Glass uchar *buffer, unsigned len, bool read) 1312e192b24SSimon Glass { 1322e192b24SSimon Glass int ret = 0; 1332e192b24SSimon Glass 1342e192b24SSimon Glass /* SPI */ 1352e192b24SSimon Glass #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C) 1362e192b24SSimon Glass if (read) 1372e192b24SSimon Glass spi_read(addr, alen, buffer, len); 1382e192b24SSimon Glass else 1392e192b24SSimon Glass spi_write(addr, alen, buffer, len); 1402e192b24SSimon Glass #else /* I2C */ 1412e192b24SSimon Glass 1422e192b24SSimon Glass #if defined(CONFIG_SYS_I2C_EEPROM_BUS) 1432e192b24SSimon Glass i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS); 1442e192b24SSimon Glass #endif 1452e192b24SSimon Glass 1462e192b24SSimon Glass if (read) 1472e192b24SSimon Glass ret = i2c_read(addr[0], offset, alen - 1, buffer, len); 1482e192b24SSimon Glass else 1492e192b24SSimon Glass ret = i2c_write(addr[0], offset, alen - 1, buffer, len); 1502e192b24SSimon Glass 1512e192b24SSimon Glass if (ret) 1522e192b24SSimon Glass ret = 1; 1532e192b24SSimon Glass #endif 1542e192b24SSimon Glass return ret; 1552e192b24SSimon Glass } 1562e192b24SSimon Glass 1572e192b24SSimon Glass static int eeprom_rw(unsigned dev_addr, unsigned offset, uchar *buffer, 1582e192b24SSimon Glass unsigned cnt, bool read) 1592e192b24SSimon Glass { 1602e192b24SSimon Glass unsigned end = offset + cnt; 1612e192b24SSimon Glass unsigned alen, len; 1622e192b24SSimon Glass int rcode = 0; 1632e192b24SSimon Glass uchar addr[3]; 1642e192b24SSimon Glass 1652e192b24SSimon Glass while (offset < end) { 1662e192b24SSimon Glass alen = eeprom_addr(dev_addr, offset, addr); 1672e192b24SSimon Glass 1682e192b24SSimon Glass len = eeprom_len(offset, end); 1692e192b24SSimon Glass 1702e192b24SSimon Glass rcode = eeprom_rw_block(offset, addr, alen, buffer, len, read); 1712e192b24SSimon Glass 1722e192b24SSimon Glass buffer += len; 1732e192b24SSimon Glass offset += len; 1742e192b24SSimon Glass 1752e192b24SSimon Glass if (!read) 1762e192b24SSimon Glass udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000); 1772e192b24SSimon Glass } 1782e192b24SSimon Glass 1792e192b24SSimon Glass return rcode; 1802e192b24SSimon Glass } 1812e192b24SSimon Glass 1822e192b24SSimon Glass int eeprom_read(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt) 1832e192b24SSimon Glass { 1842e192b24SSimon Glass /* 1852e192b24SSimon Glass * Read data until done or would cross a page boundary. 1862e192b24SSimon Glass * We must write the address again when changing pages 1872e192b24SSimon Glass * because the next page may be in a different device. 1882e192b24SSimon Glass */ 1892e192b24SSimon Glass return eeprom_rw(dev_addr, offset, buffer, cnt, 1); 1902e192b24SSimon Glass } 1912e192b24SSimon Glass 1922e192b24SSimon Glass int eeprom_write(unsigned dev_addr, unsigned offset, 1932e192b24SSimon Glass uchar *buffer, unsigned cnt) 1942e192b24SSimon Glass { 1952e192b24SSimon Glass int ret; 1962e192b24SSimon Glass 1972e192b24SSimon Glass eeprom_write_enable(dev_addr, 1); 1982e192b24SSimon Glass 1992e192b24SSimon Glass /* 2002e192b24SSimon Glass * Write data until done or would cross a write page boundary. 2012e192b24SSimon Glass * We must write the address again when changing pages 2022e192b24SSimon Glass * because the address counter only increments within a page. 2032e192b24SSimon Glass */ 2042e192b24SSimon Glass ret = eeprom_rw(dev_addr, offset, buffer, cnt, 0); 2052e192b24SSimon Glass 2062e192b24SSimon Glass eeprom_write_enable(dev_addr, 0); 2072e192b24SSimon Glass return ret; 2082e192b24SSimon Glass } 2092e192b24SSimon Glass 210*c40f0372SNikita Kiryanov static int parse_numeric_param(char *str) 211*c40f0372SNikita Kiryanov { 212*c40f0372SNikita Kiryanov char *endptr; 213*c40f0372SNikita Kiryanov int value = simple_strtol(str, &endptr, 16); 214*c40f0372SNikita Kiryanov 215*c40f0372SNikita Kiryanov return (*endptr != '\0') ? -1 : value; 216*c40f0372SNikita Kiryanov } 217*c40f0372SNikita Kiryanov 218*c40f0372SNikita Kiryanov /** 219*c40f0372SNikita Kiryanov * parse_i2c_bus_addr - parse the i2c bus and i2c devaddr parameters 220*c40f0372SNikita Kiryanov * 221*c40f0372SNikita Kiryanov * @i2c_bus: address to store the i2c bus 222*c40f0372SNikita Kiryanov * @i2c_addr: address to store the device i2c address 223*c40f0372SNikita Kiryanov * @argc: count of command line arguments left to parse 224*c40f0372SNikita Kiryanov * @argv: command line arguments left to parse 225*c40f0372SNikita Kiryanov * @argc_no_bus_addr: argc value we expect to see when bus & addr aren't given 226*c40f0372SNikita Kiryanov * 227*c40f0372SNikita Kiryanov * @returns: number of arguments parsed or CMD_RET_USAGE if error 228*c40f0372SNikita Kiryanov */ 229*c40f0372SNikita Kiryanov static int parse_i2c_bus_addr(int *i2c_bus, ulong *i2c_addr, int argc, 230*c40f0372SNikita Kiryanov char * const argv[], int argc_no_bus_addr) 231*c40f0372SNikita Kiryanov { 232*c40f0372SNikita Kiryanov int argc_no_bus = argc_no_bus_addr + 1; 233*c40f0372SNikita Kiryanov int argc_bus_addr = argc_no_bus_addr + 2; 234*c40f0372SNikita Kiryanov 235*c40f0372SNikita Kiryanov #ifdef CONFIG_SYS_DEF_EEPROM_ADDR 236*c40f0372SNikita Kiryanov if (argc == argc_no_bus_addr) { 237*c40f0372SNikita Kiryanov *i2c_bus = -1; 238*c40f0372SNikita Kiryanov *i2c_addr = CONFIG_SYS_DEF_EEPROM_ADDR; 239*c40f0372SNikita Kiryanov 240*c40f0372SNikita Kiryanov return 0; 241*c40f0372SNikita Kiryanov } 242*c40f0372SNikita Kiryanov #endif 243*c40f0372SNikita Kiryanov if (argc == argc_no_bus) { 244*c40f0372SNikita Kiryanov *i2c_bus = -1; 245*c40f0372SNikita Kiryanov *i2c_addr = parse_numeric_param(argv[0]); 246*c40f0372SNikita Kiryanov 247*c40f0372SNikita Kiryanov return 1; 248*c40f0372SNikita Kiryanov } 249*c40f0372SNikita Kiryanov 250*c40f0372SNikita Kiryanov if (argc == argc_bus_addr) { 251*c40f0372SNikita Kiryanov *i2c_bus = parse_numeric_param(argv[0]); 252*c40f0372SNikita Kiryanov *i2c_addr = parse_numeric_param(argv[1]); 253*c40f0372SNikita Kiryanov 254*c40f0372SNikita Kiryanov return 2; 255*c40f0372SNikita Kiryanov } 256*c40f0372SNikita Kiryanov 257*c40f0372SNikita Kiryanov return CMD_RET_USAGE; 258*c40f0372SNikita Kiryanov } 259*c40f0372SNikita Kiryanov 260aa9e6044SNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 261aa9e6044SNikita Kiryanov #include <eeprom_layout.h> 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 274aa9e6044SNikita Kiryanov enum eeprom_action { 275aa9e6044SNikita Kiryanov EEPROM_PRINT, 276aa9e6044SNikita Kiryanov EEPROM_UPDATE, 277aa9e6044SNikita Kiryanov EEPROM_ACTION_INVALID, 278aa9e6044SNikita Kiryanov }; 279aa9e6044SNikita Kiryanov 280aa9e6044SNikita Kiryanov static enum eeprom_action parse_action(char *cmd) 281aa9e6044SNikita Kiryanov { 282aa9e6044SNikita Kiryanov if (!strncmp(cmd, "print", 5)) 283aa9e6044SNikita Kiryanov return EEPROM_PRINT; 284aa9e6044SNikita Kiryanov if (!strncmp(cmd, "update", 6)) 285aa9e6044SNikita Kiryanov return EEPROM_UPDATE; 286aa9e6044SNikita Kiryanov 287aa9e6044SNikita Kiryanov return EEPROM_ACTION_INVALID; 288aa9e6044SNikita Kiryanov } 289aa9e6044SNikita Kiryanov 290aa9e6044SNikita Kiryanov static int eeprom_execute_command(enum eeprom_action action, int i2c_bus, 291aa9e6044SNikita Kiryanov int i2c_addr, int layout_ver, char *key, 292aa9e6044SNikita Kiryanov char *value) 293aa9e6044SNikita Kiryanov { 294aa9e6044SNikita Kiryanov int rcode; 295aa9e6044SNikita Kiryanov struct eeprom_layout layout; 296aa9e6044SNikita Kiryanov 297aa9e6044SNikita Kiryanov if (action == EEPROM_ACTION_INVALID) 298aa9e6044SNikita Kiryanov return CMD_RET_USAGE; 299aa9e6044SNikita Kiryanov 300aa9e6044SNikita Kiryanov eeprom_init(i2c_bus); 301aa9e6044SNikita Kiryanov rcode = eeprom_read(i2c_addr, 0, eeprom_buf, CONFIG_SYS_EEPROM_SIZE); 302aa9e6044SNikita Kiryanov if (rcode < 0) 303aa9e6044SNikita Kiryanov return rcode; 304aa9e6044SNikita Kiryanov 305aa9e6044SNikita Kiryanov eeprom_layout_setup(&layout, eeprom_buf, CONFIG_SYS_EEPROM_SIZE, 306aa9e6044SNikita Kiryanov layout_ver); 307aa9e6044SNikita Kiryanov 308aa9e6044SNikita Kiryanov if (action == EEPROM_PRINT) { 309aa9e6044SNikita Kiryanov layout.print(&layout); 310aa9e6044SNikita Kiryanov return 0; 311aa9e6044SNikita Kiryanov } 312aa9e6044SNikita Kiryanov 313aa9e6044SNikita Kiryanov layout.update(&layout, key, value); 314aa9e6044SNikita Kiryanov 315aa9e6044SNikita Kiryanov rcode = eeprom_write(i2c_addr, 0, layout.data, CONFIG_SYS_EEPROM_SIZE); 316aa9e6044SNikita Kiryanov 317aa9e6044SNikita Kiryanov return rcode; 318aa9e6044SNikita Kiryanov } 319aa9e6044SNikita Kiryanov 320aa9e6044SNikita Kiryanov #define NEXT_PARAM(argc, index) { (argc)--; (index)++; } 321aa9e6044SNikita Kiryanov static int do_eeprom_layout(cmd_tbl_t *cmdtp, int flag, int argc, 322aa9e6044SNikita Kiryanov char * const argv[]) 323aa9e6044SNikita Kiryanov { 324aa9e6044SNikita Kiryanov int layout_ver = LAYOUT_VERSION_AUTODETECT; 325aa9e6044SNikita Kiryanov enum eeprom_action action = EEPROM_ACTION_INVALID; 326aa9e6044SNikita Kiryanov int i2c_bus = -1, i2c_addr = -1, index = 0; 327aa9e6044SNikita Kiryanov char *field_name = ""; 328aa9e6044SNikita Kiryanov char *field_value = ""; 329aa9e6044SNikita Kiryanov 330aa9e6044SNikita Kiryanov if (argc <= 1) 331aa9e6044SNikita Kiryanov return CMD_RET_USAGE; 332aa9e6044SNikita Kiryanov 333aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); /* Skip program name */ 334aa9e6044SNikita Kiryanov 335aa9e6044SNikita Kiryanov action = parse_action(argv[index]); 336aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 337aa9e6044SNikita Kiryanov 338aa9e6044SNikita Kiryanov if (argc <= 1) 339aa9e6044SNikita Kiryanov return CMD_RET_USAGE; 340aa9e6044SNikita Kiryanov 341aa9e6044SNikita Kiryanov if (!strcmp(argv[index], "-l")) { 342aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 343aa9e6044SNikita Kiryanov 344aa9e6044SNikita Kiryanov layout_ver = eeprom_parse_layout_version(argv[index]); 345aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 346aa9e6044SNikita Kiryanov } 347aa9e6044SNikita Kiryanov 348aa9e6044SNikita Kiryanov if (argc <= 1) 349aa9e6044SNikita Kiryanov return CMD_RET_USAGE; 350aa9e6044SNikita Kiryanov 351aa9e6044SNikita Kiryanov i2c_bus = parse_numeric_param(argv[index]); 352aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 353aa9e6044SNikita Kiryanov 354aa9e6044SNikita Kiryanov i2c_addr = parse_numeric_param(argv[index]); 355aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 356aa9e6044SNikita Kiryanov 357aa9e6044SNikita Kiryanov if (action == EEPROM_PRINT) 358aa9e6044SNikita Kiryanov goto done; 359aa9e6044SNikita Kiryanov 360aa9e6044SNikita Kiryanov if (argc) { 361aa9e6044SNikita Kiryanov field_name = argv[index]; 362aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 363aa9e6044SNikita Kiryanov } 364aa9e6044SNikita Kiryanov 365aa9e6044SNikita Kiryanov if (argc) { 366aa9e6044SNikita Kiryanov field_value = argv[index]; 367aa9e6044SNikita Kiryanov NEXT_PARAM(argc, index); 368aa9e6044SNikita Kiryanov } 369aa9e6044SNikita Kiryanov 370aa9e6044SNikita Kiryanov done: 371aa9e6044SNikita Kiryanov return eeprom_execute_command(action, i2c_bus, i2c_addr, layout_ver, 372aa9e6044SNikita Kiryanov field_name, field_value); 373aa9e6044SNikita Kiryanov } 374aa9e6044SNikita Kiryanov 375aa9e6044SNikita Kiryanov #endif 376aa9e6044SNikita Kiryanov 3772e192b24SSimon Glass static int do_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 3782e192b24SSimon Glass { 3792e192b24SSimon Glass const char *const fmt = 3802e192b24SSimon Glass "\nEEPROM @0x%lX %s: addr %08lx off %04lx count %ld ... "; 3812e192b24SSimon Glass char * const *args = &argv[2]; 3822e192b24SSimon Glass int rcode; 3832e192b24SSimon Glass ulong dev_addr, addr, off, cnt; 3842e192b24SSimon Glass int bus_addr; 3852e192b24SSimon Glass 386aa9e6044SNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 387aa9e6044SNikita Kiryanov if (argc >= 2) { 388aa9e6044SNikita Kiryanov if (!strcmp(argv[1], "update") || !strcmp(argv[1], "print")) 389aa9e6044SNikita Kiryanov return do_eeprom_layout(cmdtp, flag, argc, argv); 390aa9e6044SNikita Kiryanov } 391aa9e6044SNikita Kiryanov #endif 392aa9e6044SNikita Kiryanov 393*c40f0372SNikita Kiryanov rcode = parse_i2c_bus_addr(&bus_addr, &dev_addr, argc - 2, argv + 2, 3); 394*c40f0372SNikita Kiryanov if (rcode == CMD_RET_USAGE) 395*c40f0372SNikita Kiryanov return rcode; 3962e192b24SSimon Glass 3972e192b24SSimon Glass addr = simple_strtoul(*args++, NULL, 16); 3982e192b24SSimon Glass off = simple_strtoul(*args++, NULL, 16); 3992e192b24SSimon Glass cnt = simple_strtoul(*args++, NULL, 16); 4002e192b24SSimon Glass 4012e192b24SSimon Glass eeprom_init(bus_addr); 4022e192b24SSimon Glass 4032e192b24SSimon Glass if (strcmp(argv[1], "read") == 0) { 4042e192b24SSimon Glass printf(fmt, dev_addr, argv[1], addr, off, cnt); 4052e192b24SSimon Glass 4062e192b24SSimon Glass rcode = eeprom_read(dev_addr, off, (uchar *)addr, cnt); 4072e192b24SSimon Glass 4082e192b24SSimon Glass puts("done\n"); 4092e192b24SSimon Glass return rcode; 4102e192b24SSimon Glass } else if (strcmp(argv[1], "write") == 0) { 4112e192b24SSimon Glass printf(fmt, dev_addr, argv[1], addr, off, cnt); 4122e192b24SSimon Glass 4132e192b24SSimon Glass rcode = eeprom_write(dev_addr, off, (uchar *)addr, cnt); 4142e192b24SSimon Glass 4152e192b24SSimon Glass puts("done\n"); 4162e192b24SSimon Glass return rcode; 4172e192b24SSimon Glass } 4182e192b24SSimon Glass 4192e192b24SSimon Glass return CMD_RET_USAGE; 4202e192b24SSimon Glass } 4212e192b24SSimon Glass 4222e192b24SSimon Glass U_BOOT_CMD( 423aa9e6044SNikita Kiryanov eeprom, 8, 1, do_eeprom, 4242e192b24SSimon Glass "EEPROM sub-system", 4252e192b24SSimon Glass "read <bus> <devaddr> addr off cnt\n" 4262e192b24SSimon Glass "eeprom write <bus> <devaddr> addr off cnt\n" 4272e192b24SSimon Glass " - read/write `cnt' bytes from `devaddr` EEPROM at offset `off'" 428aa9e6044SNikita Kiryanov #ifdef CONFIG_CMD_EEPROM_LAYOUT 429aa9e6044SNikita Kiryanov "\n" 430aa9e6044SNikita Kiryanov "eeprom print [-l <layout_version>] bus devaddr\n" 431aa9e6044SNikita Kiryanov " - Print layout fields and their data in human readable format\n" 432aa9e6044SNikita Kiryanov "eeprom update [-l <layout_version>] bus devaddr <field_name> <field_value>\n" 433aa9e6044SNikita Kiryanov " - Update a specific eeprom field with new data.\n" 434aa9e6044SNikita Kiryanov " The new data must be written in the same human readable format as shown by the print command.\n" 435aa9e6044SNikita Kiryanov "\n" 436aa9e6044SNikita Kiryanov "LAYOUT VERSIONS\n" 437aa9e6044SNikita Kiryanov "The -l option can be used to force the command to interpret the EEPROM data using the chosen layout.\n" 438aa9e6044SNikita Kiryanov "If the -l option is omitted, the command will auto detect the layout based on the data in the EEPROM.\n" 439aa9e6044SNikita Kiryanov "The values which can be provided with the -l option are:\n" 440aa9e6044SNikita Kiryanov CONFIG_EEPROM_LAYOUT_HELP_STRING"\n" 441aa9e6044SNikita Kiryanov #endif 4422e192b24SSimon Glass ) 443