refactor(spi_flash): reorganize header files and improve API encapsulation

This commit reorganizes SPI flash header files to better reflect their
visibility and intended usage:

1. Rename `esp_flash_port/` to `esp_flash_chips/`:
   - Better reflects that these headers are for chip driver implementations
   - All chip driver headers moved to `esp_flash_chips/` directory
   - Added README.md explaining semi-public nature of these headers

2. Move internal headers to `esp_private/`:
   - `esp_flash_internal.h` -> `esp_private/esp_flash_internal.h`
   - `memspi_host_driver.h` -> `esp_private/memspi_host_driver.h`

3. Move chip driver related headers to `esp_flash_chips/`:
   - `esp_private/esp_flash_types.h` -> `esp_flash_chips/esp_flash_types.h`
   - `spi_flash/spi_flash_defs.h` -> `esp_flash_chips/spi_flash_defs.h`
   - `spi_flash_override.h` -> `esp_flash_chips/spi_flash_override.h`
   - All `spi_flash_chip_*.h` headers moved to `esp_flash_chips/`

4. Code improvements:
   - Remove unused includes (e.g., `spi_flash_override.h` from `cache_utils.c`)
   - Use public API `esp_flash_get_size()` instead of direct member access
   - Add `esp_flash_is_quad_mode` to linker.lf for IRAM placement

5. Documentation updates:
   - Add README.md in `esp_flash_chips/` explaining semi-public headers
   - Update programming guide with warnings about internal headers
   - Update both English and Chinese documentation

6. Update all references across the codebase:
   - Update includes in `spi_flash` component
   - Update `bootloader_support`, `app_update`, `esp_tee`, `espcoredump`
   - Update example projects

Breaking changes:
- Headers moved to new locations require include path updates
- `custom_flash_driver` example temporarily disabled until external
  components are updated
This commit is contained in:
Xiao Xufeng
2026-01-29 03:28:30 +08:00
parent 170061e971
commit 3411286544
78 changed files with 371 additions and 220 deletions
@@ -0,0 +1,50 @@
# ESP Flash Chips Directory
## Overview
This directory contains header files for implementing custom SPI flash chip drivers. These headers are **semi-public** - they are intended for expert users who need to implement custom chip drivers for unsupported flash chips, but they are **not considered stable API** and may change without notice.
## Intended Use
These headers are provided for:
- **Expert users** who need to implement custom chip drivers for flash chips not supported by ESP-IDF
- **Advanced developers** who need to extend or modify existing chip driver behavior
- **Internal ESP-IDF development** for implementing official chip drivers
## Important Warnings
⚠️ **These headers are NOT stable API**
- The structure and content of these headers may change in any ESP-IDF release
- No backward compatibility is guaranteed
- These headers are not part of the public API contract
- Changes may break custom chip driver implementations without notice
⚠️ **Use at your own risk**
- Custom chip drivers using these headers may break when upgrading ESP-IDF
- Thorough testing is required after each ESP-IDF version upgrade
- Consider contributing your chip driver to ESP-IDF or [3rd party flash drivers repo](https://github.com/espressif/esp-flash-drivers) instead of maintaining it separately
## Directory Contents
- `spi_flash_chip_driver.h` - Core chip driver interface definitions
- `esp_flash_types.h` - Internal flash type definitions
- `spi_flash_chip_*.h` - Header files for specific chip driver implementations that you may reuse (especially the generic driver)
- `spi_flash_override.h` - Flash override configuration structures for those parts outside the scope of esp_flash driver, usually used in the startup code
## When to Use These Headers
✅ **Appropriate use cases:**
- Implementing a driver for a new flash chip model
- Extending functionality of an existing chip driver
- Debugging chip-specific flash issues
See [example](examples/storage/custom_flash_driver) on how to implement the driver for a custom flash chip.
❌ **Not appropriate for:**
- Regular application development (use public APIs in `esp_flash.h` instead)
- Production code that needs stable API guarantees
@@ -0,0 +1,100 @@
/*
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#include <stdint.h>
#include <stdbool.h>
#include "esp_bit_defs.h"
#include "hal/spi_flash_types.h"
#ifdef __cplusplus
extern "C" {
#endif
struct spi_flash_chip_t;
typedef struct spi_flash_chip_t spi_flash_chip_t;
/** @brief OS-level integration hooks for accessing flash chips inside a running OS
*
* This structure is used internally by the SPI flash driver and should not be used directly by applications.
* It's defined here because some instances need to be allocated statically in the startup code.
*/
typedef struct esp_flash_os_functions_t {
/**
* Flags for start function
*/
/** Limit CPU frequency during flash operations (ESP32-C5 only, 240MHz).
*/
#define ESP_FLASH_START_FLAG_LIMIT_CPU_FREQ BIT(0)
/**
* Called before commencing any flash operation. Does not need to be
* recursive (ie is called at most once for each call to 'end').
*/
esp_err_t (*start)(void *arg, uint32_t flags);
/** Called after completing any flash operation. */
esp_err_t (*end)(void *arg);
/** Called before any erase/write operations to check whether the region is limited by the OS */
esp_err_t (*region_protected)(void* arg, size_t start_addr, size_t size);
/** Delay for at least 'us' microseconds. Called in between 'start' and 'end'. */
esp_err_t (*delay_us)(void *arg, uint32_t us);
/** Called for get temp buffer when buffer from application cannot be directly read into/write from. */
void *(*get_temp_buffer)(void* arg, size_t reqest_size, size_t* out_size);
/** Called for release temp buffer. */
void (*release_temp_buffer)(void *arg, void *temp_buf);
#define SPI_FLASH_YIELD_REQ_YIELD BIT(0)
#define SPI_FLASH_YIELD_REQ_SUSPEND BIT(1)
/** Yield to other tasks. Called during erase operations.
* @return ESP_OK means yield needs to be called (got an event to handle), while ESP_ERR_TIMEOUT means skip yield.*/
esp_err_t (*check_yield)(void *arg, uint32_t chip_status, uint32_t* out_request);
#define SPI_FLASH_YIELD_STA_RESUME BIT(2)
/** Yield to other tasks. Called during erase operations. */
esp_err_t (*yield)(void *arg, uint32_t* out_status);
/** Called for get system time. */
int64_t (*get_system_time)(void *arg);
#define SPI_FLASH_OS_IS_ERASING_STATUS_FLAG BIT(0)
/** Call to set flash operation status */
void (*set_flash_op_status)(uint32_t op_status);
} esp_flash_os_functions_t;
/** @brief Structure to describe a SPI flash chip connected to the system.
*
* This structure is used internally by the SPI flash driver and should not be used directly by applications.
* It's defined here because some instances need to be allocated statically in the startup code.
*/
struct esp_flash_t {
spi_flash_host_inst_t* host; ///< Pointer to hardware-specific "host_driver" structure. Must be initialized before used.
const spi_flash_chip_t *chip_drv; ///< Pointer to chip-model-specific "adapter" structure. If NULL, will be detected during initialisation.
const esp_flash_os_functions_t *os_func; ///< Pointer to os-specific hook structure. Call ``esp_flash_init_os_functions()`` to setup this field, after the host is properly initialized.
void *os_func_data; ///< Pointer to argument for os-specific hooks. Left NULL and will be initialized with ``os_func``.
esp_flash_io_mode_t read_mode; ///< Configured SPI flash read mode. Set before ``esp_flash_init`` is called.
uint32_t size; ///< Size of SPI flash in bytes. If 0, size will be detected during initialisation. Note: this stands for the size in the binary image header. If you want to get the flash physical size, please call `esp_flash_get_physical_size`.
uint32_t chip_id; ///< Detected chip id.
uint32_t busy :1; ///< This flag is used to verify chip's status.
uint32_t hpm_dummy_ena :1; ///< This flag is used to verify whether flash works under HPM status.
uint32_t reserved_flags :30; ///< reserved.
int clock_source; ///< Clock source for GPSPI.
};
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_flash.h"
#include "esp_flash_chips/spi_flash_chip_driver.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP
extern const spi_flash_chip_t esp_flash_chip_boya;
#else
extern __attribute__((weak)) const spi_flash_chip_t esp_flash_chip_boya;
#endif
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,232 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_flash.h"
#include "esp_attr.h"
#include "esp_flash_chips/esp_flash_types.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct spi_flash_chip_t spi_flash_chip_t;
/** Timeout configurations for flash operations, all in us */
typedef struct {
uint32_t idle_timeout; ///< Default timeout for other commands to be sent by host and get done by flash
uint32_t chip_erase_timeout; ///< Timeout for chip erase operation
uint32_t block_erase_timeout; ///< Timeout for block erase operation
uint32_t sector_erase_timeout; ///< Timeout for sector erase operation
uint32_t page_program_timeout; ///< Timeout for page program operation
} flash_chip_op_timeout_t;
typedef enum {
SPI_FLASH_REG_STATUS = 1,
} spi_flash_register_t;
typedef enum {
SPI_FLASH_CHIP_CAP_SUSPEND = BIT(0), ///< Flash chip support suspend feature.
SPI_FLASH_CHIP_CAP_32MB_SUPPORT = BIT(1), ///< Flash chip driver support flash size larger than 32M Bytes.
SPI_FLASH_CHIP_CAP_UNIQUE_ID = BIT(2), ///< Flash chip driver support read the flash unique id.
} spi_flash_caps_t;
/** @brief SPI flash chip driver definition structure.
*
* The chip driver structure contains chip-specific pointers to functions to perform SPI flash operations, and some
* chip-specific numeric values.
*
* @note This is not a public API. These functions are called from the public API (declared in
* esp_flash.h). They assume the caller has already validated arguments and enabled relevant protections
* (disabling flash cache, prevent concurrent SPI access, etc.)
*
* Do not call chip driver functions directly in other contexts.
*
* A generic driver for generic chips and its related operations are defined in
* spi_flash_chip_generic.h which can be used as building blocks for written
* new/specific SPI flash chip drivers.
*
* @note All of these functions may be called with SPI flash cache disabled, so must only ever access IRAM/DRAM/ROM.
*/
struct spi_flash_chip_t {
const char *name; ///< Name of the chip driver
const flash_chip_op_timeout_t *timeout; ///< Timeout configuration for this chip
/* Probe to detect if a supported SPI flash chip is found.
*
* Attempts to configure 'chip' with these operations and probes for a matching SPI flash chip.
*
* Auto-detection of a SPI flash chip calls this function in turn on each registered driver (see esp_flash_registered_flash_drivers).
*
* ID - as read by spi_flash_generic_read_id() - is supplied so each probe
* function doesn't need to unnecessarily read ID, but probe is permitted
* to interrogate flash in any non-destructive way.
*
* It is permissible for the driver to modify the 'chip' structure if probing succeeds (specifically, to assign something to the
* driver_data pointer if that is useful for the driver.)
*
* @return ESP_OK if probing was successful, an error otherwise. Driver may
* assume that returning ESP_OK means it has claimed this chip.
*/
esp_err_t (*probe)(esp_flash_t *chip, uint32_t flash_id);
esp_err_t (*reset)(esp_flash_t *chip);
/* Detect SPI flash size
*
* Interrogate the chip to detect its size.
*/
esp_err_t (*detect_size)(esp_flash_t *chip, uint32_t *size);
/* Erase the entire chip
Caller has verified the chip is not write protected.
*/
esp_err_t (*erase_chip)(esp_flash_t *chip);
/* Erase a sector of the chip. Sector size is specified in the 'sector_size' field.
sector_address is an offset in bytes.
Caller has verified that this sector should be non-write-protected.
*/
esp_err_t (*erase_sector)(esp_flash_t *chip, uint32_t sector_address);
/* Erase a multi-sector block of the chip. Block size is specified in the 'block_erase_size' field.
sector_address is an offset in bytes.
Caller has verified that this block should be non-write-protected.
*/
esp_err_t (*erase_block)(esp_flash_t *chip, uint32_t block_address);
uint32_t sector_size; /* Sector is minimum erase size */
uint32_t block_erase_size; /* Optimal (fastest) block size for multi-sector erases on this chip */
/* Read the write protect status of the entire chip. */
esp_err_t (*get_chip_write_protect)(esp_flash_t *chip, bool *out_write_protected);
/* Set the write protect status of the entire chip. */
esp_err_t (*set_chip_write_protect)(esp_flash_t *chip, bool chip_write_protect);
/* Number of individually write protectable regions on this chip. Range 0-63. */
uint8_t num_protectable_regions;
/* Pointer to an array describing each protectable region. Should have num_protectable_regions elements. */
const esp_flash_region_t *protectable_regions;
/* Get a bitmask describing all protectable regions on the chip. Each bit represents one entry in the
protectable_regions array, ie bit (1<<N) is set then the region at array entry N is write protected. */
esp_err_t (*get_protected_regions)(esp_flash_t *chip, uint64_t *regions);
/* Set protectable regions on the chip. Each bit represents on entry in the protectable regions array. */
esp_err_t (*set_protected_regions)(esp_flash_t *chip, uint64_t regions);
/* Read data from the chip.
*
* Before calling this function, the caller will have called chip->drv->set_read_mode(chip) in order to configure the chip's read mode correctly.
*/
esp_err_t (*read)(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length);
/* Write any amount of data to the chip.
*/
esp_err_t (*write)(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length);
/* Use the page program command to write data to the chip.
*
* This function is expected to be called by chip->drv->write (if the
* chip->drv->write implementation doesn't call it then it can be left as NULL.)
*
* - The length argument supplied to this function is at most 'page_size' bytes.
*
* - The region between 'address' and 'address + length' will not cross a page_size aligned boundary (the write
* implementation is expected to split such a write into two before calling page_program.)
*/
esp_err_t (*program_page)(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length);
/* Page size as written by the page_program function. Usually 256 bytes. */
uint32_t page_size;
/* Perform an encrypted write to the chip, using internal flash encryption hardware. */
esp_err_t (*write_encrypted)(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length);
/* Wait for the SPI flash chip to be idle (any write operation to be complete.) This function is both called from the higher-level API functions, and from other functions in this structure.
timeout_ms should be a timeout (in milliseconds) before the function returns ESP_ERR_TIMEOUT. This is useful to avoid hanging
if the chip is otherwise unresponsive (ie returns all 0xFF or similar.)
*/
esp_err_t (*wait_idle)(esp_flash_t *chip, uint32_t timeout_us);
/* Configure both the SPI host and the chip for the read mode specified in chip->read_mode.
*
* This function is called by the higher-level API before the 'read' function is called.
*
* Can return ESP_ERR_FLASH_UNSUPPORTED_HOST or ESP_ERR_FLASH_UNSUPPORTED_CHIP if the specified mode is unsupported.
*/
esp_err_t (*set_io_mode)(esp_flash_t *chip);
/*
* Get whether the Quad Enable (QE) is set. (*out_io_mode)=SPI_FLASH_QOUT if
* enabled, otherwise disabled
*/
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);
/** Yield to other tasks. Called during erase operations. */
esp_err_t (*yield)(esp_flash_t *chip, uint32_t wip);
/** Setup flash suspend configuration. */
esp_err_t (*sus_setup)(esp_flash_t *chip);
/**
* Read the chip unique ID.
*/
esp_err_t (*read_unique_id)(esp_flash_t *chip, uint64_t* flash_unique_id);
/**
* Get the capabilities of the flash chip. See SPI_FLASH_CHIP_CAP_* macros as reference.
*/
spi_flash_caps_t (*get_chip_caps)(esp_flash_t *chip);
/**
* Configure the host registers to use the specified read mode set in the ``chip->read_mode``.
*/
esp_err_t (*config_host_io_mode)(esp_flash_t *chip, uint32_t flags);
};
/* Pointer to an array of pointers to all known drivers for flash chips. This array is used
by esp_flash_init() to detect the flash chip driver, if none is supplied by the caller.
Array is terminated with a NULL pointer.
This pointer can be overwritten with a pointer to a new array, to update the list of known flash chips.
*/
extern const spi_flash_chip_t **esp_flash_registered_chips;
/**
* @brief Helper function to check if a specific flash chip driver is linked.
*
* Logs a warning if the driver for the detected chip is not linked.
*
* @param chip Pointer to an `esp_flash_t` structure representing the flash chip instance.
* This structure typically contains information about the chip's characteristics and state.
* @param device_id A 24-bit value representing the unique identifier (ID) of the flash chip.
* This ID is used to match the chip against known drivers.
*/
void spi_flash_chip_list_check(esp_flash_t *chip, uint32_t device_id);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,40 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_flash.h"
#include "esp_flash_chips/spi_flash_chip_driver.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* GD (GigaDevice) 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.
*
* Note that this is for GD chips with product ID 40H (GD25Q) and 60H (GD25LQ). The chip diver uses
* different commands to write the SR2 register according to the chip ID. For GD25Q40 - GD25Q16
* chips, and GD25LQ chips, WRSR (01H) command is used; while WRSR2 (31H) is used for GD25Q32 -
* GD25Q127 chips.
*/
esp_err_t spi_flash_chip_gd_probe(esp_flash_t *chip, uint32_t flash_id);
esp_err_t spi_flash_chip_gd_set_io_mode(esp_flash_t *chip);
esp_err_t spi_flash_chip_gd_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode);
#ifdef CONFIG_SPI_FLASH_SUPPORT_GD_CHIP
extern const spi_flash_chip_t esp_flash_chip_gd;
#else
extern __attribute__((weak)) const spi_flash_chip_t esp_flash_chip_gd;
#endif
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,410 @@
/*
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_flash.h"
#include "esp_flash_chips/spi_flash_chip_driver.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* The 'chip_generic' SPI flash operations are a lowest common subset of SPI
* flash commands, that work across most chips.
*
* These can be used as-is via the esp_flash_common_chip_driver chip_drv, or
* they can be used as "base chip_drv" functions when creating a new
* spi_flash_host_driver_t chip_drv structure.
*
* All of the functions in this header are internal functions, not part of a
* public API. See esp_flash.h for the public API.
*/
/**
* @brief Generic probe function
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param flash_id expected manufacture id.
*
* @return ESP_OK if the id read from chip->drv_read_id matches (always).
*/
esp_err_t spi_flash_chip_generic_probe(esp_flash_t *chip, uint32_t flash_id);
/**
* @brief Generic reset function
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
*
* @return ESP_OK if sending success, or error code passed from ``common_command`` or ``wait_idle`` functions of host driver.
*/
esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip);
/**
* @brief Generic size detection function
*
* Tries to detect the size of chip by using the lower 4 bits of the chip->drv->read_id result = N, and assuming size is 2 ^ N.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param size Output of the detected size
*
* @return
* - ESP_OK if success
* - ESP_ERR_FLASH_UNSUPPORTED_CHIP if the manufacturer id is not correct, which may means an error in the reading
* - or other error passed from the ``read_id`` function of host driver
*/
esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size);
/**
* @brief Erase chip by using the generic erase chip command.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
*
* @return
* - ESP_OK if success
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
* - or other error passed from the ``set_write_protect``, ``wait_idle`` or ``erase_chip`` function of host driver
*/
esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip);
/**
* @brief Erase sector by using the generic sector erase command.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param start_address Start address of the sector to erase
*
* @return
* - ESP_OK if success
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
* - or other error passed from the ``set_write_protect``, ``wait_idle`` or ``erase_sector`` function of host driver
*/
esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address);
/**
* @brief Erase block by the generic 64KB block erase command
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param start_address Start address of the block to erase
*
* @return
* - ESP_OK if success
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
* - or other error passed from the ``set_write_protect``, ``wait_idle`` or ``erase_block`` function of host driver
*/
esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_address);
/**
* @brief Read from flash by using a read command that matches the programmed
* read mode.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param buffer Buffer to hold the data read from flash
* @param address Start address of the data on the flash
* @param length Length to read
*
* @return always ESP_OK currently
*/
esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length);
/**
* @brief Perform a page program using the page program command.
*
* @note Length of each call should not excced the limitation in
* ``chip->host->max_write_bytes``. This function is called in
* ``spi_flash_chip_generic_write`` recursively until the whole page is
* programmed. Strongly suggest to call ``spi_flash_chip_generic_write``
* instead.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param buffer Buffer holding the data to program
* @param address Start address to write to flash
* @param length Length to write, no longer than ``chip->host->max_write_bytes``.
*
* @return
* - ESP_OK if success
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
* - or other error passed from the ``wait_idle`` or ``program_page`` function of host driver
*/
esp_err_t
spi_flash_chip_generic_page_program(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length);
/**
* @brief Perform a generic write. Split the write buffer into page program
* operations, and call chip->chip_drv->page-program() for each.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param buffer Buffer holding the data to program
* @param address Start address to write to flash
* @param length Length to write
*
* @return
* - ESP_OK if success
* - or other error passed from the ``wait_idle`` or ``program_page`` function of host driver
*/
esp_err_t spi_flash_chip_generic_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length);
/**
* @brief Perform a write using on-chip flash encryption. Not implemented yet.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param buffer Buffer holding the data to program
* @param address Start address to write to flash
* @param length Length to write
*
* @return always ESP_ERR_FLASH_UNSUPPORTED_HOST.
*/
esp_err_t
spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length);
/**
* @brief Send the write enable or write disable command and verify the expected bit (1) in
* the status register is set.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param write_protect true to enable write protection, false to send write enable.
*
* @return
* - ESP_OK if success
* - or other error passed from the ``wait_idle``, ``read_status`` or
* ``set_write_protect`` function of host driver
*/
esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write_protect);
/**
* @brief Check whether WEL (write enable latch) bit is set in the Status Register read from RDSR.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param out_write_protect Output of whether the write protect is set.
*
* @return
* - ESP_OK if success
* - or other error passed from the ``read_status`` function of host driver
*/
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
/**
* @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
* progress bit) to be cleared.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param timeout_us Time to wait before timeout, in us.
*
* @return
* - ESP_OK if success
* - ESP_ERR_TIMEOUT if not idle before timeout
* - or other error passed from the ``wait_idle`` or ``read_status`` function of host driver
*/
esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_us);
/**
* @brief Set the specified SPI read mode according to the data in the chip
* context. Set quad enable status register bit if needed.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
*
* @return
* - ESP_OK if success
* - ESP_ERR_TIMEOUT if not idle before timeout
* - or other error passed from the ``set_write_protect`` or ``common_command`` function of host driver
*/
esp_err_t spi_flash_chip_generic_set_io_mode(esp_flash_t *chip);
/**
* Get whether the Quad Enable (QE) is set.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param out_quad_mode Pointer to store the output mode.
* - SPI_FLASH_QOUT: QE is enabled
* - otherwise: QE is disabled
*
* @return
* - ESP_OK if success
* - or other error passed from the ``common_command`` function of host driver
*/
esp_err_t spi_flash_chip_generic_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_quad_mode);
/**
* @brief Read the chip unique ID.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param flash_unique_id Pointer to store output unique id.
*
* @return
* - ESP_OK if success
* - ESP_ERR_NOT_SUPPORTED if the chip doesn't support read id.
*/
esp_err_t spi_flash_chip_generic_read_unique_id(esp_flash_t *chip, uint64_t* flash_unique_id);
/**
* Generic 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_generic;
/*******************************************************************************
* Utilities
*******************************************************************************/
/// Function pointer type for reading status register with QE bit.
typedef esp_err_t (*esp_flash_rdsr_func_t)(esp_flash_t* chip, uint32_t* out_sr);
/**
* Use RDSR2 (35H) to read bit 15-8 of the SR, and RDSR (05H) to read bit 7-0.
*
* @param chip Pointer to SPI flash chip to use.
* @param out_sr Pointer to buffer to hold the status register, 16 bits.
*
* @return ESP_OK if success, otherwise error code passed from the
* `common_command` function of the host driver.
*/
esp_err_t spi_flash_common_read_status_16b_rdsr_rdsr2(esp_flash_t* chip, uint32_t* out_sr);
/**
* Use RDSR2 (35H) to read bit 15-8 of the SR.
*
* @param chip Pointer to SPI flash chip to use.
* @param out_sr Pointer to buffer to hold the status register, 8 bits.
*
* @return ESP_OK if success, otherwise error code passed from the
* `common_command` function of the host driver.
*/
esp_err_t spi_flash_common_read_status_8b_rdsr2(esp_flash_t* chip, uint32_t* out_sr);
/**
* Use RDSR (05H) to read bit 7-0 of the SR.
*
* @param chip Pointer to SPI flash chip to use.
* @param out_sr Pointer to buffer to hold the status register, 8 bits.
*
* @return ESP_OK if success, otherwise error code passed from the
* `common_command` function of the host driver.
*/
esp_err_t spi_flash_common_read_status_8b_rdsr(esp_flash_t* chip, uint32_t* out_sr);
/// Function pointer type for writing status register with QE bit.
typedef esp_err_t (*esp_flash_wrsr_func_t)(esp_flash_t* chip, uint32_t sr);
/**
* Use WRSR (01H) to write bit 7-0 of the SR.
*
* @param chip Pointer to SPI flash chip to use.
* @param sr Value of the status register to write, 8 bits.
*
* @return ESP_OK if success, otherwise error code passed from the
* `common_command` function of the host driver.
*/
esp_err_t spi_flash_common_write_status_8b_wrsr(esp_flash_t* chip, uint32_t sr);
/**
* Use WRSR (01H) to write bit 15-0 of the SR.
*
* @param chip Pointer to SPI flash chip to use.
* @param sr Value of the status register to write, 16 bits.
*
* @return ESP_OK if success, otherwise error code passed from the
* `common_command` function of the host driver.
*/
esp_err_t spi_flash_common_write_status_16b_wrsr(esp_flash_t* chip, uint32_t sr);
/**
* Use WRSR2 (31H) to write bit 15-8 of the SR.
*
* @param chip Pointer to SPI flash chip to use.
* @param sr Value of the status register to write, 8 bits.
*
* @return ESP_OK if success, otherwise error code passed from the
* `common_command` function of the host driver.
*/
esp_err_t spi_flash_common_write_status_8b_wrsr2(esp_flash_t* chip, uint32_t sr);
/**
* @brief Utility function for set_read_mode chip_drv function. If required,
* set and check the QE bit in the flash chip to enable the QIO/QOUT mode.
*
* Most chip QE enable follows a common pattern, though commands to read/write
* the status register may be different, as well as the position of QE bit.
*
* Registers to actually do Quad transitions and command to be sent in reading
* should also be configured via
* spi_flash_chip_generic_config_host_io_mode().
*
* Note that the bit length and qe position of wrsr_func, rdsr_func and
* qe_sr_bit should be consistent.
*
* @param chip Pointer to SPI flash chip to use.
* @param wrsr_func Function pointer for writing the status register
* @param rdsr_func Function pointer for reading the status register
* @param qe_sr_bit status with the qe bit only.
*
* @return always ESP_OK (currently).
*/
esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t wrsr_func, esp_flash_rdsr_func_t rdsr_func, uint32_t qe_sr_bit);
/**
* @brief Configure the host registers to use the specified read mode set in
* the ``chip->read_mode``.
*
* Usually called in chip_drv read() functions before actual reading
* 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 flags Special rules to configure io mode, (i.e. Whether 32 bit commands will be used (Currently only W25Q256 and GD25Q256 are supported))
*
* @return
* - ESP_OK if success
* - ESP_ERR_FLASH_NOT_INITIALISED if chip not initialized properly
* - 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, uint32_t flags);
#define SPI_FLASH_CONFIG_IO_MODE_32B_ADDR BIT(0)
/**
* @brief Handle explicit yield requests
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param wip Write (erase) in progress, `true` if this function is called during waiting idle of a erase/write command; else `false`.
* @return ESP_OK if success, otherwise failed.
*/
esp_err_t spi_flash_chip_generic_yield(esp_flash_t* chip, uint32_t wip);
/**
* @brief Setup for flash suspend command configuration.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @return ESP_OK
*/
esp_err_t spi_flash_chip_generic_suspend_cmd_conf(esp_flash_t *chip);
/**
*
* @brief Read the chip unique ID unsupported function.
*
* @param chip Pointer to SPI flash chip to use.
* @param flash_unique_id Pointer to store output unique id (Although this function is an unsupported function, but the parameter should be kept for the consistence of the function pointer).
* @return Always ESP_ERR_NOT_SUPPORTED.
*/
esp_err_t spi_flash_chip_generic_read_unique_id_none(esp_flash_t *chip, uint64_t* flash_unique_id);
/// Default timeout configuration used by most chips
extern const flash_chip_op_timeout_t spi_flash_chip_generic_timeout;
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,35 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_flash.h"
#include "esp_flash_chips/spi_flash_chip_driver.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* ISSI 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.
*/
esp_err_t spi_flash_chip_issi_probe(esp_flash_t *chip, uint32_t flash_id);
esp_err_t spi_flash_chip_issi_set_io_mode(esp_flash_t *chip);
esp_err_t spi_flash_chip_issi_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode);
#ifdef CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP
extern const spi_flash_chip_t esp_flash_chip_issi;
#else
extern __attribute__((weak)) const spi_flash_chip_t esp_flash_chip_issi;
#endif
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_flash.h"
#include "esp_flash_chips/spi_flash_chip_driver.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* MXIC 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.
*/
#ifdef CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP
extern const spi_flash_chip_t esp_flash_chip_mxic;
#else
extern __attribute__((weak)) const spi_flash_chip_t esp_flash_chip_mxic;
#endif
/**
* MXIC OPI 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.
*/
#ifdef CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP
extern const spi_flash_chip_t esp_flash_chip_mxic_opi;
#else
extern __attribute__((weak)) const spi_flash_chip_t esp_flash_chip_mxic_opi;
#endif
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_flash.h"
#include "esp_flash_chips/spi_flash_chip_driver.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_SPI_FLASH_SUPPORT_TH_CHIP
extern const spi_flash_chip_t esp_flash_chip_th;
#else
extern __attribute__((weak)) const spi_flash_chip_t esp_flash_chip_th;
#endif
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_flash.h"
#include "esp_flash_chips/spi_flash_chip_driver.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* 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.
*/
#ifdef CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP
extern const spi_flash_chip_t esp_flash_chip_winbond;
#else
extern __attribute__((weak)) const spi_flash_chip_t esp_flash_chip_winbond;
#endif
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,87 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/soc_caps.h"
#pragma once
/* SPI commands (actual on-wire commands not SPI controller bitmasks)
Suitable for use with spi_flash_hal_common_command static function.
*/
#define CMD_RDID 0x9F
#define CMD_RDUID 0x4B /* Read the flash unique ID*/
#define CMD_WRSR 0x01
#define SR_WIP (1<<0) /* Status register write-in-progress bit */
#define SR_WREN (1<<1) /* Status register write enable bit */
#define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */
#define CMD_WREN 0x06
#define CMD_WRDI 0x04
#define CMD_RDSR 0x05
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
#define CMD_RDSCUR 0x2B /* MXIC-specific, read security register */
#define CMD_8READ 0xEC /* MXIC-specific, 8 I/O read */
#define CMD_8DTRD 0xEE /* MXIC-specific, 8 I/O DTR read */
#define CMD_RDFR 0x48 /* ISSI-specific, read function register */
#define CMD_FASTRD_QIO 0xEB
#define CMD_FASTRD_QIO_4B 0xEC
#define CMD_FASTRD_QUAD 0x6B
#define CMD_FASTRD_QUAD_4B 0x6C
#define CMD_FASTRD_DIO 0xBB
#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_SECTOR_ERASE 0x20
#define CMD_SECTOR_ERASE_4B 0x21
#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_SUSPEND 0x75
#define CMD_RESUME 0x7A
#define CMD_HPMEN 0xA3 /* Enable High Performance mode on flash */
#define CMD_WRAP 0x77
#define CMD_BURST_RD 0xC0 /* wrap(0x77) and burst read are functionally same. But commands and formats is different */
#define CMD_RST_EN 0x66
#define CMD_RST_DEV 0x99
#define CMD_RDSFDP 0x5A /* Read the SFDP of the flash */
#define SPI_FLASH_DIO_DUMMY_BITLEN 4
#define SPI_FLASH_QIO_DUMMY_BITLEN 6
#define SPI_FLASH_DIO_ADDR_BITLEN 24
#define SPI_FLASH_QIO_ADDR_BITLEN 24
#define SPI_FLASH_QOUT_ADDR_BITLEN 24
#define SPI_FLASH_QOUT_DUMMY_BITLEN 8
#define SPI_FLASH_DOUT_ADDR_BITLEN 24
#define SPI_FLASH_DOUT_DUMMY_BITLEN 8
#define SPI_FLASH_FASTRD_ADDR_BITLEN 24
#define SPI_FLASH_FASTRD_DUMMY_BITLEN 8
#define SPI_FLASH_SLOWRD_ADDR_BITLEN 24
#define SPI_FLASH_SLOWRD_DUMMY_BITLEN 0
#define SPI_FLASH_OPISTR_ADDR_BITLEN 32
#define SPI_FLASH_OPISTR_DUMMY_BITLEN 20
#define SPI_FLASH_OPIDTR_ADDR_BITLEN 32
#define SPI_FLASH_OPIDTR_DUMMY_BITLEN 40
#define SPI_FLASH_QIO_HPM_DUMMY_BITLEN 10
#define SPI_FLASH_DIO_HPM_DUMMY_BITLEN 8
// Flash vendors.
#define SPI_FLASH_GD 0xC8
#define SPI_FLASH_ISSI 0x9D
#define SPI_FLASH_MXIC 0xC2
#define SPI_FLASH_XMC_1 0x20
#define SPI_FLASH_XMC_2 0x46
#define SPI_FLASH_WINBOND 0xEF
#define SPI_FLASH_TH 0xCD
#define SPI_FLASH_BY 0x68
@@ -0,0 +1,105 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Structure for flash dummy bits.
* For some flash chips, dummy bits are configurable under different conditions.
*/
typedef struct {
uint8_t dio_dummy;
uint8_t dout_dummy;
uint8_t qio_dummy;
uint8_t qout_dummy;
uint8_t fastrd_dummy;
} spi_flash_hpm_dummy_conf_t;
typedef enum {
SPI_FLASH_HPM_CMD_NEEDED, // Means that in the certain condition, flash needs to enter the high performance mode by command.
SPI_FLASH_HPM_DUMMY_NEEDED, // Means that in the certain condition, flash needs to enter the high performance mode by adjusting dummy.
SPI_FLASH_HPM_WRITE_SR_NEEDED, // Means that in the certain condition, flash needs to enter the high performance mode by writing status register.
SPI_FLASH_HPM_UNNEEDED, // Means that flash doesn't need to enter the high performance mode.
SPI_FLASH_HPM_BEYOND_LIMIT, // Means that flash has no capability to meet that condition.
} spi_flash_requirement_t;
typedef void (*spi_flash_hpm_enable_fn_t)(void);
typedef esp_err_t (*spi_flash_hpf_check_fn_t)(void);
typedef void (*spi_flash_get_chip_dummy_fn_t)(spi_flash_hpm_dummy_conf_t *dummy_conf);
typedef esp_err_t (*spi_flash_hpm_probe_fn_t)(uint32_t flash_id);
typedef spi_flash_requirement_t (*spi_flash_hpm_chip_requirement_check_t)(uint32_t flash_id, uint32_t freq_mhz, int voltage_mv, int temperature);
typedef struct __attribute__((packed))
{
const char *method; /* Flash HPM method */
spi_flash_hpm_probe_fn_t probe;
spi_flash_hpm_chip_requirement_check_t chip_hpm_requirement_check;
spi_flash_hpm_enable_fn_t flash_hpm_enable;
spi_flash_hpf_check_fn_t flash_hpf_check;
spi_flash_get_chip_dummy_fn_t flash_get_dummy;
} spi_flash_hpm_info_t;
/**
* @brief Enum for user to select valid wrap size.
*/
typedef enum {
FLASH_WRAP_SIZE_8B = 8,
FLASH_WRAP_SIZE_16B = 16,
FLASH_WRAP_SIZE_32B = 32,
FLASH_WRAP_SIZE_64B = 64,
} spi_flash_wrap_size_t;
/**
* @brief Probe flash wrap method
*
* @param flash_id Flash chip ID
*
* @return ESP_OK: If succeed
*/
typedef esp_err_t (*spi_flash_wrap_probe_fn_t)(uint32_t flash_id);
/**
* @brief Set flash wrap
*
* @param wrap_size: wrap_size
*
* @return ESP_OK: If succeed
*/
typedef esp_err_t (*spi_flash_wrap_set_fn_t)(spi_flash_wrap_size_t wrap_size);
/**
* @brief Clear flash wrap.
*
* @return ESP_OK: If succeed
*/
typedef esp_err_t (*spi_flash_wrap_clr_fn_t)(void);
typedef struct __attribute__((packed))
{
const char *method;
spi_flash_wrap_probe_fn_t probe;
spi_flash_wrap_set_fn_t chip_wrap_set;
spi_flash_wrap_clr_fn_t chip_wrap_clr;
} spi_flash_wrap_info_t;
/**
* Array of known flash chips and method to enable flash high performance mode.
*
* Users can override this array.
*/
extern const spi_flash_hpm_info_t __attribute__((weak)) spi_flash_hpm_enable_list[];
#ifdef __cplusplus
}
#endif