uboot/cmd/sf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Command for accessing SPI flash.
   4 *
   5 * Copyright (C) 2008 Atmel Corporation
   6 */
   7
   8#include <common.h>
   9#include <div64.h>
  10#include <dm.h>
  11#include <malloc.h>
  12#include <mapmem.h>
  13#include <spi.h>
  14#include <spi_flash.h>
  15#include <jffs2/jffs2.h>
  16#include <linux/mtd/mtd.h>
  17
  18#include <asm/io.h>
  19#include <dm/device-internal.h>
  20
  21static struct spi_flash *flash;
  22
  23/*
  24 * This function computes the length argument for the erase command.
  25 * The length on which the command is to operate can be given in two forms:
  26 * 1. <cmd> offset len  - operate on <'offset',  'len')
  27 * 2. <cmd> offset +len - operate on <'offset',  'round_up(len)')
  28 * If the second form is used and the length doesn't fall on the
  29 * sector boundary, than it will be adjusted to the next sector boundary.
  30 * If it isn't in the flash, the function will fail (return -1).
  31 * Input:
  32 *    arg: length specification (i.e. both command arguments)
  33 * Output:
  34 *    len: computed length for operation
  35 * Return:
  36 *    1: success
  37 *   -1: failure (bad format, bad address).
  38 */
  39static int sf_parse_len_arg(char *arg, ulong *len)
  40{
  41        char *ep;
  42        char round_up_len; /* indicates if the "+length" form used */
  43        ulong len_arg;
  44
  45        round_up_len = 0;
  46        if (*arg == '+') {
  47                round_up_len = 1;
  48                ++arg;
  49        }
  50
  51        len_arg = simple_strtoul(arg, &ep, 16);
  52        if (ep == arg || *ep != '\0')
  53                return -1;
  54
  55        if (round_up_len && flash->sector_size > 0)
  56                *len = ROUND(len_arg, flash->sector_size);
  57        else
  58                *len = len_arg;
  59
  60        return 1;
  61}
  62
  63/**
  64 * This function takes a byte length and a delta unit of time to compute the
  65 * approximate bytes per second
  66 *
  67 * @param len           amount of bytes currently processed
  68 * @param start_ms      start time of processing in ms
  69 * @return bytes per second if OK, 0 on error
  70 */
  71static ulong bytes_per_second(unsigned int len, ulong start_ms)
  72{
  73        /* less accurate but avoids overflow */
  74        if (len >= ((unsigned int) -1) / 1024)
  75                return len / (max(get_timer(start_ms) / 1024, 1UL));
  76        else
  77                return 1024 * len / max(get_timer(start_ms), 1UL);
  78}
  79
  80static int do_spi_flash_probe(int argc, char * const argv[])
  81{
  82        unsigned int bus = CONFIG_SF_DEFAULT_BUS;
  83        unsigned int cs = CONFIG_SF_DEFAULT_CS;
  84        unsigned int speed = CONFIG_SF_DEFAULT_SPEED;
  85        unsigned int mode = CONFIG_SF_DEFAULT_MODE;
  86        char *endp;
  87#ifdef CONFIG_DM_SPI_FLASH
  88        struct udevice *new, *bus_dev;
  89        int ret;
  90        /* In DM mode defaults will be taken from DT */
  91        speed = 0, mode = 0;
  92#else
  93        struct spi_flash *new;
  94#endif
  95
  96        if (argc >= 2) {
  97                cs = simple_strtoul(argv[1], &endp, 0);
  98                if (*argv[1] == 0 || (*endp != 0 && *endp != ':'))
  99                        return -1;
 100                if (*endp == ':') {
 101                        if (endp[1] == 0)
 102                                return -1;
 103
 104                        bus = cs;
 105                        cs = simple_strtoul(endp + 1, &endp, 0);
 106                        if (*endp != 0)
 107                                return -1;
 108                }
 109        }
 110
 111        if (argc >= 3) {
 112                speed = simple_strtoul(argv[2], &endp, 0);
 113                if (*argv[2] == 0 || *endp != 0)
 114                        return -1;
 115        }
 116        if (argc >= 4) {
 117                mode = simple_strtoul(argv[3], &endp, 16);
 118                if (*argv[3] == 0 || *endp != 0)
 119                        return -1;
 120        }
 121
 122#ifdef CONFIG_DM_SPI_FLASH
 123        /* Remove the old device, otherwise probe will just be a nop */
 124        ret = spi_find_bus_and_cs(bus, cs, &bus_dev, &new);
 125        if (!ret) {
 126                device_remove(new, DM_REMOVE_NORMAL);
 127        }
 128        flash = NULL;
 129        ret = spi_flash_probe_bus_cs(bus, cs, speed, mode, &new);
 130        if (ret) {
 131                printf("Failed to initialize SPI flash at %u:%u (error %d)\n",
 132                       bus, cs, ret);
 133                return 1;
 134        }
 135
 136        flash = dev_get_uclass_priv(new);
 137#else
 138        if (flash)
 139                spi_flash_free(flash);
 140
 141        new = spi_flash_probe(bus, cs, speed, mode);
 142        flash = new;
 143
 144        if (!new) {
 145                printf("Failed to initialize SPI flash at %u:%u\n", bus, cs);
 146                return 1;
 147        }
 148
 149        flash = new;
 150#endif
 151
 152        return 0;
 153}
 154
 155/**
 156 * Write a block of data to SPI flash, first checking if it is different from
 157 * what is already there.
 158 *
 159 * If the data being written is the same, then *skipped is incremented by len.
 160 *
 161 * @param flash         flash context pointer
 162 * @param offset        flash offset to write
 163 * @param len           number of bytes to write
 164 * @param buf           buffer to write from
 165 * @param cmp_buf       read buffer to use to compare data
 166 * @param skipped       Count of skipped data (incremented by this function)
 167 * @return NULL if OK, else a string containing the stage which failed
 168 */
 169static const char *spi_flash_update_block(struct spi_flash *flash, u32 offset,
 170                size_t len, const char *buf, char *cmp_buf, size_t *skipped)
 171{
 172        char *ptr = (char *)buf;
 173
 174        debug("offset=%#x, sector_size=%#x, len=%#zx\n",
 175              offset, flash->sector_size, len);
 176        /* Read the entire sector so to allow for rewriting */
 177        if (spi_flash_read(flash, offset, flash->sector_size, cmp_buf))
 178                return "read";
 179        /* Compare only what is meaningful (len) */
 180        if (memcmp(cmp_buf, buf, len) == 0) {
 181                debug("Skip region %x size %zx: no change\n",
 182                      offset, len);
 183                *skipped += len;
 184                return NULL;
 185        }
 186        /* Erase the entire sector */
 187        if (spi_flash_erase(flash, offset, flash->sector_size))
 188                return "erase";
 189        /* If it's a partial sector, copy the data into the temp-buffer */
 190        if (len != flash->sector_size) {
 191                memcpy(cmp_buf, buf, len);
 192                ptr = cmp_buf;
 193        }
 194        /* Write one complete sector */
 195        if (spi_flash_write(flash, offset, flash->sector_size, ptr))
 196                return "write";
 197
 198        return NULL;
 199}
 200
 201/**
 202 * Update an area of SPI flash by erasing and writing any blocks which need
 203 * to change. Existing blocks with the correct data are left unchanged.
 204 *
 205 * @param flash         flash context pointer
 206 * @param offset        flash offset to write
 207 * @param len           number of bytes to write
 208 * @param buf           buffer to write from
 209 * @return 0 if ok, 1 on error
 210 */
 211static int spi_flash_update(struct spi_flash *flash, u32 offset,
 212                size_t len, const char *buf)
 213{
 214        const char *err_oper = NULL;
 215        char *cmp_buf;
 216        const char *end = buf + len;
 217        size_t todo;            /* number of bytes to do in this pass */
 218        size_t skipped = 0;     /* statistics */
 219        const ulong start_time = get_timer(0);
 220        size_t scale = 1;
 221        const char *start_buf = buf;
 222        ulong delta;
 223
 224        if (end - buf >= 200)
 225                scale = (end - buf) / 100;
 226        cmp_buf = memalign(ARCH_DMA_MINALIGN, flash->sector_size);
 227        if (cmp_buf) {
 228                ulong last_update = get_timer(0);
 229
 230                for (; buf < end && !err_oper; buf += todo, offset += todo) {
 231                        todo = min_t(size_t, end - buf, flash->sector_size);
 232                        if (get_timer(last_update) > 100) {
 233                                printf("   \rUpdating, %zu%% %lu B/s",
 234                                       100 - (end - buf) / scale,
 235                                        bytes_per_second(buf - start_buf,
 236                                                         start_time));
 237                                last_update = get_timer(0);
 238                        }
 239                        err_oper = spi_flash_update_block(flash, offset, todo,
 240                                        buf, cmp_buf, &skipped);
 241                }
 242        } else {
 243                err_oper = "malloc";
 244        }
 245        free(cmp_buf);
 246        putc('\r');
 247        if (err_oper) {
 248                printf("SPI flash failed in %s step\n", err_oper);
 249                return 1;
 250        }
 251
 252        delta = get_timer(start_time);
 253        printf("%zu bytes written, %zu bytes skipped", len - skipped,
 254               skipped);
 255        printf(" in %ld.%lds, speed %ld B/s\n",
 256               delta / 1000, delta % 1000, bytes_per_second(len, start_time));
 257
 258        return 0;
 259}
 260
 261static int do_spi_flash_read_write(int argc, char * const argv[])
 262{
 263        unsigned long addr;
 264        void *buf;
 265        char *endp;
 266        int ret = 1;
 267        int dev = 0;
 268        loff_t offset, len, maxsize;
 269
 270        if (argc < 3)
 271                return -1;
 272
 273        addr = simple_strtoul(argv[1], &endp, 16);
 274        if (*argv[1] == 0 || *endp != 0)
 275                return -1;
 276
 277        if (mtd_arg_off_size(argc - 2, &argv[2], &dev, &offset, &len,
 278                             &maxsize, MTD_DEV_TYPE_NOR, flash->size))
 279                return -1;
 280
 281        /* Consistency checking */
 282        if (offset + len > flash->size) {
 283                printf("ERROR: attempting %s past flash size (%#x)\n",
 284                       argv[0], flash->size);
 285                return 1;
 286        }
 287
 288        buf = map_physmem(addr, len, MAP_WRBACK);
 289        if (!buf && addr) {
 290                puts("Failed to map physical memory\n");
 291                return 1;
 292        }
 293
 294        if (strcmp(argv[0], "update") == 0) {
 295                ret = spi_flash_update(flash, offset, len, buf);
 296        } else if (strncmp(argv[0], "read", 4) == 0 ||
 297                        strncmp(argv[0], "write", 5) == 0) {
 298                int read;
 299
 300                read = strncmp(argv[0], "read", 4) == 0;
 301                if (read)
 302                        ret = spi_flash_read(flash, offset, len, buf);
 303                else
 304                        ret = spi_flash_write(flash, offset, len, buf);
 305
 306                printf("SF: %zu bytes @ %#x %s: ", (size_t)len, (u32)offset,
 307                       read ? "Read" : "Written");
 308                if (ret)
 309                        printf("ERROR %d\n", ret);
 310                else
 311                        printf("OK\n");
 312        }
 313
 314        unmap_physmem(buf, len);
 315
 316        return ret == 0 ? 0 : 1;
 317}
 318
 319static int do_spi_flash_erase(int argc, char * const argv[])
 320{
 321        int ret;
 322        int dev = 0;
 323        loff_t offset, len, maxsize;
 324        ulong size;
 325
 326        if (argc < 3)
 327                return -1;
 328
 329        if (mtd_arg_off(argv[1], &dev, &offset, &len, &maxsize,
 330                        MTD_DEV_TYPE_NOR, flash->size))
 331                return -1;
 332
 333        ret = sf_parse_len_arg(argv[2], &size);
 334        if (ret != 1)
 335                return -1;
 336
 337        /* Consistency checking */
 338        if (offset + size > flash->size) {
 339                printf("ERROR: attempting %s past flash size (%#x)\n",
 340                       argv[0], flash->size);
 341                return 1;
 342        }
 343
 344        ret = spi_flash_erase(flash, offset, size);
 345        printf("SF: %zu bytes @ %#x Erased: %s\n", (size_t)size, (u32)offset,
 346               ret ? "ERROR" : "OK");
 347
 348        return ret == 0 ? 0 : 1;
 349}
 350
 351static int do_spi_protect(int argc, char * const argv[])
 352{
 353        int ret = 0;
 354        loff_t start, len;
 355        bool prot = false;
 356
 357        if (argc != 4)
 358                return -1;
 359
 360        if (!str2off(argv[2], &start)) {
 361                puts("start sector is not a valid number\n");
 362                return 1;
 363        }
 364
 365        if (!str2off(argv[3], &len)) {
 366                puts("len is not a valid number\n");
 367                return 1;
 368        }
 369
 370        if (strcmp(argv[1], "lock") == 0)
 371                prot = true;
 372        else if (strcmp(argv[1], "unlock") == 0)
 373                prot = false;
 374        else
 375                return -1;  /* Unknown parameter */
 376
 377        ret = spi_flash_protect(flash, start, len, prot);
 378
 379        return ret == 0 ? 0 : 1;
 380}
 381
 382#ifdef CONFIG_CMD_SF_TEST
 383enum {
 384        STAGE_ERASE,
 385        STAGE_CHECK,
 386        STAGE_WRITE,
 387        STAGE_READ,
 388
 389        STAGE_COUNT,
 390};
 391
 392static char *stage_name[STAGE_COUNT] = {
 393        "erase",
 394        "check",
 395        "write",
 396        "read",
 397};
 398
 399struct test_info {
 400        int stage;
 401        int bytes;
 402        unsigned base_ms;
 403        unsigned time_ms[STAGE_COUNT];
 404};
 405
 406static void show_time(struct test_info *test, int stage)
 407{
 408        uint64_t speed; /* KiB/s */
 409        int bps;        /* Bits per second */
 410
 411        speed = (long long)test->bytes * 1000;
 412        if (test->time_ms[stage])
 413                do_div(speed, test->time_ms[stage] * 1024);
 414        bps = speed * 8;
 415
 416        printf("%d %s: %u ticks, %d KiB/s %d.%03d Mbps\n", stage,
 417               stage_name[stage], test->time_ms[stage],
 418               (int)speed, bps / 1000, bps % 1000);
 419}
 420
 421static void spi_test_next_stage(struct test_info *test)
 422{
 423        test->time_ms[test->stage] = get_timer(test->base_ms);
 424        show_time(test, test->stage);
 425        test->base_ms = get_timer(0);
 426        test->stage++;
 427}
 428
 429/**
 430 * Run a test on the SPI flash
 431 *
 432 * @param flash         SPI flash to use
 433 * @param buf           Source buffer for data to write
 434 * @param len           Size of data to read/write
 435 * @param offset        Offset within flash to check
 436 * @param vbuf          Verification buffer
 437 * @return 0 if ok, -1 on error
 438 */
 439static int spi_flash_test(struct spi_flash *flash, uint8_t *buf, ulong len,
 440                           ulong offset, uint8_t *vbuf)
 441{
 442        struct test_info test;
 443        int i;
 444
 445        printf("SPI flash test:\n");
 446        memset(&test, '\0', sizeof(test));
 447        test.base_ms = get_timer(0);
 448        test.bytes = len;
 449        if (spi_flash_erase(flash, offset, len)) {
 450                printf("Erase failed\n");
 451                return -1;
 452        }
 453        spi_test_next_stage(&test);
 454
 455        if (spi_flash_read(flash, offset, len, vbuf)) {
 456                printf("Check read failed\n");
 457                return -1;
 458        }
 459        for (i = 0; i < len; i++) {
 460                if (vbuf[i] != 0xff) {
 461                        printf("Check failed at %d\n", i);
 462                        print_buffer(i, vbuf + i, 1,
 463                                     min_t(uint, len - i, 0x40), 0);
 464                        return -1;
 465                }
 466        }
 467        spi_test_next_stage(&test);
 468
 469        if (spi_flash_write(flash, offset, len, buf)) {
 470                printf("Write failed\n");
 471                return -1;
 472        }
 473        memset(vbuf, '\0', len);
 474        spi_test_next_stage(&test);
 475
 476        if (spi_flash_read(flash, offset, len, vbuf)) {
 477                printf("Read failed\n");
 478                return -1;
 479        }
 480        spi_test_next_stage(&test);
 481
 482        for (i = 0; i < len; i++) {
 483                if (buf[i] != vbuf[i]) {
 484                        printf("Verify failed at %d, good data:\n", i);
 485                        print_buffer(i, buf + i, 1,
 486                                     min_t(uint, len - i, 0x40), 0);
 487                        printf("Bad data:\n");
 488                        print_buffer(i, vbuf + i, 1,
 489                                     min_t(uint, len - i, 0x40), 0);
 490                        return -1;
 491                }
 492        }
 493        printf("Test passed\n");
 494        for (i = 0; i < STAGE_COUNT; i++)
 495                show_time(&test, i);
 496
 497        return 0;
 498}
 499
 500static int do_spi_flash_test(int argc, char * const argv[])
 501{
 502        unsigned long offset;
 503        unsigned long len;
 504        uint8_t *buf, *from;
 505        char *endp;
 506        uint8_t *vbuf;
 507        int ret;
 508
 509        if (argc < 3)
 510                return -1;
 511        offset = simple_strtoul(argv[1], &endp, 16);
 512        if (*argv[1] == 0 || *endp != 0)
 513                return -1;
 514        len = simple_strtoul(argv[2], &endp, 16);
 515        if (*argv[2] == 0 || *endp != 0)
 516                return -1;
 517
 518        vbuf = memalign(ARCH_DMA_MINALIGN, len);
 519        if (!vbuf) {
 520                printf("Cannot allocate memory (%lu bytes)\n", len);
 521                return 1;
 522        }
 523        buf = memalign(ARCH_DMA_MINALIGN, len);
 524        if (!buf) {
 525                free(vbuf);
 526                printf("Cannot allocate memory (%lu bytes)\n", len);
 527                return 1;
 528        }
 529
 530        from = map_sysmem(CONFIG_SYS_TEXT_BASE, 0);
 531        memcpy(buf, from, len);
 532        ret = spi_flash_test(flash, buf, len, offset, vbuf);
 533        free(vbuf);
 534        free(buf);
 535        if (ret) {
 536                printf("Test failed\n");
 537                return 1;
 538        }
 539
 540        return 0;
 541}
 542#endif /* CONFIG_CMD_SF_TEST */
 543
 544static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc,
 545                        char * const argv[])
 546{
 547        const char *cmd;
 548        int ret;
 549
 550        /* need at least two arguments */
 551        if (argc < 2)
 552                goto usage;
 553
 554        cmd = argv[1];
 555        --argc;
 556        ++argv;
 557
 558        if (strcmp(cmd, "probe") == 0) {
 559                ret = do_spi_flash_probe(argc, argv);
 560                goto done;
 561        }
 562
 563        /* The remaining commands require a selected device */
 564        if (!flash) {
 565                puts("No SPI flash selected. Please run `sf probe'\n");
 566                return 1;
 567        }
 568
 569        if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0 ||
 570            strcmp(cmd, "update") == 0)
 571                ret = do_spi_flash_read_write(argc, argv);
 572        else if (strcmp(cmd, "erase") == 0)
 573                ret = do_spi_flash_erase(argc, argv);
 574        else if (strcmp(cmd, "protect") == 0)
 575                ret = do_spi_protect(argc, argv);
 576#ifdef CONFIG_CMD_SF_TEST
 577        else if (!strcmp(cmd, "test"))
 578                ret = do_spi_flash_test(argc, argv);
 579#endif
 580        else
 581                ret = -1;
 582
 583done:
 584        if (ret != -1)
 585                return ret;
 586
 587usage:
 588        return CMD_RET_USAGE;
 589}
 590
 591#ifdef CONFIG_CMD_SF_TEST
 592#define SF_TEST_HELP "\nsf test offset len              " \
 593                "- run a very basic destructive test"
 594#else
 595#define SF_TEST_HELP
 596#endif
 597
 598U_BOOT_CMD(
 599        sf,     5,      1,      do_spi_flash,
 600        "SPI flash sub-system",
 601        "probe [[bus:]cs] [hz] [mode]   - init flash device on given SPI bus\n"
 602        "                                 and chip select\n"
 603        "sf read addr offset|partition len      - read `len' bytes starting at\n"
 604        "                                         `offset' or from start of mtd\n"
 605        "                                         `partition'to memory at `addr'\n"
 606        "sf write addr offset|partition len     - write `len' bytes from memory\n"
 607        "                                         at `addr' to flash at `offset'\n"
 608        "                                         or to start of mtd `partition'\n"
 609        "sf erase offset|partition [+]len       - erase `len' bytes from `offset'\n"
 610        "                                         or from start of mtd `partition'\n"
 611        "                                        `+len' round up `len' to block size\n"
 612        "sf update addr offset|partition len    - erase and write `len' bytes from memory\n"
 613        "                                         at `addr' to flash at `offset'\n"
 614        "                                         or to start of mtd `partition'\n"
 615        "sf protect lock/unlock sector len      - protect/unprotect 'len' bytes starting\n"
 616        "                                         at address 'sector'\n"
 617        SF_TEST_HELP
 618);
 619