diff --git a/components/drivers/spi/sfud/inc/sfud.h b/components/drivers/spi/sfud/inc/sfud.h index be1ccb208eb63a0ff1a62f786458e0e61c86b586..2b68c38216f707f8d20ae007529ec74c4e769ef4 100644 --- a/components/drivers/spi/sfud/inc/sfud.h +++ b/components/drivers/spi/sfud/inc/sfud.h @@ -1,7 +1,7 @@ /* * This file is part of the Serial Flash Universal Driver Library. * - * Copyright (c) 2016, Armink, + * Copyright (c) 2016-2018, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -75,6 +75,23 @@ size_t sfud_get_device_num(void); */ const sfud_flash *sfud_get_device_table(void); +#ifdef SFUD_USING_QSPI +/** + * Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode. + * + * it will find the appropriate fast-read instruction to replace the read instruction(0x03) + * fast-read instruction @see SFUD_FLASH_EXT_INFO_TABLE + * + * @note When Flash is in QSPI mode, the method must be called after sfud_device_init(). + * + * @param flash flash device + * @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4 + * + * @return result + */ +sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width); +#endif /* SFUD_USING_QSPI */ + /** * read flash data * diff --git a/components/drivers/spi/sfud/inc/sfud_cfg.h b/components/drivers/spi/sfud/inc/sfud_cfg.h index 59189a9693da402949a0ce0e356f2cf03b7aac23..051de6d577fa943a55e75262b6fce4127b81add4 100644 --- a/components/drivers/spi/sfud/inc/sfud_cfg.h +++ b/components/drivers/spi/sfud/inc/sfud_cfg.h @@ -45,6 +45,13 @@ #define SFUD_USING_SFDP #endif +/** + * SFUD will support QSPI mode. + */ +#ifdef RT_SFUD_USING_QSPI +#define SFUD_USING_QSPI +#endif + /** * Using probe flash JEDEC ID then query defined supported flash chip information table. @see SFUD_FLASH_CHIP_TABLE */ diff --git a/components/drivers/spi/sfud/inc/sfud_def.h b/components/drivers/spi/sfud/inc/sfud_def.h index 1b0e8a3986331f3d6cd2e533fecf51f348df0859..fe7876618ba6b55362fe735b5c7a5d3f765ab07a 100644 --- a/components/drivers/spi/sfud/inc/sfud_def.h +++ b/components/drivers/spi/sfud/inc/sfud_def.h @@ -1,7 +1,7 @@ /* * This file is part of the Serial Flash Universal Driver Library. * - * Copyright (c) 2016, Armink, + * Copyright (c) 2016-2018, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -78,7 +78,7 @@ if (!(EXPR)) \ else {if (__delay_temp) {__delay_temp();} retry --;} /* software version number */ -#define SFUD_SW_VERSION "1.0.6" +#define SFUD_SW_VERSION "1.1.0" /* * all defined supported command */ @@ -118,6 +118,22 @@ if (!(EXPR)) \ #define SFUD_CMD_READ_DATA 0x03 #endif +#ifndef SFUD_CMD_DUAL_OUTPUT_READ_DATA +#define SFUD_CMD_DUAL_OUTPUT_READ_DATA 0x3B +#endif + +#ifndef SFUD_CMD_DUAL_IO_READ_DATA +#define SFUD_CMD_DUAL_IO_READ_DATA 0xBB +#endif + +#ifndef SFUD_CMD_QUAD_IO_READ_DATA +#define SFUD_CMD_QUAD_IO_READ_DATA 0xEB +#endif + +#ifndef SFUD_CMD_QUAD_OUTPUT_READ_DATA +#define SFUD_CMD_QUAD_OUTPUT_READ_DATA 0x6B +#endif + #ifndef SFUD_CMD_MANUFACTURER_DEVICE_ID #define SFUD_CMD_MANUFACTURER_DEVICE_ID 0x90 #endif @@ -183,6 +199,21 @@ typedef enum { SFUD_ERR_ADDR_OUT_OF_BOUND = 5, /**< address is out of flash bound */ } sfud_err; +#ifdef SFUD_USING_QSPI +/** + * QSPI flash read cmd format + */ +typedef struct { + uint8_t instruction; + uint8_t instruction_lines; + uint8_t address_size; + uint8_t address_lines; + uint8_t alternate_bytes_lines; + uint8_t dummy_cycles; + uint8_t data_lines; +} sfud_qspi_read_cmd_format; +#endif /* SFUD_USING_QSPI */ + /* SPI bus write read data function type */ typedef sfud_err (*spi_write_read_func)(const uint8_t *write_buf, size_t write_size, uint8_t *read_buf, size_t read_size); @@ -218,7 +249,12 @@ typedef struct __sfud_spi { char *name; /* SPI bus write read data function */ sfud_err (*wr)(const struct __sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf, - size_t read_size); + size_t read_size); +#ifdef SFUD_USING_QSPI + /* QSPI fast read function */ + 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); +#endif /* lock SPI bus */ void (*lock)(const struct __sfud_spi *spi); /* unlock SPI bus */ @@ -243,6 +279,10 @@ typedef struct { } retry; void *user_data; /**< some user data */ +#ifdef SFUD_USING_QSPI + sfud_qspi_read_cmd_format read_cmd_format; /**< fast read cmd format */ +#endif + #ifdef SFUD_USING_SFDP sfud_sfdp sfdp; /**< serial flash discoverable parameters by JEDEC standard */ #endif diff --git a/components/drivers/spi/sfud/inc/sfud_flash_def.h b/components/drivers/spi/sfud/inc/sfud_flash_def.h index 2022a043b2fe7f70c287d10995e9b4d3390a70de..89223755573b87a422d633f2bef934e5d35f2a12 100644 --- a/components/drivers/spi/sfud/inc/sfud_flash_def.h +++ b/components/drivers/spi/sfud/inc/sfud_flash_def.h @@ -1,7 +1,7 @@ /* * This file is part of the Serial Flash Universal Driver Library. * - * Copyright (c) 2016-2017, Armink, + * Copyright (c) 2016-2018, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -59,11 +59,21 @@ typedef struct { uint8_t type_id; /**< memory type ID */ uint8_t capacity_id; /**< capacity ID */ uint32_t capacity; /**< flash capacity (bytes) */ - uint16_t write_mode; /**< write mode @see sfud_write_mode */ + uint16_t write_mode; /**< write mode @see sfud_write_mode */ uint32_t erase_gran; /**< erase granularity (bytes) */ uint8_t erase_gran_cmd; /**< erase granularity size block command */ } sfud_flash_chip; +#ifdef SFUD_USING_QSPI +/* QSPI flash chip's extended information compared with SPI flash */ +typedef struct { + uint8_t mf_id; /**< manufacturer ID */ + uint8_t type_id; /**< memory type ID */ + uint8_t capacity_id; /**< capacity ID */ + uint8_t read_mode; /**< supported read mode on this qspi flash chip */ +} sfud_qspi_flash_ext_info; +#endif + /* SFUD support manufacturer JEDEC ID */ #define SFUD_MF_ID_CYPRESS 0x01 #define SFUD_MF_ID_FUJITSU 0x04 @@ -131,6 +141,42 @@ typedef struct { } #endif /* SFUD_USING_FLASH_INFO_TABLE */ +#ifdef SFUD_USING_QSPI +/* This table saves flash read-fast instructions in QSPI mode, + * SFUD can use this table to select the most appropriate read instruction for flash. + * | mf_id | type_id | capacity_id | qspi_read_mode | + */ +#define SFUD_FLASH_EXT_INFO_TABLE \ +{ \ + /* W25Q40BV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x13, NORMAL_SPI_READ|DUAL_OUTPUT}, \ + /* W25Q80JV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x14, NORMAL_SPI_READ|DUAL_OUTPUT}, \ + /* W25Q16BV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x15, NORMAL_SPI_READ|DUAL_OUTPUT}, \ + /* W25Q32BV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT}, \ + /* W25Q64JV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \ + /* W25Q128JV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x18, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \ + /* W25Q256FV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x19, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \ + /* EN25Q32B */ \ + {SFUD_MF_ID_EON, 0x30, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT|QUAD_IO}, \ + /* S25FL216K */ \ + {SFUD_MF_ID_CYPRESS, 0x40, 0x15, NORMAL_SPI_READ|DUAL_OUTPUT}, \ + /* A25L080 */ \ + {SFUD_MF_ID_AMIC, 0x30, 0x14, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO}, \ + /* A25LQ64 */ \ + {SFUD_MF_ID_AMIC, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_IO}, \ + /* MX25L3206E and KH25L3206E */ \ + {SFUD_MF_ID_MICRONIX, 0x20, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT}, \ + /* GD25Q64B */ \ + {SFUD_MF_ID_GIGADEVICE, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT}, \ +} +#endif /* SFUD_USING_QSPI */ + #ifdef __cplusplus } #endif diff --git a/components/drivers/spi/sfud/src/sfud.c b/components/drivers/spi/sfud/src/sfud.c index e3376555ca909f192a5180b5bfa720847c9845f4..e22870333616112ae90c481ca326a9a40f911d61 100644 --- a/components/drivers/spi/sfud/src/sfud.c +++ b/components/drivers/spi/sfud/src/sfud.c @@ -1,7 +1,7 @@ /* * This file is part of the Serial Flash Universal Driver Library. * - * Copyright (c) 2016, Armink, + * Copyright (c) 2016-2018, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -46,6 +46,22 @@ static const sfud_mf mf_table[] = SFUD_MF_TABLE; static const sfud_flash_chip flash_chip_table[] = SFUD_FLASH_CHIP_TABLE; #endif +#ifdef SFUD_USING_QSPI +/** + * flash read data mode + */ +enum sfud_qspi_read_mode { + NORMAL_SPI_READ = 1 << 0, /**< mormal spi read mode */ + DUAL_OUTPUT = 1 << 1, /**< qspi fast read dual output */ + DUAL_IO = 1 << 2, /**< qspi fast read dual input/output */ + QUAD_OUTPUT = 1 << 3, /**< qspi fast read quad output */ + QUAD_IO = 1 << 4, /**< qspi fast read quad input/output */ +}; + +/* QSPI flash chip's extended information table */ +static const sfud_qspi_flash_ext_info qspi_flash_ext_info_table[] = SFUD_FLASH_EXT_INFO_TABLE; +#endif /* SFUD_USING_QSPI */ + static sfud_err software_init(const sfud_flash *flash); static sfud_err hardware_init(sfud_flash *flash); static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran, @@ -146,11 +162,89 @@ const sfud_flash *sfud_get_device_table(void) { return flash_table; } +#ifdef SFUD_USING_QSPI +static void qspi_set_read_cmd_format(sfud_flash *flash, uint8_t ins, uint8_t ins_lines, uint8_t addr_lines, + uint8_t dummy_cycles, uint8_t data_lines) { + /* if medium size greater than 16Mb, use 4-Byte address, instruction should be added one */ + if (flash->chip.capacity <= 0x1000000) { + flash->read_cmd_format.instruction = ins; + flash->read_cmd_format.address_size = 24; + } else { + flash->read_cmd_format.instruction = ins + 1; + flash->read_cmd_format.address_size = 32; + } + + flash->read_cmd_format.instruction_lines = ins_lines; + flash->read_cmd_format.address_lines = addr_lines; + flash->read_cmd_format.alternate_bytes_lines = 0; + flash->read_cmd_format.dummy_cycles = dummy_cycles; + flash->read_cmd_format.data_lines = data_lines; +} + +/** + * Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode. + * + * it will find the appropriate fast-read instruction to replace the read instruction(0x03) + * fast-read instruction @see SFUD_FLASH_EXT_INFO_TABLE + * + * @note When Flash is in QSPI mode, the method must be called after sfud_device_init(). + * + * @param flash flash device + * @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4 + * + * @return result + */ +sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width) { + size_t i = 0; + uint8_t read_mode = NORMAL_SPI_READ; + sfud_err result = SFUD_SUCCESS; + + SFUD_ASSERT(flash); + SFUD_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4); + + /* get read_mode, If don't found, the default is SFUD_QSPI_NORMAL_SPI_READ */ + for (i = 0; i < sizeof(qspi_flash_ext_info_table) / sizeof(sfud_qspi_flash_ext_info); i++) { + if ((qspi_flash_ext_info_table[i].mf_id == flash->chip.mf_id) + && (qspi_flash_ext_info_table[i].type_id == flash->chip.type_id) + && (qspi_flash_ext_info_table[i].capacity_id == flash->chip.capacity_id)) { + read_mode = qspi_flash_ext_info_table[i].read_mode; + } + } + + /* determine qspi supports which read mode and set read_cmd_format struct */ + switch (data_line_width) { + case 1: + qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1); + break; + case 2: + if (read_mode & DUAL_IO) { + qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_IO_READ_DATA, 1, 2, 8, 2); + } else if (read_mode & DUAL_OUTPUT) { + qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_OUTPUT_READ_DATA, 1, 1, 8, 2); + } else { + qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1); + } + break; + case 4: + if (read_mode & QUAD_IO) { + qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_IO_READ_DATA, 1, 4, 6, 4); + } else if (read_mode & QUAD_OUTPUT) { + qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_OUTPUT_READ_DATA, 1, 1, 8, 4); + } else { + qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1); + } + break; + } + + return result; +} +#endif /* SFUD_USING_QSPI */ + /** * hardware initialize */ static sfud_err hardware_init(sfud_flash *flash) { - extern sfud_err sfud_spi_port_init(sfud_flash *flash); + extern sfud_err sfud_spi_port_init(sfud_flash * flash); sfud_err result = SFUD_SUCCESS; size_t i; @@ -162,6 +256,9 @@ static sfud_err hardware_init(sfud_flash *flash) { return result; } + /* set default read instruction */ + flash->read_cmd_format.instruction = SFUD_CMD_READ_DATA; + /* SPI write read function must be initialize */ SFUD_ASSERT(flash->spi.wr); /* if the user don't configure flash chip information then using SFDP parameter or static flash parameter table */ @@ -315,10 +412,17 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t result = wait_busy(flash); if (result == SFUD_SUCCESS) { - cmd_data[0] = SFUD_CMD_READ_DATA; - make_adress_byte_array(flash, addr, &cmd_data[1]); - cmd_size = flash->addr_in_4_byte ? 5 : 4; - result = spi->wr(spi, cmd_data, cmd_size, data, size); +#ifdef SFUD_USING_QSPI + if (flash->read_cmd_format.instruction != SFUD_CMD_READ_DATA) { + result = spi->qspi_read(spi, addr, (sfud_qspi_read_cmd_format *)&flash->read_cmd_format, data, size); + } else +#endif + { + cmd_data[0] = SFUD_CMD_READ_DATA; + make_adress_byte_array(flash, addr, &cmd_data[1]); + cmd_size = flash->addr_in_4_byte ? 5 : 4; + result = spi->wr(spi, cmd_data, cmd_size, data, size); + } } /* unlock SPI */ if (spi->unlock) { @@ -328,7 +432,6 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t return result; } - /** * erase all flash data * @@ -715,8 +818,16 @@ static sfud_err reset(const sfud_flash *flash) { SFUD_ASSERT(flash); cmd_data[0] = SFUD_CMD_ENABLE_RESET; + result = spi->wr(spi, cmd_data, 1, NULL, 0); + if (result == SFUD_SUCCESS) { + result = wait_busy(flash); + } else { + SFUD_INFO("Error: Flash device reset failed."); + return result; + } + cmd_data[1] = SFUD_CMD_RESET; - result = spi->wr(spi, cmd_data, 2, NULL, 0); + result = spi->wr(spi, &cmd_data[1], 1, NULL, 0); if (result == SFUD_SUCCESS) { result = wait_busy(flash);