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