blob: d7a57ccb5c5febe400eb6133b477ccab94273e48 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*
2 * Command for accessing SPI flash.
3 *
4 * Copyright (C) 2008 Atmel Corporation
5 *
6 * SPDX-License-Identifier: GPL-2.0+
7 */
8
9#include <common.h>
10#include <malloc.h>
11#include <spi.h>
12#include <spi_flash_chip.h>
13//#include <spi_nand.h>
14#include <asm/io.h>
15#include <linux/mtd/mtd.h>
16
17#ifndef CONFIG_SF_DEFAULT_SPEED
18# define CONFIG_SF_DEFAULT_SPEED 1000000
19#endif
20#ifndef CONFIG_SF_DEFAULT_MODE
21# define CONFIG_SF_DEFAULT_MODE SPI_MODE_3
22#endif
23#ifndef CONFIG_SF_DEFAULT_CS
24# define CONFIG_SF_DEFAULT_CS 0
25#endif
26#ifndef CONFIG_SF_DEFAULT_BUS
27# define CONFIG_SF_DEFAULT_BUS 0
28#endif
29
30static int bit_count(u_char n)
31{
32 u_char c = 0;
33
34 for (c = 0; n; ++c)
35 n &= (n - 1);
36 return c ;
37}
38
39static int raw_access(struct spi_flash_chip *chip, const char *addr,
40 loff_t off, ulong count, int read)
41{
42 struct mtd_info *mtd = chip->mtd;
43 int ret = 0;
44
45 while (count--) {
46 /* Raw access */
47 struct mtd_oob_ops ops = {
48 .datbuf = (u8 *)addr,
49 .oobbuf = ((u8 *)addr) + mtd->writesize,
50 .len = mtd->writesize,
51 .ooblen = mtd->oobsize,
52 .mode = MTD_OPS_RAW,
53 };
54
55 if (read)
56 ret = mtd_read_oob(mtd, off, &ops);
57 else
58 ret = mtd_write_oob(mtd, off, &ops);
59
60 if (ret) {
61 printf("%s: error at offset %llx, ret %d\n",
62 __func__, (long long)off, ret);
63 break;
64 }
65
66 addr += mtd->writesize + mtd->oobsize;
67 off += mtd->writesize;
68 }
69
70 return ret;
71}
72
73/*
74 * This function computes the length argument for the erase command.
75 * The length on which the command is to operate can be given in two forms:
76 * 1. <cmd> offset len - operate on <'offset', 'len')
77 * 2. <cmd> offset +len - operate on <'offset', 'round_up(len)')
78 * If the second form is used and the length doesn't fall on the
79 * sector boundary, than it will be adjusted to the next sector boundary.
80 * If it isn't in the flash, the function will fail (return -1).
81 * Input:
82 * arg: length specification (i.e. both command arguments)
83 * Output:
84 * len: computed length for operation
85 * Return:
86 * 1: success
87 * -1: failure (bad format, bad address).
88 */
89static int sf_parse_len_arg(struct spi_flash_chip *chip, char *arg, ulong *len)
90{
91 struct mtd_info *mtd = chip->mtd;
92 char *ep;
93 char round_up_len; /* indicates if the "+length" form used */
94 ulong len_arg;
95
96 round_up_len = 0;
97 if (*arg == '+') {
98 round_up_len = 1;
99 ++arg;
100 }
101
102 len_arg = simple_strtoul(arg, &ep, 16);
103 if (ep == arg || *ep != '\0')
104 return -1;
105
106 if (round_up_len && mtd->erasesize > 0)
107 *len = ROUND(len_arg, mtd->erasesize);
108 else
109 *len = len_arg;
110
111 return 1;
112}
113
114static int spi_flash_dump(struct spi_flash_chip *chip, ulong off,
115 int only_oob, int repeat)
116{
117 struct mtd_info *mtd = chip->mtd;
118 struct mtd_oob_ops ops;
119 int i;
120 u_char *datbuf, *oobbuf, *p;
121 static loff_t last;
122 int ret = 0;
123 size_t retlen;
124
125 if (repeat)
126 off = last + mtd->writesize;
127
128 last = off;
129
130 datbuf = memalign(ARCH_DMA_MINALIGN, mtd->writesize);
131 if (!datbuf) {
132 puts("No memory for page buffer\n");
133 return 1;
134 }
135
136 if (mtd->oobsize) {
137 oobbuf = memalign(ARCH_DMA_MINALIGN, mtd->oobsize);
138 if (!oobbuf) {
139 puts("No memory for page buffer\n");
140 ret = 1;
141 goto free_dat;
142 }
143 }
144
145 off &= ~(mtd->writesize - 1);
146 loff_t addr = (loff_t) off;
147 if (mtd->oobsize) {
148 memset(&ops, 0, sizeof(ops));
149 ops.datbuf = datbuf;
150 ops.oobbuf = oobbuf;
151 ops.len = mtd->writesize;
152 ops.ooblen = mtd->oobsize;
153 ops.mode = MTD_OPS_RAW;
154 i = mtd_read_oob(mtd, addr, &ops);
155 if (i < 0 && i != -EUCLEAN) {
156 printf("Error (%d) reading page %08lx\n", i, off);
157 ret = 1;
158 goto free_all;
159 }
160 } else {
161 ret = mtd_read(mtd, addr, mtd->writesize, &retlen, datbuf);
162 if ((ret < 0 && ret != -EUCLEAN) || retlen != mtd->writesize)
163 return -1;
164 }
165 printf("Page %08lx dump:\n", off);
166
167 if (!only_oob) {
168 i = mtd->writesize >> 4;
169 p = datbuf;
170
171 while (i--) {
172 printf("\t%02x %02x %02x %02x %02x %02x %02x %02x"
173 " %02x %02x %02x %02x %02x %02x %02x %02x\n",
174 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
175 p[8], p[9], p[10], p[11], p[12], p[13], p[14],
176 p[15]);
177 p += 16;
178 }
179 }
180
181 if (mtd->oobsize) {
182 puts("OOB:\n");
183 i = mtd->oobsize >> 3;
184 p = oobbuf;
185 while (i--) {
186 printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
187 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
188 p += 8;
189 }
190 }
191
192free_all:
193 if (mtd->oobsize)
194 free(oobbuf);
195free_dat:
196 free(datbuf);
197
198 return ret;
199}
200
201static int spi_flash_mark_biterr(struct spi_flash_chip *chip, ulong off, int bad_ct)
202{
203 struct mtd_info *mtd = chip->mtd;
204 int i, j, k, m, bit_ct;
205 u_char *datbuf, *oobbuf, *p;
206 int ret = 0;
207
208 datbuf = memalign(ARCH_DMA_MINALIGN, mtd->writesize);
209 if (!datbuf) {
210 puts("No memory for page buffer\n");
211 return 1;
212 }
213
214 oobbuf = memalign(ARCH_DMA_MINALIGN, mtd->oobsize);
215 if (!oobbuf) {
216 puts("No memory for page buffer\n");
217 ret = 1;
218 goto free_dat;
219 }
220 off &= ~(mtd->writesize - 1);
221 loff_t addr = (loff_t) off;
222 struct mtd_oob_ops ops;
223 memset(&ops, 0, sizeof(ops));
224 ops.datbuf = datbuf;
225 ops.oobbuf = oobbuf;
226 ops.len = mtd->writesize;
227 ops.ooblen = mtd->oobsize;
228 ops.mode = MTD_OPS_RAW;
229 ret = mtd_read_oob(mtd, addr, &ops);
230 if (ret < 0 && ret != -EUCLEAN) {
231 printf("Error (%d) reading page %08lx\n", i, off);
232 ret = 1;
233 goto free_all;
234 }
235
236 i = 0;
237 bit_ct = 0;
238 while (1) {
239 j = bit_count(datbuf[i]);
240 if (bit_ct + j <= bad_ct) {
241 datbuf[i] = 0;
242 } else {
243 j = bad_ct -bit_ct;
244 m = k = 0;
245 while (1) {
246 if (datbuf[i] & (1 << k)) {
247 datbuf[i] &= ~(1 << k);
248 if (++m >= j)
249 break;
250 }
251 k++;
252 }
253 }
254
255 bit_ct += j;
256 if (bit_ct >= bad_ct)
257 break;
258
259 if (++i >= mtd->writesize) {
260 printf("No enough bit set in this page\n");
261 ret = 1;
262 goto free_all;
263 }
264 }
265
266 ret = mtd_write_oob(mtd, addr, &ops);
267 if (ret) {
268 printf("%s: write error at offset %llx, ret %d\n",
269 __func__, (long long)addr, ret);
270 ret = 1;
271 }
272
273free_all:
274 free(oobbuf);
275free_dat:
276 free(datbuf);
277
278 return ret;
279}
280
281struct spi_flash_chip *spi_flash_chip_probe(int dev)
282{
283 struct spi_flash_chip *chip;
284 int ret;
285
286 ret = spi_flash_select_dev(dev);
287 if (ret)
288 chip = NULL;
289 else
290 chip = cur_sf_chip;
291 return chip;
292}
293
294void spi_flash_chip_free(struct spi_flash_chip *chip)
295{
296}
297
298
299int spi_flash_cmd_write_yaffs(struct spi_flash_chip *chip, u32 offset,
300 size_t len, const void *buf)
301{
302 struct mtd_info *mtd = chip->mtd;
303 size_t retlen;
304 size_t leftlen = len;
305 size_t writelen;
306 size_t block_len, block_off;
307 u_char *p_buffer = buf;
308 loff_t block_start;
309 u32 writeoffset;
310 int ret = 0;
311 bool end;
312
313 while (leftlen > 0) {
314 if (offset >= chip->size)
315 return -1;
316
317 writeoffset = offset;
318 writelen = 0;
319 end = false;
320 if (mtd->type == MTD_NANDFLASH) {
321 while ((writelen < leftlen) && !end) {
322 block_start = offset & ~(loff_t)(mtd->erasesize - 1);
323 block_off = offset & (mtd->erasesize - 1);
324 block_len = mtd->erasesize - block_off;
325
326 if (!mtd_block_isbad(mtd, block_start))
327 writelen += block_len;
328 else
329 end = true;
330 offset += block_len;
331 }
332 } else
333 writelen = leftlen;
334
335 if (writelen) {
336 int page, pages;
337 size_t pagesize = mtd->writesize;
338 size_t pagesize_oob = pagesize + mtd->oobsize;
339 struct mtd_oob_ops ops;
340
341 writelen = min(writelen, leftlen);
342
343 ops.len = pagesize;
344 ops.ooblen = mtd->oobsize;
345 ops.mode = MTD_OPS_AUTO_OOB;
346 ops.ooboffs = 0;
347
348 pages = writelen / pagesize_oob;
349 for (page = 0; page < pages; page++) {
350 ops.datbuf = p_buffer;
351 ops.oobbuf = ops.datbuf + pagesize;
352
353 ret = mtd_write_oob(mtd, writeoffset, &ops);
354 if (ret != 0)
355 break;
356
357 writeoffset += pagesize;
358 p_buffer += pagesize_oob;
359 }
360
361 leftlen -= writelen;
362 }
363 }
364
365 return ret;
366}
367
368
369int spi_flash_cmd_write_ops(struct spi_flash_chip *chip, u32 offset,
370 size_t len, const void *buf)
371{
372 struct mtd_info *mtd = chip->mtd;
373 size_t retlen;
374 size_t leftlen = len;
375 size_t writelen;
376 size_t block_len, block_off;
377 loff_t block_start;
378 u32 writeoffset;
379 int ret = 0;
380 bool end;
381
382 while (leftlen > 0) {
383 if (offset >= chip->size)
384 return -1;
385
386 writeoffset = offset;
387 writelen = 0;
388 end = false;
389 if (mtd->type == MTD_NANDFLASH) {
390 while ((writelen < leftlen) && !end) {
391 block_start = offset & ~(loff_t)(mtd->erasesize - 1);
392 block_off = offset & (mtd->erasesize - 1);
393 block_len = mtd->erasesize - block_off;
394
395 if (!mtd_block_isbad(mtd, block_start))
396 writelen += block_len;
397 else
398 end = true;
399 offset += block_len;
400 }
401 } else
402 writelen = leftlen;
403
404 if (writelen) {
405 writelen = min(writelen, leftlen);
406 ret = mtd_write(mtd, writeoffset, writelen, &retlen, buf + (len - leftlen));
407 if (ret || writelen != retlen)
408 return -1;
409 leftlen -= writelen;
410 }
411 }
412
413 return ret;
414}
415
416int spi_flash_cmd_erase_ops(struct spi_flash_chip *chip, u32 offset, size_t len, bool spread)
417{
418 struct mtd_info *mtd = chip->mtd;
419 struct erase_info instr = {
420 .callback = NULL,
421 };
422 size_t leftlen;
423 size_t eraselen;
424 u32 eraseoffset;
425 u64 endaddr;
426 int ret = 0;
427 bool end;
428
429 if (offset & (mtd->erasesize - 1)) {
430 printf("%s: Unaligned address\n", __func__);
431 return -EINVAL;
432 }
433
434 if (len & (mtd->erasesize - 1)) {
435 printf("%s: warn: len=0x%x not block aligned\n", __func__, len);
436 len = roundup(len, mtd->erasesize);
437 }
438
439 leftlen = len;
440 endaddr = offset + len;
441 if (endaddr > chip->size) {
442 printf("%s: Erase past end of device\n", __func__);
443 return -EINVAL;
444 }
445
446 while (leftlen > 0) {
447 if (offset >= chip->size)
448 return -1;
449
450 eraseoffset = offset;
451 eraselen = 0;
452 end = false;
453 if (mtd->type == MTD_NANDFLASH) {
454 while ((eraselen < leftlen) && !end) {
455 if (!mtd_block_isbad(mtd, offset))
456 eraselen += mtd->erasesize;
457 else
458 end = true;
459 offset += mtd->erasesize;
460 }
461 } else {
462 eraselen = len;
463 offset += len;
464 }
465 if (eraselen) {
466 instr.addr = eraseoffset;
467 instr.len = eraselen;
468 instr.mtd = mtd;
469 ret = mtd_erase(mtd, &instr);
470 if (ret)
471 return -1;
472 }
473 if (spread)
474 leftlen -= eraselen;
475 else
476 leftlen = endaddr - offset;
477 }
478
479 return ret;
480}
481
482int spi_flash_cmd_read_ops(struct spi_flash_chip *chip, u32 offset,
483 size_t len, void *data)
484{
485 struct mtd_info *mtd = chip->mtd;
486 size_t retlen;
487 size_t leftlen = len;
488 size_t readlen;
489 size_t block_len, block_off;
490 loff_t block_start;
491 u32 readoffset;
492 int ret = 0;
493 bool end;
494
495 while (leftlen > 0) {
496 if (offset >= chip->size)
497 return -1;
498
499 readoffset = offset;
500 readlen = 0;
501 end = false;
502 if (mtd->type == MTD_NANDFLASH) {
503 while ((readlen < leftlen) && !end) {
504 block_start = offset & ~(loff_t)(mtd->erasesize - 1);
505 block_off = offset & (mtd->erasesize - 1);
506 block_len = mtd->erasesize - block_off;
507
508 if (!mtd_block_isbad(mtd, block_start))
509 readlen += block_len;
510 else
511 end = true;
512 offset += block_len;
513 }
514 } else
515 readlen = leftlen;
516 if (readlen) {
517 readlen = min(readlen, leftlen);
518 ret = mtd_read(mtd, readoffset, readlen, &retlen, data + (len - leftlen));
519 if ((ret < 0 && ret != -EUCLEAN) || readlen != retlen)
520 return -1;
521
522 leftlen -= readlen;
523 }
524 }
525 return ret;
526}
527
528/**
529 * Update an area of SPI flash by erasing and writing any blocks which need
530 * to change. Existing blocks with the correct data are left unchanged.
531 *
532 * @param flash flash context pointer
533 * @param offset flash offset to write
534 * @param len number of bytes to write
535 * @param buf buffer to write from
536 * @return 0 if ok, 1 on error
537 */
538static int spi_flash_update(struct spi_flash_chip *chip, u32 offset,
539 size_t len, const char *buf)
540{
541 int ret = 0;
542
543 ret = spi_flash_cmd_erase_ops(chip, offset, len, true);
544 if (ret) {
545 printf("SPI-FLASH: %zu bytes @ %#x Erased: ERROR\n",
546 (size_t)len, (u32)offset);
547 return ret;
548 }
549 ret = spi_flash_cmd_write_ops(chip, offset, len, buf);
550 if (ret) {
551 printf("SPI-FLASH: %zu bytes @ %#x Written: ERROR\n",
552 (size_t)len, (u32)offset);
553 }
554 return ret;
555}
556
557static int do_spi_flash_get_info(struct spi_flash_chip *chip,
558 int argc, char * const argv[])
559{
560 struct mtd_info *mtd = chip->mtd;
561 unsigned long addr;
562 struct spi_flash_info *info;
563 char *endp;
564
565 if (argc < 2)
566 return -1;
567
568 addr = simple_strtoul(argv[1], &endp, 16);
569 if (*argv[1] == 0 || *endp != 0)
570 return -1;
571
572 info = (struct spi_flash_info *)addr;
573 info->totalsize = chip->size;
574 info->erasesize = mtd->erasesize;
575 info->pagesize = mtd->writesize;
576
577#if 0
578 printf("flash info: totalsize=0x%x erase_size=0x%x page_size=0x%x\n",
579 (unsigned)info->totalsize, (unsigned)info->erasesize,
580 (unsigned)info->pagesize);
581#endif
582 return 0;
583}
584
585static int do_spi_flash_read_write(struct spi_flash_chip *chip,
586 int argc, char * const argv[])
587{
588 struct mtd_info *mtd = chip->mtd;
589 unsigned long addr;
590 unsigned long offset;
591 unsigned long len;
592 int data_len;
593 void *buf;
594 char *endp;
595 char *cmd, *s;
596 int ret = 1;
597
598 if (argc < 4)
599 return -1;
600
601 cmd = argv[0];
602 addr = simple_strtoul(argv[1], &endp, 16);
603 if (*argv[1] == 0 || *endp != 0)
604 return -1;
605 offset = simple_strtoul(argv[2], &endp, 16);
606 if (*argv[2] == 0 || *endp != 0)
607 return -1;
608 len = simple_strtoul(argv[3], &endp, 16);
609 if (*argv[3] == 0 || *endp != 0)
610 return -1;
611
612 if (mtd->protect_enabled &&
613 ((offset <= mtd->protect_start &&
614 offset + len > mtd->protect_start) ||
615 (offset >= mtd->protect_start &&
616 offset < mtd->protect_end))) {
617 printf("error: protected ared start=0x%x end=0x%x\n",
618 mtd->protect_start, mtd->protect_end);
619 return -EACCES;
620 }
621
622 data_len = len;
623 if (strcmp(argv[0], "update") == 0) {
624 if (offset + len > chip->size) {
625 printf("ERROR: attempting %s past flash size (%#llx)\n",
626 argv[0], chip->size);
627 return 1;
628 }
629
630 buf = map_physmem(addr, len, MAP_WRBACK);
631 if (!buf) {
632 puts("Failed to map physical memory\n");
633 return 1;
634 }
635
636 ret = spi_flash_update(chip, offset, len, buf);
637 printf("SPI-FLASH: %zu bytes @ %#x Updated: %s\n",
638 (size_t)len, (u32)offset, ret ? "ERROR" : "OK");
639 } else if (strncmp(argv[0], "read", 4) == 0 ||
640 strncmp(argv[0], "write", 5) == 0) {
641 int read;
642 int raw = 0;
643 int yaffs = 0;
644
645 read = strncmp(argv[0], "read", 4) == 0;
646 s = strchr(cmd, '.');
647 if (s && !strcmp(s, ".raw")) {
648 raw = 1;
649
650 if (len * mtd->writesize + offset > chip->size) {
651 puts("ERROR: Offset exceeds device limit\n");
652 return 1;
653 }
654
655 data_len = len * (mtd->writesize + mtd->oobsize);
656 } else if (s && !strcmp(s, ".yaffs")) {
657 yaffs = 1;
658 } else {
659 if (offset + len > chip->size) {
660 printf("ERROR: attempting %s past flash size (%#llx)\n",
661 argv[0], chip->size);
662 return 1;
663 }
664 }
665
666 buf = map_physmem(addr, data_len, MAP_WRBACK);
667 if (!buf) {
668 puts("Failed to map physical memory\n");
669 return 1;
670 }
671
672 if (!s) {
673 if (read)
674 ret = spi_flash_cmd_read_ops(chip, offset,
675 len, buf);
676 else
677 ret = spi_flash_cmd_write_ops(chip, offset,
678 len, buf);
679 } else if (raw) {
680 ret = raw_access(chip, buf, offset, len, read);
681 } else if (yaffs) {
682 ret = spi_flash_cmd_write_yaffs(chip, offset, len, buf);
683 } else {
684 printf("Unknown spi_flash command suffix '%s'.\n", s);
685 ret = 1;
686 goto exit;
687 }
688
689 if (ret == -EUCLEAN)
690 ret = 0;
691
692 if ( len > 0x8000)
693 printf("SPI-FLASH: %zu %s @ %#x %s: %s\n", (size_t)len,
694 raw ? "pages" : "bytes", (u32)offset,
695 read ? "Read" : "Written",
696 (ret < 0 && ret != -EUCLEAN) ? "ERROR" : "OK");
697 }
698exit:
699 unmap_physmem(buf, data_len);
700 return ret == 0 ? 0 : 1;
701}
702
703static int do_spi_flash_erase(struct spi_flash_chip *chip,
704 int argc, char * const argv[], bool spread)
705{
706 struct mtd_info *mtd = chip->mtd;
707 unsigned long offset;
708 unsigned long len;
709 char *endp;
710 int ret;
711
712 if (argc < 3)
713 return -1;
714
715 offset = simple_strtoul(argv[1], &endp, 16);
716 if (*argv[1] == 0 || *endp != 0)
717 return -1;
718
719 ret = sf_parse_len_arg(chip, argv[2], &len);
720 if (ret != 1)
721 return -1;
722
723 if (mtd->protect_enabled &&
724 ((offset <= mtd->protect_start &&
725 offset + len > mtd->protect_start) ||
726 (offset >= mtd->protect_start &&
727 offset < mtd->protect_end))) {
728 printf("error: protected ared start=0x%x end=0x%x\n",
729 mtd->protect_start, mtd->protect_end);
730 return -EACCES;
731 }
732
733 /* Consistency checking */
734 if (offset + len > chip->size) {
735 printf("ERROR: attempting %s past flash size (%#llx)\n",
736 argv[0], chip->size);
737 return 1;
738 }
739
740 ret = spi_flash_cmd_erase_ops(chip, offset, len, spread);
741 printf("SPI-FLASH: %zu bytes @ %#x Erased: %s\n",
742 (size_t)len, (u32)offset, ret ? "ERROR" : "OK");
743
744 return ret == 0 ? 0 : 1;
745}
746
747static int do_spi_flash_show_bad(struct spi_flash_chip *chip)
748{
749 struct mtd_info *mtd = chip->mtd;
750 loff_t offset;
751
752 for (offset = 0; offset < chip->size; offset += mtd->erasesize) {
753 if(mtd_block_isbad(chip, offset))
754 printf("Bad block at 0x%#llx\n", offset);
755 }
756
757 return 0;
758}
759
760static int do_spi_flash_mark_bad(struct spi_flash_chip *chip,
761 int argc, char * const argv[])
762{
763 int ret;
764 loff_t offset;
765 char *endp;
766
767 if (argc < 2)
768 return -1;
769
770 offset = simple_strtoul(argv[1], &endp, 16);
771 if (*argv[1] == 0 || *endp != 0)
772 return -1;
773
774 ret = mtd_block_markbad(chip->mtd, offset);
775 if (!ret) {
776 printf("SPI-FLASH: 0x%#llx marked as bad block\n", offset);
777 }
778
779 return ret == 0 ? 0 : 1;
780}
781
782static int do_spi_flash_dump(struct spi_flash_chip *chip,
783 int argc, char * const argv[])
784{
785 int ret;
786 loff_t offset;
787 char *endp;
788
789 if (argc < 2)
790 return -1;
791
792 offset = simple_strtoul(argv[1], &endp, 16);
793 if (*argv[1] == 0 || *endp != 0)
794 return -1;
795
796 ret = spi_flash_dump(chip, offset, 0, 0);
797 return ret == 0 ? 0 : 1;
798}
799
800static int do_spi_flash_probe(int argc, char * const argv[])
801{
802 int dev = 0;
803 char *endp;
804
805 if (argc >= 2) {
806 dev = simple_strtoul(argv[1], &endp, 16);
807 if (*argv[1] == 0 || *endp != 0)
808 return -1;
809 }
810
811 return spi_flash_select_dev(dev);
812}
813
814static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc,
815 char * const argv[])
816{
817 struct spi_flash_chip *chip;
818 const char *cmd;
819 int ret;
820
821 /* need at least two arguments */
822 if (argc < 2)
823 goto usage;
824
825 cmd = argv[1];
826 --argc;
827 ++argv;
828
829 if (strcmp(cmd, "probe") == 0) {
830 ret = do_spi_flash_probe(argc, argv);
831 goto done;
832 }
833
834 /* The remaining commands require a selected device */
835 chip = cur_sf_chip;
836 if (!chip) {
837 puts("No SPI flash selected. Please run `spi_flash probe'\n");
838 return 1;
839 }
840
841 if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0 ||
842 strcmp(cmd, "update") == 0)
843 ret = do_spi_flash_read_write(chip, argc, argv);
844 else if (strcmp(cmd, "erase") == 0)
845 ret = do_spi_flash_erase(chip, argc, argv, false);
846 else if (strcmp(cmd, "erase.spread") == 0)
847 ret = do_spi_flash_erase(chip, argc, argv, true);
848 else if (strcmp(cmd, "info") == 0)
849 ret = do_spi_flash_get_info(chip, argc, argv);
850 else if (strcmp(cmd, "bad") == 0)
851 ret = do_spi_flash_show_bad(chip);
852 else if (strcmp(cmd, "markbad") == 0)
853 ret = do_spi_flash_mark_bad(chip, argc, argv);
854 else if (strcmp(cmd, "dump") == 0)
855 ret = do_spi_flash_dump(chip, argc, argv);
856 else if (strcmp(cmd, "biterr") == 0) {
857 int bad_bit, addr;
858
859 argc -= 1;
860 argv += 1;
861
862 if (argc <= 0)
863 goto usage;
864
865 bad_bit = 1;
866 if (argc > 0)
867 addr = (ulong)simple_strtoul(argv[0], NULL, 16);
868 if (argc >= 2)
869 bad_bit = (ulong)simple_strtoul(argv[1], NULL, 16);
870
871 ret = spi_flash_mark_biterr(chip, addr, bad_bit);
872 printf(" %s\n", ret ? "Failed" : "Passed");
873
874 return ret;
875 } else
876 ret = -1;
877
878done:
879 if (ret != -1)
880 return ret;
881
882usage:
883 return CMD_RET_USAGE;
884}
885
886
887U_BOOT_CMD(
888 spi_flash, 5, 1, do_spi_flash,
889 "SPI NAND/NOR flash sub-system",
890 "probe [[bus:]cs] [hz] [mode] - init flash device on given SPI bus\n"
891 " and chip select\n"
892 "spi_flash read addr offset len - read `len' bytes starting at\n"
893 " `offset' to memory at `addr', skipping bad blocks.\n"
894 "spi_flash write addr offset len - write `len' bytes from memory\n"
895 " at `addr' to flash at `offset', skipping bad blocks.\n"
896 "spi_flash erase[.spread] offset [+]len - erase `len' bytes from `offset'\n"
897 " `+len' round up `len' to block size\n"
898 " With '.spread', erase enough for given file size, otherwise,\n"
899 " 'size' includes skipped bad blocks.\n"
900 "spi_flash info addr - get flash info, and save to addr\n"
901 "spi_flash update addr offset len - erase and write `len' bytes from memory\n"
902 " at `addr' to flash at `offset'\n"
903 "spi_flash bad - show bad blocks\n"
904 "spi_flash markbad offset - mark block include `offset' as bad block\n"
905);