spi_flash_sfud.c 29.6 KB
Newer Older
1
/*
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
5 6 7 8 9 10 11
 *
 * Change Logs:
 * Date           Author       Notes
 * 2016-09-28     armink       first version.
 */

#include <stdint.h>
马志远 已提交
12
#include <string.h>
13 14 15 16 17 18 19
#include <rtdevice.h>
#include "spi_flash.h"
#include "spi_flash_sfud.h"

#ifdef RT_USING_SFUD

#ifndef RT_SFUD_DEFAULT_SPI_CFG
20 21 22 23 24

#ifndef RT_SFUD_SPI_MAX_HZ
#define RT_SFUD_SPI_MAX_HZ 50000000
#endif

25
/* read the JEDEC SFDP command must run at 50 MHz or less */
26 27 28 29
#define RT_SFUD_DEFAULT_SPI_CFG                  \
{                                                \
    .mode = RT_SPI_MODE_0 | RT_SPI_MSB,          \
    .data_width = 8,                             \
30
    .max_hz = RT_SFUD_SPI_MAX_HZ,                \
31
}
32
#endif /* RT_SFUD_DEFAULT_SPI_CFG */
33 34 35 36 37 38 39 40

#ifdef SFUD_USING_QSPI
#define RT_SFUD_DEFAULT_QSPI_CFG                 \
{                                                \
    RT_SFUD_DEFAULT_SPI_CFG,                     \
    .medium_size = 0x800000,                     \
    .ddr_mode = 0,                               \
    .qspi_dl_width = 4,                          \
41
}
42
#endif /* SFUD_USING_QSPI */
43

B
bernard 已提交
44
static rt_err_t rt_sfud_control(rt_device_t dev, int cmd, void *args) {
45
    RT_ASSERT(dev);
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

    switch (cmd) {
    case RT_DEVICE_CTRL_BLK_GETGEOME: {
        struct rt_device_blk_geometry *geometry = (struct rt_device_blk_geometry *) args;
        struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);

        if (rtt_dev == RT_NULL || geometry == RT_NULL) {
            return -RT_ERROR;
        }

        geometry->bytes_per_sector = rtt_dev->geometry.bytes_per_sector;
        geometry->sector_count = rtt_dev->geometry.sector_count;
        geometry->block_size = rtt_dev->geometry.block_size;
        break;
    }
    case RT_DEVICE_CTRL_BLK_ERASE: {
        rt_uint32_t *addrs = (rt_uint32_t *) args, start_addr = addrs[0], end_addr = addrs[1], phy_start_addr;
        struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
        sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
        rt_size_t phy_size;

        if (addrs == RT_NULL || start_addr > end_addr || rtt_dev == RT_NULL || sfud_dev == RT_NULL) {
            return -RT_ERROR;
        }

71 72 73 74
        if (end_addr == start_addr) {
            end_addr ++;
        }

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
        phy_start_addr = start_addr * rtt_dev->geometry.bytes_per_sector;
        phy_size = (end_addr - start_addr) * rtt_dev->geometry.bytes_per_sector;

        if (sfud_erase(sfud_dev, phy_start_addr, phy_size) != SFUD_SUCCESS) {
            return -RT_ERROR;
        }
        break;
    }
    }

    return RT_EOK;
}


static rt_size_t rt_sfud_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) {
    struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
    sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
92 93 94 95

    RT_ASSERT(dev);
    RT_ASSERT(rtt_dev);
    RT_ASSERT(sfud_dev);
96
    /* change the block device's logic address to physical address */
97 98 99 100 101 102 103 104 105 106 107 108 109
    rt_off_t phy_pos = pos * rtt_dev->geometry.bytes_per_sector;
    rt_size_t phy_size = size * rtt_dev->geometry.bytes_per_sector;

    if (sfud_read(sfud_dev, phy_pos, phy_size, buffer) != SFUD_SUCCESS) {
        return 0;
    } else {
        return size;
    }
}

static rt_size_t rt_sfud_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) {
    struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
    sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
110 111 112 113

    RT_ASSERT(dev);
    RT_ASSERT(rtt_dev);
    RT_ASSERT(sfud_dev);
114
    /* change the block device's logic address to physical address */
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
    rt_off_t phy_pos = pos * rtt_dev->geometry.bytes_per_sector;
    rt_size_t phy_size = size * rtt_dev->geometry.bytes_per_sector;

    if (sfud_erase_write(sfud_dev, phy_pos, phy_size, buffer) != SFUD_SUCCESS) {
        return 0;
    } else {
        return size;
    }
}

/**
 * SPI write data then read data
 */
static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
        size_t read_size) {
    sfud_err result = SFUD_SUCCESS;
    sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
    struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
133 134 135 136

    RT_ASSERT(spi);
    RT_ASSERT(sfud_dev);
    RT_ASSERT(rtt_dev);
137 138 139
#ifdef SFUD_USING_QSPI
    struct rt_qspi_device *qspi_dev = RT_NULL;
#endif
140 141 142 143 144 145
    if (write_size) {
        RT_ASSERT(write_buf);
    }
    if (read_size) {
        RT_ASSERT(read_buf);
    }
146 147 148 149
#ifdef SFUD_USING_QSPI
    if(rtt_dev->rt_spi_device->bus->mode & RT_SPI_BUS_MODE_QSPI) {
        qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
        if (write_size && read_size) {
150
            if (rt_qspi_send_then_recv(qspi_dev, write_buf, write_size, read_buf, read_size) <= 0) {
151 152 153
                result = SFUD_ERR_TIMEOUT;
            }
        } else if (write_size) {
154
            if (rt_qspi_send(qspi_dev, write_buf, write_size) <= 0) {
155 156
                result = SFUD_ERR_TIMEOUT;
            }
157
        }
158 159 160 161 162 163 164 165 166
    }
    else
#endif
    {
        if (write_size && read_size) {
            if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) {
                result = SFUD_ERR_TIMEOUT;
            }
        } else if (write_size) {
167
            if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) <= 0) {
168 169 170
                result = SFUD_ERR_TIMEOUT;
            }
        } else {
171
            if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) <= 0) {
172 173
                result = SFUD_ERR_TIMEOUT;
            }
174 175 176 177 178 179
        }
    }

    return result;
}

180 181 182 183 184 185 186 187 188 189 190
#ifdef SFUD_USING_QSPI
/**
 * QSPI fast read data
 */
static sfud_err qspi_read(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format, uint8_t *read_buf, size_t read_size) {
    struct rt_qspi_message message;
    sfud_err result = SFUD_SUCCESS;

    sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
    struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
    struct rt_qspi_device *qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
191 192 193 194 195 196

    RT_ASSERT(spi);
    RT_ASSERT(sfud_dev);
    RT_ASSERT(rtt_dev);
    RT_ASSERT(qspi_dev);

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
    /* set message struct */
    message.instruction.content = qspi_read_cmd_format->instruction;
    message.instruction.qspi_lines = qspi_read_cmd_format->instruction_lines;

    message.address.content = addr;
    message.address.size = qspi_read_cmd_format->address_size;
    message.address.qspi_lines = qspi_read_cmd_format->address_lines;

    message.alternate_bytes.content = 0;
    message.alternate_bytes.size = 0;
    message.alternate_bytes.qspi_lines = 0;

    message.dummy_cycles = qspi_read_cmd_format->dummy_cycles;

    message.parent.send_buf = RT_NULL;
    message.parent.recv_buf = read_buf;
    message.parent.length = read_size;
    message.parent.cs_release = 1;
    message.parent.cs_take = 1;
    message.qspi_data_lines = qspi_read_cmd_format->data_lines;
217

218 219 220
    if (rt_qspi_transfer_message(qspi_dev, &message) != read_size) {
        result = SFUD_ERR_TIMEOUT;
    }
221

222 223 224 225
    return result;
}
#endif

226 227 228 229
static void spi_lock(const sfud_spi *spi) {
    sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
    struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);

230 231 232 233
    RT_ASSERT(spi);
    RT_ASSERT(sfud_dev);
    RT_ASSERT(rtt_dev);

234 235 236 237 238 239 240
    rt_mutex_take(&(rtt_dev->lock), RT_WAITING_FOREVER);
}

static void spi_unlock(const sfud_spi *spi) {
    sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
    struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);

241 242 243 244
    RT_ASSERT(spi);
    RT_ASSERT(sfud_dev);
    RT_ASSERT(rtt_dev);

245 246 247 248 249 250 251 252 253 254 255
    rt_mutex_release(&(rtt_dev->lock));
}

static void retry_delay_100us(void) {
    /* 100 microsecond delay */
    rt_thread_delay((RT_TICK_PER_SECOND * 1 + 9999) / 10000);
}

sfud_err sfud_spi_port_init(sfud_flash *flash) {
    sfud_err result = SFUD_SUCCESS;

256 257
    RT_ASSERT(flash);

258 259
    /* port SPI device interface */
    flash->spi.wr = spi_write_read;
260 261 262
#ifdef SFUD_USING_QSPI
    flash->spi.qspi_read = qspi_read;
#endif
263 264 265
    flash->spi.lock = spi_lock;
    flash->spi.unlock = spi_unlock;
    flash->spi.user_data = flash;
armink_ztl's avatar
armink_ztl 已提交
266
    if (RT_TICK_PER_SECOND < 1000) {
267
        LOG_W("[SFUD] Warning: The OS tick(%d) is less than 1000. So the flash write will take more time.", RT_TICK_PER_SECOND);
armink_ztl's avatar
armink_ztl 已提交
268
    }
269 270 271 272
    /* 100 microsecond delay */
    flash->retry.delay = retry_delay_100us;
    /* 60 seconds timeout */
    flash->retry.times = 60 * 10000;
273

274 275 276
    return result;
}

B
Bernard Xiong 已提交
277
#ifdef RT_USING_DEVICE_OPS
278
const static struct rt_device_ops flash_device_ops =
B
Bernard Xiong 已提交
279 280 281 282 283 284 285 286 287 288
{
    RT_NULL,
    RT_NULL,
    RT_NULL,
    rt_sfud_read,
    rt_sfud_write,
    rt_sfud_control
};
#endif

289
/**
290
 * Probe SPI flash by SFUD (Serial Flash Universal Driver) driver library and though SPI device by specified configuration.
291
 *
292 293
 * @param spi_flash_dev_name the name which will create SPI flash device
 * @param spi_dev_name using SPI device name
294 295
 * @param spi_cfg SPI device configuration
 * @param qspi_cfg QSPI device configuration
296
 *
297
 * @return probed SPI flash device, probe failed will return RT_NULL
298
 */
299
rt_spi_flash_device_t rt_sfud_flash_probe_ex(const char *spi_flash_dev_name, const char *spi_dev_name,
300 301
        struct rt_spi_configuration *spi_cfg, struct rt_qspi_configuration *qspi_cfg)
{
302 303 304
    rt_spi_flash_device_t rtt_dev = RT_NULL;
    sfud_flash *sfud_dev = RT_NULL;
    char *spi_flash_dev_name_bak = RT_NULL, *spi_dev_name_bak = RT_NULL;
305
    extern sfud_err sfud_device_init(sfud_flash *flash);
306 307 308
#ifdef SFUD_USING_QSPI
    struct rt_qspi_device *qspi_dev = RT_NULL;
#endif
309

310 311 312 313 314 315 316 317
    RT_ASSERT(spi_flash_dev_name);
    RT_ASSERT(spi_dev_name);

    rtt_dev = (rt_spi_flash_device_t) rt_malloc(sizeof(struct spi_flash_device));
    sfud_dev = (sfud_flash_t) rt_malloc(sizeof(sfud_flash));
    spi_flash_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_flash_dev_name) + 1);
    spi_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_dev_name) + 1);

318
    if (rtt_dev) {
319
        rt_memset(rtt_dev, 0, sizeof(struct spi_flash_device));
320
        /* initialize lock */
321
        rt_mutex_init(&(rtt_dev->lock), spi_flash_dev_name, RT_IPC_FLAG_PRIO);
322
    }
B
Bernard Xiong 已提交
323

324
    if (rtt_dev && sfud_dev && spi_flash_dev_name_bak && spi_dev_name_bak) {
325 326 327 328 329 330 331 332 333 334
        rt_memset(sfud_dev, 0, sizeof(sfud_flash));
        rt_strncpy(spi_flash_dev_name_bak, spi_flash_dev_name, rt_strlen(spi_flash_dev_name));
        rt_strncpy(spi_dev_name_bak, spi_dev_name, rt_strlen(spi_dev_name));
        /* make string end sign */
        spi_flash_dev_name_bak[rt_strlen(spi_flash_dev_name)] = '\0';
        spi_dev_name_bak[rt_strlen(spi_dev_name)] = '\0';
        /* SPI configure */
        {
            /* RT-Thread SPI device initialize */
            rtt_dev->rt_spi_device = (struct rt_spi_device *) rt_device_find(spi_dev_name);
335
            if (rtt_dev->rt_spi_device == RT_NULL || rtt_dev->rt_spi_device->parent.type != RT_Device_Class_SPIDevice) {
336
                LOG_E("ERROR: SPI device %s not found!", spi_dev_name);
337 338 339
                goto error;
            }
            sfud_dev->spi.name = spi_dev_name_bak;
340 341 342 343 344

#ifdef SFUD_USING_QSPI
            /* set the qspi line number and configure the QSPI bus */
            if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
                qspi_dev = (struct rt_qspi_device *)rtt_dev->rt_spi_device;
345 346
                qspi_cfg->qspi_dl_width = qspi_dev->config.qspi_dl_width;
                rt_qspi_configure(qspi_dev, qspi_cfg);
347 348
            }
            else
349
#endif
350
                rt_spi_configure(rtt_dev->rt_spi_device, spi_cfg);
351 352 353 354 355 356
        }
        /* SFUD flash device initialize */
        {
            sfud_dev->name = spi_flash_dev_name_bak;
            /* accessed each other */
            rtt_dev->user_data = sfud_dev;
357
            rtt_dev->rt_spi_device->user_data = rtt_dev;
358 359 360 361
            rtt_dev->flash_device.user_data = rtt_dev;
            sfud_dev->user_data = rtt_dev;
            /* initialize SFUD device */
            if (sfud_device_init(sfud_dev) != SFUD_SUCCESS) {
362
                LOG_E("ERROR: SPI flash probe failed by SPI device %s.", spi_dev_name);
363 364 365 366 367 368
                goto error;
            }
            /* when initialize success, then copy SFUD flash device's geometry to RT-Thread SPI flash device */
            rtt_dev->geometry.sector_count = sfud_dev->chip.capacity / sfud_dev->chip.erase_gran;
            rtt_dev->geometry.bytes_per_sector = sfud_dev->chip.erase_gran;
            rtt_dev->geometry.block_size = sfud_dev->chip.erase_gran;
369 370 371
#ifdef SFUD_USING_QSPI
            /* reconfigure the QSPI bus for medium size */
            if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
372 373
                qspi_cfg->medium_size = sfud_dev->chip.capacity;
                rt_qspi_configure(qspi_dev, qspi_cfg);
374 375
                if(qspi_dev->enter_qspi_mode != RT_NULL)
                    qspi_dev->enter_qspi_mode(qspi_dev);
Z
zylx 已提交
376 377 378

                /* set data lines width */
                sfud_qspi_fast_read_enable(sfud_dev, qspi_dev->config.qspi_dl_width);
379 380
            }
#endif /* SFUD_USING_QSPI */
381
        }
382

383 384
        /* register device */
        rtt_dev->flash_device.type = RT_Device_Class_Block;
B
Bernard Xiong 已提交
385 386 387
#ifdef RT_USING_DEVICE_OPS
        rtt_dev->flash_device.ops  = &flash_device_ops;
#else
388 389 390 391 392 393
        rtt_dev->flash_device.init = RT_NULL;
        rtt_dev->flash_device.open = RT_NULL;
        rtt_dev->flash_device.close = RT_NULL;
        rtt_dev->flash_device.read = rt_sfud_read;
        rtt_dev->flash_device.write = rt_sfud_write;
        rtt_dev->flash_device.control = rt_sfud_control;
B
Bernard Xiong 已提交
394
#endif
395

396 397
        rt_device_register(&(rtt_dev->flash_device), spi_flash_dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);

398
        LOG_I("Probe SPI flash %s by SPI device %s success.",spi_flash_dev_name, spi_dev_name);
399 400
        return rtt_dev;
    } else {
401
        LOG_E("ERROR: Low memory.");
402
        goto error;
403 404
    }

405
error:
406 407 408 409

    if (rtt_dev) {
        rt_mutex_detach(&(rtt_dev->lock));
    }
410 411 412 413 414
    /* may be one of objects memory was malloc success, so need free all */
    rt_free(rtt_dev);
    rt_free(sfud_dev);
    rt_free(spi_flash_dev_name_bak);
    rt_free(spi_dev_name_bak);
415

416 417
    return RT_NULL;
}
418

419 420 421 422 423 424 425 426 427 428 429 430
/**
 * Probe SPI flash by SFUD(Serial Flash Universal Driver) driver library and though SPI device.
 *
 * @param spi_flash_dev_name the name which will create SPI flash device
 * @param spi_dev_name using SPI device name
 *
 * @return probed SPI flash device, probe failed will return RT_NULL
 */
rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name)
{
    struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG;
#ifndef SFUD_USING_QSPI
431
    return rt_sfud_flash_probe_ex(spi_flash_dev_name, spi_dev_name, &cfg, RT_NULL);
432 433 434
#else
    struct rt_qspi_configuration qspi_cfg = RT_SFUD_DEFAULT_QSPI_CFG;

435
    return rt_sfud_flash_probe_ex(spi_flash_dev_name, spi_dev_name, &cfg, &qspi_cfg);
436 437 438
#endif
}

439 440 441 442 443 444 445 446 447
/**
 * Delete SPI flash device
 *
 * @param spi_flash_dev SPI flash device
 *
 * @return the operation status, RT_EOK on successful
 */
rt_err_t rt_sfud_flash_delete(rt_spi_flash_device_t spi_flash_dev) {
    sfud_flash *sfud_flash_dev = (sfud_flash *) (spi_flash_dev->user_data);
448

449 450 451 452 453 454 455 456 457 458 459
    RT_ASSERT(spi_flash_dev);
    RT_ASSERT(sfud_flash_dev);

    rt_device_unregister(&(spi_flash_dev->flash_device));

    rt_mutex_detach(&(spi_flash_dev->lock));

    rt_free(sfud_flash_dev->spi.name);
    rt_free(sfud_flash_dev->name);
    rt_free(sfud_flash_dev);
    rt_free(spi_flash_dev);
460 461 462 463

    return RT_EOK;
}

464 465 466 467 468
sfud_flash_t rt_sfud_flash_find(const char *spi_dev_name)
{
    rt_spi_flash_device_t  rtt_dev       = RT_NULL;
    struct rt_spi_device  *rt_spi_device = RT_NULL;
    sfud_flash_t           sfud_dev      = RT_NULL;
469

470
    rt_spi_device = (struct rt_spi_device *) rt_device_find(spi_dev_name);
471
    if (rt_spi_device == RT_NULL || rt_spi_device->parent.type != RT_Device_Class_SPIDevice) {
472
        LOG_E("ERROR: SPI device %s not found!", spi_dev_name);
473
        goto __error;
474 475
    }

476 477 478
    rtt_dev = (rt_spi_flash_device_t) (rt_spi_device->user_data);
    if (rtt_dev && rtt_dev->user_data) {
        sfud_dev = (sfud_flash_t) (rtt_dev->user_data);
479
        return sfud_dev;
480
    } else {
481
        LOG_E("ERROR: SFUD flash device not found!");
482
        goto __error;
483
    }
484 485 486 487 488 489 490 491 492 493 494 495

__error:
    return RT_NULL;
}

sfud_flash_t rt_sfud_flash_find_by_dev_name(const char *flash_dev_name)
{
    rt_spi_flash_device_t  rtt_dev       = RT_NULL;
    sfud_flash_t           sfud_dev      = RT_NULL;

    rtt_dev = (rt_spi_flash_device_t) rt_device_find(flash_dev_name);
    if (rtt_dev == RT_NULL || rtt_dev->flash_device.type != RT_Device_Class_Block) {
496
        LOG_E("ERROR: Flash device %s not found!", flash_dev_name);
497 498 499 500 501 502 503
        goto __error;
    }

    if (rtt_dev->user_data) {
        sfud_dev = (sfud_flash_t) (rtt_dev->user_data);
        return sfud_dev;
    } else {
504
        LOG_E("ERROR: SFUD flash device not found!");
505
        goto __error;
506 507
    }

508
__error:
509 510 511
    return RT_NULL;
}

马志远 已提交
512
#if defined(RT_USING_FINSH)
513 514 515 516 517

#include <finsh.h>

static void sf(uint8_t argc, char **argv) {

518 519
#define __is_print(ch)                ((unsigned int)((ch) - ' ') < 127u - ' ')
#define HEXDUMP_WIDTH                 16
armink_ztl's avatar
armink_ztl 已提交
520
#define CMD_PROBE_INDEX               0
521 522 523 524 525 526 527
#define CMD_READ_INDEX                1
#define CMD_WRITE_INDEX               2
#define CMD_ERASE_INDEX               3
#define CMD_RW_STATUS_INDEX           4
#define CMD_BENCH_INDEX               5

    sfud_err result = SFUD_SUCCESS;
528 529
    static const sfud_flash *sfud_dev = NULL;
    static rt_spi_flash_device_t rtt_dev = NULL, rtt_dev_bak = NULL;
530
    size_t i = 0, j = 0;
531 532

    const char* sf_help_info[] = {
armink_ztl's avatar
armink_ztl 已提交
533
            [CMD_PROBE_INDEX]     = "sf probe [spi_device]           - probe and init SPI flash by given 'spi_device'",
534 535 536 537
            [CMD_READ_INDEX]      = "sf read addr size               - read 'size' bytes starting at 'addr'",
            [CMD_WRITE_INDEX]     = "sf write addr data1 ... dataN   - write some bytes 'data' to flash starting at 'addr'",
            [CMD_ERASE_INDEX]     = "sf erase addr size              - erase 'size' bytes starting at 'addr'",
            [CMD_RW_STATUS_INDEX] = "sf status [<volatile> <status>] - read or write '1:volatile|0:non-volatile' 'status'",
538
            [CMD_BENCH_INDEX]     = "sf bench                        - full chip benchmark. DANGER: It will erase full chip!",
539 540 541 542 543 544 545 546 547 548 549 550
    };

    if (argc < 2) {
        rt_kprintf("Usage:\n");
        for (i = 0; i < sizeof(sf_help_info) / sizeof(char*); i++) {
            rt_kprintf("%s\n", sf_help_info[i]);
        }
        rt_kprintf("\n");
    } else {
        const char *operator = argv[1];
        uint32_t addr, size;

551
        if (!strcmp(operator, "probe")) {
552
            if (argc < 3) {
armink_ztl's avatar
armink_ztl 已提交
553
                rt_kprintf("Usage: %s.\n", sf_help_info[CMD_PROBE_INDEX]);
554
            } else {
555 556
                char *spi_dev_name = argv[2];
                rtt_dev_bak = rtt_dev;
557

558 559 560 561
                /* delete the old SPI flash device */
                if(rtt_dev_bak) {
                    rt_sfud_flash_delete(rtt_dev_bak);
                }
562

563 564
                rtt_dev = rt_sfud_flash_probe("sf_cmd", spi_dev_name);
                if (!rtt_dev) {
565 566
                    return;
                }
567

568 569 570
                sfud_dev = (sfud_flash_t)rtt_dev->user_data;
                if (sfud_dev->chip.capacity < 1024 * 1024) {
                    rt_kprintf("%d KB %s is current selected device.\n", sfud_dev->chip.capacity / 1024, sfud_dev->name);
571
                } else {
572 573
                    rt_kprintf("%d MB %s is current selected device.\n", sfud_dev->chip.capacity / 1024 / 1024,
                            sfud_dev->name);
574 575 576
                }
            }
        } else {
577 578
            if (!sfud_dev) {
                rt_kprintf("No flash device selected. Please run 'sf probe'.\n");
579 580 581 582 583 584 585
                return;
            }
            if (!rt_strcmp(operator, "read")) {
                if (argc < 4) {
                    rt_kprintf("Usage: %s.\n", sf_help_info[CMD_READ_INDEX]);
                    return;
                } else {
586 587
                    addr = strtol(argv[2], NULL, 0);
                    size = strtol(argv[3], NULL, 0);
588 589
                    uint8_t *data = rt_malloc(size);
                    if (data) {
590
                        result = sfud_read(sfud_dev, addr, size, data);
591 592
                        if (result == SFUD_SUCCESS) {
                            rt_kprintf("Read the %s flash data success. Start from 0x%08X, size is %ld. The data is:\n",
593
                                    sfud_dev->name, addr, size);
594
                            rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
595 596 597 598 599 600 601 602 603 604
                            for (i = 0; i < size; i += HEXDUMP_WIDTH)
                            {
                                rt_kprintf("[%08X] ", addr + i);
                                /* dump hex */
                                for (j = 0; j < HEXDUMP_WIDTH; j++) {
                                    if (i + j < size) {
                                        rt_kprintf("%02X ", data[i + j]);
                                    } else {
                                        rt_kprintf("   ");
                                    }
605
                                }
606 607 608 609 610
                                /* dump char for hex */
                                for (j = 0; j < HEXDUMP_WIDTH; j++) {
                                    if (i + j < size) {
                                        rt_kprintf("%c", __is_print(data[i + j]) ? data[i + j] : '.');
                                    }
611
                                }
612
                                rt_kprintf("\n");
613 614 615 616 617 618 619 620 621 622 623 624 625
                            }
                            rt_kprintf("\n");
                        }
                        rt_free(data);
                    } else {
                        rt_kprintf("Low memory!\n");
                    }
                }
            } else if (!rt_strcmp(operator, "write")) {
                if (argc < 4) {
                    rt_kprintf("Usage: %s.\n", sf_help_info[CMD_WRITE_INDEX]);
                    return;
                } else {
626
                    addr = strtol(argv[2], NULL, 0);
627 628 629 630
                    size = argc - 3;
                    uint8_t *data = rt_malloc(size);
                    if (data) {
                        for (i = 0; i < size; i++) {
631
                            data[i] = strtol(argv[3 + i], NULL, 0);
632
                        }
633
                        result = sfud_write(sfud_dev, addr, size, data);
634 635
                        if (result == SFUD_SUCCESS) {
                            rt_kprintf("Write the %s flash data success. Start from 0x%08X, size is %ld.\n",
636
                                    sfud_dev->name, addr, size);
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
                            rt_kprintf("Write data: ");
                            for (i = 0; i < size; i++) {
                                rt_kprintf("%d ", data[i]);
                            }
                            rt_kprintf(".\n");
                        }
                        rt_free(data);
                    } else {
                        rt_kprintf("Low memory!\n");
                    }
                }
            } else if (!rt_strcmp(operator, "erase")) {
                if (argc < 4) {
                    rt_kprintf("Usage: %s.\n", sf_help_info[CMD_ERASE_INDEX]);
                    return;
                } else {
653 654
                    addr = strtol(argv[2], NULL, 0);
                    size = strtol(argv[3], NULL, 0);
655
                    result = sfud_erase(sfud_dev, addr, size);
656
                    if (result == SFUD_SUCCESS) {
657
                        rt_kprintf("Erase the %s flash data success. Start from 0x%08X, size is %ld.\n", sfud_dev->name,
658 659 660 661 662 663
                                addr, size);
                    }
                }
            } else if (!rt_strcmp(operator, "status")) {
                if (argc < 3) {
                    uint8_t status;
664
                    result = sfud_read_status(sfud_dev, &status);
665
                    if (result == SFUD_SUCCESS) {
666
                        rt_kprintf("The %s flash status register current value is 0x%02X.\n", sfud_dev->name, status);
667 668
                    }
                } else if (argc == 4) {
669 670
                    bool is_volatile = strtol(argv[2], NULL, 0);
                    uint8_t status = strtol(argv[3], NULL, 0);
671
                    result = sfud_write_status(sfud_dev, is_volatile, status);
672
                    if (result == SFUD_SUCCESS) {
673
                        rt_kprintf("Write the %s flash status register to 0x%02X success.\n", sfud_dev->name, status);
674 675 676 677 678 679
                    }
                } else {
                    rt_kprintf("Usage: %s.\n", sf_help_info[CMD_RW_STATUS_INDEX]);
                    return;
                }
            } else if (!rt_strcmp(operator, "bench")) {
680
                if ((argc > 2 && rt_strcmp(argv[2], "yes")) || argc < 3) {
681
                    rt_kprintf("DANGER: It will erase full chip! Please run 'sf bench yes'.\n");
682 683
                    return;
                }
684 685
                /* full chip benchmark test */
                addr = 0;
686
                size = sfud_dev->chip.capacity;
687
                uint32_t start_time, time_cast;
688
                size_t write_size = SFUD_WRITE_MAX_PAGE_SIZE, read_size = SFUD_WRITE_MAX_PAGE_SIZE, cur_op_size;
689 690 691
                uint8_t *write_data = rt_malloc(write_size), *read_data = rt_malloc(read_size);

                if (write_data && read_data) {
692 693 694
                    for (i = 0; i < write_size; i ++) {
                        write_data[i] = i & 0xFF;
                    }
695
                    /* benchmark testing */
696
                    rt_kprintf("Erasing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
697
                    start_time = rt_tick_get();
698
                    result = sfud_erase(sfud_dev, addr, size);
699 700 701 702 703 704 705 706
                    if (result == SFUD_SUCCESS) {
                        time_cast = rt_tick_get() - start_time;
                        rt_kprintf("Erase benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
                                time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
                    } else {
                        rt_kprintf("Erase benchmark has an error. Error code: %d.\n", result);
                    }
                    /* write test */
707
                    rt_kprintf("Writing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
708 709
                    start_time = rt_tick_get();
                    for (i = 0; i < size; i += write_size) {
710 711 712 713 714 715
                        if (i + write_size <= size) {
                            cur_op_size = write_size;
                        } else {
                            cur_op_size = size - i;
                        }
                        result = sfud_write(sfud_dev, addr + i, cur_op_size, write_data);
716
                        if (result != SFUD_SUCCESS) {
717
                            rt_kprintf("Writing %s failed, already wr for %lu bytes, write %d each time\n", sfud_dev->name, i, write_size);
718 719 720 721 722 723 724 725 726 727 728
                            break;
                        }
                    }
                    if (result == SFUD_SUCCESS) {
                        time_cast = rt_tick_get() - start_time;
                        rt_kprintf("Write benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
                                time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
                    } else {
                        rt_kprintf("Write benchmark has an error. Error code: %d.\n", result);
                    }
                    /* read test */
729
                    rt_kprintf("Reading the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
730 731 732
                    start_time = rt_tick_get();
                    for (i = 0; i < size; i += read_size) {
                        if (i + read_size <= size) {
733
                            cur_op_size = read_size;
734
                        } else {
735
                            cur_op_size = size - i;
736
                        }
737
                        result = sfud_read(sfud_dev, addr + i, cur_op_size, read_data);
H
HubretXie 已提交
738
                        /* data check */
739
                        if (memcmp(write_data, read_data, cur_op_size))
H
HubretXie 已提交
740 741 742 743
                        {
                            rt_kprintf("Data check ERROR! Please check you flash by other command.\n");
                            result = SFUD_ERR_READ;
                        }
744

745
                        if (result != SFUD_SUCCESS) {
746
                            rt_kprintf("Read %s failed, already rd for %lu bytes, read %d each time\n", sfud_dev->name, i, read_size);
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
                            break;
                        }
                    }
                    if (result == SFUD_SUCCESS) {
                        time_cast = rt_tick_get() - start_time;
                        rt_kprintf("Read benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
                                time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
                    } else {
                        rt_kprintf("Read benchmark has an error. Error code: %d.\n", result);
                    }
                } else {
                    rt_kprintf("Low memory!\n");
                }
                rt_free(write_data);
                rt_free(read_data);
            } else {
                rt_kprintf("Usage:\n");
                for (i = 0; i < sizeof(sf_help_info) / sizeof(char*); i++) {
                    rt_kprintf("%s\n", sf_help_info[i]);
                }
                rt_kprintf("\n");
                return;
            }
            if (result != SFUD_SUCCESS) {
                rt_kprintf("This flash operate has an error. Error code: %d.\n", result);
            }
        }
    }
}
MSH_CMD_EXPORT(sf, SPI Flash operate.);
马志远 已提交
777
#endif /* defined(RT_USING_FINSH) */
778 779

#endif /* RT_USING_SFUD */