Merge branch 'feat/add_xmc_32bit_support' into 'master'

feat(spi_flash): Add XMC chip 32-bits address support

See merge request espressif/esp-idf!39161
This commit is contained in:
C.S.M
2025-05-21 15:10:26 +08:00
6 changed files with 78 additions and 15 deletions

View File

@ -34,6 +34,10 @@ __attribute__((unused)) static const char TAG[] = "spi_flash";
#error "CONFIG_SPI_FLASH_PLACE_FUNCTIONS_IN_IRAM cannot be disabled when CONFIG_SPI_FLASH_AUTO_SUSPEND is disabled."
#endif
#if CONFIG_SPI_FLASH_ROM_IMPL && (CONFIG_ESPTOOLPY_FLASHSIZE_32MB || CONFIG_ESPTOOLPY_FLASHSIZE_64MB || CONFIG_ESPTOOLPY_FLASHSIZE_128MB)
#error "Flash chip size equal or over 32MB memory cannot use driver in ROM"
#endif
/* This pointer is defined in ROM and extern-ed on targets where CONFIG_SPI_FLASH_ROM_IMPL = y*/
#if !CONFIG_SPI_FLASH_ROM_IMPL
esp_flash_t *esp_flash_default_chip = NULL;

View File

@ -15,6 +15,9 @@
#include "esp_private/spi_flash_os.h"
#include "esp_rom_caps.h"
#define IS_REGION_32BIT(start, len) ((start) + (len) > (1<<24))
#define IS_ADDR_32BIT(addr) (addr >= (1<<24))
typedef struct flash_chip_dummy {
uint8_t dio_dummy_bitlen;
uint8_t qio_dummy_bitlen;
@ -112,6 +115,41 @@ esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size)
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
static esp_err_t spi_flash_command_generic_program_4B(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length)
{
spi_flash_trans_t t = {
.command = CMD_PROGRAM_PAGE_4B,
.address_bitlen = 32,
.address = address,
.mosi_len = length,
.mosi_data = buffer,
.flags = SPI_FLASH_TRANS_FLAG_PE_CMD,
};
return chip->host->driver->common_command(chip->host, &t);
}
static esp_err_t spi_flash_command_generic_erase_sector_4B(esp_flash_t *chip, uint32_t start_address)
{
spi_flash_trans_t t = {
.command = CMD_SECTOR_ERASE_4B,
.address_bitlen = 32,
.address = start_address,
.flags = SPI_FLASH_TRANS_FLAG_PE_CMD,
};
return chip->host->driver->common_command(chip->host, &t);
}
static esp_err_t spi_flash_command_generic_erase_block_4B(esp_flash_t *chip, uint32_t start_address)
{
spi_flash_trans_t t = {
.command = CMD_LARGE_BLOCK_ERASE_4B,
.address_bitlen = 32,
.address = start_address,
.flags = SPI_FLASH_TRANS_FLAG_PE_CMD,
};
return chip->host->driver->common_command(chip->host, &t);
}
esp_err_t spi_flash_chip_generic_probe(esp_flash_t *chip, uint32_t flash_id)
{
// This is the catch-all probe function, claim the chip always if nothing
@ -173,6 +211,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip)
esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address)
{
bool addr_32b = IS_ADDR_32BIT(start_address);
esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
@ -180,7 +219,11 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_
//The chip didn't accept the previous write command. Ignore this in preparationstage.
if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
SET_FLASH_ERASE_STATUS(chip, SPI_FLASH_OS_IS_ERASING_STATUS_FLAG);
chip->host->driver->erase_sector(chip->host, start_address);
if (addr_32b) {
spi_flash_command_generic_erase_sector_4B(chip, start_address);
} else {
chip->host->driver->erase_sector(chip->host, start_address);
}
chip->busy = 1;
#ifdef CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED
err = chip->chip_drv->wait_idle(chip, ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT);
@ -199,6 +242,7 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_
esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_address)
{
bool addr_32b = IS_ADDR_32BIT(start_address);
esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
@ -206,7 +250,11 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a
//The chip didn't accept the previous write command. Ignore this in preparationstage.
if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
SET_FLASH_ERASE_STATUS(chip, SPI_FLASH_OS_IS_ERASING_STATUS_FLAG);
chip->host->driver->erase_block(chip->host, start_address);
if (addr_32b) {
spi_flash_command_generic_erase_block_4B(chip, start_address);
} else {
chip->host->driver->erase_block(chip->host, start_address);
}
chip->busy = 1;
#ifdef CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED
err = chip->chip_drv->wait_idle(chip, ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT);
@ -232,6 +280,9 @@ esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t
uint32_t config_io_flags = 0;
// Configure the host, and return
if (IS_REGION_32BIT(address, length)) {
config_io_flags |= SPI_FLASH_CONFIG_IO_MODE_32B_ADDR;
}
err = chip->chip_drv->config_host_io_mode(chip, config_io_flags);
if (err == ESP_ERR_NOT_SUPPORTED) {
@ -259,12 +310,16 @@ esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t
esp_err_t spi_flash_chip_generic_page_program(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length)
{
esp_err_t err;
bool addr_32b = IS_ADDR_32BIT(address);
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
//The chip didn't accept the previous write command. Ignore this in preparationstage.
//The chip didn't accept the previous write command. Ignore this in preparation stage.
if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
// Perform the actual Page Program command
chip->host->driver->program_page(chip->host, buffer, address, length);
if (addr_32b) {
spi_flash_command_generic_program_4B(chip, buffer, address, length);
} else {
chip->host->driver->program_page(chip->host, buffer, address, length);
}
chip->busy = 1;
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->page_program_timeout);
@ -433,48 +488,48 @@ esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, uint32_t
uint32_t read_command;
bool conf_required = false;
esp_flash_io_mode_t read_mode = chip->read_mode;
bool addr_32bit = (flags & SPI_FLASH_CONFIG_IO_MODE_32B_ADDR);
bool is_addr_32bit = (flags & SPI_FLASH_CONFIG_IO_MODE_32B_ADDR);
switch (read_mode & 0xFFFF) {
case SPI_FLASH_QIO:
//for QIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that.
addr_bitlen = SPI_FLASH_QIO_ADDR_BITLEN;
dummy_cyclelen_base = (chip->hpm_dummy_ena ? rom_flash_chip_dummy_hpm->qio_dummy_bitlen : rom_flash_chip_dummy->qio_dummy_bitlen);
read_command = (addr_32bit? CMD_FASTRD_QIO_4B: CMD_FASTRD_QIO);
read_command = (is_addr_32bit? CMD_FASTRD_QIO_4B: CMD_FASTRD_QIO);
conf_required = true;
break;
case SPI_FLASH_QOUT:
addr_bitlen = SPI_FLASH_QOUT_ADDR_BITLEN;
dummy_cyclelen_base = (chip->hpm_dummy_ena ? rom_flash_chip_dummy_hpm->qout_dummy_bitlen : rom_flash_chip_dummy->qout_dummy_bitlen);
read_command = (addr_32bit? CMD_FASTRD_QUAD_4B: CMD_FASTRD_QUAD);
read_command = (is_addr_32bit? CMD_FASTRD_QUAD_4B: CMD_FASTRD_QUAD);
break;
case SPI_FLASH_DIO:
//for DIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that.
addr_bitlen = SPI_FLASH_DIO_ADDR_BITLEN;
dummy_cyclelen_base = (chip->hpm_dummy_ena ? rom_flash_chip_dummy_hpm->dio_dummy_bitlen : rom_flash_chip_dummy->dio_dummy_bitlen);
read_command = (addr_32bit? CMD_FASTRD_DIO_4B: CMD_FASTRD_DIO);
read_command = (is_addr_32bit? CMD_FASTRD_DIO_4B: CMD_FASTRD_DIO);
conf_required = true;
break;
case SPI_FLASH_DOUT:
addr_bitlen = SPI_FLASH_DOUT_ADDR_BITLEN;
dummy_cyclelen_base = (chip->hpm_dummy_ena ? rom_flash_chip_dummy_hpm->dout_dummy_bitlen : rom_flash_chip_dummy->dout_dummy_bitlen);
read_command = (addr_32bit? CMD_FASTRD_DUAL_4B: CMD_FASTRD_DUAL);
read_command = (is_addr_32bit? CMD_FASTRD_DUAL_4B: CMD_FASTRD_DUAL);
break;
case SPI_FLASH_FASTRD:
addr_bitlen = SPI_FLASH_FASTRD_ADDR_BITLEN;
dummy_cyclelen_base = (chip->hpm_dummy_ena ? rom_flash_chip_dummy_hpm->fastrd_dummy_bitlen : rom_flash_chip_dummy->fastrd_dummy_bitlen);
read_command = (addr_32bit? CMD_FASTRD_4B: CMD_FASTRD);
read_command = (is_addr_32bit? CMD_FASTRD_4B: CMD_FASTRD);
break;
case SPI_FLASH_SLOWRD:
addr_bitlen = SPI_FLASH_SLOWRD_ADDR_BITLEN;
dummy_cyclelen_base = (chip->hpm_dummy_ena ? rom_flash_chip_dummy_hpm->slowrd_dummy_bitlen : rom_flash_chip_dummy->slowrd_dummy_bitlen);
read_command = (addr_32bit? CMD_READ_4B: CMD_READ);
read_command = (is_addr_32bit? CMD_READ_4B: CMD_READ);
break;
default:
return ESP_ERR_FLASH_NOT_INITIALISED;
}
//For W25Q256 chip, the only difference between 4-Byte address command and 3-Byte version is the command value and the address bit length.
if (addr_32bit) {
if (is_addr_32bit) {
addr_bitlen += 8;
}
@ -619,6 +674,7 @@ spi_flash_caps_t spi_flash_chip_generic_get_caps(esp_flash_t *chip)
// XMC-D support suspend
if (chip->chip_id >> 16 == 0x46) {
caps_flags |= SPI_FLASH_CHIP_CAP_SUSPEND;
caps_flags |= SPI_FLASH_CHIP_CAP_32MB_SUPPORT;
}
// XMC-D support suspend (some D series flash chip begin with 0x20, difference checked by SFDP)
@ -637,6 +693,7 @@ spi_flash_caps_t spi_flash_chip_generic_get_caps(esp_flash_t *chip)
chip->host->driver->common_command(chip->host, &t);
if((data & 0x8) == 0x8) {
caps_flags |= SPI_FLASH_CHIP_CAP_SUSPEND;
caps_flags |= SPI_FLASH_CHIP_CAP_32MB_SUPPORT;
}
}

View File

@ -15,7 +15,7 @@ Feature Supported by ESP-IDF but Not in Chip-ROM
.. list::
- Octal flash chip support. See :ref:`oct-flash-doc` for details.
- 32-bit-address support for GD25Q256. Note that this feature is an optional feature, please do read :ref:`32-bit-flash-doc` for details.
- 32-bit-address support on flash chips. Note that this feature is an optional feature, please do read :ref:`32-bit-flash-doc` for details.
- TH flash chip support.
- Kconfig option :ref:`CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED`.
- :ref:`CONFIG_SPI_FLASH_VERIFY_WRITE`, enabling this option helps you detect bad writing.

View File

@ -155,6 +155,7 @@ List of Flash chips that support this feature:
1. W25Q256
2. GD25Q256
3. XM25QH256D
Restrictions
^^^^^^^^^^^^

View File

@ -15,7 +15,7 @@ ESP-IDF 支持但不包含在芯片 ROM 中的功能
.. list::
- 八线 flash 芯片。详情请参阅 :ref:`oct-flash-doc`
- GD25Q256 32 位地址。请注意,此功能为可选功能,详情请参阅 :ref:`32-bit-flash-doc`
- Flash 的 32 位地址。请注意,此功能为可选功能,详情请参阅 :ref:`32-bit-flash-doc`
- TH flash 芯片。
- Kconfig 选项 :ref:`CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED`
- :ref:`CONFIG_SPI_FLASH_VERIFY_WRITE`,启用此选项可检测错误写入。

View File

@ -155,6 +155,7 @@ QSPI flash 芯片的 32 位地址支持
1. W25Q256
2. GD25Q256
3. XM25QH256D
限制
^^^^