Merge branch 'feature/esp_flash_32b_addr' into 'master'

esp_flash: support high capacity flash chips (32-bit address)

See merge request espressif/esp-idf!9475
This commit is contained in:
Michael (XIAO Xufeng)
2020-10-30 15:22:44 +08:00
40 changed files with 850 additions and 244 deletions

View File

@@ -316,17 +316,18 @@ static inline void spi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitlen)
} }
/** /**
* Set the command with fixed length (8 bits). * Set the command.
* *
* @param dev Beginning address of the peripheral registers. * @param dev Beginning address of the peripheral registers.
* @param command Command to send * @param command Command to send
* @param bitlen Length of the command
*/ */
static inline void spi_flash_ll_set_command8(spi_dev_t *dev, uint8_t command) static inline void spi_flash_ll_set_command(spi_dev_t *dev, uint8_t command, uint32_t bitlen)
{ {
dev->user.usr_command = 1; dev->user.usr_command = 1;
typeof(dev->user2) user2 = { typeof(dev->user2) user2 = {
.usr_command_value = command, .usr_command_value = command,
.usr_command_bitlen = (8 - 1), .usr_command_bitlen = (bitlen - 1),
}; };
dev->user2 = user2; dev->user2 = user2;
} }
@@ -362,7 +363,14 @@ static inline void spi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitlen)
*/ */
static inline void spi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, int bit_len) static inline void spi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, int bit_len)
{ {
dev->addr = (addr << (32 - bit_len)); // The blank region should be all ones
if (bit_len >= 32) {
dev->addr = addr;
dev->slv_wr_status = UINT32_MAX;
} else {
uint32_t padding_ones = (bit_len == 32? 0 : UINT32_MAX >> bit_len);
dev->addr = (addr << (32 - bit_len)) | padding_ones;
}
} }
/** /**
@@ -388,6 +396,12 @@ static inline void spi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n)
dev->user1.usr_dummy_cyclelen = dummy_n - 1; dev->user1.usr_dummy_cyclelen = dummy_n - 1;
} }
static inline void spi_flash_ll_set_hold(spi_dev_t *dev, uint32_t hold_n)
{
dev->ctrl2.hold_time = hold_n;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -275,17 +275,18 @@ static inline void gpspi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitle
} }
/** /**
* Set the command with fixed length (8 bits). * Set the command.
* *
* @param dev Beginning address of the peripheral registers. * @param dev Beginning address of the peripheral registers.
* @param command Command to send * @param command Command to send
* @param bitlen Length of the command
*/ */
static inline void gpspi_flash_ll_set_command8(spi_dev_t *dev, uint8_t command) static inline void gpspi_flash_ll_set_command(spi_dev_t *dev, uint8_t command, uint32_t bitlen)
{ {
dev->user.usr_command = 1; dev->user.usr_command = 1;
typeof(dev->user2) user2 = { typeof(dev->user2) user2 = {
.usr_command_value = command, .usr_command_value = command,
.usr_command_bitlen = (8 - 1), .usr_command_bitlen = (bitlen - 1),
}; };
dev->user2 = user2; dev->user2 = user2;
} }
@@ -321,7 +322,9 @@ static inline void gpspi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitle
*/ */
static inline void gpspi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, uint32_t bitlen) static inline void gpspi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, uint32_t bitlen)
{ {
dev->addr = (addr << (32 - bitlen)); // The blank region should be all ones
uint32_t padding_ones = (bitlen == 32? 0 : UINT32_MAX >> bitlen);
dev->addr = (addr << (32 - bitlen)) | padding_ones;
} }
/** /**
@@ -361,6 +364,12 @@ static inline void gpspi_flash_ll_set_dummy_out(spi_dev_t *dev, uint32_t out_en,
dev->ctrl.d_pol = out_lev; dev->ctrl.d_pol = out_lev;
} }
static inline void gpspi_flash_ll_set_hold(spi_dev_t *dev, uint32_t hold_n)
{
dev->ctrl2.cs_hold_time = hold_n - 1;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -54,6 +54,7 @@ typedef union {
} spi_flash_ll_clock_reg_t; } spi_flash_ll_clock_reg_t;
#ifdef GPSPI_BUILD #ifdef GPSPI_BUILD
#define spi_flash_ll_reset(dev) gpspi_flash_ll_reset((spi_dev_t*)dev) #define spi_flash_ll_reset(dev) gpspi_flash_ll_reset((spi_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) gpspi_flash_ll_cmd_is_done((spi_dev_t*)dev) #define spi_flash_ll_cmd_is_done(dev) gpspi_flash_ll_cmd_is_done((spi_dev_t*)dev)
#define spi_flash_ll_get_buffer_data(dev, buffer, read_len) gpspi_flash_ll_get_buffer_data((spi_dev_t*)dev, buffer, read_len) #define spi_flash_ll_get_buffer_data(dev, buffer, read_len) gpspi_flash_ll_get_buffer_data((spi_dev_t*)dev, buffer, read_len)
@@ -66,14 +67,17 @@ typedef union {
#define spi_flash_ll_set_clock(dev, clk) gpspi_flash_ll_set_clock((spi_dev_t*)dev, (gpspi_flash_ll_clock_reg_t*)clk) #define spi_flash_ll_set_clock(dev, clk) gpspi_flash_ll_set_clock((spi_dev_t*)dev, (gpspi_flash_ll_clock_reg_t*)clk)
#define spi_flash_ll_set_miso_bitlen(dev, bitlen) gpspi_flash_ll_set_miso_bitlen((spi_dev_t*)dev, bitlen) #define spi_flash_ll_set_miso_bitlen(dev, bitlen) gpspi_flash_ll_set_miso_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) gpspi_flash_ll_set_mosi_bitlen((spi_dev_t*)dev, bitlen) #define spi_flash_ll_set_mosi_bitlen(dev, bitlen) gpspi_flash_ll_set_mosi_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_set_command8(dev, cmd) gpspi_flash_ll_set_command8((spi_dev_t*)dev, cmd) #define spi_flash_ll_set_command(dev, cmd, bitlen) gpspi_flash_ll_set_command((spi_dev_t*)dev, cmd, bitlen)
#define spi_flash_ll_set_addr_bitlen(dev, bitlen) gpspi_flash_ll_set_addr_bitlen((spi_dev_t*)dev, bitlen) #define spi_flash_ll_set_addr_bitlen(dev, bitlen) gpspi_flash_ll_set_addr_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_get_addr_bitlen(dev) gpspi_flash_ll_get_addr_bitlen((spi_dev_t*)dev) #define spi_flash_ll_get_addr_bitlen(dev) gpspi_flash_ll_get_addr_bitlen((spi_dev_t*)dev)
#define spi_flash_ll_set_address(dev, addr) gpspi_flash_ll_set_address((spi_dev_t*)dev, addr) #define spi_flash_ll_set_address(dev, addr) gpspi_flash_ll_set_address((spi_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) gpspi_flash_ll_set_usr_address((spi_dev_t*)dev, addr, bitlen) #define spi_flash_ll_set_usr_address(dev, addr, bitlen) gpspi_flash_ll_set_usr_address((spi_dev_t*)dev, addr, bitlen)
#define spi_flash_ll_set_dummy(dev, dummy) gpspi_flash_ll_set_dummy((spi_dev_t*)dev, dummy) #define spi_flash_ll_set_dummy(dev, dummy) gpspi_flash_ll_set_dummy((spi_dev_t*)dev, dummy)
#define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev) #define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
#else #else
#define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev) #define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev) #define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
#define spi_flash_ll_erase_chip(dev) spimem_flash_ll_erase_chip((spi_mem_dev_t*)dev) #define spi_flash_ll_erase_chip(dev) spimem_flash_ll_erase_chip((spi_mem_dev_t*)dev)
@@ -91,13 +95,15 @@ typedef union {
#define spi_flash_ll_set_clock(dev, clk) spimem_flash_ll_set_clock((spi_mem_dev_t*)dev, (spimem_flash_ll_clock_reg_t*)clk) #define spi_flash_ll_set_clock(dev, clk) spimem_flash_ll_set_clock((spi_mem_dev_t*)dev, (spimem_flash_ll_clock_reg_t*)clk)
#define spi_flash_ll_set_miso_bitlen(dev, bitlen) spimem_flash_ll_set_miso_bitlen((spi_mem_dev_t*)dev, bitlen) #define spi_flash_ll_set_miso_bitlen(dev, bitlen) spimem_flash_ll_set_miso_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) spimem_flash_ll_set_mosi_bitlen((spi_mem_dev_t*)dev, bitlen) #define spi_flash_ll_set_mosi_bitlen(dev, bitlen) spimem_flash_ll_set_mosi_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_set_command8(dev, cmd) spimem_flash_ll_set_command8((spi_mem_dev_t*)dev, cmd) #define spi_flash_ll_set_command(dev, cmd, bitlen) spimem_flash_ll_set_command((spi_mem_dev_t*)dev, cmd, bitlen)
#define spi_flash_ll_set_addr_bitlen(dev, bitlen) spimem_flash_ll_set_addr_bitlen((spi_mem_dev_t*)dev, bitlen) #define spi_flash_ll_set_addr_bitlen(dev, bitlen) spimem_flash_ll_set_addr_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_get_addr_bitlen(dev) spimem_flash_ll_get_addr_bitlen((spi_mem_dev_t*) dev) #define spi_flash_ll_get_addr_bitlen(dev) spimem_flash_ll_get_addr_bitlen((spi_mem_dev_t*) dev)
#define spi_flash_ll_set_address(dev, addr) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr) #define spi_flash_ll_set_address(dev, addr) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr) #define spi_flash_ll_set_usr_address(dev, addr, bitlen) spimem_flash_ll_set_usr_address((spi_mem_dev_t*)dev, addr, bitlen)
#define spi_flash_ll_set_dummy(dev, dummy) spimem_flash_ll_set_dummy((spi_mem_dev_t*)dev, dummy) #define spi_flash_ll_set_dummy(dev, dummy) spimem_flash_ll_set_dummy((spi_mem_dev_t*)dev, dummy)
#define spi_flash_ll_set_dummy_out(dev, en, lev) spimem_flash_ll_set_dummy_out((spi_mem_dev_t*)dev, en, lev) #define spi_flash_ll_set_dummy_out(dev, en, lev) spimem_flash_ll_set_dummy_out((spi_mem_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -308,17 +308,18 @@ static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t
} }
/** /**
* Set the command with fixed length (8 bits). * Set the command.
* *
* @param dev Beginning address of the peripheral registers. * @param dev Beginning address of the peripheral registers.
* @param command Command to send * @param command Command to send
* @param bitlen Length of the command
*/ */
static inline void spimem_flash_ll_set_command8(spi_mem_dev_t *dev, uint8_t command) static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen)
{ {
dev->user.usr_command = 1; dev->user.usr_command = 1;
typeof(dev->user2) user2 = { typeof(dev->user2) user2 = {
.usr_command_value = command, .usr_command_value = command,
.usr_command_bitlen = (8 - 1), .usr_command_bitlen = (bitlen - 1),
}; };
dev->user2 = user2; dev->user2 = user2;
} }
@@ -357,6 +358,18 @@ static inline void spimem_flash_ll_set_address(spi_mem_dev_t *dev, uint32_t addr
dev->addr = addr; dev->addr = addr;
} }
/**
* Set the address to send in user mode. Should be called before commands that requires the address e.g. erase sector, read, write...
*
* @param dev Beginning address of the peripheral registers.
* @param addr Address to send
*/
static inline void spimem_flash_ll_set_usr_address(spi_mem_dev_t *dev, uint32_t addr, uint32_t bitlen)
{
(void)bitlen;
spimem_flash_ll_set_address(dev, addr);
}
/** /**
* Set the length of dummy cycles. * Set the length of dummy cycles.
* *
@@ -383,6 +396,13 @@ static inline void spimem_flash_ll_set_dummy_out(spi_mem_dev_t *dev, uint32_t ou
dev->ctrl.d_pol = out_lev; dev->ctrl.d_pol = out_lev;
} }
static inline void spimem_flash_ll_set_hold(spi_mem_dev_t *dev, uint32_t hold_n)
{
dev->ctrl2.cs_hold_time = hold_n - 1;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -57,7 +57,7 @@ typedef typeof(GPSPI2.clock) gpspi_flash_ll_clock_reg_t;
* Control * Control
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/** /**
* Reset peripheral registers before configuration and starting control * Reset peripheral registers before configuration and starting control.
* *
* @param dev Beginning address of the peripheral registers. * @param dev Beginning address of the peripheral registers.
*/ */
@@ -65,6 +65,15 @@ static inline void gpspi_flash_ll_reset(spi_dev_t *dev)
{ {
dev->user.val = 0; dev->user.val = 0;
dev->ctrl.val = 0; dev->ctrl.val = 0;
dev->clk_gate.clk_en = 1;
dev->clk_gate.mst_clk_active = 1;
dev->clk_gate.mst_clk_sel = 1;
dev->dma_conf.val = 0;
dev->dma_conf.tx_seg_trans_clr_en = 1;
dev->dma_conf.rx_seg_trans_clr_en = 1;
dev->dma_conf.dma_seg_trans_en = 0;
} }
/** /**
@@ -144,6 +153,8 @@ static inline void gpspi_flash_ll_set_buffer_data(spi_dev_t *dev, const void *bu
*/ */
static inline void gpspi_flash_ll_user_start(spi_dev_t *dev) static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
{ {
dev->cmd.update = 1;
while (dev->cmd.update);
dev->cmd.usr = 1; dev->cmd.usr = 1;
} }
@@ -156,7 +167,7 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
*/ */
static inline bool gpspi_flash_ll_host_idle(const spi_dev_t *dev) static inline bool gpspi_flash_ll_host_idle(const spi_dev_t *dev)
{ {
return false; return dev->cmd.usr == 0;
} }
/** /**
@@ -203,10 +214,10 @@ static inline void gpspi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_io_mod
ctrl.val &= ~(SPI_FCMD_QUAD_M | SPI_FADDR_QUAD_M | SPI_FREAD_QUAD_M | SPI_FCMD_DUAL_M | SPI_FADDR_DUAL_M | SPI_FREAD_DUAL_M); ctrl.val &= ~(SPI_FCMD_QUAD_M | SPI_FADDR_QUAD_M | SPI_FREAD_QUAD_M | SPI_FCMD_DUAL_M | SPI_FADDR_DUAL_M | SPI_FREAD_DUAL_M);
user.val &= ~(SPI_FWRITE_QUAD_M | SPI_FWRITE_DUAL_M); user.val &= ~(SPI_FWRITE_QUAD_M | SPI_FWRITE_DUAL_M);
// ctrl.val |= SPI_FAST_RD_MODE_M;
switch (read_mode) { switch (read_mode) {
case SPI_FLASH_FASTRD: case SPI_FLASH_FASTRD:
//the default option //the default option
case SPI_FLASH_SLOWRD:
break; break;
case SPI_FLASH_QIO: case SPI_FLASH_QIO:
ctrl.fread_quad = 1; ctrl.fread_quad = 1;
@@ -226,9 +237,6 @@ static inline void gpspi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_io_mod
ctrl.fread_dual = 1; ctrl.fread_dual = 1;
user.fwrite_dual = 1; user.fwrite_dual = 1;
break; break;
// case SPI_FLASH_SLOWRD:
// ctrl.fast_rd_mode = 0;
// break;
default: default:
abort(); abort();
} }
@@ -257,6 +265,9 @@ static inline void gpspi_flash_ll_set_clock(spi_dev_t *dev, gpspi_flash_ll_clock
static inline void gpspi_flash_ll_set_miso_bitlen(spi_dev_t *dev, uint32_t bitlen) static inline void gpspi_flash_ll_set_miso_bitlen(spi_dev_t *dev, uint32_t bitlen)
{ {
dev->user.usr_miso = bitlen > 0; dev->user.usr_miso = bitlen > 0;
if (bitlen) {
dev->ms_dlen.ms_data_bitlen = bitlen - 1;
}
} }
/** /**
@@ -269,20 +280,24 @@ static inline void gpspi_flash_ll_set_miso_bitlen(spi_dev_t *dev, uint32_t bitle
static inline void gpspi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitlen) static inline void gpspi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitlen)
{ {
dev->user.usr_mosi = bitlen > 0; dev->user.usr_mosi = bitlen > 0;
if (bitlen) {
dev->ms_dlen.ms_data_bitlen = bitlen - 1;
}
} }
/** /**
* Set the command with fixed length (8 bits). * Set the command.
* *
* @param dev Beginning address of the peripheral registers. * @param dev Beginning address of the peripheral registers.
* @param command Command to send * @param command Command to send
* @param bitlen Length of the command
*/ */
static inline void gpspi_flash_ll_set_command8(spi_dev_t *dev, uint8_t command) static inline void gpspi_flash_ll_set_command(spi_dev_t *dev, uint8_t command, uint32_t bitlen)
{ {
dev->user.usr_command = 1; dev->user.usr_command = 1;
typeof(dev->user2) user2 = { typeof(dev->user2) user2 = {
.usr_command_value = command, .usr_command_value = command,
.usr_command_bitlen = (8 - 1), .usr_command_bitlen = (bitlen - 1),
}; };
dev->user2 = user2; dev->user2 = user2;
} }
@@ -318,9 +333,12 @@ static inline void gpspi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitle
*/ */
static inline void gpspi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, uint32_t bitlen) static inline void gpspi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, uint32_t bitlen)
{ {
dev->addr = (addr << (32 - bitlen)); // The blank region should be all ones
uint32_t padding_ones = (bitlen == 32? 0 : UINT32_MAX >> bitlen);
dev->addr = (addr << (32 - bitlen)) | padding_ones;
} }
/** /**
* Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write... * Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write...
* *
@@ -358,6 +376,12 @@ static inline void gpspi_flash_ll_set_dummy_out(spi_dev_t *dev, uint32_t out_en,
dev->ctrl.d_pol = out_lev; dev->ctrl.d_pol = out_lev;
} }
static inline void gpspi_flash_ll_set_hold(spi_dev_t *dev, uint32_t hold_n)
{
dev->user1.cs_hold_time = hold_n - 1;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -66,13 +66,15 @@ typedef union {
#define spi_flash_ll_set_clock(dev, clk) gpspi_flash_ll_set_clock((spi_dev_t*)dev, (gpspi_flash_ll_clock_reg_t*)clk) #define spi_flash_ll_set_clock(dev, clk) gpspi_flash_ll_set_clock((spi_dev_t*)dev, (gpspi_flash_ll_clock_reg_t*)clk)
#define spi_flash_ll_set_miso_bitlen(dev, bitlen) gpspi_flash_ll_set_miso_bitlen((spi_dev_t*)dev, bitlen) #define spi_flash_ll_set_miso_bitlen(dev, bitlen) gpspi_flash_ll_set_miso_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) gpspi_flash_ll_set_mosi_bitlen((spi_dev_t*)dev, bitlen) #define spi_flash_ll_set_mosi_bitlen(dev, bitlen) gpspi_flash_ll_set_mosi_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_set_command8(dev, cmd) gpspi_flash_ll_set_command8((spi_dev_t*)dev, cmd) #define spi_flash_ll_set_command(dev, cmd, bitlen) gpspi_flash_ll_set_command((spi_dev_t*)dev, cmd, bitlen)
#define spi_flash_ll_set_addr_bitlen(dev, bitlen) gpspi_flash_ll_set_addr_bitlen((spi_dev_t*)dev, bitlen) #define spi_flash_ll_set_addr_bitlen(dev, bitlen) gpspi_flash_ll_set_addr_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_get_addr_bitlen(dev) gpspi_flash_ll_get_addr_bitlen((spi_dev_t*)dev) #define spi_flash_ll_get_addr_bitlen(dev) gpspi_flash_ll_get_addr_bitlen((spi_dev_t*)dev)
#define spi_flash_ll_set_address(dev, addr) gpspi_flash_ll_set_address((spi_dev_t*)dev, addr) #define spi_flash_ll_set_address(dev, addr) gpspi_flash_ll_set_address((spi_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) gpspi_flash_ll_set_usr_address((spi_dev_t*)dev, addr, bitlen) #define spi_flash_ll_set_usr_address(dev, addr, bitlen) gpspi_flash_ll_set_usr_address((spi_dev_t*)dev, addr, bitlen)
#define spi_flash_ll_set_dummy(dev, dummy) gpspi_flash_ll_set_dummy((spi_dev_t*)dev, dummy) #define spi_flash_ll_set_dummy(dev, dummy) gpspi_flash_ll_set_dummy((spi_dev_t*)dev, dummy)
#define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev) #define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
#else #else
#define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev) #define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev) #define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
@@ -91,13 +93,14 @@ typedef union {
#define spi_flash_ll_set_clock(dev, clk) spimem_flash_ll_set_clock((spi_mem_dev_t*)dev, (spimem_flash_ll_clock_reg_t*)clk) #define spi_flash_ll_set_clock(dev, clk) spimem_flash_ll_set_clock((spi_mem_dev_t*)dev, (spimem_flash_ll_clock_reg_t*)clk)
#define spi_flash_ll_set_miso_bitlen(dev, bitlen) spimem_flash_ll_set_miso_bitlen((spi_mem_dev_t*)dev, bitlen) #define spi_flash_ll_set_miso_bitlen(dev, bitlen) spimem_flash_ll_set_miso_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) spimem_flash_ll_set_mosi_bitlen((spi_mem_dev_t*)dev, bitlen) #define spi_flash_ll_set_mosi_bitlen(dev, bitlen) spimem_flash_ll_set_mosi_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_set_command8(dev, cmd) spimem_flash_ll_set_command8((spi_mem_dev_t*)dev, cmd) #define spi_flash_ll_set_command(dev, cmd, bitlen) spimem_flash_ll_set_command((spi_mem_dev_t*)dev, cmd, bitlen)
#define spi_flash_ll_set_addr_bitlen(dev, bitlen) spimem_flash_ll_set_addr_bitlen((spi_mem_dev_t*)dev, bitlen) #define spi_flash_ll_set_addr_bitlen(dev, bitlen) spimem_flash_ll_set_addr_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_get_addr_bitlen(dev) spimem_flash_ll_get_addr_bitlen((spi_mem_dev_t*) dev) #define spi_flash_ll_get_addr_bitlen(dev) spimem_flash_ll_get_addr_bitlen((spi_mem_dev_t*) dev)
#define spi_flash_ll_set_address(dev, addr) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr) #define spi_flash_ll_set_address(dev, addr) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr) #define spi_flash_ll_set_usr_address(dev, addr, bitlen) spimem_flash_ll_set_usr_address((spi_mem_dev_t*)dev, addr, bitlen)
#define spi_flash_ll_set_dummy(dev, dummy) spimem_flash_ll_set_dummy((spi_mem_dev_t*)dev, dummy) #define spi_flash_ll_set_dummy(dev, dummy) spimem_flash_ll_set_dummy((spi_mem_dev_t*)dev, dummy)
#define spi_flash_ll_set_dummy_out(dev, en, lev) spimem_flash_ll_set_dummy_out((spi_mem_dev_t*)dev, en, lev) #define spi_flash_ll_set_dummy_out(dev, en, lev) spimem_flash_ll_set_dummy_out((spi_mem_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -308,17 +308,18 @@ static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t
} }
/** /**
* Set the command with fixed length (8 bits). * Set the command.
* *
* @param dev Beginning address of the peripheral registers. * @param dev Beginning address of the peripheral registers.
* @param command Command to send * @param command Command to send
* @param bitlen Length of the command
*/ */
static inline void spimem_flash_ll_set_command8(spi_mem_dev_t *dev, uint8_t command) static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen)
{ {
dev->user.usr_command = 1; dev->user.usr_command = 1;
typeof(dev->user2) user2 = { typeof(dev->user2) user2 = {
.usr_command_value = command, .usr_command_value = command,
.usr_command_bitlen = (8 - 1), .usr_command_bitlen = (bitlen - 1),
}; };
dev->user2 = user2; dev->user2 = user2;
} }
@@ -357,6 +358,18 @@ static inline void spimem_flash_ll_set_address(spi_mem_dev_t *dev, uint32_t addr
dev->addr = addr; dev->addr = addr;
} }
/**
* Set the address to send in user mode. Should be called before commands that requires the address e.g. erase sector, read, write...
*
* @param dev Beginning address of the peripheral registers.
* @param addr Address to send
*/
static inline void spimem_flash_ll_set_usr_address(spi_mem_dev_t *dev, uint32_t addr, uint32_t bitlen)
{
(void)bitlen;
spimem_flash_ll_set_address(dev, addr);
}
/** /**
* Set the length of dummy cycles. * Set the length of dummy cycles.
* *
@@ -383,6 +396,12 @@ static inline void spimem_flash_ll_set_dummy_out(spi_mem_dev_t *dev, uint32_t ou
dev->ctrl.d_pol = out_lev; dev->ctrl.d_pol = out_lev;
} }
static inline void spimem_flash_ll_set_hold(spi_mem_dev_t *dev, uint32_t hold_n)
{
dev->ctrl2.cs_hold_time = hold_n - 1;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -40,10 +40,17 @@ typedef struct {
spi_flash_host_inst_t inst; ///< Host instance, containing host data and function pointer table. May update with the host (hardware version). spi_flash_host_inst_t inst; ///< Host instance, containing host data and function pointer table. May update with the host (hardware version).
spi_dev_t *spi; ///< Pointer to SPI peripheral registers (SP1, SPI2 or SPI3). Set before initialisation. spi_dev_t *spi; ///< Pointer to SPI peripheral registers (SP1, SPI2 or SPI3). Set before initialisation.
int cs_num; ///< Which cs pin is used, 0-2. int cs_num; ///< Which cs pin is used, 0-2.
int extra_dummy; ///< Pre-calculated extra dummy used for compensation struct {
uint8_t extra_dummy; ///< Pre-calculated extra dummy used for compensation
uint8_t reserved1; ///< Reserved, set to 0.
uint8_t cs_hold; ///< CS hold time config used by the host
uint8_t reserved2; ///< Reserved, set to 0.
};
spi_flash_ll_clock_reg_t clock_conf; ///< Pre-calculated clock configuration value spi_flash_ll_clock_reg_t clock_conf; ///< Pre-calculated clock configuration value
uint32_t reserved_config[2]; ///< The ROM has reserved some memory for configurations with one set of driver code. (e.g. QPI mode, 64-bit address mode, etc.) esp_flash_io_mode_t base_io_mode; ///< Default IO mode mask for common commands
uint32_t reserved_config[1]; ///< The ROM has reserved some memory for configurations with one set of driver code. (e.g. QPI mode, 64-bit address mode, etc.)
} spi_flash_hal_context_t; } spi_flash_hal_context_t;
_Static_assert(sizeof(spi_flash_hal_context_t) == 28, "size of spi_flash_hal_context_t incorrect. Please check data compatibility with the ROM");
/// Configuration structure for the SPI driver. /// Configuration structure for the SPI driver.
typedef struct { typedef struct {
@@ -52,6 +59,7 @@ typedef struct {
bool iomux; ///< Whether the IOMUX is used, used for timing compensation. bool iomux; ///< Whether the IOMUX is used, used for timing compensation.
int input_delay_ns; ///< Input delay on the MISO pin after the launch clock used for timing compensation. int input_delay_ns; ///< Input delay on the MISO pin after the launch clock used for timing compensation.
esp_flash_speed_t speed;///< SPI flash clock speed to work at. esp_flash_speed_t speed;///< SPI flash clock speed to work at.
uint32_t cs_hold; ///< CS hold time config used by the host
} spi_flash_hal_config_t; } spi_flash_hal_config_t;
/** /**
@@ -98,7 +106,7 @@ void spi_flash_hal_erase_chip(spi_flash_host_inst_t *host);
/** /**
* Erase a specific sector by its start address through the sector erase (20h) * Erase a specific sector by its start address through the sector erase (20h)
* command. * command. For 24bit address only.
* *
* @param host The driver context. * @param host The driver context.
* @param start_address Start address of the sector to erase. * @param start_address Start address of the sector to erase.
@@ -107,7 +115,7 @@ void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_addr
/** /**
* Erase a specific 64KB block by its start address through the 64KB block * Erase a specific 64KB block by its start address through the 64KB block
* erase (D8h) command. * erase (D8h) command. For 24bit address only.
* *
* @param host The driver context. * @param host The driver context.
* @param start_address Start address of the block to erase. * @param start_address Start address of the block to erase.
@@ -115,7 +123,7 @@ void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_addr
void spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_address); void spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_address);
/** /**
* Program a page of the flash using the page program (02h) command. * Program a page of the flash using the page program (02h) command. For 24bit address only.
* *
* @param host The driver context. * @param host The driver context.
* @param address Address of the page to program * @param address Address of the page to program

View File

@@ -15,6 +15,7 @@
#pragma once #pragma once
#include <esp_types.h> #include <esp_types.h>
#include <esp_bit_defs.h>
#include "esp_flash_err.h" #include "esp_flash_err.h"
#ifdef __cplusplus #ifdef __cplusplus
@@ -23,13 +24,19 @@ extern "C" {
/** Definition of a common transaction. Also holds the return value. */ /** Definition of a common transaction. Also holds the return value. */
typedef struct { typedef struct {
uint8_t command; ///< Command to send, always 8bits uint8_t reserved; ///< Reserved, must be 0.
uint8_t mosi_len; ///< Output data length, in bytes uint8_t mosi_len; ///< Output data length, in bytes
uint8_t miso_len; ///< Input data length, in bytes uint8_t miso_len; ///< Input data length, in bytes
uint8_t address_bitlen; ///< Length of address in bits, set to 0 if command does not need an address uint8_t address_bitlen; ///< Length of address in bits, set to 0 if command does not need an address
uint32_t address; ///< Address to perform operation on uint32_t address; ///< Address to perform operation on
const uint8_t *mosi_data; ///< Output data to salve const uint8_t *mosi_data; ///< Output data to salve
uint8_t *miso_data; ///< [out] Input data from slave, little endian uint8_t *miso_data; ///< [out] Input data from slave, little endian
uint32_t flags; ///< Flags for this transaction. Set to 0 for now.
#define SPI_FLASH_TRANS_FLAG_CMD16 BIT(0) ///< Send command of 16 bits
#define SPI_FLASH_TRANS_FLAG_IGNORE_BASEIO BIT(1) ///< Not applying the basic io mode configuration for this transaction
#define SPI_FLASH_TRANS_FLAG_BYTE_SWAP BIT(2) ///< Used for DTR mode, to swap the bytes of a pair of rising/falling edge
uint16_t command; ///< Command to send
uint8_t dummy_bitlen; ///< Basic dummy bits to use
} spi_flash_trans_t; } spi_flash_trans_t;
/** /**
@@ -53,6 +60,9 @@ typedef enum {
///Lowest speed supported by the driver, currently 5 MHz ///Lowest speed supported by the driver, currently 5 MHz
#define ESP_FLASH_SPEED_MIN ESP_FLASH_5MHZ #define ESP_FLASH_SPEED_MIN ESP_FLASH_5MHZ
// These bits are not quite like "IO mode", but are able to be appended into the io mode and used by the HAL.
#define SPI_FLASH_CONFIG_CONF_BITS BIT(31) ///< OR the io_mode with this mask, to enable the dummy output feature or replace the first several dummy bits into address to meet the requirements of conf bits. (Used in DIO/QIO/OIO mode)
/** @brief Mode used for reading from SPI flash */ /** @brief Mode used for reading from SPI flash */
typedef enum { typedef enum {
SPI_FLASH_SLOWRD = 0, ///< Data read using single I/O, some limits on speed SPI_FLASH_SLOWRD = 0, ///< Data read using single I/O, some limits on speed

View File

@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// HAL for SPI Flash (non-IRAM part)
// The IRAM part is in spi_flash_hal_iram.c, spi_flash_hal_gpspi.c, spi_flash_hal_common.inc.
#include <stdlib.h> #include <stdlib.h>
#include "hal/spi_flash_hal.h" #include "hal/spi_flash_hal.h"
#include "string.h" #include "string.h"
@@ -87,6 +90,7 @@ esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_
.cs_num = cfg->cs_num, .cs_num = cfg->cs_num,
.extra_dummy = get_dummy_n(!cfg->iomux, cfg->input_delay_ns, clock_cfg.freq), .extra_dummy = get_dummy_n(!cfg->iomux, cfg->input_delay_ns, clock_cfg.freq),
.clock_conf = clock_cfg.clock_reg_val, .clock_conf = clock_cfg.clock_reg_val,
.cs_hold = cfg->cs_hold,
}; };
ESP_EARLY_LOGD(TAG, "extra_dummy: %d", data_out->extra_dummy); ESP_EARLY_LOGD(TAG, "extra_dummy: %d", data_out->extra_dummy);

View File

@@ -16,6 +16,7 @@
#include "hal/spi_flash_hal.h" #include "hal/spi_flash_hal.h"
#include "string.h" #include "string.h"
#include "hal/hal_defs.h" #include "hal/hal_defs.h"
#include "soc/soc_caps.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#define ADDRESS_MASK_24BIT 0xFFFFFF #define ADDRESS_MASK_24BIT 0xFFFFFF
@@ -26,6 +27,12 @@ static inline spi_dev_t *get_spi_dev(spi_flash_host_inst_t *host)
return ((spi_flash_hal_context_t*)host)->spi; return ((spi_flash_hal_context_t*)host)->spi;
} }
static inline int get_host_id(spi_flash_host_inst_t* host)
{
spi_dev_t *dev = get_spi_dev(host);
return spi_flash_ll_hw_get_id(dev);
}
void spi_flash_hal_poll_cmd_done(spi_flash_host_inst_t *host) void spi_flash_hal_poll_cmd_done(spi_flash_host_inst_t *host)
{ {
while (!spi_flash_ll_cmd_is_done(get_spi_dev(host))) { while (!spi_flash_ll_cmd_is_done(get_spi_dev(host))) {
@@ -35,10 +42,14 @@ void spi_flash_hal_poll_cmd_done(spi_flash_host_inst_t *host)
esp_err_t spi_flash_hal_device_config(spi_flash_host_inst_t *host) esp_err_t spi_flash_hal_device_config(spi_flash_host_inst_t *host)
{ {
spi_flash_hal_context_t* ctx = (spi_flash_hal_context_t*)host;
spi_dev_t *dev = get_spi_dev(host); spi_dev_t *dev = get_spi_dev(host);
spi_flash_ll_reset(dev); spi_flash_ll_reset(dev);
spi_flash_ll_set_cs_pin(dev, ((spi_flash_hal_context_t*)host)->cs_num); spi_flash_ll_set_cs_pin(dev, ctx->cs_num);
spi_flash_ll_set_clock(dev, &((spi_flash_hal_context_t*)host)->clock_conf); spi_flash_ll_set_clock(dev, &ctx->clock_conf);
int cs_hold = ctx->cs_hold;
spi_flash_ll_set_hold(dev, cs_hold);
return ESP_OK; return ESP_OK;
} }
@@ -52,32 +63,39 @@ esp_err_t spi_flash_hal_configure_host_io_mode(
spi_dev_t *dev = get_spi_dev(host); spi_dev_t *dev = get_spi_dev(host);
int host_id = spi_flash_ll_hw_get_id(dev); int host_id = spi_flash_ll_hw_get_id(dev);
uint32_t extra_bits = io_mode & 0xFFFF0000;
io_mode = io_mode & 0xFFFF;
/*
* Some flash chips, when working under some IO modes (DIO, QIO and OIO in the future), treat
* the first 8 bits of the dummy bits as the bits. When the bits meet some pattern, the chip
* will go into a "continuous (XIP)" mode, where the command field will be skipped in the next
* transaction. We have to output all ones in these cycles because we don't need this feature.
*/
bool conf_required = ((extra_bits & SPI_FLASH_CONFIG_CONF_BITS) != 0);
if (!SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(host_id) && io_mode > SPI_FLASH_FASTRD) { if (!SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(host_id) && io_mode > SPI_FLASH_FASTRD) {
return ESP_ERR_NOT_SUPPORTED; return ESP_ERR_NOT_SUPPORTED;
} }
if (addr_bitlen > 24 && SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT(host_id)) {
/*
* The extra address bits (24-addr_bitlen) are used to control the M7-M0 bits right after
* the address field, to avoid the flash going into continuous read mode.
*
* On ESP32-S2 the MEMSPI (that SUPPORT_CONTROL_DUMMY_OUTPUT), the least significant
* addr_bitlen bits of the address will be used, instead of the MSBs. The driver is
* required to set the address according to the extra address bits.
*
* To reduce the time consuming for the read() function to calculate the shift of address,
* the addr_bitlen is kept to 24 bits. And the CONTROL_DUMMY_OUTPUT feature is used to
* control those bits instead.
*/
//This block is only reached when SPI_FLASH_QIO or SPI_FLASH_DIO #if SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT
assert(io_mode == SPI_FLASH_DIO || io_mode == SPI_FLASH_QIO); // The CONTROL_DUMMY_OUTPUT feature is used to control M7-M0 bits.
spi_flash_ll_set_dummy_out(dev, (conf_required? 1: 0), 1);
#else
// On ESP32, dummy output is not supported. These dummy bits will be moved into the address
// phase (and appended as ones).
if (conf_required) {
int line_width = (io_mode == SPI_FLASH_DIO? 2: 4); int line_width = (io_mode == SPI_FLASH_DIO? 2: 4);
dummy_cyclelen_base += (addr_bitlen - 24) / line_width; dummy_cyclelen_base -= 4 / line_width;
addr_bitlen = 24; addr_bitlen += 4; //extra 4 bits indicate the conf bits is included
spi_flash_ll_set_dummy_out(dev, 1, 1);
} }
#endif
spi_flash_ll_set_command8(dev, command); if (command >= 0x100) {
spi_flash_ll_set_command(dev, command, 16);
} else {
spi_flash_ll_set_command(dev, command, 8);
}
spi_flash_ll_set_addr_bitlen(dev, addr_bitlen); spi_flash_ll_set_addr_bitlen(dev, addr_bitlen);
// Add dummy cycles to compensate for latency of GPIO matrix and external delay, if necessary... // Add dummy cycles to compensate for latency of GPIO matrix and external delay, if necessary...
spi_flash_ll_set_dummy(dev, COMPUTE_DUMMY_CYCLELEN(host, dummy_cyclelen_base)); spi_flash_ll_set_dummy(dev, COMPUTE_DUMMY_CYCLELEN(host, dummy_cyclelen_base));
@@ -90,16 +108,23 @@ esp_err_t spi_flash_hal_configure_host_io_mode(
esp_err_t spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_trans_t *trans) esp_err_t spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_trans_t *trans)
{ {
host->driver->configure_host_io_mode(host, trans->command, trans->address_bitlen, 0, SPI_FLASH_FASTRD);
spi_dev_t *dev = get_spi_dev(host); spi_dev_t *dev = get_spi_dev(host);
esp_flash_io_mode_t io_mode = ((spi_flash_hal_context_t*)host)->base_io_mode;
uint16_t command = trans->command;
uint8_t dummy_bitlen = trans->dummy_bitlen;
//disable dummy if no input phase if ((trans->flags & SPI_FLASH_TRANS_FLAG_IGNORE_BASEIO) != 0) {
if (trans->miso_len == 0) { io_mode = 0;
spi_flash_ll_set_dummy(dev, 0); }
host->driver->configure_host_io_mode(host, command, trans->address_bitlen, dummy_bitlen, io_mode);
spi_flash_ll_set_usr_address(dev, trans->address, trans->address_bitlen);
//No extra dummy cycles for compensation if no input data
if (trans->miso_len == 0) {
spi_flash_ll_set_dummy(dev, dummy_bitlen);
} }
spi_flash_ll_set_usr_address(dev, (trans->address & ADDRESS_MASK_24BIT), spi_flash_ll_get_addr_bitlen(dev));
spi_flash_ll_set_mosi_bitlen(dev, trans->mosi_len * 8); spi_flash_ll_set_mosi_bitlen(dev, trans->mosi_len * 8);
spi_flash_ll_set_buffer_data(dev, trans->mosi_data, trans->mosi_len); spi_flash_ll_set_buffer_data(dev, trans->mosi_data, trans->mosi_len);
@@ -114,7 +139,9 @@ esp_err_t spi_flash_hal_read(spi_flash_host_inst_t *host, void *buffer, uint32_t
{ {
spi_dev_t *dev = get_spi_dev(host); spi_dev_t *dev = get_spi_dev(host);
int bitlen = spi_flash_ll_get_addr_bitlen(dev); int bitlen = spi_flash_ll_get_addr_bitlen(dev);
spi_flash_ll_set_usr_address(dev, address << (bitlen - 24), bitlen); //Only 24-bit and 32-bit address are supported. The extra length are for M7-M0, which should be
//filled with ones by the function below
spi_flash_ll_set_usr_address(dev, address, bitlen & (~7));
spi_flash_ll_set_miso_bitlen(dev, read_len * 8); spi_flash_ll_set_miso_bitlen(dev, read_len * 8);
spi_flash_ll_user_start(dev); spi_flash_ll_user_start(dev);
host->driver->poll_cmd_done(host); host->driver->poll_cmd_done(host);

View File

@@ -12,6 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// HAL for
// - GPSPI (SP2, SPI3) on ESP32-S2 and later
// The common part is in spi_flash_hal_common.inc
#define GPSPI_BUILD #define GPSPI_BUILD
#define spi_flash_hal_common_command spi_flash_hal_gpspi_common_command #define spi_flash_hal_common_command spi_flash_hal_gpspi_common_command

View File

@@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// HAL for
// - MEMSPI
// - SPI1~3 on ESP32
// The common part is in spi_flash_hal_common.inc
#include "spi_flash_hal_common.inc" #include "spi_flash_hal_common.inc"
void spi_flash_hal_erase_chip(spi_flash_host_inst_t *host) void spi_flash_hal_erase_chip(spi_flash_host_inst_t *host)
@@ -21,6 +26,7 @@ void spi_flash_hal_erase_chip(spi_flash_host_inst_t *host)
host->driver->poll_cmd_done(host); host->driver->poll_cmd_done(host);
} }
// Only support 24bit address
void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address) void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address)
{ {
spi_dev_t *dev = get_spi_dev(host); spi_dev_t *dev = get_spi_dev(host);
@@ -30,6 +36,7 @@ void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_addr
host->driver->poll_cmd_done(host); host->driver->poll_cmd_done(host);
} }
// Only support 24bit address
void spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_address) void spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_address)
{ {
spi_dev_t *dev = get_spi_dev(host); spi_dev_t *dev = get_spi_dev(host);
@@ -39,6 +46,7 @@ void spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_addre
host->driver->poll_cmd_done(host); host->driver->poll_cmd_done(host);
} }
// Only support 24bit address
void spi_flash_hal_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length) void spi_flash_hal_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length)
{ {
spi_dev_t *dev = get_spi_dev(host); spi_dev_t *dev = get_spi_dev(host);

View File

@@ -18,8 +18,18 @@
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 30 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 30
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 27 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 27
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B 50600
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B 50300
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B 68900
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B #ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B (359*1000) #define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B (338*1000)
#endif #endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_2KB #ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_2KB

View File

@@ -17,6 +17,17 @@
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 32 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 32
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 30 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 30
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B 53400
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B 53600
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B 64900
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B #ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B (309*1000) #define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B (309*1000)
#endif #endif
@@ -26,5 +37,5 @@
#endif #endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_ERASE #ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_ERASE
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_ERASE 40300 #define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_ERASE 37500
#endif #endif

View File

@@ -16,6 +16,17 @@
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 32 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 32
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 30 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 30
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B 53400
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B 53600
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B 68900
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B #ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B (309*1000) #define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B (309*1000)
#endif #endif

View File

@@ -93,9 +93,7 @@
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_WR_4B #ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_WR_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_WR_4B 22200 #define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_WR_4B 22200
#endif #endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B // IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B in target file
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B 53400
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_WR_2KB #ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_WR_2KB
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_WR_2KB (701*1000) #define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_WR_2KB (701*1000)
#endif #endif
@@ -110,9 +108,7 @@
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_WR_4B #ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_WR_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_WR_4B 27400 #define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_WR_4B 27400
#endif #endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B // IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B in target file
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B 53600
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_WR_2KB #ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_WR_2KB
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_WR_2KB (694*1000) #define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_WR_2KB (694*1000)
#endif #endif
@@ -140,9 +136,7 @@
#endif #endif
// Some performance value based on the test against GD chip with single_core config. // Some performance value based on the test against GD chip with single_core config.
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B // IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B in target file
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B 68900
#endif
// IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B in target file // IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B in target file
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_2KB #ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_2KB
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_2KB (475*1000) #define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_2KB (475*1000)

View File

@@ -183,7 +183,7 @@
#define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(spi_host) ({(void)spi_host; 1;}) #define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(spi_host) ({(void)spi_host; 1;})
// Peripheral doesn't support output given level during its "dummy phase" // Peripheral doesn't support output given level during its "dummy phase"
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT(spi_host) ({(void)spi_host; 0;}) #define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT 0
/*-------------------------- TIMER GROUP CAPS --------------------------------*/ /*-------------------------- TIMER GROUP CAPS --------------------------------*/
// No contents here // No contents here

View File

@@ -178,7 +178,7 @@
// Peripheral supports output given level during its "dummy phase" // Peripheral supports output given level during its "dummy phase"
// Only SPI1 supports this feature // Only SPI1 supports this feature
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT(host_id) ((host_id) == 0) #define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT 1
#define SOC_MEMSPI_IS_INDEPENDENT 1 #define SOC_MEMSPI_IS_INDEPENDENT 1

View File

@@ -27,9 +27,10 @@
#define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1 #define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1
// Peripheral supports DIO, DOUT, QIO, or QOUT // Peripheral supports DIO, DOUT, QIO, or QOUT
#define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(spi_dev) (!((void*)spi_dev == (void*)&GPSPI3)) // VSPI (SPI3) only support 1-bit mode
#define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(host_id) ((host_id) != 2)
// Peripheral supports output given level during its "dummy phase" // Peripheral supports output given level during its "dummy phase"
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT(spi_dev) (!((void*)spi_dev == (void*)&SPIMEM1)) #define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT 1
#define SOC_MEMSPI_IS_INDEPENDENT 1 #define SOC_MEMSPI_IS_INDEPENDENT 1

View File

@@ -31,6 +31,7 @@ else()
"spi_flash_chip_issi.c" "spi_flash_chip_issi.c"
"spi_flash_chip_mxic.c" "spi_flash_chip_mxic.c"
"spi_flash_chip_gd.c" "spi_flash_chip_gd.c"
"spi_flash_chip_winbond.c"
"memspi_host_driver.c") "memspi_host_driver.c")
list(APPEND cache_srcs list(APPEND cache_srcs

View File

@@ -188,6 +188,14 @@ menu "SPI Flash driver"
size. Note that the default chip driver supports the GD chips with product ID size. Note that the default chip driver supports the GD chips with product ID
60H. 60H.
config SPI_FLASH_SUPPORT_WINBOND_CHIP
bool "Winbond"
default y
help
Enable this to support auto detection of Winbond chips if chip vendor not directly
given by ``chip_drv`` member of the chip struct. This adds support for variant
chips, however will extend detecting time.
endmenu #auto detect flash chips endmenu #auto detect flash chips
endmenu endmenu

View File

@@ -149,6 +149,11 @@ bool esp_flash_chip_driver_initialized(const esp_flash_t *chip)
esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip) esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip)
{ {
// Chip init flow
// 1. Read chip id
// 2. (optional) Detect chip vendor
// 3. Get basic parameters of the chip (size, dummy count, etc.)
// 4. Init chip into desired mode (without breaking the cache!)
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
if (chip == NULL || chip->host == NULL || chip->host->driver == NULL || if (chip == NULL || chip->host == NULL || chip->host->driver == NULL ||
((memspi_host_inst_t*)chip->host)->spi == NULL) { ((memspi_host_inst_t*)chip->host)->spi == NULL) {
@@ -201,22 +206,33 @@ esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip)
return rom_spiflash_api_funcs->end(chip, err); return rom_spiflash_api_funcs->end(chip, err);
} }
//this is not public, but useful in unit tests static esp_err_t IRAM_ATTR read_id_core(esp_flash_t* chip, uint32_t* out_id, bool sanity_check)
esp_err_t IRAM_ATTR esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id)
{ {
bool installed = esp_flash_chip_driver_initialized(chip);
esp_err_t err = rom_spiflash_api_funcs->start(chip); esp_err_t err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
// Send generic RDID command twice, check for a matching result and retry in case we just powered on (inner esp_err_t (*read_id_func)(void*, uint32_t*);
// function fails if it sees all-ones or all-zeroes.) void* read_id_arg;
err = chip->host->driver->read_id(chip->host, flash_id); if (installed && chip->chip_drv->read_id) {
read_id_func = (void*)chip->chip_drv->read_id;
read_id_arg = (void*)chip;
} else {
//default option if the chip is not detected/chosen yet.
read_id_func = (void*)chip->host->driver->read_id;
read_id_arg = (void*)chip->host;
}
if (err == ESP_OK) { // check we see the same ID twice, in case of transient power-on errors // Inner function fails if it sees all-ones or all-zeroes.
err = read_id_func(read_id_arg, out_id);
if (sanity_check && err == ESP_OK) {
// Send RDID command twice, check for a matching result and retry in case we just powered on
uint32_t new_id; uint32_t new_id;
err = chip->host->driver->read_id(chip->host, &new_id); err = read_id_func(read_id_arg, &new_id);
if (err == ESP_OK && (new_id != *flash_id)) { if (err == ESP_OK && (new_id != *out_id)) {
err = ESP_ERR_FLASH_NOT_INITIALISED; err = ESP_ERR_FLASH_NOT_INITIALISED;
} }
} }
@@ -224,6 +240,23 @@ esp_err_t IRAM_ATTR esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id
return rom_spiflash_api_funcs->end(chip, err); return rom_spiflash_api_funcs->end(chip, err);
} }
// Faster version with sanity check.
// Called in esp_flash_init and unit test (though not public)
esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* out_id)
{
return read_id_core(chip, out_id, true);
}
esp_err_t esp_flash_read_id(esp_flash_t* chip, uint32_t* out_id)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
//Accept uninitialized chip when reading chip id
if (err != ESP_OK && !(err == ESP_ERR_FLASH_NOT_INITIALISED && chip != NULL)) return err;
if (out_id == NULL) return ESP_ERR_INVALID_ARG;
return read_id_core(chip, out_id, false);
}
static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip) static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
{ {
esp_err_t err; esp_err_t err;
@@ -271,23 +304,6 @@ static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
} \ } \
} while (0) } while (0)
esp_err_t IRAM_ATTR esp_flash_read_id(esp_flash_t *chip, uint32_t *out_id)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
//Accept uninitialized chip when reading chip id
if (err != ESP_OK && !(err == ESP_ERR_FLASH_NOT_INITIALISED && chip != NULL)) return err;
if (out_id == NULL) return ESP_ERR_INVALID_ARG;
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
err = chip->host->driver->read_id(chip->host, out_id);
return rom_spiflash_api_funcs->end(chip, err);
}
esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size) esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size)
{ {
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip); esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);

View File

@@ -59,6 +59,7 @@ __attribute__((unused)) static const char TAG[] = "spi_flash";
#define DEFAULT_FLASH_MODE SPI_FLASH_FASTRD #define DEFAULT_FLASH_MODE SPI_FLASH_FASTRD
#endif #endif
//TODO: modify cs hold to meet requirements of all chips!!!
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
#define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \ #define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \
.host_id = SPI_HOST,\ .host_id = SPI_HOST,\

View File

@@ -107,7 +107,7 @@ esp_err_t memspi_host_flush_cache(spi_flash_host_inst_t *host, uint32_t addr, ui
void memspi_host_erase_chip(spi_flash_host_inst_t *host); void memspi_host_erase_chip(spi_flash_host_inst_t *host);
/** /**
* Erase a sector starting from a given address. * Erase a sector starting from a given address. For 24bit address only.
* *
* @param host The driver context. * @param host The driver context.
* @param start_address Starting address of the sector. * @param start_address Starting address of the sector.
@@ -115,7 +115,7 @@ void memspi_host_erase_chip(spi_flash_host_inst_t *host);
void memspi_host_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address); void memspi_host_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address);
/** /**
* Erase a block starting from a given address. * Erase a block starting from a given address. For 24bit address only.
* *
* @param host The driver context. * @param host The driver context.
* @param start_address Starting address of the block. * @param start_address Starting address of the block.
@@ -123,7 +123,7 @@ void memspi_host_erase_sector(spi_flash_host_inst_t *host, uint32_t start_addres
void memspi_host_erase_block(spi_flash_host_inst_t *host, uint32_t start_address); void memspi_host_erase_block(spi_flash_host_inst_t *host, uint32_t start_address);
/** /**
* Program a page with contents of a buffer. * Program a page with contents of a buffer. For 24bit address only.
* *
* @param host The driver context. * @param host The driver context.
* @param buffer Buffer which contains the data to be flashed. * @param buffer Buffer which contains the data to be flashed.

View File

@@ -29,6 +29,10 @@ typedef struct {
uint32_t page_program_timeout; ///< Timeout for page program operation uint32_t page_program_timeout; ///< Timeout for page program operation
} flash_chip_op_timeout_t; } flash_chip_op_timeout_t;
typedef enum {
SPI_FLASH_REG_STATUS = 1,
} spi_flash_register_t;
/** @brief SPI flash chip driver definition structure. /** @brief SPI flash chip driver definition structure.
* *
* The chip driver structure contains chip-specific pointers to functions to perform SPI flash operations, and some * The chip driver structure contains chip-specific pointers to functions to perform SPI flash operations, and some
@@ -167,6 +171,17 @@ struct spi_flash_chip_t {
* enabled, otherwise disabled * enabled, otherwise disabled
*/ */
esp_err_t (*get_io_mode)(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode); esp_err_t (*get_io_mode)(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode);
/*
* Read the chip ID. Called when chip driver is set, but we want to know the exact chip id (to
* get the size, etc.).
*/
esp_err_t (*read_id)(esp_flash_t *chip, uint32_t* out_chip_id);
/*
* Read the requested register (status, etc.).
*/
esp_err_t (*read_reg)(esp_flash_t *chip, spi_flash_register_t reg_id, uint32_t* out_reg);
}; };
/* Pointer to an array of pointers to all known drivers for flash chips. This array is used /* Pointer to an array of pointers to all known drivers for flash chips. This array is used

View File

@@ -189,6 +189,16 @@ esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write
esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect); esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect);
#define ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT -1 #define ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT -1
/**
* @brief Send commands to read one of the reg of the chip
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param reg_id Type of the register to read
* @param out_reg Output of the register value
* @return esp_err_t Error code passed from the ``read_status`` function of host driver.
*/
esp_err_t spi_flash_chip_generic_read_reg(esp_flash_t* chip, spi_flash_register_t reg_id, uint32_t* out_reg);
/** /**
* @brief Read flash status via the RDSR command and wait for bit 0 (write in * @brief Read flash status via the RDSR command and wait for bit 0 (write in
* progress bit) to be cleared. * progress bit) to be cleared.
@@ -362,13 +372,14 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
* transactions. Also prepare the command to be sent in read functions. * transactions. Also prepare the command to be sent in read functions.
* *
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param addr_32bit Whether 32 bit commands will be used (Currently only W25Q256 is supported)
* *
* @return * @return
* - ESP_OK if success * - ESP_OK if success
* - ESP_ERR_FLASH_NOT_INITIALISED if chip not initialized properly * - ESP_ERR_FLASH_NOT_INITIALISED if chip not initialized properly
* - or other error passed from the ``configure_host_mode`` function of host driver * - or other error passed from the ``configure_host_mode`` function of host driver
*/ */
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip); esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, bool addr_32bit);
/// Default timeout configuration used by most chips /// Default timeout configuration used by most chips
const flash_chip_op_timeout_t spi_flash_chip_generic_timeout; const flash_chip_op_timeout_t spi_flash_chip_generic_timeout;

View File

@@ -0,0 +1,27 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include "esp_flash.h"
#include "spi_flash_chip_driver.h"
/**
* Winbond SPI flash chip_drv, uses all the above functions for its operations. In
* default autodetection, this is used as a catchall if a more specific chip_drv
* is not found.
*/
extern const spi_flash_chip_t esp_flash_chip_winbond;

View File

@@ -5,5 +5,6 @@ entries:
spi_flash_chip_generic (noflash) spi_flash_chip_generic (noflash)
spi_flash_chip_issi (noflash) spi_flash_chip_issi (noflash)
spi_flash_chip_mxic (noflash) spi_flash_chip_mxic (noflash)
spi_flash_chip_gd(noflash) spi_flash_chip_gd (noflash)
spi_flash_chip_winbond (noflash)
memspi_host_driver (noflash) memspi_host_driver (noflash)

View File

@@ -135,8 +135,10 @@ void memspi_host_erase_chip(spi_flash_host_inst_t *host)
host->driver->common_command(host, &t); host->driver->common_command(host, &t);
} }
// Only support 24bit address
void memspi_host_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address) void memspi_host_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address)
{ {
assert(start_address < 0x1000000);
spi_flash_trans_t t = { spi_flash_trans_t t = {
.command = CMD_SECTOR_ERASE, .command = CMD_SECTOR_ERASE,
.address_bitlen = 24, .address_bitlen = 24,
@@ -145,8 +147,10 @@ void memspi_host_erase_sector(spi_flash_host_inst_t *host, uint32_t start_addres
host->driver->common_command(host, &t); host->driver->common_command(host, &t);
} }
// Only support 24bit address
void memspi_host_erase_block(spi_flash_host_inst_t *host, uint32_t start_address) void memspi_host_erase_block(spi_flash_host_inst_t *host, uint32_t start_address)
{ {
assert(start_address < 0x1000000);
spi_flash_trans_t t = { spi_flash_trans_t t = {
.command = CMD_LARGE_BLOCK_ERASE, .command = CMD_LARGE_BLOCK_ERASE,
.address_bitlen = 24, .address_bitlen = 24,
@@ -155,8 +159,10 @@ void memspi_host_erase_block(spi_flash_host_inst_t *host, uint32_t start_address
host->driver->common_command(host, &t); host->driver->common_command(host, &t);
} }
// Only support 24bit address
void memspi_host_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length) void memspi_host_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length)
{ {
assert(address + length <= 0x1000000);
spi_flash_trans_t t = { spi_flash_trans_t t = {
.command = CMD_PROGRAM_PAGE, .command = CMD_PROGRAM_PAGE,
.address_bitlen = 24, .address_bitlen = 24,

View File

@@ -27,25 +27,34 @@
#define CMD_RDSR 0x05 #define CMD_RDSR 0x05
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */ #define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
#define CMD_FASTRD_QIO 0xEB #define CMD_FASTRD_QIO 0xEB
#define CMD_FASTRD_QUAD 0x6B #define CMD_FASTRD_QIO_4B 0xEC
#define CMD_FASTRD_DIO 0xBB #define CMD_FASTRD_QUAD 0x6B
#define CMD_FASTRD_DUAL 0x3B #define CMD_FASTRD_QUAD_4B 0x6C
#define CMD_FASTRD 0x0B #define CMD_FASTRD_DIO 0xBB
#define CMD_READ 0x03 /* Speed limited */ #define CMD_FASTRD_DIO_4B 0xBC
#define CMD_FASTRD_DUAL 0x3B
#define CMD_FASTRD_DUAL_4B 0x3C
#define CMD_FASTRD 0x0B
#define CMD_FASTRD_4B 0x0C
#define CMD_READ 0x03 /* Speed limited */
#define CMD_READ_4B 0x13 /* Speed limited */
#define CMD_CHIP_ERASE 0xC7 #define CMD_CHIP_ERASE 0xC7
#define CMD_SECTOR_ERASE 0x20 #define CMD_SECTOR_ERASE 0x20
#define CMD_LARGE_BLOCK_ERASE 0xD8 /* 64KB block erase command */ #define CMD_SECTOR_ERASE_4B 0x21
#define CMD_PROGRAM_PAGE 0x02 #define CMD_LARGE_BLOCK_ERASE 0xD8 /* 64KB block erase command */
#define CMD_LARGE_BLOCK_ERASE_4B 0xDC /* 64KB block erase command */
#define CMD_PROGRAM_PAGE 0x02
#define CMD_PROGRAM_PAGE_4B 0x12
#define CMD_RST_EN 0x66 #define CMD_RST_EN 0x66
#define CMD_RST_DEV 0x99 #define CMD_RST_DEV 0x99
#define SPI_FLASH_DIO_ADDR_BITLEN (24+4) #define SPI_FLASH_DIO_ADDR_BITLEN 24
#define SPI_FLASH_DIO_DUMMY_BITLEN 2 #define SPI_FLASH_DIO_DUMMY_BITLEN 4
#define SPI_FLASH_QIO_ADDR_BITLEN (24+8) #define SPI_FLASH_QIO_ADDR_BITLEN 24
#define SPI_FLASH_QIO_DUMMY_BITLEN 4 #define SPI_FLASH_QIO_DUMMY_BITLEN 6
#define SPI_FLASH_QOUT_ADDR_BITLEN 24 #define SPI_FLASH_QOUT_ADDR_BITLEN 24
#define SPI_FLASH_QOUT_DUMMY_BITLEN 8 #define SPI_FLASH_QOUT_DUMMY_BITLEN 8
#define SPI_FLASH_DOUT_ADDR_BITLEN 24 #define SPI_FLASH_DOUT_ADDR_BITLEN 24

View File

@@ -18,6 +18,7 @@
#include "spi_flash_chip_issi.h" #include "spi_flash_chip_issi.h"
#include "spi_flash_chip_mxic.h" #include "spi_flash_chip_mxic.h"
#include "spi_flash_chip_gd.h" #include "spi_flash_chip_gd.h"
#include "spi_flash_chip_winbond.h"
#include "sdkconfig.h" #include "sdkconfig.h"
/* /*
@@ -38,6 +39,9 @@ static const spi_flash_chip_t *default_registered_chips[] = {
#endif #endif
#ifdef CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP #ifdef CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP
&esp_flash_chip_mxic, &esp_flash_chip_mxic,
#endif
#ifdef CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP
&esp_flash_chip_winbond,
#endif #endif
// Default chip drivers that will accept all chip ID. // Default chip drivers that will accept all chip ID.
// FM, Winbond and XMC chips are supposed to be supported by this chip driver. // FM, Winbond and XMC chips are supposed to be supported by this chip driver.

View File

@@ -91,7 +91,6 @@ const spi_flash_chip_t esp_flash_chip_gd = {
.get_chip_write_protect = spi_flash_chip_generic_get_write_protect, .get_chip_write_protect = spi_flash_chip_generic_get_write_protect,
.set_chip_write_protect = spi_flash_chip_generic_set_write_protect, .set_chip_write_protect = spi_flash_chip_generic_set_write_protect,
// TODO support protected regions on ISSI flash
.num_protectable_regions = 0, .num_protectable_regions = 0,
.protectable_regions = NULL, .protectable_regions = NULL,
.get_protected_regions = NULL, .get_protected_regions = NULL,
@@ -106,4 +105,6 @@ const spi_flash_chip_t esp_flash_chip_gd = {
.wait_idle = spi_flash_chip_generic_wait_idle, .wait_idle = spi_flash_chip_generic_wait_idle,
.set_io_mode = spi_flash_chip_gd_set_io_mode, .set_io_mode = spi_flash_chip_gd_set_io_mode,
.get_io_mode = spi_flash_chip_gd_get_io_mode, .get_io_mode = spi_flash_chip_gd_get_io_mode,
.read_reg = spi_flash_chip_generic_read_reg,
}; };

View File

@@ -191,7 +191,7 @@ esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t
uint8_t temp_buffer[64]; //spiflash hal max length of read no longer than 64byte uint8_t temp_buffer[64]; //spiflash hal max length of read no longer than 64byte
// Configure the host, and return // Configure the host, and return
err = spi_flash_chip_generic_config_host_io_mode(chip); err = spi_flash_chip_generic_config_host_io_mode(chip, false);
if (err == ESP_ERR_NOT_SUPPORTED) { if (err == ESP_ERR_NOT_SUPPORTED) {
ESP_LOGE(TAG, "configure host io mode failed - unsupported"); ESP_LOGE(TAG, "configure host io mode failed - unsupported");
@@ -313,6 +313,11 @@ esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_
return ESP_OK; return ESP_OK;
} }
esp_err_t spi_flash_chip_generic_read_reg(esp_flash_t* chip, spi_flash_register_t reg_id, uint32_t* out_reg)
{
return chip->host->driver->read_status(chip->host, (uint8_t*)out_reg);
}
esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_us) esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_us)
{ {
bool timeout_en = (timeout_us != ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT); bool timeout_en = (timeout_us != ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT);
@@ -330,10 +335,13 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u
return err; return err;
} }
err = chip->host->driver->read_status(chip->host, &status); uint32_t read;
err = chip->chip_drv->read_reg(chip, SPI_FLASH_REG_STATUS, &read);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
status = read;
if ((status & SR_WIP) == 0) { if ((status & SR_WIP) == 0) {
break; // Write in progress is complete break; // Write in progress is complete
} }
@@ -349,51 +357,62 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u
return (timeout_us > 0) ? ESP_OK : ESP_ERR_TIMEOUT; return (timeout_us > 0) ? ESP_OK : ESP_ERR_TIMEOUT;
} }
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip) esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, bool addr_32bit)
{ {
uint32_t dummy_cyclelen_base; uint32_t dummy_cyclelen_base;
uint32_t addr_bitlen; uint32_t addr_bitlen;
uint32_t read_command; uint32_t read_command;
bool conf_required = false;
esp_flash_io_mode_t read_mode = chip->read_mode;
switch (chip->read_mode) { switch (read_mode & 0xFFFF) {
case SPI_FLASH_QIO: case SPI_FLASH_QIO:
//for QIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that. //for QIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that.
addr_bitlen = SPI_FLASH_QIO_ADDR_BITLEN; addr_bitlen = SPI_FLASH_QIO_ADDR_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->qio_dummy_bitlen; dummy_cyclelen_base = rom_flash_chip_dummy->qio_dummy_bitlen;
read_command = CMD_FASTRD_QIO; read_command = (addr_32bit? CMD_FASTRD_QIO_4B: CMD_FASTRD_QIO);
conf_required = true;
break; break;
case SPI_FLASH_QOUT: case SPI_FLASH_QOUT:
addr_bitlen = SPI_FLASH_QOUT_ADDR_BITLEN; addr_bitlen = SPI_FLASH_QOUT_ADDR_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->qout_dummy_bitlen; dummy_cyclelen_base = rom_flash_chip_dummy->qout_dummy_bitlen;
read_command = CMD_FASTRD_QUAD; read_command = (addr_32bit? CMD_FASTRD_QUAD_4B: CMD_FASTRD_QUAD);
break; break;
case SPI_FLASH_DIO: case SPI_FLASH_DIO:
//for DIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that. //for DIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that.
addr_bitlen = SPI_FLASH_DIO_ADDR_BITLEN; addr_bitlen = SPI_FLASH_DIO_ADDR_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->dio_dummy_bitlen; dummy_cyclelen_base = rom_flash_chip_dummy->dio_dummy_bitlen;
read_command = CMD_FASTRD_DIO; read_command = (addr_32bit? CMD_FASTRD_DIO_4B: CMD_FASTRD_DIO);
conf_required = true;
break; break;
case SPI_FLASH_DOUT: case SPI_FLASH_DOUT:
addr_bitlen = SPI_FLASH_DOUT_ADDR_BITLEN; addr_bitlen = SPI_FLASH_DOUT_ADDR_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->dout_dummy_bitlen; dummy_cyclelen_base = rom_flash_chip_dummy->dout_dummy_bitlen;
read_command = CMD_FASTRD_DUAL; read_command = (addr_32bit? CMD_FASTRD_DUAL_4B: CMD_FASTRD_DUAL);
break; break;
case SPI_FLASH_FASTRD: case SPI_FLASH_FASTRD:
addr_bitlen = SPI_FLASH_FASTRD_ADDR_BITLEN; addr_bitlen = SPI_FLASH_FASTRD_ADDR_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->fastrd_dummy_bitlen; dummy_cyclelen_base = rom_flash_chip_dummy->fastrd_dummy_bitlen;
read_command = CMD_FASTRD; read_command = (addr_32bit? CMD_FASTRD_4B: CMD_FASTRD);
break; break;
case SPI_FLASH_SLOWRD: case SPI_FLASH_SLOWRD:
addr_bitlen = SPI_FLASH_SLOWRD_ADDR_BITLEN; addr_bitlen = SPI_FLASH_SLOWRD_ADDR_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->slowrd_dummy_bitlen; dummy_cyclelen_base = rom_flash_chip_dummy->slowrd_dummy_bitlen;
read_command = CMD_READ; read_command = (addr_32bit? CMD_READ_4B: CMD_READ);
break; break;
default: default:
return ESP_ERR_FLASH_NOT_INITIALISED; return ESP_ERR_FLASH_NOT_INITIALISED;
} }
//For W25Q256 chip, the only difference between 4-Byte address command and 3-Byte version is the command value and the address bit length.
if (addr_32bit) {
addr_bitlen += 8;
}
return chip->host->driver->configure_host_io_mode(chip->host, read_command, addr_bitlen, dummy_cyclelen_base, if (conf_required) {
chip->read_mode); read_mode |= SPI_FLASH_CONFIG_CONF_BITS;
}
return chip->host->driver->configure_host_io_mode(chip->host, read_command, addr_bitlen, dummy_cyclelen_base, read_mode);
} }
esp_err_t spi_flash_chip_generic_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode) esp_err_t spi_flash_chip_generic_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode)
@@ -455,6 +474,8 @@ const spi_flash_chip_t esp_flash_chip_generic = {
.wait_idle = spi_flash_chip_generic_wait_idle, .wait_idle = spi_flash_chip_generic_wait_idle,
.set_io_mode = spi_flash_chip_generic_set_io_mode, .set_io_mode = spi_flash_chip_generic_set_io_mode,
.get_io_mode = spi_flash_chip_generic_get_io_mode, .get_io_mode = spi_flash_chip_generic_get_io_mode,
.read_reg = spi_flash_chip_generic_read_reg,
}; };
/******************************************************************************* /*******************************************************************************
@@ -586,4 +607,4 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
chip->chip_drv->set_chip_write_protect(chip, true); chip->chip_drv->set_chip_write_protect(chip, true);
} }
return ret; return ret;
} }

View File

@@ -77,7 +77,6 @@ const spi_flash_chip_t esp_flash_chip_issi = {
.get_chip_write_protect = spi_flash_chip_generic_get_write_protect, .get_chip_write_protect = spi_flash_chip_generic_get_write_protect,
.set_chip_write_protect = spi_flash_chip_generic_set_write_protect, .set_chip_write_protect = spi_flash_chip_generic_set_write_protect,
// TODO support protected regions on ISSI flash
.num_protectable_regions = 0, .num_protectable_regions = 0,
.protectable_regions = NULL, .protectable_regions = NULL,
.get_protected_regions = NULL, .get_protected_regions = NULL,
@@ -92,4 +91,6 @@ const spi_flash_chip_t esp_flash_chip_issi = {
.wait_idle = spi_flash_chip_generic_wait_idle, .wait_idle = spi_flash_chip_generic_wait_idle,
.set_io_mode = spi_flash_chip_issi_set_io_mode, .set_io_mode = spi_flash_chip_issi_set_io_mode,
.get_io_mode = spi_flash_chip_issi_get_io_mode, .get_io_mode = spi_flash_chip_issi_get_io_mode,
.read_reg = spi_flash_chip_generic_read_reg,
}; };

View File

@@ -35,6 +35,7 @@ esp_err_t spi_flash_chip_issi_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t
// Use the same implementation as ISSI chips // Use the same implementation as ISSI chips
#define spi_flash_chip_mxic_set_io_mode spi_flash_chip_issi_set_io_mode #define spi_flash_chip_mxic_set_io_mode spi_flash_chip_issi_set_io_mode
#define spi_flash_chip_mxic_get_io_mode spi_flash_chip_issi_get_io_mode #define spi_flash_chip_mxic_get_io_mode spi_flash_chip_issi_get_io_mode
#define spi_flash_chip_mxic_read_reg spi_flash_chip_generic_read_reg
static const char chip_name[] = "mxic"; static const char chip_name[] = "mxic";
@@ -55,7 +56,6 @@ const spi_flash_chip_t esp_flash_chip_mxic = {
.get_chip_write_protect = spi_flash_chip_generic_get_write_protect, .get_chip_write_protect = spi_flash_chip_generic_get_write_protect,
.set_chip_write_protect = spi_flash_chip_generic_set_write_protect, .set_chip_write_protect = spi_flash_chip_generic_set_write_protect,
// TODO support protected regions on MXIC flash
.num_protectable_regions = 0, .num_protectable_regions = 0,
.protectable_regions = NULL, .protectable_regions = NULL,
.get_protected_regions = NULL, .get_protected_regions = NULL,
@@ -70,4 +70,6 @@ const spi_flash_chip_t esp_flash_chip_mxic = {
.wait_idle = spi_flash_chip_generic_wait_idle, .wait_idle = spi_flash_chip_generic_wait_idle,
.set_io_mode = spi_flash_chip_mxic_set_io_mode, .set_io_mode = spi_flash_chip_mxic_set_io_mode,
.get_io_mode = spi_flash_chip_mxic_get_io_mode, .get_io_mode = spi_flash_chip_mxic_get_io_mode,
.read_reg = spi_flash_chip_mxic_read_reg,
}; };

View File

@@ -0,0 +1,214 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <string.h>
#include <sys/param.h> // For MIN/MAX
#include "esp_log.h"
#include "spi_flash_chip_generic.h"
#include "spi_flash_defs.h"
#define REGION_32BIT(start, len) ((start) + (len) > (1<<24))
#define ADDR_32BIT(addr) (addr >= (1<<24))
static const char TAG[] = "chip_wb";
/* Driver for Winbond flash chip */
static esp_err_t spi_flash_command_winbond_program_4B(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length);
static esp_err_t spi_flash_command_winbond_erase_sector_4B(esp_flash_t *chip, uint32_t start_address);
static esp_err_t spi_flash_command_erase_block_4B(esp_flash_t *chip, uint32_t start_address);
esp_err_t spi_flash_chip_winbond_probe(esp_flash_t *chip, uint32_t flash_id)
{
/* Check manufacturer and product IDs match our desired masks */
const uint8_t MFG_ID = 0xEF;
if (flash_id >> 16 != MFG_ID) {
return ESP_ERR_NOT_FOUND;
}
return ESP_OK;
}
esp_err_t spi_flash_chip_winbond_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length)
{
esp_err_t err = ESP_OK;
const uint32_t page_size = chip->chip_drv->page_size;
uint32_t align_address;
uint8_t temp_buffer[64]; //spiflash hal max length of read no longer than 64byte
// Configure the host, and return
err = spi_flash_chip_generic_config_host_io_mode(chip, REGION_32BIT(address, length));
if (err == ESP_ERR_NOT_SUPPORTED) {
ESP_LOGE(TAG, "configure host io mode failed - unsupported");
return err;
}
while (err == ESP_OK && length > 0) {
memset(temp_buffer, 0xFF, sizeof(temp_buffer));
uint32_t read_len = chip->host->driver->read_data_slicer(chip->host, address, length, &align_address, page_size);
uint32_t left_off = address - align_address;
uint32_t data_len = MIN(align_address + read_len, address + length) - address;
err = chip->host->driver->read(chip->host, temp_buffer, align_address, read_len);
memcpy(buffer, temp_buffer + left_off, data_len);
address += data_len;
buffer = (void *)((intptr_t)buffer + data_len);
length = length - data_len;
}
return err;
}
esp_err_t spi_flash_chip_winbond_page_program(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length)
{
esp_err_t err;
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
if (err == ESP_OK) {
// Perform the actual Page Program command
err = spi_flash_command_winbond_program_4B(chip, buffer, address, length);
if (err != ESP_OK) {
return err;
}
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->page_program_timeout);
}
return err;
}
esp_err_t spi_flash_chip_winbond_erase_sector(esp_flash_t *chip, uint32_t start_address)
{
esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
}
if (err == ESP_OK) {
err = spi_flash_command_winbond_erase_sector_4B(chip, start_address);
if (err != ESP_OK) {
return err;
}
//to save time, flush cache here
if (chip->host->driver->flush_cache) {
err = chip->host->driver->flush_cache(chip->host, start_address, chip->chip_drv->sector_size);
if (err != ESP_OK) {
return err;
}
}
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->sector_erase_timeout);
}
return err;
}
esp_err_t spi_flash_chip_winbond_erase_block(esp_flash_t *chip, uint32_t start_address)
{
esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
}
if (err == ESP_OK) {
err = spi_flash_command_erase_block_4B(chip, start_address);
if (err != ESP_OK) {
return err;
}
//to save time, flush cache here
if (chip->host->driver->flush_cache) {
err = chip->host->driver->flush_cache(chip->host, start_address, chip->chip_drv->block_erase_size);
if (err != ESP_OK) {
return err;
}
}
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->block_erase_timeout);
}
return err;
}
static const char chip_name[] = "winbond";
// The issi chip can use the functions for generic chips except from set read mode and probe,
// So we only replace these two functions.
const spi_flash_chip_t esp_flash_chip_winbond = {
.name = chip_name,
.timeout = &spi_flash_chip_generic_timeout,
.probe = spi_flash_chip_winbond_probe,
.reset = spi_flash_chip_generic_reset,
.detect_size = spi_flash_chip_generic_detect_size,
.erase_chip = spi_flash_chip_generic_erase_chip,
.erase_sector = spi_flash_chip_winbond_erase_sector,
.erase_block = spi_flash_chip_winbond_erase_block,
.sector_size = 4 * 1024,
.block_erase_size = 64 * 1024,
.get_chip_write_protect = spi_flash_chip_generic_get_write_protect,
.set_chip_write_protect = spi_flash_chip_generic_set_write_protect,
.num_protectable_regions = 0,
.protectable_regions = NULL,
.get_protected_regions = NULL,
.set_protected_regions = NULL,
.read = spi_flash_chip_winbond_read,
.write = spi_flash_chip_generic_write,
.program_page = spi_flash_chip_winbond_page_program,
.page_size = 256,
.write_encrypted = spi_flash_chip_generic_write_encrypted,
.wait_idle = spi_flash_chip_generic_wait_idle,
.set_io_mode = spi_flash_chip_generic_set_io_mode,
.get_io_mode = spi_flash_chip_generic_get_io_mode,
.read_reg = spi_flash_chip_generic_read_reg,
};
static esp_err_t spi_flash_command_winbond_program_4B(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length)
{
bool addr_4b = ADDR_32BIT(address);
spi_flash_trans_t t = {
.command = (addr_4b? CMD_PROGRAM_PAGE_4B: CMD_PROGRAM_PAGE),
.address_bitlen = (addr_4b? 32: 24),
.address = address,
.mosi_len = length,
.mosi_data = buffer,
};
return chip->host->driver->common_command(chip->host, &t);
}
esp_err_t spi_flash_command_winbond_erase_sector_4B(esp_flash_t *chip, uint32_t start_address)
{
bool addr_4b = ADDR_32BIT(start_address);
spi_flash_trans_t t = {
.command = (addr_4b? CMD_SECTOR_ERASE_4B: CMD_SECTOR_ERASE),
.address_bitlen = (addr_4b? 32: 24),
.address = start_address,
};
return chip->host->driver->common_command(chip->host, &t);
}
esp_err_t spi_flash_command_erase_block_4B(esp_flash_t *chip, uint32_t start_address)
{
bool addr_4b = ADDR_32BIT(start_address);
spi_flash_trans_t t = {
.command = (addr_4b? CMD_LARGE_BLOCK_ERASE_4B: CMD_LARGE_BLOCK_ERASE),
.address_bitlen = (addr_4b? 32: 24),
.address = start_address,
};
return chip->host->driver->common_command(chip->host, &t);
}

View File

@@ -27,6 +27,7 @@
static uint8_t sector_buf[4096]; static uint8_t sector_buf[4096];
#define MAX_ADDR_24BIT 0x1000000
#define TEST_SPI_SPEED ESP_FLASH_10MHZ #define TEST_SPI_SPEED ESP_FLASH_10MHZ
#define TEST_SPI_READ_MODE SPI_FLASH_FASTRD #define TEST_SPI_READ_MODE SPI_FLASH_FASTRD
// #define FORCE_GPIO_MATRIX // #define FORCE_GPIO_MATRIX
@@ -92,7 +93,7 @@ static uint8_t sector_buf[4096];
#define TEST_CONFIG_NUM (sizeof(config_list)/sizeof(flashtest_config_t)) #define TEST_CONFIG_NUM (sizeof(config_list)/sizeof(flashtest_config_t))
typedef void (*flash_test_func_t)(esp_flash_t* chip); typedef void (*flash_test_func_t)(const esp_partition_t *part);
/* Use FLASH_TEST_CASE for SPI flash tests that only use the main SPI flash chip /* Use FLASH_TEST_CASE for SPI flash tests that only use the main SPI flash chip
*/ */
@@ -348,39 +349,63 @@ static void setup_new_chip(const flashtest_config_t* test_cfg, esp_flash_t** out
TEST_ESP_OK(err); TEST_ESP_OK(err);
err = esp_flash_init(init_chip); err = esp_flash_init(init_chip);
TEST_ESP_OK(err); TEST_ESP_OK(err);
uint32_t size;
err = esp_flash_get_size(init_chip, &size);
TEST_ESP_OK(err);
ESP_LOGI(TAG, "Flash size: 0x%08X", size);
*out_chip = init_chip; *out_chip = init_chip;
} }
void teardown_test_chip(esp_flash_t* chip, spi_host_device_t host) static void teardown_test_chip(esp_flash_t* chip)
{ {
spi_host_device_t host_id;
get_chip_host(chip, &host_id, NULL);
//happen to work when chip==NULL //happen to work when chip==NULL
spi_bus_remove_flash_device(chip); spi_bus_remove_flash_device(chip);
release_bus(host); release_bus(host_id);
}
static void flash_test_core(flash_test_func_t func, const flashtest_config_t* config)
{
esp_flash_t* chip;
setup_new_chip(config, &chip);
uint32_t size;
esp_err_t err = esp_flash_get_size(chip, &size);
TEST_ESP_OK(err);
ESP_LOGI(TAG, "Flash size: 0x%08X", size);
const esp_partition_t* test_part = get_test_data_partition();
TEST_ASSERT_NOT_EQUAL(NULL, test_part->flash_chip);
esp_partition_t part = *test_part;
part.flash_chip = chip;
ESP_LOGI(TAG, "Testing chip %p, address 0x%08X...", part.flash_chip, part.address);
(*func)(&part);
// For flash with size over 16MB, add one extra round of test for the 32-bit address area
if (size > MAX_ADDR_24BIT) {
part.address = 0x1030000;
part.size = 0x0010000;
ESP_LOGI(TAG, "Testing chip %p, address 0x%08X...", part.flash_chip, part.address);
(*func)(&part);
}
teardown_test_chip(chip);
} }
static void flash_test_func(flash_test_func_t func, int test_num) static void flash_test_func(flash_test_func_t func, int test_num)
{ {
esp_log_level_set("gpio", ESP_LOG_NONE);
for (int i = 0; i < test_num; i++) { for (int i = 0; i < test_num; i++) {
ESP_LOGI(TAG, "Testing config %d/%d", i, test_num); ESP_LOGI(TAG, "Testing config %d/%d", i+1, test_num);
flashtest_config_t* config = &config_list[i]; flash_test_core(func, &config_list[i]);
esp_flash_t* chip;
setup_new_chip(config, &chip);
(*func)(chip);
teardown_test_chip(chip, config->host_id);
} }
ESP_LOGI(TAG, "Completed %d configs", test_num); ESP_LOGI(TAG, "Completed %d configs", test_num);
} }
/* ---------- Test code start ------------*/ /* ---------- Test code start ------------*/
static void test_metadata(esp_flash_t *chip) static void test_metadata(const esp_partition_t* part)
{ {
ESP_LOGI(TAG, "Testing chip %p...", chip); esp_flash_t* chip = part->flash_chip;
uint32_t id, size; uint32_t id, size;
TEST_ESP_OK(esp_flash_read_id(chip, &id)); TEST_ESP_OK(esp_flash_read_id(chip, &id));
TEST_ESP_OK(esp_flash_get_size(chip, &size)); TEST_ESP_OK(esp_flash_get_size(chip, &size));
@@ -390,9 +415,9 @@ static void test_metadata(esp_flash_t *chip)
FLASH_TEST_CASE("SPI flash metadata functions", test_metadata); FLASH_TEST_CASE("SPI flash metadata functions", test_metadata);
FLASH_TEST_CASE_3("SPI flash metadata functions", test_metadata); FLASH_TEST_CASE_3("SPI flash metadata functions", test_metadata);
static uint32_t erase_test_region(esp_flash_t *chip, int num_sectors) static uint32_t erase_test_region(const esp_partition_t *part, int num_sectors)
{ {
const esp_partition_t *part = get_test_data_partition(); esp_flash_t* chip = part->flash_chip;
uint32_t offs = part->address; uint32_t offs = part->address;
/* chip should be initialised */ /* chip should be initialised */
@@ -419,10 +444,10 @@ static uint32_t erase_test_region(esp_flash_t *chip, int num_sectors)
return offs; return offs;
} }
void test_simple_read_write(esp_flash_t *chip) void test_simple_read_write(const esp_partition_t* part)
{ {
ESP_LOGI(TAG, "Testing chip %p...", chip); esp_flash_t* chip = part->flash_chip;
uint32_t offs = erase_test_region(chip, 1); uint32_t offs = erase_test_region(part, 1);
const int test_seed = 778; const int test_seed = 778;
srand(test_seed); srand(test_seed);
@@ -450,10 +475,10 @@ void test_simple_read_write(esp_flash_t *chip)
FLASH_TEST_CASE("SPI flash simple read/write", test_simple_read_write); FLASH_TEST_CASE("SPI flash simple read/write", test_simple_read_write);
FLASH_TEST_CASE_3("SPI flash simple read/write", test_simple_read_write); FLASH_TEST_CASE_3("SPI flash simple read/write", test_simple_read_write);
void test_unaligned_read_write(esp_flash_t *chip) void test_unaligned_read_write(const esp_partition_t* part)
{ {
ESP_LOGI(TAG, "Testing chip %p...", chip); esp_flash_t* chip = part->flash_chip;
uint32_t offs = erase_test_region(chip, 2); uint32_t offs = erase_test_region(part, 2);
const char *msg = "i am a message"; const char *msg = "i am a message";
TEST_ASSERT(strlen(msg) + 1 % 4 != 0); TEST_ASSERT(strlen(msg) + 1 % 4 != 0);
@@ -471,12 +496,12 @@ void test_unaligned_read_write(esp_flash_t *chip)
FLASH_TEST_CASE("SPI flash unaligned read/write", test_unaligned_read_write); FLASH_TEST_CASE("SPI flash unaligned read/write", test_unaligned_read_write);
FLASH_TEST_CASE_3("SPI flash unaligned read/write", test_unaligned_read_write); FLASH_TEST_CASE_3("SPI flash unaligned read/write", test_unaligned_read_write);
void test_single_read_write(esp_flash_t* chip) void test_single_read_write(const esp_partition_t* part)
{ {
const int seed = 699; esp_flash_t* chip = part->flash_chip;
ESP_LOGI(TAG, "Testing chip %p...", chip); uint32_t offs = erase_test_region(part, 2);
uint32_t offs = erase_test_region(chip, 2);
const int seed = 699;
srand(seed); srand(seed);
for (unsigned v = 0; v < 512; v++) { for (unsigned v = 0; v < 512; v++) {
uint32_t data = rand(); uint32_t data = rand();
@@ -499,11 +524,12 @@ FLASH_TEST_CASE_3("SPI flash single byte reads/writes", test_single_read_write);
/* this test is notable because it generates a lot of unaligned reads/writes, /* this test is notable because it generates a lot of unaligned reads/writes,
and also reads/writes across both a sector boundary & many page boundaries. and also reads/writes across both a sector boundary & many page boundaries.
*/ */
void test_three_byte_read_write(esp_flash_t *chip) void test_three_byte_read_write(const esp_partition_t* part)
{ {
esp_flash_t* chip = part->flash_chip;
uint32_t offs = erase_test_region(part, 2);
const int seed = 700; const int seed = 700;
ESP_LOGI(TAG, "Testing chip %p...", chip);
uint32_t offs = erase_test_region(chip, 2);
esp_rom_printf("offs:%X\n", offs); esp_rom_printf("offs:%X\n", offs);
srand(seed); srand(seed);
@@ -524,11 +550,9 @@ void test_three_byte_read_write(esp_flash_t *chip)
FLASH_TEST_CASE("SPI flash three byte reads/writes", test_three_byte_read_write); FLASH_TEST_CASE("SPI flash three byte reads/writes", test_three_byte_read_write);
FLASH_TEST_CASE_3("SPI flash three byte reads/writes", test_three_byte_read_write); FLASH_TEST_CASE_3("SPI flash three byte reads/writes", test_three_byte_read_write);
void test_erase_large_region(esp_flash_t *chip) void test_erase_large_region(const esp_partition_t *part)
{ {
ESP_LOGI(TAG, "Testing chip %p...", chip); esp_flash_t* chip = part->flash_chip;
const esp_partition_t *part = get_test_data_partition();
/* Write some noise at the start and the end of the region */ /* Write some noise at the start and the end of the region */
const char *ohai = "OHAI"; const char *ohai = "OHAI";
@@ -557,8 +581,10 @@ void test_erase_large_region(esp_flash_t *chip)
FLASH_TEST_CASE("SPI flash erase large region", test_erase_large_region); FLASH_TEST_CASE("SPI flash erase large region", test_erase_large_region);
FLASH_TEST_CASE_3("SPI flash erase large region", test_erase_large_region); FLASH_TEST_CASE_3("SPI flash erase large region", test_erase_large_region);
static void test_write_protection(esp_flash_t* chip) static void test_write_protection(const esp_partition_t* part)
{ {
esp_flash_t* chip = part->flash_chip;
bool wp = true; bool wp = true;
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
ret = esp_flash_get_chip_write_protect(chip, &wp); ret = esp_flash_get_chip_write_protect(chip, &wp);
@@ -591,9 +617,9 @@ static const uint8_t large_const_buffer[16400] = {
43 // last byte 43 // last byte
}; };
static void test_write_large_buffer(esp_flash_t *chip, const uint8_t *source, size_t length); static void test_write_large_buffer(const esp_partition_t *part, const uint8_t *source, size_t length);
static void write_large_buffer(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length); static void write_large_buffer(const esp_partition_t *part, const uint8_t *source, size_t length);
static void read_and_check(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length); static void read_and_check(const esp_partition_t *part, const uint8_t *source, size_t length);
// Internal functions for testing, from esp_flash_api.c // Internal functions for testing, from esp_flash_api.c
esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe); esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe);
@@ -621,8 +647,10 @@ static bool is_mxic_chip(esp_flash_t* chip)
return (spi_flash_chip_mxic_probe(chip, flash_id)==ESP_OK); return (spi_flash_chip_mxic_probe(chip, flash_id)==ESP_OK);
} }
IRAM_ATTR NOINLINE_ATTR static void test_toggle_qe(esp_flash_t* chip) IRAM_ATTR NOINLINE_ATTR static void test_toggle_qe(const esp_partition_t* part)
{ {
esp_flash_t* chip = part->flash_chip;
bool qe; bool qe;
if (chip == NULL) { if (chip == NULL) {
chip = esp_flash_default_chip; chip = esp_flash_default_chip;
@@ -669,33 +697,8 @@ IRAM_ATTR NOINLINE_ATTR static void test_toggle_qe(esp_flash_t* chip)
FLASH_TEST_CASE_IGNORE("Test esp_flash_write can toggle QE bit", test_toggle_qe); FLASH_TEST_CASE_IGNORE("Test esp_flash_write can toggle QE bit", test_toggle_qe);
FLASH_TEST_CASE_3_IGNORE("Test esp_flash_write can toggle QE bit", test_toggle_qe); FLASH_TEST_CASE_3_IGNORE("Test esp_flash_write can toggle QE bit", test_toggle_qe);
void test_permutations_part(const flashtest_config_t* config, esp_partition_t* part, void* source_buf, size_t length)
void test_permutations(flashtest_config_t* config)
{ {
//replace config pointer with pointer to internal temporary config
flashtest_config_t temp_cfg;
memcpy(&temp_cfg, config, sizeof(flashtest_config_t));
flashtest_config_t* cfg = &temp_cfg;
esp_flash_t* chip;
const int length = sizeof(large_const_buffer);
uint8_t *source_buf = malloc(length);
TEST_ASSERT_NOT_NULL(source_buf);
srand(778);
for (int i = 0; i < length; i++) {
source_buf[i] = rand();
}
const esp_partition_t *part = get_test_data_partition();
TEST_ASSERT(part->size > length + 2 + SPI_FLASH_SEC_SIZE);
//write data to be read, and use the lowest speed to write and read to make sure success
cfg->io_mode = SPI_FLASH_READ_MODE_MIN;
cfg->speed = ESP_FLASH_SPEED_MIN;
setup_new_chip(cfg, &chip);
write_large_buffer(chip, part, source_buf, length);
read_and_check(chip, part, source_buf, length);
teardown_test_chip(chip, cfg->host_id);
if (config->host_id != -1) { if (config->host_id != -1) {
esp_flash_speed_t speed = ESP_FLASH_SPEED_MIN; esp_flash_speed_t speed = ESP_FLASH_SPEED_MIN;
while (speed != ESP_FLASH_SPEED_MAX) { while (speed != ESP_FLASH_SPEED_MAX) {
@@ -703,27 +706,90 @@ void test_permutations(flashtest_config_t* config)
//the io mode will switch frequently. //the io mode will switch frequently.
esp_flash_io_mode_t io_mode = SPI_FLASH_READ_MODE_MIN; esp_flash_io_mode_t io_mode = SPI_FLASH_READ_MODE_MIN;
while (io_mode != SPI_FLASH_READ_MODE_MAX) { while (io_mode != SPI_FLASH_READ_MODE_MAX) {
cfg->io_mode = io_mode; if (io_mode > SPI_FLASH_FASTRD &&
cfg->speed = speed; !SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(config->host_id)) {
if (io_mode > SPI_FLASH_FASTRD\
&& !SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(cfg->host_id)) {
io_mode++; io_mode++;
continue; continue;
} }
setup_new_chip(cfg, &chip); esp_flash_t* chip;
flashtest_config_t temp_config = *config;
temp_config.io_mode = io_mode;
temp_config.speed = speed;
setup_new_chip(&temp_config, &chip);
ESP_LOGI(TAG, "test flash io mode: %d, speed: %d", io_mode, speed); ESP_LOGI(TAG, "test flash io mode: %d, speed: %d", io_mode, speed);
read_and_check(chip, part, source_buf, length); part->flash_chip = chip;
teardown_test_chip(chip, cfg->host_id); read_and_check(part, source_buf, length);
teardown_test_chip(chip);
io_mode++; io_mode++;
} }
speed++; speed++;
} }
} else { } else {
//test main flash //test main flash
write_large_buffer(NULL, part, source_buf, length); part->flash_chip = NULL;
read_and_check(NULL, part, source_buf, length); read_and_check(part, source_buf, length);
}
}
void test_permutations_chip(const flashtest_config_t* config)
{
esp_log_level_set("gpio", ESP_LOG_NONE);
esp_flash_t* chip;
flashtest_config_t temp_config = *config;
// Use the lowest speed to read configs, data and write data to make sure success
temp_config.io_mode = SPI_FLASH_READ_MODE_MIN;
temp_config.speed = ESP_FLASH_SPEED_MIN;
setup_new_chip(&temp_config, &chip);
//Get size to determine whether to test one extra partition
uint32_t size;
esp_err_t err = esp_flash_get_size(chip, &size);
TEST_ESP_OK(err);
ESP_LOGI(TAG, "Flash size: 0x%08X", size);
bool addr_32bit = (size > MAX_ADDR_24BIT);
// Get test partition, and locate temporary partitions according to the default one
const esp_partition_t* test_part = get_test_data_partition();
const int length = sizeof(large_const_buffer);
TEST_ASSERT(test_part->size > length + 2 + SPI_FLASH_SEC_SIZE);
esp_partition_t part[2] = {};
part[0] = *test_part;
part[0].flash_chip = chip;
// For flash with size over 16MB, add one extra round of test for the 32-bit address area
if (addr_32bit) {
part[1] = *test_part;
part[1].flash_chip = chip;
part[1].address = 0x1030000;
part[1].size = 0x0010000;
} else {
part[1].size = 0;
}
// Prepare test data and write to the specified region
uint8_t *source_buf = malloc(length);
TEST_ASSERT_NOT_NULL(source_buf);
srand(778);
for (int i = 0; i < length; i++) {
source_buf[i] = rand();
}
for (int i = 0; i < 2; i++) {
if (part[i].size == 0) continue;
write_large_buffer(&part[i], source_buf, length);
}
teardown_test_chip(chip);
for (int i = 0; i < 2; i++) {
if (part[i].size == 0) continue;
part[i].flash_chip = (esp_flash_t*)-1;
ESP_LOGI(TAG, "Testing address 0x%08X...", part[i].address);
test_permutations_part(config, &part[i], source_buf, length);
} }
free(source_buf); free(source_buf);
@@ -731,42 +797,44 @@ void test_permutations(flashtest_config_t* config)
TEST_CASE("SPI flash test reading with all speed/mode permutations", "[esp_flash]") TEST_CASE("SPI flash test reading with all speed/mode permutations", "[esp_flash]")
{ {
test_permutations(&config_list[0]); test_permutations_chip(&config_list[0]);
} }
#ifndef CONFIG_SPIRAM #ifndef CONFIG_SPIRAM
TEST_CASE("SPI flash test reading with all speed/mode permutations, 3 chips", "[esp_flash][test_env=UT_T1_ESP_FLASH]") TEST_CASE("SPI flash test reading with all speed/mode permutations, 3 chips", "[esp_flash][test_env=UT_T1_ESP_FLASH]")
{ {
for (int i = 0; i < TEST_CONFIG_NUM; i++) { for (int i = 0; i < TEST_CONFIG_NUM; i++) {
test_permutations(&config_list[i]); test_permutations_chip(&config_list[i]);
} }
} }
#endif #endif
static void test_write_large_const_buffer(esp_flash_t* chip)
static void test_write_large_const_buffer(const esp_partition_t* part)
{ {
test_write_large_buffer(chip, large_const_buffer, sizeof(large_const_buffer)); test_write_large_buffer(part, large_const_buffer, sizeof(large_const_buffer));
} }
FLASH_TEST_CASE("Test esp_flash_write large const buffer", test_write_large_const_buffer); FLASH_TEST_CASE("Test esp_flash_write large const buffer", test_write_large_const_buffer);
FLASH_TEST_CASE_3("Test esp_flash_write large const buffer", test_write_large_const_buffer); FLASH_TEST_CASE_3("Test esp_flash_write large const buffer", test_write_large_const_buffer);
static void test_write_large_ram_buffer(esp_flash_t* chip) static void test_write_large_ram_buffer(const esp_partition_t* part)
{ {
// buffer in RAM // buffer in RAM
uint8_t *source_buf = malloc(sizeof(large_const_buffer)); uint8_t *source_buf = malloc(sizeof(large_const_buffer));
TEST_ASSERT_NOT_NULL(source_buf); TEST_ASSERT_NOT_NULL(source_buf);
memcpy(source_buf, large_const_buffer, sizeof(large_const_buffer)); memcpy(source_buf, large_const_buffer, sizeof(large_const_buffer));
test_write_large_buffer(chip, source_buf, sizeof(large_const_buffer)); test_write_large_buffer(part, source_buf, sizeof(large_const_buffer));
free(source_buf); free(source_buf);
} }
FLASH_TEST_CASE("Test esp_flash_write large RAM buffer", test_write_large_ram_buffer); FLASH_TEST_CASE("Test esp_flash_write large RAM buffer", test_write_large_ram_buffer);
FLASH_TEST_CASE_3("Test esp_flash_write large RAM buffer", test_write_large_ram_buffer); FLASH_TEST_CASE_3("Test esp_flash_write large RAM buffer", test_write_large_ram_buffer);
static void write_large_buffer(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length) static void write_large_buffer(const esp_partition_t *part, const uint8_t *source, size_t length)
{ {
printf("Writing chip %p, %d bytes from source %p\n", chip, length, source); esp_flash_t* chip = part->flash_chip;
printf("Writing chip %p %p, %d bytes from source %p\n", chip, (void*)part->address, length, source);
ESP_ERROR_CHECK( esp_flash_erase_region(chip, part->address, (length + SPI_FLASH_SEC_SIZE) & ~(SPI_FLASH_SEC_SIZE - 1)) ); ESP_ERROR_CHECK( esp_flash_erase_region(chip, part->address, (length + SPI_FLASH_SEC_SIZE) & ~(SPI_FLASH_SEC_SIZE - 1)) );
@@ -774,9 +842,10 @@ static void write_large_buffer(esp_flash_t *chip, const esp_partition_t *part, c
ESP_ERROR_CHECK( esp_flash_write(chip, source, part->address + 1, length) ); ESP_ERROR_CHECK( esp_flash_write(chip, source, part->address + 1, length) );
} }
static void read_and_check(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length) static void read_and_check(const esp_partition_t *part, const uint8_t *source, size_t length)
{ {
printf("Checking chip %p, %d bytes\n", chip, length); esp_flash_t* chip = part->flash_chip;
printf("Checking chip %p 0x%08X, %d bytes\n", chip, part->address, length);
uint8_t *buf = malloc(length); uint8_t *buf = malloc(length);
TEST_ASSERT_NOT_NULL(buf); TEST_ASSERT_NOT_NULL(buf);
ESP_ERROR_CHECK( esp_flash_read(chip, buf, part->address + 1, length) ); ESP_ERROR_CHECK( esp_flash_read(chip, buf, part->address + 1, length) );
@@ -798,14 +867,12 @@ static void read_and_check(esp_flash_t *chip, const esp_partition_t *part, const
TEST_ASSERT_EQUAL_HEX8(0xFF, ends[3]); TEST_ASSERT_EQUAL_HEX8(0xFF, ends[3]);
} }
static void test_write_large_buffer(esp_flash_t *chip, const uint8_t *source, size_t length) static void test_write_large_buffer(const esp_partition_t* part, const uint8_t *source, size_t length)
{ {
ESP_LOGI(TAG, "Testing chip %p...", chip);
const esp_partition_t *part = get_test_data_partition();
TEST_ASSERT(part->size > length + 2 + SPI_FLASH_SEC_SIZE); TEST_ASSERT(part->size > length + 2 + SPI_FLASH_SEC_SIZE);
write_large_buffer(chip, part, source, length); write_large_buffer(part, source, length);
read_and_check(chip, part, source, length); read_and_check(part, source, length);
} }
typedef struct { typedef struct {
@@ -889,18 +956,12 @@ static uint32_t measure_read(const char* name, const esp_partition_t* part, uint
return time_measure_end(&time_ctx); return time_measure_end(&time_ctx);
} }
#define MEAS_WRITE(n) (measure_write("write in "#n"-byte chunks", &test_part, data_to_write, n)) #define MEAS_WRITE(n) (measure_write("write in "#n"-byte chunks", part, data_to_write, n))
#define MEAS_READ(n) (measure_read("read in "#n"-byte chunks", &test_part, data_read, n)) #define MEAS_READ(n) (measure_read("read in "#n"-byte chunks", part, data_read, n))
static void test_flash_read_write_performance(esp_flash_t* chip) static void test_flash_read_write_performance(const esp_partition_t *part)
{ {
const esp_partition_t *part = get_test_data_partition(); esp_flash_t* chip = part->flash_chip;
// Copy to new partition variable and replace the chip member
// Actually there's no "partition" in the external flash on runners. We just don't bother creating a new partition variable.
esp_partition_t test_part;
memcpy(&test_part, part, sizeof(esp_partition_t));
test_part.flash_chip = chip;
const int total_len = SPI_FLASH_SEC_SIZE; const int total_len = SPI_FLASH_SEC_SIZE;
uint8_t *data_to_write = heap_caps_malloc(total_len, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); uint8_t *data_to_write = heap_caps_malloc(total_len, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
uint8_t *data_read = heap_caps_malloc(total_len, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); uint8_t *data_read = heap_caps_malloc(total_len, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
@@ -910,10 +971,10 @@ static void test_flash_read_write_performance(esp_flash_t* chip)
data_to_write[i] = rand(); data_to_write[i] = rand();
} }
uint32_t erase_1 = measure_erase(&test_part); uint32_t erase_1 = measure_erase(part);
uint32_t speed_WR_4B = MEAS_WRITE(4); uint32_t speed_WR_4B = MEAS_WRITE(4);
uint32_t speed_RD_4B = MEAS_READ(4); uint32_t speed_RD_4B = MEAS_READ(4);
uint32_t erase_2 = measure_erase(&test_part); uint32_t erase_2 = measure_erase(part);
uint32_t speed_WR_2KB = MEAS_WRITE(2048); uint32_t speed_WR_2KB = MEAS_WRITE(2048);
uint32_t speed_RD_2KB = MEAS_READ(2048); uint32_t speed_RD_2KB = MEAS_READ(2048);
@@ -958,7 +1019,6 @@ static void test_flash_read_write_performance(esp_flash_t* chip)
FLASH_TEST_CASE("Test esp_flash read/write performance", test_flash_read_write_performance); FLASH_TEST_CASE("Test esp_flash read/write performance", test_flash_read_write_performance);
FLASH_TEST_CASE_3("Test esp_flash read/write performance", test_flash_read_write_performance); FLASH_TEST_CASE_3("Test esp_flash read/write performance", test_flash_read_write_performance);
#ifdef CONFIG_SPIRAM_USE_MALLOC #ifdef CONFIG_SPIRAM_USE_MALLOC
/* Utility: Read into a small internal RAM buffer using esp_flash_read() and compare what /* Utility: Read into a small internal RAM buffer using esp_flash_read() and compare what
@@ -978,8 +1038,9 @@ static void s_test_compare_flash_contents_small_reads(esp_flash_t *chip, const u
free(ibuf); free(ibuf);
} }
static void test_flash_read_large_psram_buffer(esp_flash_t *chip) static void test_flash_read_large_psram_buffer(const esp_partition_t *part)
{ {
esp_flash_t* chip = part->flash_chip;
const size_t BUF_SZ = 256 * 1024; // Too large for internal RAM const size_t BUF_SZ = 256 * 1024; // Too large for internal RAM
const size_t TEST_OFFS = 0x1000; // Can be any offset, really const size_t TEST_OFFS = 0x1000; // Can be any offset, really
@@ -998,8 +1059,9 @@ FLASH_TEST_CASE("esp_flash_read large PSRAM buffer", test_flash_read_large_psram
/* similar to above test, but perform it under memory pressure */ /* similar to above test, but perform it under memory pressure */
static void test_flash_read_large_psram_buffer_low_internal_mem(esp_flash_t *chip) static void test_flash_read_large_psram_buffer_low_internal_mem(const esp_partition_t *part)
{ {
esp_flash_t* chip = part->flash_chip;
const size_t BUF_SZ = 256 * 1024; // Too large for internal RAM const size_t BUF_SZ = 256 * 1024; // Too large for internal RAM
const size_t REMAINING_INTERNAL = 1024; // Exhaust internal memory until maximum free block is less than this const size_t REMAINING_INTERNAL = 1024; // Exhaust internal memory until maximum free block is less than this
const size_t TEST_OFFS = 0x8000; const size_t TEST_OFFS = 0x8000;

View File

@@ -69,6 +69,26 @@ static int cmp_or_dump(const void *a, const void *b, size_t len)
return r; return r;
} }
static void IRAM_ATTR fix_rom_func(void)
{
#ifdef CONFIG_IDF_TARGET_ESP32S2
esp_rom_spiflash_read_mode_t read_mode;
# if defined CONFIG_ESPTOOLPY_FLASHMODE_QIO
read_mode = ESP_ROM_SPIFLASH_QIO_MODE;
# elif defined CONFIG_ESPTOOLPY_FLASHMODE_QOUT
read_mode = ESP_ROM_SPIFLASH_QOUT_MODE;
# elif defined CONFIG_ESPTOOLPY_FLASHMODE_DIO
read_mode = ESP_ROM_SPIFLASH_DIO_MODE;
# elif defined CONFIG_ESPTOOLPY_FLASHMODE_DOUT
read_mode = ESP_ROM_SPIFLASH_DOUT_MODE;
# endif
//Currently only call this can fix the rom_read issue, maybe we need to call more functions (freq, dummy, etc) in the future
spi_flash_disable_interrupts_caches_and_other_cpu();
esp_rom_spiflash_config_readmode(read_mode);
spi_flash_enable_interrupts_caches_and_other_cpu();
#endif
}
static void IRAM_ATTR test_read(int src_off, int dst_off, int len) static void IRAM_ATTR test_read(int src_off, int dst_off, int len)
{ {
uint32_t src_buf[16]; uint32_t src_buf[16];
@@ -161,6 +181,8 @@ static void IRAM_ATTR test_write(int dst_off, int src_off, int len)
} }
ESP_ERROR_CHECK(spi_flash_write(start + dst_off, src_buf + src_off, len)); ESP_ERROR_CHECK(spi_flash_write(start + dst_off, src_buf + src_off, len));
fix_rom_func();
spi_flash_disable_interrupts_caches_and_other_cpu(); spi_flash_disable_interrupts_caches_and_other_cpu();
esp_rom_spiflash_result_t rc = esp_rom_spiflash_read(start, dst_buf, sizeof(dst_buf)); esp_rom_spiflash_result_t rc = esp_rom_spiflash_read(start, dst_buf, sizeof(dst_buf));
spi_flash_enable_interrupts_caches_and_other_cpu(); spi_flash_enable_interrupts_caches_and_other_cpu();

View File

@@ -41,6 +41,7 @@ components/esp_wifi/esp32/include/phy_init_data.h
components/spi_flash/include/spi_flash_chip_issi.h components/spi_flash/include/spi_flash_chip_issi.h
components/spi_flash/include/spi_flash_chip_mxic.h components/spi_flash/include/spi_flash_chip_mxic.h
components/spi_flash/include/spi_flash_chip_gd.h components/spi_flash/include/spi_flash_chip_gd.h
components/spi_flash/include/spi_flash_chip_winbond.h
components/spi_flash/include/memspi_host_driver.h components/spi_flash/include/memspi_host_driver.h
components/spi_flash/include/spi_flash_chip_driver.h components/spi_flash/include/spi_flash_chip_driver.h
components/spi_flash/include/spi_flash_chip_generic.h components/spi_flash/include/spi_flash_chip_generic.h