Remove the cmd_ prefix from command files
[oweals/u-boot.git] / cmd / eeprom.c
diff --git a/cmd/eeprom.c b/cmd/eeprom.c
new file mode 100644 (file)
index 0000000..571240a
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * (C) Copyright 2000, 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ * Support for read and write access to EEPROM like memory devices. This
+ * includes regular EEPROM as well as  FRAM (ferroelectic nonvolaile RAM).
+ * FRAM devices read and write data at bus speed. In particular, there is no
+ * write delay. Also, there is no limit imposed on the number of bytes that can
+ * be transferred with a single read or write.
+ *
+ * Use the following configuration options to ensure no unneeded performance
+ * degradation (typical for EEPROM) is incured for FRAM memory:
+ *
+ * #define CONFIG_SYS_I2C_FRAM
+ * #undef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
+ *
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+#include <i2c.h>
+
+#ifndef        CONFIG_SYS_I2C_SPEED
+#define        CONFIG_SYS_I2C_SPEED    50000
+#endif
+
+#ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS  0
+#endif
+
+#ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS      8
+#endif
+
+#define        EEPROM_PAGE_SIZE        (1 << CONFIG_SYS_EEPROM_PAGE_WRITE_BITS)
+#define        EEPROM_PAGE_OFFSET(x)   ((x) & (EEPROM_PAGE_SIZE - 1))
+
+/*
+ * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is
+ *   0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM.
+ *
+ * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is
+ *   0x00000nxx for EEPROM address selectors and page number at n.
+ */
+#if !defined(CONFIG_SPI) || defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
+#if !defined(CONFIG_SYS_I2C_EEPROM_ADDR_LEN) || \
+       (CONFIG_SYS_I2C_EEPROM_ADDR_LEN < 1) || \
+       (CONFIG_SYS_I2C_EEPROM_ADDR_LEN > 2)
+#error CONFIG_SYS_I2C_EEPROM_ADDR_LEN must be 1 or 2
+#endif
+#endif
+
+__weak int eeprom_write_enable(unsigned dev_addr, int state)
+{
+       return 0;
+}
+
+void eeprom_init(int bus)
+{
+       /* SPI EEPROM */
+#if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
+       spi_init_f();
+#endif
+
+       /* I2C EEPROM */
+#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C_SOFT)
+#if defined(CONFIG_SYS_I2C)
+       if (bus >= 0)
+               i2c_set_bus_num(bus);
+#endif
+       i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+}
+
+static int eeprom_addr(unsigned dev_addr, unsigned offset, uchar *addr)
+{
+       unsigned blk_off;
+       int alen;
+
+       blk_off = offset & 0xff;        /* block offset */
+#if CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1
+       addr[0] = offset >> 8;          /* block number */
+       addr[1] = blk_off;              /* block offset */
+       alen = 2;
+#else
+       addr[0] = offset >> 16;         /* block number */
+       addr[1] = offset >>  8;         /* upper address octet */
+       addr[2] = blk_off;              /* lower address octet */
+       alen = 3;
+#endif /* CONFIG_SYS_I2C_EEPROM_ADDR_LEN */
+
+       addr[0] |= dev_addr;            /* insert device address */
+
+       return alen;
+}
+
+static int eeprom_len(unsigned offset, unsigned end)
+{
+       unsigned len = end - offset;
+
+       /*
+        * For a FRAM device there is no limit on the number of the
+        * bytes that can be ccessed with the single read or write
+        * operation.
+        */
+#if !defined(CONFIG_SYS_I2C_FRAM)
+       unsigned blk_off = offset & 0xff;
+       unsigned maxlen = EEPROM_PAGE_SIZE - EEPROM_PAGE_OFFSET(blk_off);
+
+       if (maxlen > I2C_RXTX_LEN)
+               maxlen = I2C_RXTX_LEN;
+
+       if (len > maxlen)
+               len = maxlen;
+#endif
+
+       return len;
+}
+
+static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen,
+                          uchar *buffer, unsigned len, bool read)
+{
+       int ret = 0;
+
+       /* SPI */
+#if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
+       if (read)
+               spi_read(addr, alen, buffer, len);
+       else
+               spi_write(addr, alen, buffer, len);
+#else  /* I2C */
+
+#if defined(CONFIG_SYS_I2C_EEPROM_BUS)
+       i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS);
+#endif
+
+       if (read)
+               ret = i2c_read(addr[0], offset, alen - 1, buffer, len);
+       else
+               ret = i2c_write(addr[0], offset, alen - 1, buffer, len);
+
+       if (ret)
+               ret = 1;
+#endif
+       return ret;
+}
+
+static int eeprom_rw(unsigned dev_addr, unsigned offset, uchar *buffer,
+                    unsigned cnt, bool read)
+{
+       unsigned end = offset + cnt;
+       unsigned alen, len;
+       int rcode = 0;
+       uchar addr[3];
+
+       while (offset < end) {
+               alen = eeprom_addr(dev_addr, offset, addr);
+
+               len = eeprom_len(offset, end);
+
+               rcode = eeprom_rw_block(offset, addr, alen, buffer, len, read);
+
+               buffer += len;
+               offset += len;
+
+               if (!read)
+                       udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
+       }
+
+       return rcode;
+}
+
+int eeprom_read(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt)
+{
+       /*
+        * Read data until done or would cross a page boundary.
+        * We must write the address again when changing pages
+        * because the next page may be in a different device.
+        */
+       return eeprom_rw(dev_addr, offset, buffer, cnt, 1);
+}
+
+int eeprom_write(unsigned dev_addr, unsigned offset,
+                uchar *buffer, unsigned cnt)
+{
+       int ret;
+
+       eeprom_write_enable(dev_addr, 1);
+
+       /*
+        * Write data until done or would cross a write page boundary.
+        * We must write the address again when changing pages
+        * because the address counter only increments within a page.
+        */
+       ret = eeprom_rw(dev_addr, offset, buffer, cnt, 0);
+
+       eeprom_write_enable(dev_addr, 0);
+       return ret;
+}
+
+static int do_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       const char *const fmt =
+               "\nEEPROM @0x%lX %s: addr %08lx  off %04lx  count %ld ... ";
+       char * const *args = &argv[2];
+       int rcode;
+       ulong dev_addr, addr, off, cnt;
+       int bus_addr;
+
+       switch (argc) {
+#ifdef CONFIG_SYS_DEF_EEPROM_ADDR
+       case 5:
+               bus_addr = -1;
+               dev_addr = CONFIG_SYS_DEF_EEPROM_ADDR;
+               break;
+#endif
+       case 6:
+               bus_addr = -1;
+               dev_addr = simple_strtoul(*args++, NULL, 16);
+               break;
+       case 7:
+               bus_addr = simple_strtoul(*args++, NULL, 16);
+               dev_addr = simple_strtoul(*args++, NULL, 16);
+               break;
+       default:
+               return CMD_RET_USAGE;
+       }
+
+       addr = simple_strtoul(*args++, NULL, 16);
+       off = simple_strtoul(*args++, NULL, 16);
+       cnt = simple_strtoul(*args++, NULL, 16);
+
+       eeprom_init(bus_addr);
+
+       if (strcmp(argv[1], "read") == 0) {
+               printf(fmt, dev_addr, argv[1], addr, off, cnt);
+
+               rcode = eeprom_read(dev_addr, off, (uchar *)addr, cnt);
+
+               puts("done\n");
+               return rcode;
+       } else if (strcmp(argv[1], "write") == 0) {
+               printf(fmt, dev_addr, argv[1], addr, off, cnt);
+
+               rcode = eeprom_write(dev_addr, off, (uchar *)addr, cnt);
+
+               puts("done\n");
+               return rcode;
+       }
+
+       return CMD_RET_USAGE;
+}
+
+U_BOOT_CMD(
+       eeprom, 7,      1,      do_eeprom,
+       "EEPROM sub-system",
+       "read  <bus> <devaddr> addr off cnt\n"
+       "eeprom write <bus> <devaddr> addr off cnt\n"
+       "       - read/write `cnt' bytes from `devaddr` EEPROM at offset `off'"
+)