Blame view
cmd/eeprom.c
11 KB
83d290c56 SPDX: Convert all... |
1 |
// SPDX-License-Identifier: GPL-2.0+ |
3863585bb Initial revision |
2 3 4 |
/* * (C) Copyright 2000, 2001 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. |
3863585bb Initial revision |
5 |
*/ |
d4f5c7289 FRAM memory acces... |
6 7 8 9 |
/* * 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 |
10 |
* write delay. Also, there is no limit imposed on the number of bytes that can |
d4f5c7289 FRAM memory acces... |
11 |
* be transferred with a single read or write. |
6617aae9b Add new board spe... |
12 |
* |
d4f5c7289 FRAM memory acces... |
13 14 |
* Use the following configuration options to ensure no unneeded performance * degradation (typical for EEPROM) is incured for FRAM memory: |
6617aae9b Add new board spe... |
15 |
* |
6d0f6bcf3 rename CFG_ macro... |
16 17 |
* #define CONFIG_SYS_I2C_FRAM * #undef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS |
d4f5c7289 FRAM memory acces... |
18 19 |
* */ |
3863585bb Initial revision |
20 21 22 23 |
#include <common.h> #include <config.h> #include <command.h> #include <i2c.h> |
e7c2729bb eeprom: use eepro... |
24 |
#include <eeprom_layout.h> |
3863585bb Initial revision |
25 |
|
4f296d09e eeprom: Shuffle c... |
26 27 |
#ifndef CONFIG_SYS_I2C_SPEED #define CONFIG_SYS_I2C_SPEED 50000 |
98f4a3dfc Add SM501 support... |
28 |
#endif |
3863585bb Initial revision |
29 |
|
d738746cc eeprom: Pull out ... |
30 31 32 |
#ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS #define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 0 #endif |
6717e3c84 eeprom: Pull out ... |
33 34 35 |
#ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS #define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 8 #endif |
a6e7b7744 i2c/eeprom: Alway... |
36 37 38 |
#ifndef I2C_RXTX_LEN #define I2C_RXTX_LEN 128 #endif |
6717e3c84 eeprom: Pull out ... |
39 40 |
#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... |
41 |
/* |
6d0f6bcf3 rename CFG_ macro... |
42 |
* for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is |
3863585bb Initial revision |
43 44 |
* 0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM. * |
6d0f6bcf3 rename CFG_ macro... |
45 |
* for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is |
3863585bb Initial revision |
46 47 |
* 0x00000nxx for EEPROM address selectors and page number at n. */ |
548738b4d cmd_eeprom: I2C u... |
48 |
#if !defined(CONFIG_SPI) || defined(CONFIG_ENV_EEPROM_IS_ON_I2C) |
4f296d09e eeprom: Shuffle c... |
49 |
#if !defined(CONFIG_SYS_I2C_EEPROM_ADDR_LEN) || \ |
d4e69e617 eeprom: Clean up ... |
50 51 |
(CONFIG_SYS_I2C_EEPROM_ADDR_LEN < 1) || \ (CONFIG_SYS_I2C_EEPROM_ADDR_LEN > 2) |
6d0f6bcf3 rename CFG_ macro... |
52 |
#error CONFIG_SYS_I2C_EEPROM_ADDR_LEN must be 1 or 2 |
3863585bb Initial revision |
53 54 |
#endif #endif |
52cd47c9a eeprom: Make eepr... |
55 56 57 58 |
__weak int eeprom_write_enable(unsigned dev_addr, int state) { return 0; } |
4f296d09e eeprom: Shuffle c... |
59 |
|
354e3ed75 eeprom: Add bus a... |
60 |
void eeprom_init(int bus) |
4f296d09e eeprom: Shuffle c... |
61 |
{ |
4f296d09e eeprom: Shuffle c... |
62 |
/* I2C EEPROM */ |
354e3ed75 eeprom: Add bus a... |
63 64 65 |
#if defined(CONFIG_SYS_I2C) if (bus >= 0) i2c_set_bus_num(bus); |
4f296d09e eeprom: Shuffle c... |
66 67 68 |
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); #endif } |
02c321cf8 eeprom: Pull out ... |
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
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 ... |
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
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 ... |
112 113 114 115 |
static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen, uchar *buffer, unsigned len, bool read) { int ret = 0; |
0c07a9b40 eeprom: Add devic... |
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
#if defined(CONFIG_DM_I2C) && defined(CONFIG_SYS_I2C_EEPROM_BUS) struct udevice *dev; ret = i2c_get_chip_for_busnum(CONFIG_SYS_I2C_EEPROM_BUS, addr[0], alen - 1, &dev); if (ret) { printf("%s: Cannot find udev for a bus %d ", __func__, CONFIG_SYS_I2C_EEPROM_BUS); return CMD_RET_FAILURE; } if (read) ret = dm_i2c_read(dev, offset, buffer, len); else ret = dm_i2c_write(dev, offset, buffer, len); #else /* Non DM I2C support - will be removed */ |
9132088b0 eeprom: Pull out ... |
134 135 136 137 138 139 140 141 |
#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); |
0c07a9b40 eeprom: Add devic... |
142 143 144 |
#endif /* CONFIG_DM_I2C && CONFIG_SYS_I2C_EEPROM_BUS */ if (ret) ret = CMD_RET_FAILURE; |
9132088b0 eeprom: Pull out ... |
145 146 |
return ret; } |
1a37889b0 eeprom: Pull out ... |
147 148 |
static int eeprom_rw(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt, bool read) |
3863585bb Initial revision |
149 150 |
{ unsigned end = offset + cnt; |
1a37889b0 eeprom: Pull out ... |
151 |
unsigned alen, len; |
3863585bb Initial revision |
152 |
int rcode = 0; |
02c321cf8 eeprom: Pull out ... |
153 |
uchar addr[3]; |
3863585bb Initial revision |
154 |
|
3863585bb Initial revision |
155 |
while (offset < end) { |
02c321cf8 eeprom: Pull out ... |
156 |
alen = eeprom_addr(dev_addr, offset, addr); |
3863585bb Initial revision |
157 |
|
39b6f98bd eeprom: Pull out ... |
158 |
len = eeprom_len(offset, end); |
d4f5c7289 FRAM memory acces... |
159 |
|
1a37889b0 eeprom: Pull out ... |
160 |
rcode = eeprom_rw_block(offset, addr, alen, buffer, len, read); |
9132088b0 eeprom: Pull out ... |
161 |
|
3863585bb Initial revision |
162 163 |
buffer += len; offset += len; |
1a37889b0 eeprom: Pull out ... |
164 165 166 |
if (!read) udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000); |
3863585bb Initial revision |
167 |
} |
d4f5c7289 FRAM memory acces... |
168 |
|
3863585bb Initial revision |
169 170 |
return rcode; } |
1a37889b0 eeprom: Pull out ... |
171 |
int eeprom_read(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt) |
3863585bb Initial revision |
172 |
{ |
1a37889b0 eeprom: Pull out ... |
173 174 175 176 177 178 179 |
/* * 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 ... |
180 181 |
int eeprom_write(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt) |
1a37889b0 eeprom: Pull out ... |
182 183 |
{ int ret; |
3863585bb Initial revision |
184 |
|
52cd47c9a eeprom: Make eepr... |
185 |
eeprom_write_enable(dev_addr, 1); |
4f296d09e eeprom: Shuffle c... |
186 187 |
/* * Write data until done or would cross a write page boundary. |
3863585bb Initial revision |
188 189 190 |
* We must write the address again when changing pages * because the address counter only increments within a page. */ |
52bc7c7e2 eeprom: fix eepro... |
191 |
ret = eeprom_rw(dev_addr, offset, buffer, cnt, 0); |
52cd47c9a eeprom: Make eepr... |
192 193 |
eeprom_write_enable(dev_addr, 0); |
1a37889b0 eeprom: Pull out ... |
194 |
return ret; |
3863585bb Initial revision |
195 |
} |
c40f03723 eeprom: refactor ... |
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 243 244 |
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 ... |
245 |
#ifdef CONFIG_CMD_EEPROM_LAYOUT |
aa9e60441 cmd: eeprom: add ... |
246 247 248 249 250 251 252 |
__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... |
253 |
#endif |
aa9e60441 cmd: eeprom: add ... |
254 |
enum eeprom_action { |
e7c2729bb eeprom: use eepro... |
255 256 |
EEPROM_READ, EEPROM_WRITE, |
aa9e60441 cmd: eeprom: add ... |
257 258 259 260 261 262 263 |
EEPROM_PRINT, EEPROM_UPDATE, EEPROM_ACTION_INVALID, }; static enum eeprom_action parse_action(char *cmd) { |
3dc9be820 eeprom: merge cmd... |
264 265 266 267 268 |
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 ... |
269 270 271 272 |
if (!strncmp(cmd, "print", 5)) return EEPROM_PRINT; if (!strncmp(cmd, "update", 6)) return EEPROM_UPDATE; |
3dc9be820 eeprom: merge cmd... |
273 |
#endif |
aa9e60441 cmd: eeprom: add ... |
274 275 276 |
return EEPROM_ACTION_INVALID; } |
aa9e60441 cmd: eeprom: add ... |
277 |
static int eeprom_execute_command(enum eeprom_action action, int i2c_bus, |
e7c2729bb eeprom: use eepro... |
278 279 |
ulong i2c_addr, int layout_ver, char *key, char *value, ulong addr, ulong off, ulong cnt) |
aa9e60441 cmd: eeprom: add ... |
280 |
{ |
e7c2729bb eeprom: use eepro... |
281 282 283 284 285 |
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 ... |
286 |
struct eeprom_layout layout; |
e7c2729bb eeprom: use eepro... |
287 |
#endif |
aa9e60441 cmd: eeprom: add ... |
288 289 290 291 292 |
if (action == EEPROM_ACTION_INVALID) return CMD_RET_USAGE; eeprom_init(i2c_bus); |
e7c2729bb eeprom: use eepro... |
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
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 ... |
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
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... |
327 |
#endif |
aa9e60441 cmd: eeprom: add ... |
328 329 330 331 332 |
return rcode; } #define NEXT_PARAM(argc, index) { (argc)--; (index)++; } |
3dc9be820 eeprom: merge cmd... |
333 |
int do_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
aa9e60441 cmd: eeprom: add ... |
334 335 336 |
{ int layout_ver = LAYOUT_VERSION_AUTODETECT; enum eeprom_action action = EEPROM_ACTION_INVALID; |
3dc9be820 eeprom: merge cmd... |
337 338 339 |
int i2c_bus = -1, index = 0; ulong i2c_addr = -1, addr = 0, cnt = 0, off = 0; int ret; |
aa9e60441 cmd: eeprom: add ... |
340 341 342 343 344 345 346 347 348 349 |
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... |
350 |
if (action == EEPROM_ACTION_INVALID) |
aa9e60441 cmd: eeprom: add ... |
351 |
return CMD_RET_USAGE; |
3dc9be820 eeprom: merge cmd... |
352 353 354 355 356 357 358 |
#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 ... |
359 |
} |
3dc9be820 eeprom: merge cmd... |
360 |
#endif |
aa9e60441 cmd: eeprom: add ... |
361 |
|
3dc9be820 eeprom: merge cmd... |
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
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 ... |
378 |
return CMD_RET_USAGE; |
3dc9be820 eeprom: merge cmd... |
379 |
} |
aa9e60441 cmd: eeprom: add ... |
380 |
|
3dc9be820 eeprom: merge cmd... |
381 382 |
if (ret == CMD_RET_USAGE) return ret; |
aa9e60441 cmd: eeprom: add ... |
383 |
|
3dc9be820 eeprom: merge cmd... |
384 |
while (ret--) |
aa9e60441 cmd: eeprom: add ... |
385 |
NEXT_PARAM(argc, index); |
aa9e60441 cmd: eeprom: add ... |
386 |
|
3dc9be820 eeprom: merge cmd... |
387 388 389 390 |
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 ... |
391 |
NEXT_PARAM(argc, index); |
3dc9be820 eeprom: merge cmd... |
392 |
cnt = parse_numeric_param(argv[index]); |
aa9e60441 cmd: eeprom: add ... |
393 |
} |
aa9e60441 cmd: eeprom: add ... |
394 |
#ifdef CONFIG_CMD_EEPROM_LAYOUT |
3dc9be820 eeprom: merge cmd... |
395 396 397 398 399 |
if (action == EEPROM_UPDATE) { field_name = argv[index]; NEXT_PARAM(argc, index); field_value = argv[index]; NEXT_PARAM(argc, index); |
aa9e60441 cmd: eeprom: add ... |
400 401 |
} #endif |
3dc9be820 eeprom: merge cmd... |
402 403 |
return eeprom_execute_command(action, i2c_bus, i2c_addr, layout_ver, field_name, field_value, addr, off, cnt); |
4f296d09e eeprom: Shuffle c... |
404 |
} |
8bde7f776 * Code cleanup: |
405 |
|
0d4983930 Patch by Kenneth ... |
406 |
U_BOOT_CMD( |
aa9e60441 cmd: eeprom: add ... |
407 |
eeprom, 8, 1, do_eeprom, |
2fb2604d5 Command usage cle... |
408 |
"EEPROM sub-system", |
d4fec4e98 eeprom: Add suppo... |
409 410 411 412 |
"read <bus> <devaddr> addr off cnt " "eeprom write <bus> <devaddr> addr off cnt " |
a89c33db9 General help mess... |
413 |
" - read/write `cnt' bytes from `devaddr` EEPROM at offset `off'" |
aa9e60441 cmd: eeprom: add ... |
414 415 416 |
#ifdef CONFIG_CMD_EEPROM_LAYOUT " " |
3dc9be820 eeprom: merge cmd... |
417 418 |
"eeprom print [-l <layout_version>] <bus> <devaddr> " |
aa9e60441 cmd: eeprom: add ... |
419 420 |
" - Print layout fields and their data in human readable format " |
3dc9be820 eeprom: merge cmd... |
421 422 |
"eeprom update [-l <layout_version>] <bus> <devaddr> field_name field_value " |
aa9e60441 cmd: eeprom: add ... |
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
" - 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:... |
440 |
) |