Merge branch 'bugfix/flash_user_command_with_pms_v5.4' into 'release/v5.4'

fix(flash): flash erase operation may fail to raise PMS exception (v5.4)

See merge request espressif/esp-idf!47456
This commit is contained in:
morris
2026-04-17 19:07:42 +08:00
2 changed files with 22 additions and 2 deletions
+17
View File
@@ -178,6 +178,23 @@ esp_err_t spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_tr
io_mode = trans->io_mode;
}
#if CONFIG_IDF_TARGET_ESP32S3
// On ESP32S3, PMS is enabled only if user_command = 1, user_addr = 1, and user_mosi = 1
// While for other targets, user_command = 1, user_addr = 1, and user_miso = 0 are the conditions to enable PMS.
// While erase command doesn't have mosi data, so PMS cannot be enabled
// The workaround is to send the low 8 bits of the address in data phase, in such way, user_mosi will be set to 1
if (command != 0x00 && trans->address_bitlen > 0 && trans->mosi_len == 0 && trans->miso_len == 0) {
uint32_t addr = trans->address;
// Split addr into two phases
trans->address_bitlen -= 8;
trans->address = addr >> 8; // the high bits of the addr
trans->mosi_len = 1;
trans->mosi_data = (uint8_t[]) {
(uint8_t)(addr & 0xFF)
}; // the low 8 bits of the addr
}
#endif
host->driver->configure_host_io_mode(host, command, trans->address_bitlen, dummy_bitlen, io_mode);
spi_flash_ll_set_usr_address(dev, trans->address, trans->address_bitlen);
@@ -88,7 +88,7 @@ esp_err_t spi_flash_chip_mxic_opi_set_write_protect(esp_flash_t *chip, bool writ
static void spi_flash_chip_mxic_opi_get_data_length_zoom(esp_flash_io_mode_t io_mode, uint32_t *length_zoom)
{
/* Under STR mode, one byte occupies one single clock. While under DTR mode, one byte occupies half clock.
For exmaple, if an operation needs 3 clock dummy, host send 3 dummy bytes under STR mode, while 6 dummy bytes under DTR mode.
For example, if an operation needs 3 clock dummy, host send 3 dummy bytes under STR mode, while 6 dummy bytes under DTR mode.
Therefore, we need to adjust data zoom to fit the clock here. */
assert((io_mode == SPI_FLASH_OPI_STR) || (io_mode == SPI_FLASH_OPI_DTR));
*length_zoom = (io_mode == SPI_FLASH_OPI_STR) ? 1 : 2;
@@ -208,6 +208,7 @@ esp_err_t spi_flash_chip_mxic_opi_erase_sector(esp_flash_t *chip, uint32_t start
.command = CMD_OPI_FLASH_MXIC(CMD_SECTOR_ERASE_4B),
.address_bitlen = 32,
.address = start_address,
.flags = SPI_FLASH_TRANS_FLAG_PE_CMD,
};
err = chip->host->driver->common_command(chip->host, &t);
chip->busy = 1;
@@ -237,6 +238,7 @@ esp_err_t spi_flash_chip_mxic_opi_erase_block(esp_flash_t *chip, uint32_t start_
.command = CMD_OPI_FLASH_MXIC(CMD_LARGE_BLOCK_ERASE_4B),
.address_bitlen = 32,
.address = start_address,
.flags = SPI_FLASH_TRANS_FLAG_PE_CMD,
};
err = chip->host->driver->common_command(chip->host, &t);
chip->busy = 1;
@@ -268,6 +270,7 @@ esp_err_t spi_flash_chip_mxic_opi_page_program(esp_flash_t *chip, const void *bu
.address = address,
.mosi_len = length,
.mosi_data = buffer,
.flags = SPI_FLASH_TRANS_FLAG_PE_CMD,
};
chip->host->driver->common_command(chip->host, &t);
chip->busy = 1;
@@ -358,7 +361,7 @@ esp_err_t spi_flash_chip_xmic_opi_set_io_mode(esp_flash_t *chip)
}
// This function should only be called after opi mode initialization. So, only configure for OPI-STR/OPI-DTR mode
// not support other mode in this file, return `ESP_ERR_FLASH_NOT_INITIALISED` directely.
// not support other mode in this file, return `ESP_ERR_FLASH_NOT_INITIALISED` directly.
esp_err_t spi_flash_chip_xmic_opi_config_host_io_mode(esp_flash_t *chip, uint32_t flags)
{
uint32_t dummy_cyclelen_base;