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