esp_flash: refactor to make host driver function a const table

This is also part of ESP32-S3 ROM changes
This commit is contained in:
Michael (XIAO Xufeng)
2020-05-07 14:46:41 +08:00
parent f99ba33920
commit c796bd5e63
13 changed files with 204 additions and 220 deletions

View File

@@ -37,11 +37,13 @@
* implementations that also use the SPI peripheral. * implementations that also use the SPI peripheral.
*/ */
typedef struct { 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_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; int extra_dummy; ///< Pre-calculated extra dummy used for compensation
spi_flash_ll_clock_reg_t clock_conf; spi_flash_ll_clock_reg_t clock_conf; ///< Pre-calculated clock configuration value
} spi_flash_memspi_data_t; 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.)
} spi_flash_hal_context_t;
/// Configuration structure for the SPI driver. /// Configuration structure for the SPI driver.
typedef struct { typedef struct {
@@ -50,7 +52,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.
} spi_flash_memspi_config_t; } spi_flash_hal_config_t;
/** /**
* Configure SPI flash hal settings. * Configure SPI flash hal settings.
@@ -62,16 +64,16 @@ typedef struct {
* - ESP_OK: success * - ESP_OK: success
* - ESP_ERR_INVALID_ARG: the data buffer is not in the DRAM. * - ESP_ERR_INVALID_ARG: the data buffer is not in the DRAM.
*/ */
esp_err_t spi_flash_hal_init(spi_flash_memspi_data_t *data_out, const spi_flash_memspi_config_t *cfg); esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_hal_config_t *cfg);
/** /**
* Configure the device-related register before transactions. * Configure the device-related register before transactions.
* *
* @param driver The driver context. * @param host The driver context.
* *
* @return always return ESP_OK. * @return always return ESP_OK.
*/ */
esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *driver); esp_err_t spi_flash_hal_device_config(spi_flash_host_inst_t *host);
/** /**
* Send an user-defined spi transaction to the device. * Send an user-defined spi transaction to the device.
@@ -80,60 +82,60 @@ esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *driver);
* particular commands. Since this function supports timing compensation, it is * particular commands. Since this function supports timing compensation, it is
* also used to receive some data when the frequency is high. * also used to receive some data when the frequency is high.
* *
* @param driver The driver context. * @param host The driver context.
* @param trans The transaction to send, also holds the received data. * @param trans The transaction to send, also holds the received data.
* *
* @return always return ESP_OK. * @return always return ESP_OK.
*/ */
esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *driver, spi_flash_trans_t *trans); esp_err_t spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_trans_t *trans);
/** /**
* Erase whole flash chip by using the erase chip (C7h) command. * Erase whole flash chip by using the erase chip (C7h) command.
* *
* @param driver The driver context. * @param host The driver context.
*/ */
void spi_flash_hal_erase_chip(spi_flash_host_driver_t *driver); 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.
* *
* @param driver 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.
*/ */
void spi_flash_hal_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_address); void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address);
/** /**
* 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.
* *
* @param driver 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.
*/ */
void spi_flash_hal_erase_block(spi_flash_host_driver_t *driver, 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.
* *
* @param driver The driver context. * @param host The driver context.
* @param address Address of the page to program * @param address Address of the page to program
* @param buffer Data to program * @param buffer Data to program
* @param length Size of the buffer in bytes, no larger than ``SPI_FLASH_HAL_MAX_WRITE_BYTES`` (64) bytes. * @param length Size of the buffer in bytes, no larger than ``SPI_FLASH_HAL_MAX_WRITE_BYTES`` (64) bytes.
*/ */
void spi_flash_hal_program_page(spi_flash_host_driver_t *driver, 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);
/** /**
* Read from the flash. Call ``spi_flash_hal_configure_host_read_mode`` to * Read from the flash. Call ``spi_flash_hal_configure_host_read_mode`` to
* configure the read command before calling this function. * configure the read command before calling this function.
* *
* @param driver The driver context. * @param host The driver context.
* @param buffer Buffer to store the read data * @param buffer Buffer to store the read data
* @param address Address to read * @param address Address to read
* @param length Length to read, no larger than ``SPI_FLASH_HAL_MAX_READ_BYTES`` (64) bytes. * @param length Length to read, no larger than ``SPI_FLASH_HAL_MAX_READ_BYTES`` (64) bytes.
* *
* @return always return ESP_OK. * @return always return ESP_OK.
*/ */
esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *driver, void *buffer, uint32_t address, uint32_t read_len); esp_err_t spi_flash_hal_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len);
/** /**
* @brief Send the write enable (06h) or write disable (04h) command to the flash chip. * @brief Send the write enable (06h) or write disable (04h) command to the flash chip.
@@ -143,16 +145,16 @@ esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *driver, void *buffer, uint
* *
* @return always return ESP_OK. * @return always return ESP_OK.
*/ */
esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_driver_t *chip_drv, bool wp); esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_inst_t *host, bool wp);
/** /**
* Check whether the SPI host is idle and can perform other operations. * Check whether the SPI host is idle and can perform other operations.
* *
* @param driver The driver context. * @param host The driver context.
* *
* @return ture if idle, otherwise false. * @return ture if idle, otherwise false.
*/ */
bool spi_flash_hal_host_idle(spi_flash_host_driver_t *driver); bool spi_flash_hal_host_idle(spi_flash_host_inst_t *host);
/** /**
* @brief Configure the SPI host hardware registers for the specified io mode. * @brief Configure the SPI host hardware registers for the specified io mode.
@@ -177,7 +179,7 @@ bool spi_flash_hal_host_idle(spi_flash_host_driver_t *driver);
* - Common write: set command value, address value (or length to 0 if not * - Common write: set command value, address value (or length to 0 if not
* used), disable dummy phase, and set output data. * used), disable dummy phase, and set output data.
* *
* @param driver The driver context * @param host The driver context
* @param io_mode The HW read mode to use * @param io_mode The HW read mode to use
* @param addr_bitlen Length of the address phase, in bits * @param addr_bitlen Length of the address phase, in bits
* @param dummy_cyclelen_base Base cycles of the dummy phase, some extra dummy cycles may be appended to compensate the timing. * @param dummy_cyclelen_base Base cycles of the dummy phase, some extra dummy cycles may be appended to compensate the timing.
@@ -185,34 +187,34 @@ bool spi_flash_hal_host_idle(spi_flash_host_driver_t *driver);
* *
* @return always return ESP_OK. * @return always return ESP_OK.
*/ */
esp_err_t spi_flash_hal_configure_host_io_mode(spi_flash_host_driver_t *driver, uint32_t command, uint32_t addr_bitlen, esp_err_t spi_flash_hal_configure_host_io_mode(spi_flash_host_inst_t *host, uint32_t command, uint32_t addr_bitlen,
int dummy_cyclelen_base, esp_flash_io_mode_t io_mode); int dummy_cyclelen_base, esp_flash_io_mode_t io_mode);
/** /**
* Poll until the last operation is done. * Poll until the last operation is done.
* *
* @param driver The driver context. * @param host The driver context.
*/ */
void spi_flash_hal_poll_cmd_done(spi_flash_host_driver_t *driver); void spi_flash_hal_poll_cmd_done(spi_flash_host_inst_t *host);
/** /**
* Check whether the given buffer can be used as the write buffer directly. If 'chip' is connected to the main SPI bus, we can only write directly from * Check whether the given buffer can be used as the write buffer directly. If 'chip' is connected to the main SPI bus, we can only write directly from
* regions that are accessible ith cache disabled. * * regions that are accessible ith cache disabled. *
* *
* @param driver The driver context * @param host The driver context
* @param p The buffer holding data to send. * @param p The buffer holding data to send.
* *
* @return True if the buffer can be used to send data, otherwise false. * @return True if the buffer can be used to send data, otherwise false.
*/ */
bool spi_flash_hal_supports_direct_write(spi_flash_host_driver_t *driver, const void *p); bool spi_flash_hal_supports_direct_write(spi_flash_host_inst_t *host, const void *p);
/** /**
* Check whether the given buffer can be used as the read buffer directly. If 'chip' is connected to the main SPI bus, we can only read directly from * Check whether the given buffer can be used as the read buffer directly. If 'chip' is connected to the main SPI bus, we can only read directly from
* regions that are accessible ith cache disabled. * * regions that are accessible ith cache disabled. *
* *
* @param driver The driver context * @param host The driver context
* @param p The buffer to hold the received data. * @param p The buffer to hold the received data.
* *
* @return True if the buffer can be used to receive data, otherwise false. * @return True if the buffer can be used to receive data, otherwise false.
*/ */
bool spi_flash_hal_supports_direct_read(spi_flash_host_driver_t *driver, const void *p); bool spi_flash_hal_supports_direct_read(spi_flash_host_inst_t *host, const void *p);

View File

@@ -68,55 +68,57 @@ typedef enum {
///Slowest io mode supported by ESP32, currently SlowRd ///Slowest io mode supported by ESP32, currently SlowRd
#define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD #define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD
struct spi_flash_host_driver_t; struct spi_flash_host_driver_s;
typedef struct spi_flash_host_driver_t spi_flash_host_driver_t; typedef struct spi_flash_host_driver_s spi_flash_host_driver_t;
/** SPI Flash Host driver instance */
typedef struct {
const struct spi_flash_host_driver_s* driver; ///< Pointer to the implementation function table
// Implementations can wrap this structure into their own ones, and append other data here
} spi_flash_host_inst_t ;
/** Host driver configuration and context structure. */ /** Host driver configuration and context structure. */
struct spi_flash_host_driver_t { struct spi_flash_host_driver_s {
/**
* Configuration and static data used by the specific host driver. The type
* is determined by the host driver.
*/
void *driver_data;
/** /**
* Configure the device-related register before transactions. This saves * Configure the device-related register before transactions. This saves
* some time to re-configure those registers when we send continuously * some time to re-configure those registers when we send continuously
*/ */
esp_err_t (*dev_config)(spi_flash_host_driver_t *driver); esp_err_t (*dev_config)(spi_flash_host_inst_t *host);
/** /**
* Send an user-defined spi transaction to the device. * Send an user-defined spi transaction to the device.
*/ */
esp_err_t (*common_command)(spi_flash_host_driver_t *driver, spi_flash_trans_t *t); esp_err_t (*common_command)(spi_flash_host_inst_t *host, spi_flash_trans_t *t);
/** /**
* Read flash ID. * Read flash ID.
*/ */
esp_err_t (*read_id)(spi_flash_host_driver_t *driver, uint32_t *id); esp_err_t (*read_id)(spi_flash_host_inst_t *host, uint32_t *id);
/** /**
* Erase whole flash chip. * Erase whole flash chip.
*/ */
void (*erase_chip)(spi_flash_host_driver_t *driver); void (*erase_chip)(spi_flash_host_inst_t *host);
/** /**
* Erase a specific sector by its start address. * Erase a specific sector by its start address.
*/ */
void (*erase_sector)(spi_flash_host_driver_t *driver, uint32_t start_address); void (*erase_sector)(spi_flash_host_inst_t *host, uint32_t start_address);
/** /**
* Erase a specific block by its start address. * Erase a specific block by its start address.
*/ */
void (*erase_block)(spi_flash_host_driver_t *driver, uint32_t start_address); void (*erase_block)(spi_flash_host_inst_t *host, uint32_t start_address);
/** /**
* Read the status of the flash chip. * Read the status of the flash chip.
*/ */
esp_err_t (*read_status)(spi_flash_host_driver_t *driver, uint8_t *out_sr); esp_err_t (*read_status)(spi_flash_host_inst_t *host, uint8_t *out_sr);
/** /**
* Disable write protection. * Disable write protection.
*/ */
esp_err_t (*set_write_protect)(spi_flash_host_driver_t *driver, bool wp); esp_err_t (*set_write_protect)(spi_flash_host_inst_t *host, bool wp);
/** /**
* Program a page of the flash. Check ``max_write_bytes`` for the maximum allowed writing length. * Program a page of the flash. Check ``max_write_bytes`` for the maximum allowed writing length.
*/ */
void (*program_page)(spi_flash_host_driver_t *driver, const void *buffer, uint32_t address, uint32_t length); void (*program_page)(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length);
/** Check whether given buffer can be directly used to write */ /** Check whether given buffer can be directly used to write */
bool (*supports_direct_write)(spi_flash_host_driver_t *driver, const void *p); bool (*supports_direct_write)(spi_flash_host_inst_t *host, const void *p);
/** /**
* Slicer for write data. The `program_page` should be called iteratively with the return value * Slicer for write data. The `program_page` should be called iteratively with the return value
* of this function. * of this function.
@@ -127,13 +129,14 @@ struct spi_flash_host_driver_t {
* @param page_size Physical page size of the flash chip * @param page_size Physical page size of the flash chip
* @return Length that can be actually written in one `program_page` call * @return Length that can be actually written in one `program_page` call
*/ */
int (*write_data_slicer)(uint32_t address, uint32_t len, uint32_t *align_addr, uint32_t page_size); int (*write_data_slicer)(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_addr,
uint32_t page_size);
/** /**
* Read data from the flash. Check ``max_read_bytes`` for the maximum allowed reading length. * Read data from the flash. Check ``max_read_bytes`` for the maximum allowed reading length.
*/ */
esp_err_t (*read)(spi_flash_host_driver_t *driver, void *buffer, uint32_t address, uint32_t read_len); esp_err_t (*read)(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len);
/** Check whether given buffer can be directly used to read */ /** Check whether given buffer can be directly used to read */
bool (*supports_direct_read)(spi_flash_host_driver_t *driver, const void *p); bool (*supports_direct_read)(spi_flash_host_inst_t *host, const void *p);
/** /**
* Slicer for read data. The `read` should be called iteratively with the return value * Slicer for read data. The `read` should be called iteratively with the return value
* of this function. * of this function.
@@ -144,26 +147,26 @@ struct spi_flash_host_driver_t {
* @param page_size Physical page size of the flash chip * @param page_size Physical page size of the flash chip
* @return Length that can be actually read in one `read` call * @return Length that can be actually read in one `read` call
*/ */
int (*read_data_slicer)(uint32_t address, uint32_t len, uint32_t *align_addr, uint32_t page_size); int (*read_data_slicer)(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_addr, uint32_t page_size);
/** /**
* Check whether the host is idle to perform new operations. * Check whether the host is idle to perform new operations.
*/ */
bool (*host_idle)(spi_flash_host_driver_t *driver); bool (*host_idle)(spi_flash_host_inst_t *host);
/** /**
* Configure the host to work at different read mode. Responsible to compensate the timing and set IO mode. * Configure the host to work at different read mode. Responsible to compensate the timing and set IO mode.
*/ */
esp_err_t (*configure_host_io_mode)(spi_flash_host_driver_t *driver, uint32_t command, esp_err_t (*configure_host_io_mode)(spi_flash_host_inst_t *host, uint32_t command,
uint32_t addr_bitlen, int dummy_bitlen_base, uint32_t addr_bitlen, int dummy_bitlen_base,
esp_flash_io_mode_t io_mode); esp_flash_io_mode_t io_mode);
/** /**
* Internal use, poll the HW until the last operation is done. * Internal use, poll the HW until the last operation is done.
*/ */
void (*poll_cmd_done)(spi_flash_host_driver_t *driver); void (*poll_cmd_done)(spi_flash_host_inst_t *host);
/** /**
* For some host (SPI1), they are shared with a cache. When the data is * For some host (SPI1), they are shared with a cache. When the data is
* modified, the cache needs to be flushed. Left NULL if not supported. * modified, the cache needs to be flushed. Left NULL if not supported.
*/ */
esp_err_t (*flush_cache)(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size); esp_err_t (*flush_cache)(spi_flash_host_inst_t* host, uint32_t addr, uint32_t size);
}; };
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -63,7 +63,7 @@ static inline int get_dummy_n(bool gpio_is_used, int input_delay_ns, int eff_clk
return apb_period_n / apbclk_n; return apb_period_n / apbclk_n;
} }
esp_err_t spi_flash_hal_init(spi_flash_memspi_data_t *data_out, const spi_flash_memspi_config_t *cfg) esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_hal_config_t *cfg)
{ {
if (!esp_ptr_internal(data_out)) { if (!esp_ptr_internal(data_out)) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
@@ -77,7 +77,8 @@ esp_err_t spi_flash_hal_init(spi_flash_memspi_data_t *data_out, const spi_flash_
} }
#endif #endif
*data_out = (spi_flash_memspi_data_t) { *data_out = (spi_flash_hal_context_t) {
.inst = data_out->inst, // Keeps the function pointer table
.spi = spi_flash_ll_get_hw(cfg->host_id), .spi = spi_flash_ll_get_hw(cfg->host_id),
.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),
@@ -88,18 +89,18 @@ esp_err_t spi_flash_hal_init(spi_flash_memspi_data_t *data_out, const spi_flash_
return ESP_OK; return ESP_OK;
} }
bool spi_flash_hal_supports_direct_write(spi_flash_host_driver_t *host, const void *p) bool spi_flash_hal_supports_direct_write(spi_flash_host_inst_t *host, const void *p)
{ {
bool direct_write = ( ((spi_flash_memspi_data_t *)host->driver_data)->spi != spi_flash_ll_get_hw(SPI_HOST) bool direct_write = ( ((spi_flash_hal_context_t *)host)->spi != spi_flash_ll_get_hw(SPI_HOST)
|| esp_ptr_in_dram(p) ); || esp_ptr_in_dram(p) );
return direct_write; return direct_write;
} }
bool spi_flash_hal_supports_direct_read(spi_flash_host_driver_t *host, const void *p) bool spi_flash_hal_supports_direct_read(spi_flash_host_inst_t *host, const void *p)
{ {
//currently the host doesn't support to read through dma, no word-aligned requirements //currently the host doesn't support to read through dma, no word-aligned requirements
bool direct_read = ( ((spi_flash_memspi_data_t *)host->driver_data)->spi != spi_flash_ll_get_hw(SPI_HOST) bool direct_read = ( ((spi_flash_hal_context_t *)host)->spi != spi_flash_ll_get_hw(SPI_HOST)
|| esp_ptr_in_dram(p) ); || esp_ptr_in_dram(p) );
return direct_read; return direct_read;
} }

View File

@@ -19,32 +19,31 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#define ADDRESS_MASK_24BIT 0xFFFFFF #define ADDRESS_MASK_24BIT 0xFFFFFF
#define COMPUTE_DUMMY_CYCLELEN(host, base) ((base) + ((spi_flash_memspi_data_t *)(host)->driver_data)->extra_dummy) #define COMPUTE_DUMMY_CYCLELEN(host, base) ((base) + ((spi_flash_hal_context_t*)host)->extra_dummy)
static inline spi_dev_t *get_spi_dev(spi_flash_host_driver_t *host) static inline spi_dev_t *get_spi_dev(spi_flash_host_inst_t *host)
{ {
return ((spi_flash_memspi_data_t *)host->driver_data)->spi; return ((spi_flash_hal_context_t*)host)->spi;
} }
void spi_flash_hal_poll_cmd_done(spi_flash_host_driver_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))) {
//nop //nop
} }
} }
esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *host) esp_err_t spi_flash_hal_device_config(spi_flash_host_inst_t *host)
{ {
spi_flash_memspi_data_t *drv_data = (spi_flash_memspi_data_t *)host->driver_data;
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, drv_data->cs_num); spi_flash_ll_set_cs_pin(dev, ((spi_flash_hal_context_t*)host)->cs_num);
spi_flash_ll_set_clock(dev, &drv_data->clock_conf); spi_flash_ll_set_clock(dev, &((spi_flash_hal_context_t*)host)->clock_conf);
return ESP_OK; return ESP_OK;
} }
esp_err_t spi_flash_hal_configure_host_io_mode( esp_err_t spi_flash_hal_configure_host_io_mode(
spi_flash_host_driver_t *host, spi_flash_host_inst_t *host,
uint32_t command, uint32_t command,
uint32_t addr_bitlen, uint32_t addr_bitlen,
int dummy_cyclelen_base, int dummy_cyclelen_base,
@@ -89,9 +88,9 @@ esp_err_t spi_flash_hal_configure_host_io_mode(
return ESP_OK; return ESP_OK;
} }
esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_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->configure_host_io_mode(host, trans->command, trans->address_bitlen, 0, SPI_FLASH_FASTRD); 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);
@@ -106,19 +105,19 @@ esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *host, spi_flash_
spi_flash_ll_set_miso_bitlen(dev, trans->miso_len * 8); spi_flash_ll_set_miso_bitlen(dev, trans->miso_len * 8);
spi_flash_ll_user_start(dev); spi_flash_ll_user_start(dev);
host->poll_cmd_done(host); host->driver->poll_cmd_done(host);
spi_flash_ll_get_buffer_data(dev, trans->miso_data, trans->miso_len); spi_flash_ll_get_buffer_data(dev, trans->miso_data, trans->miso_len);
return ESP_OK; return ESP_OK;
} }
esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *host, void *buffer, uint32_t address, uint32_t read_len) esp_err_t spi_flash_hal_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len)
{ {
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); spi_flash_ll_set_usr_address(dev, address << (bitlen - 24), bitlen);
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->poll_cmd_done(host); host->driver->poll_cmd_done(host);
spi_flash_ll_get_buffer_data(dev, buffer, read_len); spi_flash_ll_get_buffer_data(dev, buffer, read_len);
return ESP_OK; return ESP_OK;
} }

View File

@@ -22,18 +22,18 @@
#include "spi_flash_hal_common.inc" #include "spi_flash_hal_common.inc"
bool spi_flash_hal_gpspi_supports_direct_write(spi_flash_host_driver_t *host, const void *p) bool spi_flash_hal_gpspi_supports_direct_write(spi_flash_host_inst_t *host, const void *p)
{ {
return true; return true;
} }
bool spi_flash_hal_gpspi_supports_direct_read(spi_flash_host_driver_t *host, const void *p) bool spi_flash_hal_gpspi_supports_direct_read(spi_flash_host_inst_t *host, const void *p)
{ {
return true; return true;
} }
bool spi_flash_hal_gpspi_host_idle(spi_flash_host_driver_t *chip_drv) bool spi_flash_hal_gpspi_host_idle(spi_flash_host_inst_t *host)
{ {
spi_dev_t *dev = get_spi_dev(chip_drv); spi_dev_t *dev = get_spi_dev(host);
return spi_flash_ll_host_idle(dev); return spi_flash_ll_host_idle(dev);
} }

View File

@@ -14,51 +14,51 @@
#include "spi_flash_hal_common.inc" #include "spi_flash_hal_common.inc"
void spi_flash_hal_erase_chip(spi_flash_host_driver_t *host) void spi_flash_hal_erase_chip(spi_flash_host_inst_t *host)
{ {
spi_dev_t *dev = get_spi_dev(host); spi_dev_t *dev = get_spi_dev(host);
spi_flash_ll_erase_chip(dev); spi_flash_ll_erase_chip(dev);
host->poll_cmd_done(host); host->driver->poll_cmd_done(host);
} }
void spi_flash_hal_erase_sector(spi_flash_host_driver_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);
spi_flash_ll_set_addr_bitlen(dev, 24); spi_flash_ll_set_addr_bitlen(dev, 24);
spi_flash_ll_set_address(dev, start_address & ADDRESS_MASK_24BIT); spi_flash_ll_set_address(dev, start_address & ADDRESS_MASK_24BIT);
spi_flash_ll_erase_sector(dev); spi_flash_ll_erase_sector(dev);
host->poll_cmd_done(host); host->driver->poll_cmd_done(host);
} }
void spi_flash_hal_erase_block(spi_flash_host_driver_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);
spi_flash_ll_set_addr_bitlen(dev, 24); spi_flash_ll_set_addr_bitlen(dev, 24);
spi_flash_ll_set_address(dev, start_address & ADDRESS_MASK_24BIT); spi_flash_ll_set_address(dev, start_address & ADDRESS_MASK_24BIT);
spi_flash_ll_erase_block(dev); spi_flash_ll_erase_block(dev);
host->poll_cmd_done(host); host->driver->poll_cmd_done(host);
} }
void spi_flash_hal_program_page(spi_flash_host_driver_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);
spi_flash_ll_set_addr_bitlen(dev, 24); spi_flash_ll_set_addr_bitlen(dev, 24);
spi_flash_ll_set_address(dev, (address & ADDRESS_MASK_24BIT) | (length << 24)); spi_flash_ll_set_address(dev, (address & ADDRESS_MASK_24BIT) | (length << 24));
spi_flash_ll_program_page(dev, buffer, length); spi_flash_ll_program_page(dev, buffer, length);
host->poll_cmd_done(host); host->driver->poll_cmd_done(host);
} }
esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_driver_t *host, bool wp) esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_inst_t *host, bool wp)
{ {
spi_dev_t *dev = get_spi_dev(host); spi_dev_t *dev = get_spi_dev(host);
spi_flash_ll_set_write_protect(dev, wp); spi_flash_ll_set_write_protect(dev, wp);
host->poll_cmd_done(host); host->driver->poll_cmd_done(host);
return ESP_OK; return ESP_OK;
} }
bool spi_flash_hal_host_idle(spi_flash_host_driver_t *chip_drv) bool spi_flash_hal_host_idle(spi_flash_host_inst_t *host)
{ {
spi_dev_t *dev = get_spi_dev(chip_drv); spi_dev_t *dev = get_spi_dev(host);
bool idle = spi_flash_ll_host_idle(dev); bool idle = spi_flash_ll_host_idle(dev);
// Not clear if this is necessary, or only necessary if // Not clear if this is necessary, or only necessary if

View File

@@ -103,7 +103,7 @@ static esp_err_t IRAM_ATTR spiflash_start_default(esp_flash_t *chip)
return err; return err;
} }
} }
chip->host->dev_config(chip->host); chip->host->driver->dev_config(chip->host);
return ESP_OK; return ESP_OK;
} }
@@ -151,8 +151,8 @@ 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)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
if (chip == NULL || chip->host == NULL || chip->host->driver_data == NULL || if (chip == NULL || chip->host == NULL || chip->host->driver == NULL ||
((memspi_host_data_t*)chip->host->driver_data)->spi == NULL) { ((memspi_host_inst_t*)chip->host)->spi == NULL) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
@@ -212,11 +212,11 @@ esp_err_t IRAM_ATTR esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id
// Send generic RDID command twice, check for a matching result and retry in case we just powered on (inner // Send generic RDID command twice, check for a matching result and retry in case we just powered on (inner
// function fails if it sees all-ones or all-zeroes.) // function fails if it sees all-ones or all-zeroes.)
err = chip->host->read_id(chip->host, flash_id); err = chip->host->driver->read_id(chip->host, flash_id);
if (err == ESP_OK) { // check we see the same ID twice, in case of transient power-on errors if (err == ESP_OK) { // check we see the same ID twice, in case of transient power-on errors
uint32_t new_id; uint32_t new_id;
err = chip->host->read_id(chip->host, &new_id); err = chip->host->driver->read_id(chip->host, &new_id);
if (err == ESP_OK && (new_id != *flash_id)) { if (err == ESP_OK && (new_id != *flash_id)) {
err = ESP_ERR_FLASH_NOT_INITIALISED; err = ESP_ERR_FLASH_NOT_INITIALISED;
} }
@@ -284,7 +284,7 @@ esp_err_t IRAM_ATTR esp_flash_read_id(esp_flash_t *chip, uint32_t *out_id)
return err; return err;
} }
err = chip->host->read_id(chip->host, out_id); err = chip->host->driver->read_id(chip->host, out_id);
return rom_spiflash_api_funcs->end(chip, err); return rom_spiflash_api_funcs->end(chip, err);
} }
@@ -553,7 +553,7 @@ esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t add
} }
//when the cache is disabled, only the DRAM can be read, check whether we need to receive in another buffer in DRAM. //when the cache is disabled, only the DRAM can be read, check whether we need to receive in another buffer in DRAM.
bool direct_read = chip->host->supports_direct_read(chip->host, buffer); bool direct_read = chip->host->driver->supports_direct_read(chip->host, buffer);
uint8_t* temp_buffer = NULL; uint8_t* temp_buffer = NULL;
//each time, we at most read this length //each time, we at most read this length
@@ -617,7 +617,7 @@ esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint3
} }
//when the cache is disabled, only the DRAM can be read, check whether we need to copy the data first //when the cache is disabled, only the DRAM can be read, check whether we need to copy the data first
bool direct_write = chip->host->supports_direct_write(chip->host, buffer); bool direct_write = chip->host->driver->supports_direct_write(chip->host, buffer);
err = ESP_OK; err = ESP_OK;
/* Write output in chunks, either by buffering on stack or /* Write output in chunks, either by buffering on stack or

View File

@@ -116,8 +116,7 @@ esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_d
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
esp_flash_t *chip = NULL; esp_flash_t *chip = NULL;
spi_flash_host_driver_t *host = NULL; memspi_host_inst_t *host = NULL;
memspi_host_data_t *host_data = NULL;
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
uint32_t caps = MALLOC_CAP_DEFAULT; uint32_t caps = MALLOC_CAP_DEFAULT;
@@ -129,23 +128,16 @@ esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_d
goto fail; goto fail;
} }
host = (spi_flash_host_driver_t*)heap_caps_malloc(sizeof(spi_flash_host_driver_t), caps); host = (memspi_host_inst_t*)heap_caps_malloc(sizeof(memspi_host_inst_t), caps);
*chip = (esp_flash_t) { *chip = (esp_flash_t) {
.read_mode = config->io_mode, .read_mode = config->io_mode,
.host = host, .host = (spi_flash_host_inst_t*)host,
}; };
if (!host) { if (!host) {
ret = ESP_ERR_NO_MEM; ret = ESP_ERR_NO_MEM;
goto fail; goto fail;
} }
host_data = (memspi_host_data_t*)heap_caps_malloc(sizeof(memspi_host_data_t), caps);
host->driver_data = host_data;
if (!host_data) {
ret = ESP_ERR_NO_MEM;
goto fail;
}
int dev_id = -1; int dev_id = -1;
esp_err_t err = esp_flash_init_os_functions(chip, config->host_id, &dev_id); esp_err_t err = esp_flash_init_os_functions(chip, config->host_id, &dev_id);
if (err == ESP_ERR_NOT_SUPPORTED) { if (err == ESP_ERR_NOT_SUPPORTED) {
@@ -173,7 +165,7 @@ esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_d
.input_delay_ns = config->input_delay_ns, .input_delay_ns = config->input_delay_ns,
.speed = config->speed, .speed = config->speed,
}; };
err = memspi_host_init_pointers(host, host_data, &host_cfg); err = memspi_host_init_pointers(host, &host_cfg);
if (err != ESP_OK) { if (err != ESP_OK) {
ret = err; ret = err;
goto fail; goto fail;
@@ -195,10 +187,7 @@ esp_err_t spi_bus_remove_flash_device(esp_flash_t *chip)
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
esp_flash_deinit_os_functions(chip); esp_flash_deinit_os_functions(chip);
if (chip->host) {
free(chip->host->driver_data);
free(chip->host); free(chip->host);
}
free(chip); free(chip);
return ESP_OK; return ESP_OK;
} }
@@ -209,13 +198,11 @@ extern const esp_flash_os_functions_t esp_flash_noos_functions;
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL #ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
static DRAM_ATTR memspi_host_data_t default_driver_data; static DRAM_ATTR memspi_host_inst_t esp_flash_default_host;
static DRAM_ATTR spi_flash_host_driver_t esp_flash_default_host_drv = ESP_FLASH_DEFAULT_HOST_DRIVER();
static DRAM_ATTR esp_flash_t default_chip = { static DRAM_ATTR esp_flash_t default_chip = {
.read_mode = DEFAULT_FLASH_MODE, .read_mode = DEFAULT_FLASH_MODE,
.host = &esp_flash_default_host_drv, .host = (spi_flash_host_inst_t*)&esp_flash_default_host,
.os_func = &esp_flash_noos_functions, .os_func = &esp_flash_noos_functions,
}; };
@@ -229,12 +216,14 @@ esp_err_t esp_flash_init_default_chip(void)
#endif #endif
//the host is already initialized, only do init for the data and load it to the host //the host is already initialized, only do init for the data and load it to the host
spi_flash_hal_init(&default_driver_data, &cfg); esp_err_t err = memspi_host_init_pointers(&esp_flash_default_host, &cfg);
default_chip.host->driver_data = &default_driver_data; if (err != ESP_OK) {
return err;
}
// ROM TODO: account for non-standard default pins in efuse // ROM TODO: account for non-standard default pins in efuse
// ROM TODO: to account for chips which are slow to power on, maybe keep probing in a loop here // ROM TODO: to account for chips which are slow to power on, maybe keep probing in a loop here
esp_err_t err = esp_flash_init(&default_chip); err = esp_flash_init(&default_chip);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }

View File

@@ -80,7 +80,7 @@ typedef struct {
risk. risk.
*/ */
struct esp_flash_t { struct esp_flash_t {
spi_flash_host_driver_t *host; ///< Pointer to hardware-specific "host_driver" structure. Must be initialized before used. 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 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. 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.

View File

@@ -38,20 +38,19 @@
} }
/// configuration for the memspi host /// configuration for the memspi host
typedef spi_flash_memspi_config_t memspi_host_config_t; typedef spi_flash_hal_config_t memspi_host_config_t;
/// context for the memspi host /// context for the memspi host
typedef spi_flash_memspi_data_t memspi_host_data_t; typedef spi_flash_hal_context_t memspi_host_inst_t;
/** /**
* Initialize the memory SPI host. * Initialize the memory SPI host.
* *
* @param host Pointer to the host structure. * @param host Pointer to the host structure.
* @param data Pointer to allocated space to hold the context of host driver.
* @param cfg Pointer to configuration structure * @param cfg Pointer to configuration structure
* *
* @return always return ESP_OK * @return always return ESP_OK
*/ */
esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_data_t *data, const memspi_host_config_t *cfg); esp_err_t memspi_host_init_pointers(memspi_host_inst_t *host, const memspi_host_config_t *cfg);
/******************************************************************************* /*******************************************************************************
* NOTICE * NOTICE
@@ -66,7 +65,7 @@ esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_d
* High speed implementation of RDID through memspi interface relying on the * High speed implementation of RDID through memspi interface relying on the
* ``common_command``. * ``common_command``.
* *
* @param driver The driver context. * @param host The driver context.
* @param id Output of the read ID from the slave. * @param id Output of the read ID from the slave.
* *
* @return * @return
@@ -74,82 +73,82 @@ esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_d
* - ESP_ERR_FLASH_NO_RESPONSE: if no response from chip * - ESP_ERR_FLASH_NO_RESPONSE: if no response from chip
* - or other cases from ``spi_hal_common_command`` * - or other cases from ``spi_hal_common_command``
*/ */
esp_err_t memspi_host_read_id_hs(spi_flash_host_driver_t *driver, uint32_t *id); esp_err_t memspi_host_read_id_hs(spi_flash_host_inst_t *host, uint32_t *id);
/** /**
* High speed implementation of RDSR through memspi interface relying on the * High speed implementation of RDSR through memspi interface relying on the
* ``common_command``. * ``common_command``.
* *
* @param driver The driver context. * @param host The driver context.
* @param id Output of the read ID from the slave. * @param id Output of the read ID from the slave.
* *
* @return * @return
* - ESP_OK: if success * - ESP_OK: if success
* - or other cases from ``spi_hal_common_command`` * - or other cases from ``spi_hal_common_command``
*/ */
esp_err_t memspi_host_read_status_hs(spi_flash_host_driver_t *driver, uint8_t *out_sr); esp_err_t memspi_host_read_status_hs(spi_flash_host_inst_t *host, uint8_t *out_sr);
/** /**
* Flush the cache (if needed) after the contents are modified. * Flush the cache (if needed) after the contents are modified.
* *
* @param driver The driver context. * @param host The driver context.
* @param addr Start address of the modified region * @param addr Start address of the modified region
* @param size Size of the region modified. * @param size Size of the region modified.
* *
* @return always ESP_OK. * @return always ESP_OK.
*/ */
esp_err_t memspi_host_flush_cache(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size); esp_err_t memspi_host_flush_cache(spi_flash_host_inst_t *host, uint32_t addr, uint32_t size);
/** /**
* Erase contents of entire chip. * Erase contents of entire chip.
* *
* @param driver The driver context. * @param host The driver context.
*/ */
void memspi_host_erase_chip(spi_flash_host_driver_t *driver); 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.
* *
* @param driver The driver context. * @param host The driver context.
* @param start_address Starting address of the sector. * @param start_address Starting address of the sector.
*/ */
void memspi_host_erase_sector(spi_flash_host_driver_t *driver, 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.
* *
* @param driver The driver context. * @param host The driver context.
* @param start_address Starting address of the block. * @param start_address Starting address of the block.
*/ */
void memspi_host_erase_block(spi_flash_host_driver_t *driver, 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.
* *
* @param driver 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.
* @param address Starting address of where to flash the data. * @param address Starting address of where to flash the data.
* @param length The number of bytes to flash. * @param length The number of bytes to flash.
*/ */
void memspi_host_program_page(spi_flash_host_driver_t *driver, 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);
/** /**
* Set ability to write to chip. * Set ability to write to chip.
* *
* @param driver The driver context. * @param host The driver context.
* @param wp Enable or disable write protect (true - enable, false - disable). * @param wp Enable or disable write protect (true - enable, false - disable).
*/ */
esp_err_t memspi_host_set_write_protect(spi_flash_host_driver_t *driver, bool wp); esp_err_t memspi_host_set_write_protect(spi_flash_host_inst_t *host, bool wp);
/** /**
* Read data to buffer. * Read data to buffer.
* *
* @param driver The driver context. * @param host The driver context.
* @param buffer Buffer which contains the data to be read. * @param buffer Buffer which contains the data to be read.
* @param address Starting address of where to read the data. * @param address Starting address of where to read the data.
* @param length The number of bytes to read. * @param length The number of bytes to read.
*/ */
esp_err_t memspi_host_read(spi_flash_host_driver_t *driver, void *buffer, uint32_t address, uint32_t read_len); esp_err_t memspi_host_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len);
/** /**
* @brief Slicer for read data used in non-encrypted regions. This slicer does nothing but * @brief Slicer for read data used in non-encrypted regions. This slicer does nothing but
@@ -162,7 +161,7 @@ esp_err_t memspi_host_read(spi_flash_host_driver_t *driver, void *buffer, uint32
* *
* @return Length that can actually be read in one `read` call in `spi_flash_host_driver_t`. * @return Length that can actually be read in one `read` call in `spi_flash_host_driver_t`.
*/ */
int memspi_host_read_data_slicer(uint32_t address, uint32_t len, uint32_t *align_address, uint32_t page_size); int memspi_host_read_data_slicer(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_address, uint32_t page_size);
/** /**
* @brief Slicer for write data used in non-encrypted regions. This slicer limit the length to the * @brief Slicer for write data used in non-encrypted regions. This slicer limit the length to the
@@ -176,4 +175,4 @@ int memspi_host_read_data_slicer(uint32_t address, uint32_t len, uint32_t *align
* *
* @return Length that can actually be written in one `program_page` call in `spi_flash_host_driver_t`. * @return Length that can actually be written in one `program_page` call in `spi_flash_host_driver_t`.
*/ */
int memspi_host_write_data_slicer(uint32_t address, uint32_t len, uint32_t *align_address, uint32_t page_size); int memspi_host_write_data_slicer(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_address, uint32_t page_size);

View File

@@ -23,22 +23,22 @@
#define SPI_FLASH_HAL_MAX_READ_BYTES 64 #define SPI_FLASH_HAL_MAX_READ_BYTES 64
static const char TAG[] = "memspi"; static const char TAG[] = "memspi";
static const spi_flash_host_driver_t esp_flash_default_host = ESP_FLASH_DEFAULT_HOST_DRIVER(); DRAM_ATTR static const spi_flash_host_driver_t esp_flash_default_host = ESP_FLASH_DEFAULT_HOST_DRIVER();
#ifdef CONFIG_IDF_TARGET_ESP32S2 #ifdef CONFIG_IDF_TARGET_ESP32S2
extern void spi_flash_hal_gpspi_poll_cmd_done(spi_flash_host_driver_t *driver); extern void spi_flash_hal_gpspi_poll_cmd_done(spi_flash_host_inst_t *host);
extern esp_err_t spi_flash_hal_gpspi_device_config(spi_flash_host_driver_t *driver); extern esp_err_t spi_flash_hal_gpspi_device_config(spi_flash_host_inst_t *host);
esp_err_t spi_flash_hal_gpspi_configure_host_io_mode( esp_err_t spi_flash_hal_gpspi_configure_host_io_mode(
spi_flash_host_driver_t *host, spi_flash_host_inst_t *host,
uint32_t command, uint32_t command,
uint32_t addr_bitlen, uint32_t addr_bitlen,
int dummy_cyclelen_base, int dummy_cyclelen_base,
esp_flash_io_mode_t io_mode); esp_flash_io_mode_t io_mode);
extern esp_err_t spi_flash_hal_gpspi_common_command(spi_flash_host_driver_t *chip_drv, spi_flash_trans_t *trans); extern esp_err_t spi_flash_hal_gpspi_common_command(spi_flash_host_inst_t *host, spi_flash_trans_t *trans);
extern esp_err_t spi_flash_hal_gpspi_read(spi_flash_host_driver_t *chip_drv, void *buffer, uint32_t address, uint32_t read_len); extern esp_err_t spi_flash_hal_gpspi_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len);
extern bool spi_flash_hal_gpspi_host_idle(spi_flash_host_driver_t *chip_drv); extern bool spi_flash_hal_gpspi_host_idle(spi_flash_host_inst_t *host);
extern bool spi_flash_hal_gpspi_supports_direct_write(spi_flash_host_driver_t *driver, const void *p); extern bool spi_flash_hal_gpspi_supports_direct_write(spi_flash_host_inst_t *host, const void *p);
extern bool spi_flash_hal_gpspi_supports_direct_read(spi_flash_host_driver_t *driver, const void *p); extern bool spi_flash_hal_gpspi_supports_direct_read(spi_flash_host_inst_t *host, const void *p);
/** Default configuration for GPSPI */ /** Default configuration for GPSPI */
static const spi_flash_host_driver_t esp_flash_gpspi_host = { static const spi_flash_host_driver_t esp_flash_gpspi_host = {
@@ -63,32 +63,23 @@ static const spi_flash_host_driver_t esp_flash_gpspi_host = {
}; };
#endif #endif
esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_data_t *data, const memspi_host_config_t *cfg) esp_err_t memspi_host_init_pointers(memspi_host_inst_t *host, const memspi_host_config_t *cfg)
{ {
#ifdef CONFIG_IDF_TARGET_ESP32 #ifdef CONFIG_IDF_TARGET_ESP32
memcpy(host, &esp_flash_default_host, sizeof(spi_flash_host_driver_t)); host->inst.driver = &esp_flash_default_host;
#elif CONFIG_IDF_TARGET_ESP32S2 #elif CONFIG_IDF_TARGET_ESP32S2
if (cfg->host_id == SPI_HOST) if (cfg->host_id == SPI_HOST)
memcpy(host, &esp_flash_default_host, sizeof(spi_flash_host_driver_t)); host->inst.driver = &esp_flash_default_host;
else { else {
memcpy(host, &esp_flash_gpspi_host, sizeof(spi_flash_host_driver_t)); host->inst.driver = &esp_flash_gpspi_host;
} }
#endif #endif
esp_err_t err = spi_flash_hal_init(data, cfg); esp_err_t err = spi_flash_hal_init(host, cfg);
if (err != ESP_OK) {
return err; return err;
}
host->driver_data = data;
//some functions are not required if not SPI1
if ((void*)data->spi != (void*)spi_flash_ll_get_hw(SPI_HOST)) {
host->flush_cache = NULL;
}
return ESP_OK;
} }
esp_err_t memspi_host_read_id_hs(spi_flash_host_driver_t *host, uint32_t *id) esp_err_t memspi_host_read_id_hs(spi_flash_host_inst_t *host, uint32_t *id)
{ {
uint32_t id_buf = 0; uint32_t id_buf = 0;
spi_flash_trans_t t = { spi_flash_trans_t t = {
@@ -96,7 +87,7 @@ esp_err_t memspi_host_read_id_hs(spi_flash_host_driver_t *host, uint32_t *id)
.miso_len = 3, .miso_len = 3,
.miso_data = ((uint8_t*) &id_buf), .miso_data = ((uint8_t*) &id_buf),
}; };
host->common_command(host, &t); host->driver->common_command(host, &t);
uint32_t raw_flash_id = id_buf; uint32_t raw_flash_id = id_buf;
ESP_EARLY_LOGV(TAG, "raw_chip_id: %X\n", raw_flash_id); ESP_EARLY_LOGV(TAG, "raw_chip_id: %X\n", raw_flash_id);
@@ -112,7 +103,7 @@ esp_err_t memspi_host_read_id_hs(spi_flash_host_driver_t *host, uint32_t *id)
return ESP_OK; return ESP_OK;
} }
esp_err_t memspi_host_read_status_hs(spi_flash_host_driver_t *driver, uint8_t *out_sr) esp_err_t memspi_host_read_status_hs(spi_flash_host_inst_t *host, uint8_t *out_sr)
{ {
//NOTE: we do have a read id function, however it doesn't work in high freq //NOTE: we do have a read id function, however it doesn't work in high freq
uint32_t stat_buf = 0; uint32_t stat_buf = 0;
@@ -121,7 +112,7 @@ esp_err_t memspi_host_read_status_hs(spi_flash_host_driver_t *driver, uint8_t *o
.miso_data = ((uint8_t*) &stat_buf), .miso_data = ((uint8_t*) &stat_buf),
.miso_len = 1 .miso_len = 1
}; };
esp_err_t err = driver->common_command(driver, &t); esp_err_t err = host->driver->common_command(host, &t);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
@@ -129,42 +120,42 @@ esp_err_t memspi_host_read_status_hs(spi_flash_host_driver_t *driver, uint8_t *o
return ESP_OK; return ESP_OK;
} }
esp_err_t memspi_host_flush_cache(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size) esp_err_t memspi_host_flush_cache(spi_flash_host_inst_t *host, uint32_t addr, uint32_t size)
{ {
if ((void*)((memspi_host_data_t*)(driver->driver_data))->spi == (void*) spi_flash_ll_get_hw(SPI_HOST)) { if ((void*)((memspi_host_inst_t*)host)->spi == (void*) spi_flash_ll_get_hw(SPI_HOST)) {
spi_flash_check_and_flush_cache(addr, size); spi_flash_check_and_flush_cache(addr, size);
} }
return ESP_OK; return ESP_OK;
} }
void memspi_host_erase_chip(spi_flash_host_driver_t *chip_drv) void memspi_host_erase_chip(spi_flash_host_inst_t *host)
{ {
spi_flash_trans_t t = { 0 }; spi_flash_trans_t t = { 0 };
t.command = CMD_CHIP_ERASE; t.command = CMD_CHIP_ERASE;
chip_drv->common_command(chip_drv, &t); host->driver->common_command(host, &t);
} }
void memspi_host_erase_sector(spi_flash_host_driver_t *chip_drv, uint32_t start_address) void memspi_host_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address)
{ {
spi_flash_trans_t t = { spi_flash_trans_t t = {
.command = CMD_SECTOR_ERASE, .command = CMD_SECTOR_ERASE,
.address_bitlen = 24, .address_bitlen = 24,
.address = start_address .address = start_address
}; };
chip_drv->common_command(chip_drv, &t); host->driver->common_command(host, &t);
} }
void memspi_host_erase_block(spi_flash_host_driver_t *chip_drv, uint32_t start_address) void memspi_host_erase_block(spi_flash_host_inst_t *host, uint32_t start_address)
{ {
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,
.address = start_address, .address = start_address,
}; };
chip_drv->common_command(chip_drv, &t); host->driver->common_command(host, &t);
} }
void memspi_host_program_page(spi_flash_host_driver_t *chip_drv, 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)
{ {
spi_flash_trans_t t = { spi_flash_trans_t t = {
.command = CMD_PROGRAM_PAGE, .command = CMD_PROGRAM_PAGE,
@@ -173,10 +164,10 @@ void memspi_host_program_page(spi_flash_host_driver_t *chip_drv, const void *buf
.mosi_len = length, .mosi_len = length,
.mosi_data = buffer .mosi_data = buffer
}; };
chip_drv->common_command(chip_drv, &t); host->driver->common_command(host, &t);
} }
esp_err_t memspi_host_read(spi_flash_host_driver_t *chip_drv, void *buffer, uint32_t address, uint32_t read_len) esp_err_t memspi_host_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len)
{ {
spi_flash_trans_t t = { spi_flash_trans_t t = {
.command = CMD_READ, .command = CMD_READ,
@@ -185,22 +176,22 @@ esp_err_t memspi_host_read(spi_flash_host_driver_t *chip_drv, void *buffer, uint
.miso_len = read_len, .miso_len = read_len,
.miso_data = buffer .miso_data = buffer
}; };
chip_drv->common_command(chip_drv, &t); host->driver->common_command(host, &t);
return ESP_OK; return ESP_OK;
} }
esp_err_t memspi_host_set_write_protect(spi_flash_host_driver_t *chip_drv, bool wp) esp_err_t memspi_host_set_write_protect(spi_flash_host_inst_t *host, bool wp)
{ {
spi_flash_trans_t t = { spi_flash_trans_t t = {
.command = wp ? CMD_WRDI : CMD_WREN .command = wp ? CMD_WRDI : CMD_WREN
}; };
chip_drv->common_command(chip_drv, &t); host->driver->common_command(host, &t);
return ESP_OK; return ESP_OK;
} }
// When encryption is enabled, etc. the data slicer may be complicated // When encryption is enabled, etc. the data slicer may be complicated
// This is the simple case where the hardware has no other requirements than the size and page boundary // This is the simple case where the hardware has no other requirements than the size and page boundary
int memspi_host_write_data_slicer(uint32_t address, uint32_t len, uint32_t *align_address, uint32_t page_size) int memspi_host_write_data_slicer(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_address, uint32_t page_size)
{ {
uint32_t align_addr = address; uint32_t align_addr = address;
uint32_t end_bound = (align_addr/page_size + 1) * page_size; uint32_t end_bound = (align_addr/page_size + 1) * page_size;
@@ -210,7 +201,7 @@ int memspi_host_write_data_slicer(uint32_t address, uint32_t len, uint32_t *alig
return MIN(max_len, len); return MIN(max_len, len);
} }
int memspi_host_read_data_slicer(uint32_t address, uint32_t len, uint32_t *align_address, uint32_t page_size) int memspi_host_read_data_slicer(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_address, uint32_t page_size)
{ {
// Shouldn't read longer than SPI_FLASH_HAL_MAX_READ_BYTES // Shouldn't read longer than SPI_FLASH_HAL_MAX_READ_BYTES
uint32_t max_len = SPI_FLASH_HAL_MAX_READ_BYTES; uint32_t max_len = SPI_FLASH_HAL_MAX_READ_BYTES;

View File

@@ -76,7 +76,7 @@ esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip)
t = (spi_flash_trans_t) { t = (spi_flash_trans_t) {
.command = CMD_RST_EN, .command = CMD_RST_EN,
}; };
esp_err_t err = chip->host->common_command(chip->host, &t); esp_err_t err = chip->host->driver->common_command(chip->host, &t);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
@@ -84,7 +84,7 @@ esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip)
t = (spi_flash_trans_t) { t = (spi_flash_trans_t) {
.command = CMD_RST_DEV, .command = CMD_RST_DEV,
}; };
err = chip->host->common_command(chip->host, &t); err = chip->host->driver->common_command(chip->host, &t);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
@@ -118,10 +118,10 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip)
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout); err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
} }
if (err == ESP_OK) { if (err == ESP_OK) {
chip->host->erase_chip(chip->host); chip->host->driver->erase_chip(chip->host);
//to save time, flush cache here //to save time, flush cache here
if (chip->host->flush_cache) { if (chip->host->driver->flush_cache) {
err = chip->host->flush_cache(chip->host, 0, chip->size); err = chip->host->driver->flush_cache(chip->host, 0, chip->size);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
@@ -138,10 +138,10 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout); err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
} }
if (err == ESP_OK) { if (err == ESP_OK) {
chip->host->erase_sector(chip->host, start_address); chip->host->driver->erase_sector(chip->host, start_address);
//to save time, flush cache here //to save time, flush cache here
if (chip->host->flush_cache) { if (chip->host->driver->flush_cache) {
err = chip->host->flush_cache(chip->host, start_address, chip->chip_drv->sector_size); err = chip->host->driver->flush_cache(chip->host, start_address, chip->chip_drv->sector_size);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
@@ -158,10 +158,10 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout); err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
} }
if (err == ESP_OK) { if (err == ESP_OK) {
chip->host->erase_block(chip->host, start_address); chip->host->driver->erase_block(chip->host, start_address);
//to save time, flush cache here //to save time, flush cache here
if (chip->host->flush_cache) { if (chip->host->driver->flush_cache) {
err = chip->host->flush_cache(chip->host, start_address, chip->chip_drv->block_erase_size); err = chip->host->driver->flush_cache(chip->host, start_address, chip->chip_drv->block_erase_size);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
@@ -188,10 +188,10 @@ esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t
while (err == ESP_OK && length > 0) { while (err == ESP_OK && length > 0) {
memset(temp_buffer, 0xFF, sizeof(temp_buffer)); memset(temp_buffer, 0xFF, sizeof(temp_buffer));
uint32_t read_len = chip->host->read_data_slicer(address, length, &align_address, page_size); 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 left_off = address - align_address;
uint32_t data_len = MIN(align_address + read_len, address + length) - address; uint32_t data_len = MIN(align_address + read_len, address + length) - address;
err = chip->host->read(chip->host, temp_buffer, align_address, read_len); err = chip->host->driver->read(chip->host, temp_buffer, align_address, read_len);
memcpy(buffer, temp_buffer + left_off, data_len); memcpy(buffer, temp_buffer + left_off, data_len);
@@ -211,7 +211,7 @@ esp_err_t spi_flash_chip_generic_page_program(esp_flash_t *chip, const void *buf
if (err == ESP_OK) { if (err == ESP_OK) {
// Perform the actual Page Program command // Perform the actual Page Program command
chip->host->program_page(chip->host, buffer, address, length); chip->host->driver->program_page(chip->host, buffer, address, length);
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->page_program_timeout); err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->page_program_timeout);
} }
@@ -227,7 +227,7 @@ esp_err_t spi_flash_chip_generic_write(esp_flash_t *chip, const void *buffer, ui
while (err == ESP_OK && length > 0) { while (err == ESP_OK && length > 0) {
memset(temp_buffer, 0xFF, sizeof(temp_buffer)); memset(temp_buffer, 0xFF, sizeof(temp_buffer));
uint32_t page_len = chip->host->write_data_slicer(address, length, &align_address, page_size); uint32_t page_len = chip->host->driver->write_data_slicer(chip->host, address, length, &align_address, page_size);
uint32_t left_off = address - align_address; uint32_t left_off = address - align_address;
uint32_t write_len = MIN(align_address + page_len, address + length) - address; uint32_t write_len = MIN(align_address + page_len, address + length) - address;
memcpy(temp_buffer + left_off, buffer, write_len); memcpy(temp_buffer + left_off, buffer, write_len);
@@ -241,8 +241,8 @@ esp_err_t spi_flash_chip_generic_write(esp_flash_t *chip, const void *buffer, ui
length -= write_len; length -= write_len;
} }
} }
if (err == ESP_OK && chip->host->flush_cache) { if (err == ESP_OK && chip->host->driver->flush_cache) {
err = chip->host->flush_cache(chip->host, address, length); err = chip->host->driver->flush_cache(chip->host, address, length);
} }
return err; return err;
} }
@@ -259,7 +259,7 @@ esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout); err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
if (err == ESP_OK) { if (err == ESP_OK) {
chip->host->set_write_protect(chip->host, write_protect); chip->host->driver->set_write_protect(chip->host, write_protect);
} }
bool wp_read; bool wp_read;
@@ -276,7 +276,7 @@ esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
uint8_t status; uint8_t status;
assert(out_write_protect!=NULL); assert(out_write_protect!=NULL);
err = chip->host->read_status(chip->host, &status); err = chip->host->driver->read_status(chip->host, &status);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
@@ -287,7 +287,7 @@ esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_
esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_us) esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_us)
{ {
while (chip->host->host_idle(chip->host) && *timeout_us > 0) { while (chip->host->driver->host_idle(chip->host) && *timeout_us > 0) {
#if HOST_DELAY_INTERVAL_US > 0 #if HOST_DELAY_INTERVAL_US > 0
if (*timeout_us > 1) { if (*timeout_us > 1) {
int delay = MIN(HOST_DELAY_INTERVAL_US, *timeout_us); int delay = MIN(HOST_DELAY_INTERVAL_US, *timeout_us);
@@ -314,7 +314,7 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u
return err; return err;
} }
err = chip->host->read_status(chip->host, &status); err = chip->host->driver->read_status(chip->host, &status);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
@@ -374,7 +374,7 @@ esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip)
return ESP_ERR_FLASH_NOT_INITIALISED; return ESP_ERR_FLASH_NOT_INITIALISED;
} }
return chip->host->configure_host_io_mode(chip->host, read_command, addr_bitlen, dummy_cyclelen_base, return chip->host->driver->configure_host_io_mode(chip->host, read_command, addr_bitlen, dummy_cyclelen_base,
chip->read_mode); chip->read_mode);
} }
@@ -451,7 +451,7 @@ static esp_err_t spi_flash_common_read_qe_sr(esp_flash_t *chip, uint8_t qe_rdsr_
.miso_data = (uint8_t*) &sr_buf, .miso_data = (uint8_t*) &sr_buf,
.miso_len = qe_sr_bitwidth / 8, .miso_len = qe_sr_bitwidth / 8,
}; };
esp_err_t ret = chip->host->common_command(chip->host, &t); esp_err_t ret = chip->host->driver->common_command(chip->host, &t);
*sr = sr_buf; *sr = sr_buf;
return ret; return ret;
} }
@@ -464,7 +464,7 @@ static esp_err_t spi_flash_common_write_qe_sr(esp_flash_t *chip, uint8_t qe_wrsr
.mosi_len = qe_sr_bitwidth / 8, .mosi_len = qe_sr_bitwidth / 8,
.miso_len = 0, .miso_len = 0,
}; };
return chip->host->common_command(chip->host, &t); return chip->host->driver->common_command(chip->host, &t);
} }
esp_err_t spi_flash_common_read_status_16b_rdsr_rdsr2(esp_flash_t* chip, uint32_t* out_sr) esp_err_t spi_flash_common_read_status_16b_rdsr_rdsr2(esp_flash_t* chip, uint32_t* out_sr)

View File

@@ -8,6 +8,7 @@
#include "esp_flash.h" #include "esp_flash.h"
#include "driver/spi_common_internal.h" #include "driver/spi_common_internal.h"
#include "esp_flash_spi_init.h" #include "esp_flash_spi_init.h"
#include "memspi_host_driver.h"
#include <esp_attr.h> #include <esp_attr.h>
#include "esp_log.h" #include "esp_log.h"
@@ -18,7 +19,6 @@
#include "soc/io_mux_reg.h" #include "soc/io_mux_reg.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#include "hal/spi_flash_hal.h"
#include "ccomp_timer.h" #include "ccomp_timer.h"
#include "esp_rom_gpio.h" #include "esp_rom_gpio.h"
@@ -175,9 +175,9 @@ static void get_chip_host(esp_flash_t* chip, spi_host_device_t* out_host_id, int
host_id = SPI_HOST; host_id = SPI_HOST;
cs_id = 0; cs_id = 0;
} else { } else {
spi_flash_memspi_data_t* driver_data = (spi_flash_memspi_data_t*)chip->host->driver_data; spi_flash_hal_context_t* host_data = (spi_flash_hal_context_t*)chip->host;
host_id = spi_flash_ll_hw_get_id(driver_data->spi); host_id = spi_flash_ll_hw_get_id(host_data->spi);
cs_id = driver_data->cs_num; cs_id = host_data->cs_num;
} }
if (out_host_id) { if (out_host_id) {
*out_host_id = host_id; *out_host_id = host_id;