1*2e192b24SSimon Glass /* 2*2e192b24SSimon Glass * (C) Copyright 2000, 2001 3*2e192b24SSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4*2e192b24SSimon Glass * 5*2e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 6*2e192b24SSimon Glass */ 7*2e192b24SSimon Glass 8*2e192b24SSimon Glass /* 9*2e192b24SSimon Glass * Support for read and write access to EEPROM like memory devices. This 10*2e192b24SSimon Glass * includes regular EEPROM as well as FRAM (ferroelectic nonvolaile RAM). 11*2e192b24SSimon Glass * FRAM devices read and write data at bus speed. In particular, there is no 12*2e192b24SSimon Glass * write delay. Also, there is no limit imposed on the number of bytes that can 13*2e192b24SSimon Glass * be transferred with a single read or write. 14*2e192b24SSimon Glass * 15*2e192b24SSimon Glass * Use the following configuration options to ensure no unneeded performance 16*2e192b24SSimon Glass * degradation (typical for EEPROM) is incured for FRAM memory: 17*2e192b24SSimon Glass * 18*2e192b24SSimon Glass * #define CONFIG_SYS_I2C_FRAM 19*2e192b24SSimon Glass * #undef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 20*2e192b24SSimon Glass * 21*2e192b24SSimon Glass */ 22*2e192b24SSimon Glass 23*2e192b24SSimon Glass #include <common.h> 24*2e192b24SSimon Glass #include <config.h> 25*2e192b24SSimon Glass #include <command.h> 26*2e192b24SSimon Glass #include <i2c.h> 27*2e192b24SSimon Glass 28*2e192b24SSimon Glass #ifndef CONFIG_SYS_I2C_SPEED 29*2e192b24SSimon Glass #define CONFIG_SYS_I2C_SPEED 50000 30*2e192b24SSimon Glass #endif 31*2e192b24SSimon Glass 32*2e192b24SSimon Glass #ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 33*2e192b24SSimon Glass #define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 0 34*2e192b24SSimon Glass #endif 35*2e192b24SSimon Glass 36*2e192b24SSimon Glass #ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 37*2e192b24SSimon Glass #define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 8 38*2e192b24SSimon Glass #endif 39*2e192b24SSimon Glass 40*2e192b24SSimon Glass #define EEPROM_PAGE_SIZE (1 << CONFIG_SYS_EEPROM_PAGE_WRITE_BITS) 41*2e192b24SSimon Glass #define EEPROM_PAGE_OFFSET(x) ((x) & (EEPROM_PAGE_SIZE - 1)) 42*2e192b24SSimon Glass 43*2e192b24SSimon Glass /* 44*2e192b24SSimon Glass * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is 45*2e192b24SSimon Glass * 0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM. 46*2e192b24SSimon Glass * 47*2e192b24SSimon Glass * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is 48*2e192b24SSimon Glass * 0x00000nxx for EEPROM address selectors and page number at n. 49*2e192b24SSimon Glass */ 50*2e192b24SSimon Glass #if !defined(CONFIG_SPI) || defined(CONFIG_ENV_EEPROM_IS_ON_I2C) 51*2e192b24SSimon Glass #if !defined(CONFIG_SYS_I2C_EEPROM_ADDR_LEN) || \ 52*2e192b24SSimon Glass (CONFIG_SYS_I2C_EEPROM_ADDR_LEN < 1) || \ 53*2e192b24SSimon Glass (CONFIG_SYS_I2C_EEPROM_ADDR_LEN > 2) 54*2e192b24SSimon Glass #error CONFIG_SYS_I2C_EEPROM_ADDR_LEN must be 1 or 2 55*2e192b24SSimon Glass #endif 56*2e192b24SSimon Glass #endif 57*2e192b24SSimon Glass 58*2e192b24SSimon Glass __weak int eeprom_write_enable(unsigned dev_addr, int state) 59*2e192b24SSimon Glass { 60*2e192b24SSimon Glass return 0; 61*2e192b24SSimon Glass } 62*2e192b24SSimon Glass 63*2e192b24SSimon Glass void eeprom_init(int bus) 64*2e192b24SSimon Glass { 65*2e192b24SSimon Glass /* SPI EEPROM */ 66*2e192b24SSimon Glass #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C) 67*2e192b24SSimon Glass spi_init_f(); 68*2e192b24SSimon Glass #endif 69*2e192b24SSimon Glass 70*2e192b24SSimon Glass /* I2C EEPROM */ 71*2e192b24SSimon Glass #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C_SOFT) 72*2e192b24SSimon Glass #if defined(CONFIG_SYS_I2C) 73*2e192b24SSimon Glass if (bus >= 0) 74*2e192b24SSimon Glass i2c_set_bus_num(bus); 75*2e192b24SSimon Glass #endif 76*2e192b24SSimon Glass i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); 77*2e192b24SSimon Glass #endif 78*2e192b24SSimon Glass } 79*2e192b24SSimon Glass 80*2e192b24SSimon Glass static int eeprom_addr(unsigned dev_addr, unsigned offset, uchar *addr) 81*2e192b24SSimon Glass { 82*2e192b24SSimon Glass unsigned blk_off; 83*2e192b24SSimon Glass int alen; 84*2e192b24SSimon Glass 85*2e192b24SSimon Glass blk_off = offset & 0xff; /* block offset */ 86*2e192b24SSimon Glass #if CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 87*2e192b24SSimon Glass addr[0] = offset >> 8; /* block number */ 88*2e192b24SSimon Glass addr[1] = blk_off; /* block offset */ 89*2e192b24SSimon Glass alen = 2; 90*2e192b24SSimon Glass #else 91*2e192b24SSimon Glass addr[0] = offset >> 16; /* block number */ 92*2e192b24SSimon Glass addr[1] = offset >> 8; /* upper address octet */ 93*2e192b24SSimon Glass addr[2] = blk_off; /* lower address octet */ 94*2e192b24SSimon Glass alen = 3; 95*2e192b24SSimon Glass #endif /* CONFIG_SYS_I2C_EEPROM_ADDR_LEN */ 96*2e192b24SSimon Glass 97*2e192b24SSimon Glass addr[0] |= dev_addr; /* insert device address */ 98*2e192b24SSimon Glass 99*2e192b24SSimon Glass return alen; 100*2e192b24SSimon Glass } 101*2e192b24SSimon Glass 102*2e192b24SSimon Glass static int eeprom_len(unsigned offset, unsigned end) 103*2e192b24SSimon Glass { 104*2e192b24SSimon Glass unsigned len = end - offset; 105*2e192b24SSimon Glass 106*2e192b24SSimon Glass /* 107*2e192b24SSimon Glass * For a FRAM device there is no limit on the number of the 108*2e192b24SSimon Glass * bytes that can be ccessed with the single read or write 109*2e192b24SSimon Glass * operation. 110*2e192b24SSimon Glass */ 111*2e192b24SSimon Glass #if !defined(CONFIG_SYS_I2C_FRAM) 112*2e192b24SSimon Glass unsigned blk_off = offset & 0xff; 113*2e192b24SSimon Glass unsigned maxlen = EEPROM_PAGE_SIZE - EEPROM_PAGE_OFFSET(blk_off); 114*2e192b24SSimon Glass 115*2e192b24SSimon Glass if (maxlen > I2C_RXTX_LEN) 116*2e192b24SSimon Glass maxlen = I2C_RXTX_LEN; 117*2e192b24SSimon Glass 118*2e192b24SSimon Glass if (len > maxlen) 119*2e192b24SSimon Glass len = maxlen; 120*2e192b24SSimon Glass #endif 121*2e192b24SSimon Glass 122*2e192b24SSimon Glass return len; 123*2e192b24SSimon Glass } 124*2e192b24SSimon Glass 125*2e192b24SSimon Glass static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen, 126*2e192b24SSimon Glass uchar *buffer, unsigned len, bool read) 127*2e192b24SSimon Glass { 128*2e192b24SSimon Glass int ret = 0; 129*2e192b24SSimon Glass 130*2e192b24SSimon Glass /* SPI */ 131*2e192b24SSimon Glass #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C) 132*2e192b24SSimon Glass if (read) 133*2e192b24SSimon Glass spi_read(addr, alen, buffer, len); 134*2e192b24SSimon Glass else 135*2e192b24SSimon Glass spi_write(addr, alen, buffer, len); 136*2e192b24SSimon Glass #else /* I2C */ 137*2e192b24SSimon Glass 138*2e192b24SSimon Glass #if defined(CONFIG_SYS_I2C_EEPROM_BUS) 139*2e192b24SSimon Glass i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS); 140*2e192b24SSimon Glass #endif 141*2e192b24SSimon Glass 142*2e192b24SSimon Glass if (read) 143*2e192b24SSimon Glass ret = i2c_read(addr[0], offset, alen - 1, buffer, len); 144*2e192b24SSimon Glass else 145*2e192b24SSimon Glass ret = i2c_write(addr[0], offset, alen - 1, buffer, len); 146*2e192b24SSimon Glass 147*2e192b24SSimon Glass if (ret) 148*2e192b24SSimon Glass ret = 1; 149*2e192b24SSimon Glass #endif 150*2e192b24SSimon Glass return ret; 151*2e192b24SSimon Glass } 152*2e192b24SSimon Glass 153*2e192b24SSimon Glass static int eeprom_rw(unsigned dev_addr, unsigned offset, uchar *buffer, 154*2e192b24SSimon Glass unsigned cnt, bool read) 155*2e192b24SSimon Glass { 156*2e192b24SSimon Glass unsigned end = offset + cnt; 157*2e192b24SSimon Glass unsigned alen, len; 158*2e192b24SSimon Glass int rcode = 0; 159*2e192b24SSimon Glass uchar addr[3]; 160*2e192b24SSimon Glass 161*2e192b24SSimon Glass while (offset < end) { 162*2e192b24SSimon Glass alen = eeprom_addr(dev_addr, offset, addr); 163*2e192b24SSimon Glass 164*2e192b24SSimon Glass len = eeprom_len(offset, end); 165*2e192b24SSimon Glass 166*2e192b24SSimon Glass rcode = eeprom_rw_block(offset, addr, alen, buffer, len, read); 167*2e192b24SSimon Glass 168*2e192b24SSimon Glass buffer += len; 169*2e192b24SSimon Glass offset += len; 170*2e192b24SSimon Glass 171*2e192b24SSimon Glass if (!read) 172*2e192b24SSimon Glass udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000); 173*2e192b24SSimon Glass } 174*2e192b24SSimon Glass 175*2e192b24SSimon Glass return rcode; 176*2e192b24SSimon Glass } 177*2e192b24SSimon Glass 178*2e192b24SSimon Glass int eeprom_read(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt) 179*2e192b24SSimon Glass { 180*2e192b24SSimon Glass /* 181*2e192b24SSimon Glass * Read data until done or would cross a page boundary. 182*2e192b24SSimon Glass * We must write the address again when changing pages 183*2e192b24SSimon Glass * because the next page may be in a different device. 184*2e192b24SSimon Glass */ 185*2e192b24SSimon Glass return eeprom_rw(dev_addr, offset, buffer, cnt, 1); 186*2e192b24SSimon Glass } 187*2e192b24SSimon Glass 188*2e192b24SSimon Glass int eeprom_write(unsigned dev_addr, unsigned offset, 189*2e192b24SSimon Glass uchar *buffer, unsigned cnt) 190*2e192b24SSimon Glass { 191*2e192b24SSimon Glass int ret; 192*2e192b24SSimon Glass 193*2e192b24SSimon Glass eeprom_write_enable(dev_addr, 1); 194*2e192b24SSimon Glass 195*2e192b24SSimon Glass /* 196*2e192b24SSimon Glass * Write data until done or would cross a write page boundary. 197*2e192b24SSimon Glass * We must write the address again when changing pages 198*2e192b24SSimon Glass * because the address counter only increments within a page. 199*2e192b24SSimon Glass */ 200*2e192b24SSimon Glass ret = eeprom_rw(dev_addr, offset, buffer, cnt, 0); 201*2e192b24SSimon Glass 202*2e192b24SSimon Glass eeprom_write_enable(dev_addr, 0); 203*2e192b24SSimon Glass return ret; 204*2e192b24SSimon Glass } 205*2e192b24SSimon Glass 206*2e192b24SSimon Glass static int do_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 207*2e192b24SSimon Glass { 208*2e192b24SSimon Glass const char *const fmt = 209*2e192b24SSimon Glass "\nEEPROM @0x%lX %s: addr %08lx off %04lx count %ld ... "; 210*2e192b24SSimon Glass char * const *args = &argv[2]; 211*2e192b24SSimon Glass int rcode; 212*2e192b24SSimon Glass ulong dev_addr, addr, off, cnt; 213*2e192b24SSimon Glass int bus_addr; 214*2e192b24SSimon Glass 215*2e192b24SSimon Glass switch (argc) { 216*2e192b24SSimon Glass #ifdef CONFIG_SYS_DEF_EEPROM_ADDR 217*2e192b24SSimon Glass case 5: 218*2e192b24SSimon Glass bus_addr = -1; 219*2e192b24SSimon Glass dev_addr = CONFIG_SYS_DEF_EEPROM_ADDR; 220*2e192b24SSimon Glass break; 221*2e192b24SSimon Glass #endif 222*2e192b24SSimon Glass case 6: 223*2e192b24SSimon Glass bus_addr = -1; 224*2e192b24SSimon Glass dev_addr = simple_strtoul(*args++, NULL, 16); 225*2e192b24SSimon Glass break; 226*2e192b24SSimon Glass case 7: 227*2e192b24SSimon Glass bus_addr = simple_strtoul(*args++, NULL, 16); 228*2e192b24SSimon Glass dev_addr = simple_strtoul(*args++, NULL, 16); 229*2e192b24SSimon Glass break; 230*2e192b24SSimon Glass default: 231*2e192b24SSimon Glass return CMD_RET_USAGE; 232*2e192b24SSimon Glass } 233*2e192b24SSimon Glass 234*2e192b24SSimon Glass addr = simple_strtoul(*args++, NULL, 16); 235*2e192b24SSimon Glass off = simple_strtoul(*args++, NULL, 16); 236*2e192b24SSimon Glass cnt = simple_strtoul(*args++, NULL, 16); 237*2e192b24SSimon Glass 238*2e192b24SSimon Glass eeprom_init(bus_addr); 239*2e192b24SSimon Glass 240*2e192b24SSimon Glass if (strcmp(argv[1], "read") == 0) { 241*2e192b24SSimon Glass printf(fmt, dev_addr, argv[1], addr, off, cnt); 242*2e192b24SSimon Glass 243*2e192b24SSimon Glass rcode = eeprom_read(dev_addr, off, (uchar *)addr, cnt); 244*2e192b24SSimon Glass 245*2e192b24SSimon Glass puts("done\n"); 246*2e192b24SSimon Glass return rcode; 247*2e192b24SSimon Glass } else if (strcmp(argv[1], "write") == 0) { 248*2e192b24SSimon Glass printf(fmt, dev_addr, argv[1], addr, off, cnt); 249*2e192b24SSimon Glass 250*2e192b24SSimon Glass rcode = eeprom_write(dev_addr, off, (uchar *)addr, cnt); 251*2e192b24SSimon Glass 252*2e192b24SSimon Glass puts("done\n"); 253*2e192b24SSimon Glass return rcode; 254*2e192b24SSimon Glass } 255*2e192b24SSimon Glass 256*2e192b24SSimon Glass return CMD_RET_USAGE; 257*2e192b24SSimon Glass } 258*2e192b24SSimon Glass 259*2e192b24SSimon Glass U_BOOT_CMD( 260*2e192b24SSimon Glass eeprom, 7, 1, do_eeprom, 261*2e192b24SSimon Glass "EEPROM sub-system", 262*2e192b24SSimon Glass "read <bus> <devaddr> addr off cnt\n" 263*2e192b24SSimon Glass "eeprom write <bus> <devaddr> addr off cnt\n" 264*2e192b24SSimon Glass " - read/write `cnt' bytes from `devaddr` EEPROM at offset `off'" 265*2e192b24SSimon Glass ) 266