source: SVN/rincon/u-boot/common/cmd_eeprom.c @ 55

Last change on this file since 55 was 55, checked in by Tim Harvey, 2 years ago

rincon: added latest u-boot source

restored form server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 11.4 KB
Line 
1/*
2 * (C) Copyright 2000, 2001
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 *
23 */
24
25/*
26 * Support for read and write access to EEPROM like memory devices. This
27 * includes regular EEPROM as well as  FRAM (ferroelectic nonvolaile RAM).
28 * FRAM devices read and write data at bus speed. In particular, there is no
29 * write delay. Also, there is no limit imposed on the numer of bytes that can
30 * be transferred with a single read or write.
31 *
32 * Use the following configuration options to ensure no unneeded performance
33 * degradation (typical for EEPROM) is incured for FRAM memory:
34 *
35 * #define CFG_I2C_FRAM
36 * #undef CFG_EEPROM_PAGE_WRITE_DELAY_MS
37 *
38 */
39
40#include <common.h>
41#include <config.h>
42#include <command.h>
43#include <i2c.h>
44
45extern void eeprom_init  (void);
46extern int  eeprom_read  (unsigned dev_addr, unsigned offset,
47                          uchar *buffer, unsigned cnt);
48extern int  eeprom_write (unsigned dev_addr, unsigned offset,
49                          uchar *buffer, unsigned cnt);
50#if defined(CFG_EEPROM_WREN)
51extern int eeprom_write_enable (unsigned dev_addr, int state);
52#endif
53
54
55#if defined(CFG_EEPROM_X40430)
56        /* Maximum number of times to poll for acknowledge after write */
57#define MAX_ACKNOWLEDGE_POLLS   10
58#endif
59
60/* ------------------------------------------------------------------------- */
61
62#if defined(CONFIG_CMD_EEPROM)
63int do_eeprom ( cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
64{
65        const char *const fmt =
66                "\nEEPROM @0x%lX %s: addr %08lx  off %04lx  count %ld ... ";
67
68#if defined(CFG_I2C_MULTI_EEPROMS)
69        if (argc == 6) {
70                ulong dev_addr = simple_strtoul (argv[2], NULL, 16);
71                ulong addr = simple_strtoul (argv[3], NULL, 16);
72                ulong off  = simple_strtoul (argv[4], NULL, 16);
73                ulong cnt  = simple_strtoul (argv[5], NULL, 16);
74#else
75        if (argc == 5) {
76                ulong dev_addr = CFG_DEF_EEPROM_ADDR;
77                ulong addr = simple_strtoul (argv[2], NULL, 16);
78                ulong off  = simple_strtoul (argv[3], NULL, 16);
79                ulong cnt  = simple_strtoul (argv[4], NULL, 16);
80#endif /* CFG_I2C_MULTI_EEPROMS */
81
82# ifndef CONFIG_SPI
83                eeprom_init ();
84# endif /* !CONFIG_SPI */
85
86                if (strcmp (argv[1], "read") == 0) {
87                        int rcode;
88
89                        printf (fmt, dev_addr, argv[1], addr, off, cnt);
90
91                        rcode = eeprom_read (dev_addr, off, (uchar *) addr, cnt);
92
93                        puts ("done\n");
94                        return rcode;
95                } else if (strcmp (argv[1], "write") == 0) {
96                        int rcode;
97
98                        printf (fmt, dev_addr, argv[1], addr, off, cnt);
99
100                        rcode = eeprom_write (dev_addr, off, (uchar *) addr, cnt);
101
102                        puts ("done\n");
103                        return rcode;
104                }
105        }
106
107        printf ("Usage:\n%s\n", cmdtp->usage);
108        return 1;
109}
110#endif
111
112/*-----------------------------------------------------------------------
113 *
114 * for CFG_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is
115 *   0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM.
116 *
117 * for CFG_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is
118 *   0x00000nxx for EEPROM address selectors and page number at n.
119 */
120
121#ifndef CONFIG_SPI
122#if !defined(CFG_I2C_EEPROM_ADDR_LEN) || CFG_I2C_EEPROM_ADDR_LEN < 1 || CFG_I2C_EEPROM_ADDR_LEN > 2
123#error CFG_I2C_EEPROM_ADDR_LEN must be 1 or 2
124#endif
125#endif
126
127int eeprom_read (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt)
128{
129        unsigned end = offset + cnt;
130        unsigned blk_off;
131        int rcode = 0;
132
133        /* Read data until done or would cross a page boundary.
134         * We must write the address again when changing pages
135         * because the next page may be in a different device.
136         */
137        while (offset < end) {
138                unsigned alen, len;
139#if !defined(CFG_I2C_FRAM)
140                unsigned maxlen;
141#endif
142
143#if CFG_I2C_EEPROM_ADDR_LEN == 1 && !defined(CONFIG_SPI_X)
144                uchar addr[2];
145
146                blk_off = offset & 0xFF;        /* block offset */
147
148                addr[0] = offset >> 8;          /* block number */
149                addr[1] = blk_off;              /* block offset */
150                alen    = 2;
151#else
152                uchar addr[3];
153
154                blk_off = offset & 0xFF;        /* block offset */
155
156                addr[0] = offset >> 16;         /* block number */
157                addr[1] = offset >>  8;         /* upper address octet */
158                addr[2] = blk_off;              /* lower address octet */
159                alen    = 3;
160#endif  /* CFG_I2C_EEPROM_ADDR_LEN, CONFIG_SPI_X */
161
162                addr[0] |= dev_addr;            /* insert device address */
163
164                len = end - offset;
165
166                /*
167                 * For a FRAM device there is no limit on the number of the
168                 * bytes that can be ccessed with the single read or write
169                 * operation.
170                 */
171#if !defined(CFG_I2C_FRAM)
172                maxlen = 0x100 - blk_off;
173                if (maxlen > I2C_RXTX_LEN)
174                        maxlen = I2C_RXTX_LEN;
175                if (len > maxlen)
176                        len = maxlen;
177#endif
178
179#ifdef CONFIG_SPI
180                spi_read (addr, alen, buffer, len);
181#else
182                if (i2c_read (addr[0], offset, alen-1, buffer, len) != 0)
183                        rcode = 1;
184#endif
185                buffer += len;
186                offset += len;
187        }
188
189        return rcode;
190}
191
192/*-----------------------------------------------------------------------
193 *
194 * for CFG_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is
195 *   0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM.
196 *
197 * for CFG_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is
198 *   0x00000nxx for EEPROM address selectors and page number at n.
199 */
200
201int eeprom_write (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt)
202{
203        unsigned end = offset + cnt;
204        unsigned blk_off;
205        int rcode = 0;
206
207#if defined(CFG_EEPROM_X40430)
208        uchar   contr_r_addr[2];
209        uchar   addr_void[2];
210        uchar   contr_reg[2];
211        uchar   ctrl_reg_v;
212        int     i;
213#endif
214
215#if defined(CFG_EEPROM_WREN)
216        eeprom_write_enable (dev_addr,1);
217#endif
218        /* Write data until done or would cross a write page boundary.
219         * We must write the address again when changing pages
220         * because the address counter only increments within a page.
221         */
222
223        while (offset < end) {
224                unsigned alen, len;
225#if !defined(CFG_I2C_FRAM)
226                unsigned maxlen;
227#endif
228
229#if CFG_I2C_EEPROM_ADDR_LEN == 1 && !defined(CONFIG_SPI_X)
230                uchar addr[2];
231
232                blk_off = offset & 0xFF;        /* block offset */
233
234                addr[0] = offset >> 8;          /* block number */
235                addr[1] = blk_off;              /* block offset */
236                alen    = 2;
237#else
238                uchar addr[3];
239
240                blk_off = offset & 0xFF;        /* block offset */
241
242                addr[0] = offset >> 16;         /* block number */
243                addr[1] = offset >>  8;         /* upper address octet */
244                addr[2] = blk_off;              /* lower address octet */
245                alen    = 3;
246#endif  /* CFG_I2C_EEPROM_ADDR_LEN, CONFIG_SPI_X */
247
248                addr[0] |= dev_addr;            /* insert device address */
249
250                len = end - offset;
251
252                /*
253                 * For a FRAM device there is no limit on the number of the
254                 * bytes that can be ccessed with the single read or write
255                 * operation.
256                 */
257#if !defined(CFG_I2C_FRAM)
258
259#if defined(CFG_EEPROM_PAGE_WRITE_BITS)
260
261#define EEPROM_PAGE_SIZE        (1 << CFG_EEPROM_PAGE_WRITE_BITS)
262#define EEPROM_PAGE_OFFSET(x)   ((x) & (EEPROM_PAGE_SIZE - 1))
263
264                maxlen = EEPROM_PAGE_SIZE - EEPROM_PAGE_OFFSET(blk_off);
265#else
266                maxlen = 0x100 - blk_off;
267#endif
268                if (maxlen > I2C_RXTX_LEN)
269                        maxlen = I2C_RXTX_LEN;
270
271                if (len > maxlen)
272                        len = maxlen;
273#endif
274
275#ifdef CONFIG_SPI
276                spi_write (addr, alen, buffer, len);
277#else
278#if defined(CFG_EEPROM_X40430)
279                /* Get the value of the control register.
280                 * Set current address (internal pointer in the x40430)
281                 * to 0x1ff.
282                 */
283                contr_r_addr[0] = 9;
284                contr_r_addr[1] = 0xff;
285                addr_void[0]    = 0;
286                addr_void[1]    = addr[1];
287#ifdef CFG_I2C_EEPROM_ADDR
288                contr_r_addr[0] |= CFG_I2C_EEPROM_ADDR;
289                addr_void[0]    |= CFG_I2C_EEPROM_ADDR;
290#endif
291                contr_reg[0] = 0xff;
292                if (i2c_read (contr_r_addr[0], contr_r_addr[1], 1, contr_reg, 1) != 0) {
293                        rcode = 1;
294                }
295                ctrl_reg_v = contr_reg[0];
296
297                /* Are any of the eeprom blocks write protected?
298                 */
299                if (ctrl_reg_v & 0x18) {
300                        ctrl_reg_v &= ~0x18;   /* reset block protect bits  */
301                        ctrl_reg_v |=  0x02;   /* set write enable latch    */
302                        ctrl_reg_v &= ~0x04;   /* clear RWEL                */
303
304                        /* Set write enable latch.
305                         */
306                        contr_reg[0] = 0x02;
307                        if (i2c_write (contr_r_addr[0], 0xff, 1, contr_reg, 1) != 0) {
308                                rcode = 1;
309                        }
310
311                        /* Set register write enable latch.
312                         */
313                        contr_reg[0] = 0x06;
314                        if (i2c_write (contr_r_addr[0], 0xFF, 1, contr_reg, 1) != 0) {
315                                rcode = 1;
316                        }
317
318                        /* Modify ctrl register.
319                         */
320                        contr_reg[0] = ctrl_reg_v;
321                        if (i2c_write (contr_r_addr[0], 0xFF, 1, contr_reg, 1) != 0) {
322                                rcode = 1;
323                        }
324
325                        /* The write (above) is an operation on NV memory.
326                         * These can take some time (~5ms), and the device
327                         * will not respond to further I2C messages till
328                         * it's completed the write.
329                         * So poll device for an I2C acknowledge.
330                         * When we get one we know we can continue with other
331                         * operations.
332                         */
333                        contr_reg[0] = 0;
334                        for (i = 0; i < MAX_ACKNOWLEDGE_POLLS; i++) {
335                                if (i2c_read (addr_void[0], addr_void[1], 1, contr_reg, 1) == 0)
336                                        break;  /* got ack */
337#if defined(CFG_EEPROM_PAGE_WRITE_DELAY_MS)
338                                udelay(CFG_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
339#endif
340                        }
341                        if (i == MAX_ACKNOWLEDGE_POLLS) {
342                                puts ("EEPROM poll acknowledge failed\n");
343                                rcode = 1;
344                        }
345                }
346
347                /* Is the write enable latch on?.
348                 */
349                else if (!(ctrl_reg_v & 0x02)) {
350                        /* Set write enable latch.
351                         */
352                        contr_reg[0] = 0x02;
353                        if (i2c_write (contr_r_addr[0], 0xFF, 1, contr_reg, 1) != 0) {
354                               rcode = 1;
355                        }
356                }
357                /* Write is enabled ... now write eeprom value.
358                 */
359#endif
360                if (i2c_write (addr[0], offset, alen-1, buffer, len) != 0)
361                        rcode = 1;
362
363#endif
364                buffer += len;
365                offset += len;
366
367#if defined(CFG_EEPROM_PAGE_WRITE_DELAY_MS)
368                udelay(CFG_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
369#endif
370        }
371#if defined(CFG_EEPROM_WREN)
372        eeprom_write_enable (dev_addr,0);
373#endif
374        return rcode;
375}
376
377#ifndef CONFIG_SPI
378int
379eeprom_probe (unsigned dev_addr, unsigned offset)
380{
381        unsigned char chip;
382
383        /* Probe the chip address
384         */
385#if CFG_I2C_EEPROM_ADDR_LEN == 1 && !defined(CONFIG_SPI_X)
386        chip = offset >> 8;             /* block number */
387#else
388        chip = offset >> 16;            /* block number */
389#endif  /* CFG_I2C_EEPROM_ADDR_LEN, CONFIG_SPI_X */
390
391        chip |= dev_addr;               /* insert device address */
392
393        return (i2c_probe (chip));
394}
395#endif
396
397/*-----------------------------------------------------------------------
398 * Set default values
399 */
400#ifndef CFG_I2C_SPEED
401#define CFG_I2C_SPEED   50000
402#endif
403
404#ifndef CFG_I2C_SLAVE
405#define CFG_I2C_SLAVE   0xFE
406#endif
407
408void eeprom_init  (void)
409{
410#if defined(CONFIG_SPI)
411        spi_init_f ();
412#endif
413#if defined(CONFIG_HARD_I2C) || \
414    defined(CONFIG_SOFT_I2C)
415        i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
416#endif
417}
418/*-----------------------------------------------------------------------
419 */
420
421/***************************************************/
422
423#if defined(CONFIG_CMD_EEPROM)
424
425#ifdef CFG_I2C_MULTI_EEPROMS
426U_BOOT_CMD(
427        eeprom, 6,      1,      do_eeprom,
428        "eeprom  - EEPROM sub-system\n",
429        "read  devaddr addr off cnt\n"
430        "eeprom write devaddr addr off cnt\n"
431        "       - read/write `cnt' bytes from `devaddr` EEPROM at offset `off'\n"
432);
433#else /* One EEPROM */
434U_BOOT_CMD(
435        eeprom, 5,      1,      do_eeprom,
436        "eeprom  - EEPROM sub-system\n",
437        "read  addr off cnt\n"
438        "eeprom write addr off cnt\n"
439        "       - read/write `cnt' bytes at EEPROM offset `off'\n"
440);
441#endif /* CFG_I2C_MULTI_EEPROMS */
442
443#endif
Note: See TracBrowser for help on using the repository browser.