From 6ead06c6d5cfe0323e6e0e14edacbc6b9dfbec30 Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Thu, 15 May 2025 14:50:56 +0800 Subject: [PATCH] feat(spi_flash): Add XMC chip 32-bits address support --- components/spi_flash/esp_flash_spi_init.c | 4 + components/spi_flash/spi_flash_chip_generic.c | 83 ++++++++++++++++--- .../spi_flash/spi_flash_idf_vs_rom.rst | 2 +- .../spi_flash/spi_flash_optional_feature.rst | 1 + .../spi_flash/spi_flash_idf_vs_rom.rst | 2 +- .../spi_flash/spi_flash_optional_feature.rst | 1 + 6 files changed, 78 insertions(+), 15 deletions(-) diff --git a/components/spi_flash/esp_flash_spi_init.c b/components/spi_flash/esp_flash_spi_init.c index e0f30a9d0b..65e6759a3f 100644 --- a/components/spi_flash/esp_flash_spi_init.c +++ b/components/spi_flash/esp_flash_spi_init.c @@ -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; diff --git a/components/spi_flash/spi_flash_chip_generic.c b/components/spi_flash/spi_flash_chip_generic.c index 94efb8215a..019644a8ab 100644 --- a/components/spi_flash/spi_flash_chip_generic.c +++ b/components/spi_flash/spi_flash_chip_generic.c @@ -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; } } diff --git a/docs/en/api-reference/peripherals/spi_flash/spi_flash_idf_vs_rom.rst b/docs/en/api-reference/peripherals/spi_flash/spi_flash_idf_vs_rom.rst index 9a7b58e802..a3c500a49f 100644 --- a/docs/en/api-reference/peripherals/spi_flash/spi_flash_idf_vs_rom.rst +++ b/docs/en/api-reference/peripherals/spi_flash/spi_flash_idf_vs_rom.rst @@ -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. diff --git a/docs/en/api-reference/peripherals/spi_flash/spi_flash_optional_feature.rst b/docs/en/api-reference/peripherals/spi_flash/spi_flash_optional_feature.rst index 8b99de0c0a..15eedf7f29 100644 --- a/docs/en/api-reference/peripherals/spi_flash/spi_flash_optional_feature.rst +++ b/docs/en/api-reference/peripherals/spi_flash/spi_flash_optional_feature.rst @@ -155,6 +155,7 @@ List of Flash chips that support this feature: 1. W25Q256 2. GD25Q256 +3. XM25QH256D Restrictions ^^^^^^^^^^^^ diff --git a/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_idf_vs_rom.rst b/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_idf_vs_rom.rst index cc2ed38203..276f780054 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_idf_vs_rom.rst +++ b/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_idf_vs_rom.rst @@ -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`,启用此选项可检测错误写入。 diff --git a/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_optional_feature.rst b/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_optional_feature.rst index 4123c8ea88..a97693efea 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_optional_feature.rst +++ b/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_optional_feature.rst @@ -155,6 +155,7 @@ QSPI flash 芯片的 32 位地址支持 1. W25Q256 2. GD25Q256 +3. XM25QH256D 限制 ^^^^