Blame view
cmd/eeprom.c
10.8 KB
3863585bb Initial revision |
1 2 3 4 |
/* * (C) Copyright 2000, 2001 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * |
1a4596601 Add GPL-2.0+ SPDX... |
5 |
* SPDX-License-Identifier: GPL-2.0+ |
3863585bb Initial revision |
6 |
*/ |
d4f5c7289 FRAM memory acces... |
7 8 9 10 |
/* * Support for read and write access to EEPROM like memory devices. This * includes regular EEPROM as well as FRAM (ferroelectic nonvolaile RAM). * FRAM devices read and write data at bus speed. In particular, there is no |
e506a0069 cmd_eeprom: typo |
11 |
* write delay. Also, there is no limit imposed on the number of bytes that can |
d4f5c7289 FRAM memory acces... |
12 |
* be transferred with a single read or write. |
6617aae9b Add new board spe... |
13 |
* |
d4f5c7289 FRAM memory acces... |
14 15 |
* Use the following configuration options to ensure no unneeded performance * degradation (typical for EEPROM) is incured for FRAM memory: |
6617aae9b Add new board spe... |
16 |
* |
6d0f6bcf3 rename CFG_ macro... |
17 18 |
* #define CONFIG_SYS_I2C_FRAM * #undef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS |
d4f5c7289 FRAM memory acces... |
19 20 |
* */ |
3863585bb Initial revision |
21 22 23 24 |
#include <common.h> #include <config.h> #include <command.h> #include <i2c.h> |
e7c2729bb eeprom: use eepro... |
25 |
#include <eeprom_layout.h> |
3863585bb Initial revision |
26 |
|
4f296d09e eeprom: Shuffle c... |
27 28 |
#ifndef CONFIG_SYS_I2C_SPEED #define CONFIG_SYS_I2C_SPEED 50000 |
98f4a3dfc Add SM501 support... |
29 |
#endif |
3863585bb Initial revision |
30 |
|
d738746cc eeprom: Pull out ... |
31 32 33 |
#ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS #define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 0 #endif |
6717e3c84 eeprom: Pull out ... |
34 35 36 |
#ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS #define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 8 #endif |
a6e7b7744 i2c/eeprom: Alway... |
37 38 39 |
#ifndef I2C_RXTX_LEN #define I2C_RXTX_LEN 128 #endif |
6717e3c84 eeprom: Pull out ... |
40 41 |
#define EEPROM_PAGE_SIZE (1 << CONFIG_SYS_EEPROM_PAGE_WRITE_BITS) #define EEPROM_PAGE_OFFSET(x) ((x) & (EEPROM_PAGE_SIZE - 1)) |
4f296d09e eeprom: Shuffle c... |
42 |
/* |
6d0f6bcf3 rename CFG_ macro... |
43 |
* for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is |
3863585bb Initial revision |
44 45 |
* 0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM. * |
6d0f6bcf3 rename CFG_ macro... |
46 |
* for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is |
3863585bb Initial revision |
47 48 |
* 0x00000nxx for EEPROM address selectors and page number at n. */ |
548738b4d cmd_eeprom: I2C u... |
49 |
#if !defined(CONFIG_SPI) || defined(CONFIG_ENV_EEPROM_IS_ON_I2C) |
4f296d09e eeprom: Shuffle c... |
50 |
#if !defined(CONFIG_SYS_I2C_EEPROM_ADDR_LEN) || \ |
d4e69e617 eeprom: Clean up ... |
51 52 |
(CONFIG_SYS_I2C_EEPROM_ADDR_LEN < 1) || \ (CONFIG_SYS_I2C_EEPROM_ADDR_LEN > 2) |
6d0f6bcf3 rename CFG_ macro... |
53 |
#error CONFIG_SYS_I2C_EEPROM_ADDR_LEN must be 1 or 2 |
3863585bb Initial revision |
54 55 |
#endif #endif |
52cd47c9a eeprom: Make eepr... |
56 57 58 59 |
__weak int eeprom_write_enable(unsigned dev_addr, int state) { return 0; } |
4f296d09e eeprom: Shuffle c... |
60 |
|
354e3ed75 eeprom: Add bus a... |
61 |
void eeprom_init(int bus) |
4f296d09e eeprom: Shuffle c... |
62 63 64 |
{ /* SPI EEPROM */ #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C) |
8eee40a60 eeprom: Suck the ... |
65 |
spi_init_f(); |
4f296d09e eeprom: Shuffle c... |
66 67 68 |
#endif /* I2C EEPROM */ |
354e3ed75 eeprom: Add bus a... |
69 70 71 |
#if defined(CONFIG_SYS_I2C) if (bus >= 0) i2c_set_bus_num(bus); |
4f296d09e eeprom: Shuffle c... |
72 73 74 |
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); #endif } |
02c321cf8 eeprom: Pull out ... |
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
static int eeprom_addr(unsigned dev_addr, unsigned offset, uchar *addr) { unsigned blk_off; int alen; blk_off = offset & 0xff; /* block offset */ #if CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 addr[0] = offset >> 8; /* block number */ addr[1] = blk_off; /* block offset */ alen = 2; #else addr[0] = offset >> 16; /* block number */ addr[1] = offset >> 8; /* upper address octet */ addr[2] = blk_off; /* lower address octet */ alen = 3; #endif /* CONFIG_SYS_I2C_EEPROM_ADDR_LEN */ addr[0] |= dev_addr; /* insert device address */ return alen; } |
39b6f98bd eeprom: Pull out ... |
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
static int eeprom_len(unsigned offset, unsigned end) { unsigned len = end - offset; /* * For a FRAM device there is no limit on the number of the * bytes that can be ccessed with the single read or write * operation. */ #if !defined(CONFIG_SYS_I2C_FRAM) unsigned blk_off = offset & 0xff; unsigned maxlen = EEPROM_PAGE_SIZE - EEPROM_PAGE_OFFSET(blk_off); if (maxlen > I2C_RXTX_LEN) maxlen = I2C_RXTX_LEN; if (len > maxlen) len = maxlen; #endif return len; } |
9132088b0 eeprom: Pull out ... |
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen, uchar *buffer, unsigned len, bool read) { int ret = 0; /* SPI */ #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C) if (read) spi_read(addr, alen, buffer, len); else spi_write(addr, alen, buffer, len); #else /* I2C */ #if defined(CONFIG_SYS_I2C_EEPROM_BUS) i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS); #endif if (read) ret = i2c_read(addr[0], offset, alen - 1, buffer, len); else ret = i2c_write(addr[0], offset, alen - 1, buffer, len); if (ret) ret = 1; #endif return ret; } |
1a37889b0 eeprom: Pull out ... |
145 146 |
static int eeprom_rw(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt, bool read) |
3863585bb Initial revision |
147 148 |
{ unsigned end = offset + cnt; |
1a37889b0 eeprom: Pull out ... |
149 |
unsigned alen, len; |
3863585bb Initial revision |
150 |
int rcode = 0; |
02c321cf8 eeprom: Pull out ... |
151 |
uchar addr[3]; |
3863585bb Initial revision |
152 |
|
3863585bb Initial revision |
153 |
while (offset < end) { |
02c321cf8 eeprom: Pull out ... |
154 |
alen = eeprom_addr(dev_addr, offset, addr); |
3863585bb Initial revision |
155 |
|
39b6f98bd eeprom: Pull out ... |
156 |
len = eeprom_len(offset, end); |
d4f5c7289 FRAM memory acces... |
157 |
|
1a37889b0 eeprom: Pull out ... |
158 |
rcode = eeprom_rw_block(offset, addr, alen, buffer, len, read); |
9132088b0 eeprom: Pull out ... |
159 |
|
3863585bb Initial revision |
160 161 |
buffer += len; offset += len; |
1a37889b0 eeprom: Pull out ... |
162 163 164 |
if (!read) udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000); |
3863585bb Initial revision |
165 |
} |
d4f5c7289 FRAM memory acces... |
166 |
|
3863585bb Initial revision |
167 168 |
return rcode; } |
1a37889b0 eeprom: Pull out ... |
169 |
int eeprom_read(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt) |
3863585bb Initial revision |
170 |
{ |
1a37889b0 eeprom: Pull out ... |
171 172 173 174 175 176 177 |
/* * Read data until done or would cross a page boundary. * We must write the address again when changing pages * because the next page may be in a different device. */ return eeprom_rw(dev_addr, offset, buffer, cnt, 1); } |
d4e69e617 eeprom: Clean up ... |
178 179 |
int eeprom_write(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt) |
1a37889b0 eeprom: Pull out ... |
180 181 |
{ int ret; |
3863585bb Initial revision |
182 |
|
52cd47c9a eeprom: Make eepr... |
183 |
eeprom_write_enable(dev_addr, 1); |
4f296d09e eeprom: Shuffle c... |
184 185 |
/* * Write data until done or would cross a write page boundary. |
3863585bb Initial revision |
186 187 188 |
* We must write the address again when changing pages * because the address counter only increments within a page. */ |
52bc7c7e2 eeprom: fix eepro... |
189 |
ret = eeprom_rw(dev_addr, offset, buffer, cnt, 0); |
52cd47c9a eeprom: Make eepr... |
190 191 |
eeprom_write_enable(dev_addr, 0); |
1a37889b0 eeprom: Pull out ... |
192 |
return ret; |
3863585bb Initial revision |
193 |
} |
c40f03723 eeprom: refactor ... |
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
static int parse_numeric_param(char *str) { char *endptr; int value = simple_strtol(str, &endptr, 16); return (*endptr != '\0') ? -1 : value; } /** * parse_i2c_bus_addr - parse the i2c bus and i2c devaddr parameters * * @i2c_bus: address to store the i2c bus * @i2c_addr: address to store the device i2c address * @argc: count of command line arguments left to parse * @argv: command line arguments left to parse * @argc_no_bus_addr: argc value we expect to see when bus & addr aren't given * * @returns: number of arguments parsed or CMD_RET_USAGE if error */ static int parse_i2c_bus_addr(int *i2c_bus, ulong *i2c_addr, int argc, char * const argv[], int argc_no_bus_addr) { int argc_no_bus = argc_no_bus_addr + 1; int argc_bus_addr = argc_no_bus_addr + 2; #ifdef CONFIG_SYS_DEF_EEPROM_ADDR if (argc == argc_no_bus_addr) { *i2c_bus = -1; *i2c_addr = CONFIG_SYS_DEF_EEPROM_ADDR; return 0; } #endif if (argc == argc_no_bus) { *i2c_bus = -1; *i2c_addr = parse_numeric_param(argv[0]); return 1; } if (argc == argc_bus_addr) { *i2c_bus = parse_numeric_param(argv[0]); *i2c_addr = parse_numeric_param(argv[1]); return 2; } return CMD_RET_USAGE; } |
aa9e60441 cmd: eeprom: add ... |
243 |
#ifdef CONFIG_CMD_EEPROM_LAYOUT |
aa9e60441 cmd: eeprom: add ... |
244 245 246 247 248 249 250 |
__weak int eeprom_parse_layout_version(char *str) { return LAYOUT_VERSION_UNRECOGNIZED; } static unsigned char eeprom_buf[CONFIG_SYS_EEPROM_SIZE]; |
e7c2729bb eeprom: use eepro... |
251 |
#endif |
aa9e60441 cmd: eeprom: add ... |
252 |
enum eeprom_action { |
e7c2729bb eeprom: use eepro... |
253 254 |
EEPROM_READ, EEPROM_WRITE, |
aa9e60441 cmd: eeprom: add ... |
255 256 257 258 259 260 261 |
EEPROM_PRINT, EEPROM_UPDATE, EEPROM_ACTION_INVALID, }; static enum eeprom_action parse_action(char *cmd) { |
3dc9be820 eeprom: merge cmd... |
262 263 264 265 266 |
if (!strncmp(cmd, "read", 4)) return EEPROM_READ; if (!strncmp(cmd, "write", 5)) return EEPROM_WRITE; #ifdef CONFIG_CMD_EEPROM_LAYOUT |
aa9e60441 cmd: eeprom: add ... |
267 268 269 270 |
if (!strncmp(cmd, "print", 5)) return EEPROM_PRINT; if (!strncmp(cmd, "update", 6)) return EEPROM_UPDATE; |
3dc9be820 eeprom: merge cmd... |
271 |
#endif |
aa9e60441 cmd: eeprom: add ... |
272 273 274 |
return EEPROM_ACTION_INVALID; } |
aa9e60441 cmd: eeprom: add ... |
275 |
static int eeprom_execute_command(enum eeprom_action action, int i2c_bus, |
e7c2729bb eeprom: use eepro... |
276 277 |
ulong i2c_addr, int layout_ver, char *key, char *value, ulong addr, ulong off, ulong cnt) |
aa9e60441 cmd: eeprom: add ... |
278 |
{ |
e7c2729bb eeprom: use eepro... |
279 280 281 282 283 |
int rcode = 0; const char *const fmt = " EEPROM @0x%lX %s: addr %08lx off %04lx count %ld ... "; #ifdef CONFIG_CMD_EEPROM_LAYOUT |
aa9e60441 cmd: eeprom: add ... |
284 |
struct eeprom_layout layout; |
e7c2729bb eeprom: use eepro... |
285 |
#endif |
aa9e60441 cmd: eeprom: add ... |
286 287 288 289 290 |
if (action == EEPROM_ACTION_INVALID) return CMD_RET_USAGE; eeprom_init(i2c_bus); |
e7c2729bb eeprom: use eepro... |
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
if (action == EEPROM_READ) { printf(fmt, i2c_addr, "read", addr, off, cnt); rcode = eeprom_read(i2c_addr, off, (uchar *)addr, cnt); puts("done "); return rcode; } else if (action == EEPROM_WRITE) { printf(fmt, i2c_addr, "write", addr, off, cnt); rcode = eeprom_write(i2c_addr, off, (uchar *)addr, cnt); puts("done "); return rcode; } #ifdef CONFIG_CMD_EEPROM_LAYOUT |
aa9e60441 cmd: eeprom: add ... |
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
rcode = eeprom_read(i2c_addr, 0, eeprom_buf, CONFIG_SYS_EEPROM_SIZE); if (rcode < 0) return rcode; eeprom_layout_setup(&layout, eeprom_buf, CONFIG_SYS_EEPROM_SIZE, layout_ver); if (action == EEPROM_PRINT) { layout.print(&layout); return 0; } layout.update(&layout, key, value); rcode = eeprom_write(i2c_addr, 0, layout.data, CONFIG_SYS_EEPROM_SIZE); |
e7c2729bb eeprom: use eepro... |
325 |
#endif |
aa9e60441 cmd: eeprom: add ... |
326 327 328 329 330 |
return rcode; } #define NEXT_PARAM(argc, index) { (argc)--; (index)++; } |
3dc9be820 eeprom: merge cmd... |
331 |
int do_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
aa9e60441 cmd: eeprom: add ... |
332 333 334 |
{ int layout_ver = LAYOUT_VERSION_AUTODETECT; enum eeprom_action action = EEPROM_ACTION_INVALID; |
3dc9be820 eeprom: merge cmd... |
335 336 337 |
int i2c_bus = -1, index = 0; ulong i2c_addr = -1, addr = 0, cnt = 0, off = 0; int ret; |
aa9e60441 cmd: eeprom: add ... |
338 339 340 341 342 343 344 345 346 347 |
char *field_name = ""; char *field_value = ""; if (argc <= 1) return CMD_RET_USAGE; NEXT_PARAM(argc, index); /* Skip program name */ action = parse_action(argv[index]); NEXT_PARAM(argc, index); |
3dc9be820 eeprom: merge cmd... |
348 |
if (action == EEPROM_ACTION_INVALID) |
aa9e60441 cmd: eeprom: add ... |
349 |
return CMD_RET_USAGE; |
3dc9be820 eeprom: merge cmd... |
350 351 352 353 354 355 356 |
#ifdef CONFIG_CMD_EEPROM_LAYOUT if (action == EEPROM_PRINT || action == EEPROM_UPDATE) { if (!strcmp(argv[index], "-l")) { NEXT_PARAM(argc, index); layout_ver = eeprom_parse_layout_version(argv[index]); NEXT_PARAM(argc, index); } |
aa9e60441 cmd: eeprom: add ... |
357 |
} |
3dc9be820 eeprom: merge cmd... |
358 |
#endif |
aa9e60441 cmd: eeprom: add ... |
359 |
|
3dc9be820 eeprom: merge cmd... |
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
switch (action) { case EEPROM_READ: case EEPROM_WRITE: ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc, argv + index, 3); break; case EEPROM_PRINT: ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc, argv + index, 0); break; case EEPROM_UPDATE: ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc, argv + index, 2); break; default: /* Get compiler to stop whining */ |
aa9e60441 cmd: eeprom: add ... |
376 |
return CMD_RET_USAGE; |
3dc9be820 eeprom: merge cmd... |
377 |
} |
aa9e60441 cmd: eeprom: add ... |
378 |
|
3dc9be820 eeprom: merge cmd... |
379 380 |
if (ret == CMD_RET_USAGE) return ret; |
aa9e60441 cmd: eeprom: add ... |
381 |
|
3dc9be820 eeprom: merge cmd... |
382 |
while (ret--) |
aa9e60441 cmd: eeprom: add ... |
383 |
NEXT_PARAM(argc, index); |
aa9e60441 cmd: eeprom: add ... |
384 |
|
3dc9be820 eeprom: merge cmd... |
385 386 387 388 |
if (action == EEPROM_READ || action == EEPROM_WRITE) { addr = parse_numeric_param(argv[index]); NEXT_PARAM(argc, index); off = parse_numeric_param(argv[index]); |
aa9e60441 cmd: eeprom: add ... |
389 |
NEXT_PARAM(argc, index); |
3dc9be820 eeprom: merge cmd... |
390 |
cnt = parse_numeric_param(argv[index]); |
aa9e60441 cmd: eeprom: add ... |
391 |
} |
aa9e60441 cmd: eeprom: add ... |
392 |
#ifdef CONFIG_CMD_EEPROM_LAYOUT |
3dc9be820 eeprom: merge cmd... |
393 394 395 396 397 |
if (action == EEPROM_UPDATE) { field_name = argv[index]; NEXT_PARAM(argc, index); field_value = argv[index]; NEXT_PARAM(argc, index); |
aa9e60441 cmd: eeprom: add ... |
398 399 |
} #endif |
3dc9be820 eeprom: merge cmd... |
400 401 |
return eeprom_execute_command(action, i2c_bus, i2c_addr, layout_ver, field_name, field_value, addr, off, cnt); |
4f296d09e eeprom: Shuffle c... |
402 |
} |
8bde7f776 * Code cleanup: |
403 |
|
0d4983930 Patch by Kenneth ... |
404 |
U_BOOT_CMD( |
aa9e60441 cmd: eeprom: add ... |
405 |
eeprom, 8, 1, do_eeprom, |
2fb2604d5 Command usage cle... |
406 |
"EEPROM sub-system", |
d4fec4e98 eeprom: Add suppo... |
407 408 409 410 |
"read <bus> <devaddr> addr off cnt " "eeprom write <bus> <devaddr> addr off cnt " |
a89c33db9 General help mess... |
411 |
" - read/write `cnt' bytes from `devaddr` EEPROM at offset `off'" |
aa9e60441 cmd: eeprom: add ... |
412 413 414 |
#ifdef CONFIG_CMD_EEPROM_LAYOUT " " |
3dc9be820 eeprom: merge cmd... |
415 416 |
"eeprom print [-l <layout_version>] <bus> <devaddr> " |
aa9e60441 cmd: eeprom: add ... |
417 418 |
" - Print layout fields and their data in human readable format " |
3dc9be820 eeprom: merge cmd... |
419 420 |
"eeprom update [-l <layout_version>] <bus> <devaddr> field_name field_value " |
aa9e60441 cmd: eeprom: add ... |
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 |
" - Update a specific eeprom field with new data. " " The new data must be written in the same human readable format as shown by the print command. " " " "LAYOUT VERSIONS " "The -l option can be used to force the command to interpret the EEPROM data using the chosen layout. " "If the -l option is omitted, the command will auto detect the layout based on the data in the EEPROM. " "The values which can be provided with the -l option are: " CONFIG_EEPROM_LAYOUT_HELP_STRING" " #endif |
0e350f81e common: commands:... |
438 |
) |