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