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

This commit is contained in:
Michael (XIAO Xufeng)
2020-07-27 03:13:07 +08:00
parent 54e8ec29b2
commit 3bacf35310
31 changed files with 559 additions and 111 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

@@ -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,13 @@ 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 +62,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 +107,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 +138,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

@@ -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

@@ -30,6 +30,6 @@
#define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(spi_dev) (!((void*)spi_dev == (void*)&GPSPI3)) #define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(spi_dev) (!((void*)spi_dev == (void*)&GPSPI3))
// 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,
}; };
/******************************************************************************* /*******************************************************************************

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

@@ -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