From 0860f46220b5bafc5592bc8f0faf67c9c8b0ed77 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Thu, 9 Mar 2017 10:29:00 +0300 Subject: [PATCH] spi_flash: Fixed bug in SPI flash ROM driver to work with embedded flash chip 1) fixed SPI_read_status: added check for flash busy flag in matrix mode 2) fixed SPI_page_program: enable write before writing data to SPI FIFO 3) SPI flash ROM funcs replacement is controlled via menuconfig option --- .../bootloader/src/main/bootloader_start.c | 28 +- components/bootloader/src/main/component.mk | 4 + .../bootloader/src/main/flash_qio_mode.c | 14 +- .../bootloader_support/src/bootloader_flash.c | 18 +- components/esp32/component.mk | 4 + components/esp32/include/rom/spi_flash.h | 299 +++---- components/esp32/ld/esp32.common.ld | 1 + components/esp32/ld/esp32.rom.ld | 45 +- components/esp32/ld/esp32.rom.spiflash.ld | 23 + components/spi_flash/Kconfig | 8 + components/spi_flash/flash_ops.c | 111 ++- components/spi_flash/spi_flash_rom_patch.c | 732 +++++++++++++++++- components/spi_flash/test/test_partitions.c | 4 +- components/spi_flash/test/test_read_write.c | 10 +- docs/security/flash-encryption.rst | 2 +- 15 files changed, 982 insertions(+), 321 deletions(-) create mode 100644 components/esp32/ld/esp32.rom.spiflash.ld diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index 0df7d0294..536077af4 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -248,7 +248,7 @@ void bootloader_main() #endif esp_image_header_t fhdr; bootloader_state_t bs; - SpiFlashOpResult spiRet1,spiRet2; + esp_rom_spiflash_result_t spiRet1,spiRet2; esp_ota_select_entry_t sa,sb; const esp_ota_select_entry_t *ota_select_map; @@ -258,7 +258,7 @@ void bootloader_main() /* disable watch dog here */ REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN ); REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN ); - SPIUnlock(); + esp_rom_spiflash_unlock(); ESP_LOGI(TAG, "Enabling RNG early entropy source..."); bootloader_random_enable(); @@ -298,7 +298,7 @@ void bootloader_main() memcpy(&sb, (uint8_t *)ota_select_map + SPI_SEC_SIZE, sizeof(esp_ota_select_entry_t)); bootloader_munmap(ota_select_map); if(sa.ota_seq == 0xFFFFFFFF && sb.ota_seq == 0xFFFFFFFF) { - // init status flash + // init status flash if (bs.factory.offset != 0) { // if have factory bin,boot factory bin load_part_pos = bs.factory; } else { @@ -308,19 +308,19 @@ void bootloader_main() sb.ota_seq = 0x00; sb.crc = ota_select_crc(&sb); - Cache_Read_Disable(0); - spiRet1 = SPIEraseSector(bs.ota_info.offset/0x1000); - spiRet2 = SPIEraseSector(bs.ota_info.offset/0x1000+1); - if (spiRet1 != SPI_FLASH_RESULT_OK || spiRet2 != SPI_FLASH_RESULT_OK ) { + Cache_Read_Disable(0); + spiRet1 = esp_rom_spiflash_erase_sector(bs.ota_info.offset/0x1000); + spiRet2 = esp_rom_spiflash_erase_sector(bs.ota_info.offset/0x1000+1); + if (spiRet1 != ESP_ROM_SPIFLASH_RESULT_OK || spiRet2 != ESP_ROM_SPIFLASH_RESULT_OK ) { ESP_LOGE(TAG, SPI_ERROR_LOG); return; - } - spiRet1 = SPIWrite(bs.ota_info.offset,(uint32_t *)&sa,sizeof(esp_ota_select_entry_t)); - spiRet2 = SPIWrite(bs.ota_info.offset + 0x1000,(uint32_t *)&sb,sizeof(esp_ota_select_entry_t)); - if (spiRet1 != SPI_FLASH_RESULT_OK || spiRet2 != SPI_FLASH_RESULT_OK ) { + } + spiRet1 = esp_rom_spiflash_write(bs.ota_info.offset,(uint32_t *)&sa,sizeof(esp_ota_select_entry_t)); + spiRet2 = esp_rom_spiflash_write(bs.ota_info.offset + 0x1000,(uint32_t *)&sb,sizeof(esp_ota_select_entry_t)); + if (spiRet1 != ESP_ROM_SPIFLASH_RESULT_OK || spiRet2 != ESP_ROM_SPIFLASH_RESULT_OK ) { ESP_LOGE(TAG, SPI_ERROR_LOG); return; - } + } Cache_Read_Enable(0); } //TODO:write data in ota info @@ -545,7 +545,7 @@ static void set_cache_and_start_app( uint32_t drom_size, uint32_t irom_addr, uint32_t irom_load_addr, - uint32_t irom_size, + uint32_t irom_size, uint32_t entry_addr) { ESP_LOGD(TAG, "configure drom and irom and start"); @@ -602,7 +602,7 @@ static void update_flash_config(const esp_image_header_t* pfhdr) } Cache_Read_Disable( 0 ); // Set flash chip size - SPIParamCfg(g_rom_flashchip.deviceId, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); + esp_rom_spiflash_config_param(g_rom_flashchip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); // TODO: set mode // TODO: set frequency Cache_Flush(0); diff --git a/components/bootloader/src/main/component.mk b/components/bootloader/src/main/component.mk index b3d3c084f..d324e1de2 100644 --- a/components/bootloader/src/main/component.mk +++ b/components/bootloader/src/main/component.mk @@ -11,6 +11,10 @@ LINKER_SCRIPTS := \ $(IDF_PATH)/components/esp32/ld/esp32.peripherals.ld \ esp32.bootloader.rom.ld +ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH +LINKER_SCRIPTS += $(IDF_PATH)/components/esp32/ld/esp32.rom.spiflash.ld +endif + COMPONENT_ADD_LDFLAGS := -L $(COMPONENT_PATH) -lmain $(addprefix -T ,$(LINKER_SCRIPTS)) COMPONENT_ADD_LINKER_DEPS := $(LINKER_SCRIPTS) diff --git a/components/bootloader/src/main/flash_qio_mode.c b/components/bootloader/src/main/flash_qio_mode.c index c1afc1e03..4b2ec3088 100644 --- a/components/bootloader/src/main/flash_qio_mode.c +++ b/components/bootloader/src/main/flash_qio_mode.c @@ -110,7 +110,7 @@ void bootloader_enable_qio_mode(void) int i; ESP_LOGD(TAG, "Probing for QIO mode enable..."); - SPI_Wait_Idle(&g_rom_flashchip); + esp_rom_spiflash_wait_idle(&g_rom_flashchip); /* Set up some of the SPIFLASH user/ctrl variables which don't change while we're probing using execute_flash_command() */ @@ -150,7 +150,7 @@ static void enable_qio_mode(read_status_fn_t read_status_fn, { uint32_t status; - SPI_Wait_Idle(&g_rom_flashchip); + esp_rom_spiflash_wait_idle(&g_rom_flashchip); status = read_status_fn(); ESP_LOGD(TAG, "Initial flash chip status 0x%x", status); @@ -159,7 +159,7 @@ static void enable_qio_mode(read_status_fn_t read_status_fn, execute_flash_command(CMD_WREN, 0, 0, 0); write_status_fn(status | (1< 1 : skip (n - 1) commands. */ -uint16_t SPI_Common_Command(SpiCommonCmd *cmd); +uint16_t esp_rom_spiflash_common_cmd(esp_rom_spiflash_common_cmd_t *cmd); /** * @brief Unlock SPI write protect. @@ -331,11 +331,11 @@ uint16_t SPI_Common_Command(SpiCommonCmd *cmd); * * @param None. * - * @return SPI_FLASH_RESULT_OK : Unlock OK. - * SPI_FLASH_RESULT_ERR : Unlock error. - * SPI_FLASH_RESULT_TIMEOUT : Unlock timeout. + * @return ESP_ROM_SPIFLASH_RESULT_OK : Unlock OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Unlock error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Unlock timeout. */ -SpiFlashOpResult SPIUnlock(void); +esp_rom_spiflash_result_t esp_rom_spiflash_unlock(void); /** * @brief SPI write protect. @@ -343,11 +343,11 @@ SpiFlashOpResult SPIUnlock(void); * * @param None. * - * @return SPI_FLASH_RESULT_OK : Lock OK. - * SPI_FLASH_RESULT_ERR : Lock error. - * SPI_FLASH_RESULT_TIMEOUT : Lock timeout. + * @return ESP_ROM_SPIFLASH_RESULT_OK : Lock OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Lock error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Lock timeout. */ -SpiFlashOpResult SPILock(void); +esp_rom_spiflash_result_t esp_rom_spiflash_lock(void); /** * @brief Update SPI Flash parameter. @@ -365,11 +365,12 @@ SpiFlashOpResult SPILock(void); * * @param uint32_t status_mask : The Mask used when read status from Flash(use single CMD). * - * @return SPI_FLASH_RESULT_OK : Update OK. - * SPI_FLASH_RESULT_ERR : Update error. - * SPI_FLASH_RESULT_TIMEOUT : Update timeout. + * @return ESP_ROM_SPIFLASH_RESULT_OK : Update OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Update error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Update timeout. */ -SpiFlashOpResult SPIParamCfg(uint32_t deviceId, uint32_t chip_size, uint32_t block_size, uint32_t sector_size, uint32_t page_size, uint32_t status_mask); +esp_rom_spiflash_result_t esp_rom_spiflash_config_param(uint32_t deviceId, uint32_t chip_size, uint32_t block_size, + uint32_t sector_size, uint32_t page_size, uint32_t status_mask); /** * @brief Erase whole flash chip. @@ -377,11 +378,11 @@ SpiFlashOpResult SPIParamCfg(uint32_t deviceId, uint32_t chip_size, uint32_t blo * * @param None * - * @return SPI_FLASH_RESULT_OK : Erase OK. - * SPI_FLASH_RESULT_ERR : Erase error. - * SPI_FLASH_RESULT_TIMEOUT : Erase timeout. + * @return ESP_ROM_SPIFLASH_RESULT_OK : Erase OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Erase error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Erase timeout. */ -SpiFlashOpResult SPIEraseChip(void); +esp_rom_spiflash_result_t esp_rom_spiflash_erase_chip(void); /** * @brief Erase a 64KB block of flash @@ -390,11 +391,11 @@ SpiFlashOpResult SPIEraseChip(void); * * @param uint32_t block_num : Which block to erase. * - * @return SPI_FLASH_RESULT_OK : Erase OK. - * SPI_FLASH_RESULT_ERR : Erase error. - * SPI_FLASH_RESULT_TIMEOUT : Erase timeout. + * @return ESP_ROM_SPIFLASH_RESULT_OK : Erase OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Erase error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Erase timeout. */ -SpiFlashOpResult SPIEraseBlock(uint32_t block_num); +esp_rom_spiflash_result_t esp_rom_spiflash_erase_block(uint32_t block_num); /** * @brief Erase a sector of flash. @@ -403,11 +404,11 @@ SpiFlashOpResult SPIEraseBlock(uint32_t block_num); * * @param uint32_t sector_num : Which sector to erase. * - * @return SPI_FLASH_RESULT_OK : Erase OK. - * SPI_FLASH_RESULT_ERR : Erase error. - * SPI_FLASH_RESULT_TIMEOUT : Erase timeout. + * @return ESP_ROM_SPIFLASH_RESULT_OK : Erase OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Erase error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Erase timeout. */ -SpiFlashOpResult SPIEraseSector(uint32_t sector_num); +esp_rom_spiflash_result_t esp_rom_spiflash_erase_sector(uint32_t sector_num); /** * @brief Erase some sectors. @@ -417,11 +418,11 @@ SpiFlashOpResult SPIEraseSector(uint32_t sector_num); * * @param uint32_t area_len : Length to erase, should be sector aligned. * - * @return SPI_FLASH_RESULT_OK : Erase OK. - * SPI_FLASH_RESULT_ERR : Erase error. - * SPI_FLASH_RESULT_TIMEOUT : Erase timeout. + * @return ESP_ROM_SPIFLASH_RESULT_OK : Erase OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Erase error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Erase timeout. */ -SpiFlashOpResult SPIEraseArea(uint32_t start_addr, uint32_t area_len); +esp_rom_spiflash_result_t esp_rom_spiflash_erase_area(uint32_t start_addr, uint32_t area_len); /** * @brief Write Data to Flash, you should Erase it yourself if need. @@ -433,11 +434,11 @@ SpiFlashOpResult SPIEraseArea(uint32_t start_addr, uint32_t area_len); * * @param uint32_t len : Length to write, should be 4 bytes aligned. * - * @return SPI_FLASH_RESULT_OK : Write OK. - * SPI_FLASH_RESULT_ERR : Write error. - * SPI_FLASH_RESULT_TIMEOUT : Write timeout. + * @return ESP_ROM_SPIFLASH_RESULT_OK : Write OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Write error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Write timeout. */ -SpiFlashOpResult SPIWrite(uint32_t dest_addr, const uint32_t *src, int32_t len); +esp_rom_spiflash_result_t esp_rom_spiflash_write(uint32_t dest_addr, const uint32_t *src, int32_t len); /** * @brief Read Data from Flash, you should Erase it yourself if need. @@ -449,11 +450,11 @@ SpiFlashOpResult SPIWrite(uint32_t dest_addr, const uint32_t *src, int32_t len); * * @param uint32_t len : Length to read, should be 4 bytes aligned. * - * @return SPI_FLASH_RESULT_OK : Read OK. - * SPI_FLASH_RESULT_ERR : Read error. - * SPI_FLASH_RESULT_TIMEOUT : Read timeout. + * @return ESP_ROM_SPIFLASH_RESULT_OK : Read OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Read error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Read timeout. */ -SpiFlashOpResult SPIRead(uint32_t src_addr, uint32_t *dest, int32_t len); +esp_rom_spiflash_result_t esp_rom_spiflash_read(uint32_t src_addr, uint32_t *dest, int32_t len); /** * @brief SPI1 go into encrypto mode. @@ -463,7 +464,7 @@ SpiFlashOpResult SPIRead(uint32_t src_addr, uint32_t *dest, int32_t len); * * @return None */ -void SPI_Write_Encrypt_Enable(void); +void esp_rom_spiflash_write_encrypted_enable(void); /** * @brief Prepare 32 Bytes data to encrpto writing, you should Erase it yourself if need. @@ -473,11 +474,11 @@ void SPI_Write_Encrypt_Enable(void); * * @param uint32_t *data : The pointer to data which is to write. * - * @return SPI_FLASH_RESULT_OK : Prepare OK. - * SPI_FLASH_RESULT_ERR : Prepare error. - * SPI_FLASH_RESULT_TIMEOUT : Prepare timeout. + * @return ESP_ROM_SPIFLASH_RESULT_OK : Prepare OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Prepare error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Prepare timeout. */ -SpiFlashOpResult SPI_Prepare_Encrypt_Data(uint32_t flash_addr, uint32_t *data); +esp_rom_spiflash_result_t esp_rom_spiflash_prepare_encrypted_data(uint32_t flash_addr, uint32_t *data); /** * @brief SPI1 go out of encrypto mode. @@ -487,7 +488,7 @@ SpiFlashOpResult SPI_Prepare_Encrypt_Data(uint32_t flash_addr, uint32_t *data); * * @return None */ -void SPI_Write_Encrypt_Disable(void); +void esp_rom_spiflash_write_encrypted_disable(void); /** * @brief Write data to flash with transparent encryption. @@ -503,11 +504,11 @@ void SPI_Write_Encrypt_Disable(void); * * @param uint32_t len : Length to write, should be 32 bytes aligned. * - * @return SPI_FLASH_RESULT_OK : Data written successfully. - * SPI_FLASH_RESULT_ERR : Encryption write error. - * SPI_FLASH_RESULT_TIMEOUT : Encrypto write timeout. + * @return ESP_ROM_SPIFLASH_RESULT_OK : Data written successfully. + * ESP_ROM_SPIFLASH_RESULT_ERR : Encryption write error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Encrypto write timeout. */ -SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, uint32_t *data, uint32_t len); +esp_rom_spiflash_result_t esp_rom_spiflash_write_encrypted(uint32_t flash_addr, uint32_t *data, uint32_t len); /** @brief Wait until SPI flash write operation is complete @@ -517,16 +518,16 @@ SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, uint32_t *data, uint32_t * Reads the Write In Progress bit of the SPI flash status register, * repeats until this bit is zero (indicating write complete). * - * @return SPI_FLASH_RESULT_OK : Write is complete - * SPI_FLASH_RESULT_ERR : Error while reading status. + * @return ESP_ROM_SPIFLASH_RESULT_OK : Write is complete + * ESP_ROM_SPIFLASH_RESULT_ERR : Error while reading status. */ -SpiFlashOpResult SPI_Wait_Idle(SpiFlashChip *spi); +esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *spi); -/** @brief Global SpiFlashChip structure used by ROM functions +/** @brief Global esp_rom_spiflash_chip_t structure used by ROM functions * */ -extern SpiFlashChip g_rom_flashchip; +extern esp_rom_spiflash_chip_t g_rom_flashchip; /** * @} diff --git a/components/esp32/ld/esp32.common.ld b/components/esp32/ld/esp32.common.ld index 8d5a9c427..75ac7e328 100644 --- a/components/esp32/ld/esp32.common.ld +++ b/components/esp32/ld/esp32.common.ld @@ -97,6 +97,7 @@ SECTIONS *libnet80211.a:ieee80211_misc.o(.literal .text .literal.* .text.*) *libhal.a:(.literal .text .literal.* .text.*) *libcoexist.a:(.literal .text .literal.* .text.*) + *libspi_flash.a:spi_flash_rom_patch.o(.literal .text .literal.* .text.*) _iram_text_end = ABSOLUTE(.); } > iram0_0_seg diff --git a/components/esp32/ld/esp32.rom.ld b/components/esp32/ld/esp32.rom.ld index 6cbd2fc74..6529e31df 100644 --- a/components/esp32/ld/esp32.rom.ld +++ b/components/esp32/ld/esp32.rom.ld @@ -125,7 +125,7 @@ PROVIDE ( __divdi3 = 0x4000ca84 ); PROVIDE ( __divsc3 = 0x40064200 ); PROVIDE ( __divsf3 = 0x4000234c ); PROVIDE ( __divsi3 = 0x4000c7b8 ); -PROVIDE ( dummy_len_plus = 0x3ffae290 ); +PROVIDE ( g_rom_spiflash_dummy_len_plus = 0x3ffae290 ); PROVIDE ( __dummy_lock = 0x4000c728 ); PROVIDE ( __dummy_lock_try = 0x4000c730 ); PROVIDE ( ecc_env = 0x3ffb8d60 ); @@ -1349,13 +1349,10 @@ PROVIDE ( sbrk = 0x400017f4 ); PROVIDE ( _sbrk_r = 0x4000bce4 ); PROVIDE ( __sccl = 0x4000c498 ); PROVIDE ( __sclose = 0x400011b8 ); -PROVIDE ( SelectSpiFunction = 0x40061f84 ); -PROVIDE ( SelectSpiQIO = 0x40061ddc ); PROVIDE ( __seofread = 0x40001148 ); PROVIDE ( setjmp = 0x40056268 ); PROVIDE ( setlocale = 0x40059568 ); PROVIDE ( _setlocale_r = 0x4005950c ); -PROVIDE ( SetSpiDrvs = 0x40061e78 ); PROVIDE ( __sf_fake_stderr = 0x3ff96458 ); PROVIDE ( __sf_fake_stdin = 0x3ff96498 ); PROVIDE ( __sf_fake_stdout = 0x3ff96478 ); @@ -1404,40 +1401,6 @@ PROVIDE ( slc_set_host_io_max_window = 0x4000b89c ); PROVIDE ( slc_to_host_chain_recycle = 0x4000b758 ); PROVIDE ( __smakebuf_r = 0x40059108 ); PROVIDE ( specialModP256 = 0x4001600c ); -PROVIDE ( spi_cache_sram_init = 0x400626e4 ); -PROVIDE ( SPIClkConfig = 0x40062bc8 ); -PROVIDE ( SPI_Common_Command = 0x4006246c ); -PROVIDE ( spi_dummy_len_fix = 0x40061d90 ); -PROVIDE ( SPI_Encrypt_Write = 0x40062e78 ); -PROVIDE ( SPIEraseArea = 0x400631ac ); -PROVIDE ( SPIEraseBlock = 0x40062c4c ); -PROVIDE ( SPIEraseChip = 0x40062c14 ); -PROVIDE ( SPIEraseSector = 0x40062ccc ); -PROVIDE ( spi_flash_attach = 0x40062a6c ); -/* NB: SPIUnlock @ 0x400628b0 has been replaced with an updated - version in the "spi_flash" component */ -PROVIDE ( SPILock = 0x400628f0 ); -PROVIDE ( SPIMasterReadModeCnfig = 0x40062b64 ); -PROVIDE ( spi_modes = 0x3ff99270 ); -PROVIDE ( SPIParamCfg = 0x40063238 ); -PROVIDE ( SPI_Prepare_Encrypt_Data = 0x40062e1c ); -PROVIDE ( SPIRead = 0x40062ed8 ); -PROVIDE ( SPIReadModeCnfig = 0x40062944 ); -/* This is static function, but can be used, not generated by script*/ -PROVIDE ( SPI_read_status = 0x4006226c ); -/* This is static function, but can be used, not generated by script*/ -PROVIDE ( SPI_read_status_high = 0x40062448 ); -PROVIDE ( SPI_user_command_read = 0x400621b0 ); -PROVIDE ( SPI_flashchip_data = 0x3ffae270 ); -PROVIDE ( SPIWrite = 0x40062d50 ); -/* This is static function, but can be used, not generated by script*/ -PROVIDE ( SPI_write_enable = 0x40062320 ); -PROVIDE ( SPI_Write_Encrypt_Disable = 0x40062e60 ); -PROVIDE ( SPI_Write_Encrypt_Enable = 0x40062df4 ); -/* This is static function, but can be used, not generated by script*/ -PROVIDE ( SPI_write_status = 0x400622f0 ); -/* This is static function, but can be used, not generated by script */ -PROVIDE ( SPI_Wait_Idle = 0x400622c0 ); PROVIDE ( srand = 0x40001004 ); PROVIDE ( __sread = 0x40001118 ); PROVIDE ( __srefill_r = 0x400593d4 ); @@ -1569,6 +1532,12 @@ PROVIDE ( xthal_set_intclear = 0x4000c1ec ); PROVIDE ( _xtos_set_intlevel = 0x4000bfdc ); PROVIDE ( g_ticks_per_us_pro = 0x3ffe01e0 ); PROVIDE ( g_ticks_per_us_app = 0x3ffe40f0 ); +PROVIDE ( esp_rom_spiflash_config_param = 0x40063238 ); +PROVIDE ( esp_rom_spiflash_read_user_cmd = 0x400621b0 ); +PROVIDE ( esp_rom_spiflash_write_encrypted_disable = 0x40062e60 ); +PROVIDE ( esp_rom_spiflash_write_encrypted_enable = 0x40062df4 ); +PROVIDE ( esp_rom_spiflash_prepare_encrypted_data = 0x40062e1c ); +PROVIDE ( g_rom_spiflash_chip = 0x3ffae270 ); /* These functions are xtos-related (or call xtos-related functions) and do not play well diff --git a/components/esp32/ld/esp32.rom.spiflash.ld b/components/esp32/ld/esp32.rom.spiflash.ld new file mode 100644 index 000000000..64af6a4b9 --- /dev/null +++ b/components/esp32/ld/esp32.rom.spiflash.ld @@ -0,0 +1,23 @@ +/* + Address table for SPI driver functions in ESP32 ROM. + These functions are only linked from ROM when SPI_FLASH_ROM_DRIVER_PATCH is not set in configuration. +*/ + +PROVIDE ( esp_rom_spiflash_write_encrypted = 0x40062e78 ); +PROVIDE ( esp_rom_spiflash_erase_area = 0x400631ac ); +PROVIDE ( esp_rom_spiflash_erase_block = 0x40062c4c ); +PROVIDE ( esp_rom_spiflash_erase_chip = 0x40062c14 ); +PROVIDE ( esp_rom_spiflash_erase_sector = 0x40062ccc ); +PROVIDE ( esp_rom_spiflash_lock = 0x400628f0 ); +PROVIDE ( esp_rom_spiflash_read = 0x40062ed8 ); +PROVIDE ( esp_rom_spiflash_config_readmode = 0x40062944 ); +PROVIDE ( esp_rom_spiflash_read_status = 0x4006226c ); +PROVIDE ( esp_rom_spiflash_read_statushigh = 0x40062448 ); +PROVIDE ( esp_rom_spiflash_write = 0x40062d50 ); +PROVIDE ( esp_rom_spiflash_enable_write = 0x40062320 ); +PROVIDE ( esp_rom_spiflash_write_status = 0x400622f0 ); + +/* always using patched versions of these functions +PROVIDE ( esp_rom_spiflash_wait_idle = 0x400622c0 ); +PROVIDE ( esp_rom_spiflash_unlock = 0x400????? ); +*/ diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index 154dc7c30..1aa2d0a49 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -11,6 +11,14 @@ config SPI_FLASH_ENABLE_COUNTERS These APIs may be used to collect performance data for spi_flash APIs and to help understand behaviour of libraries which use SPI flash. +config SPI_FLASH_ROM_DRIVER_PATCH + bool "Enable SPI flash ROM driver patched functions" + default y + help + Enable this flag to use patched versions of SPI flash ROM driver functions. + This option is needed to write to flash on ESP32-D2WD, and any configuration + where external SPI flash is connected to non-default pins. + endmenu diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index 86101ef04..725c34be0 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -42,7 +42,7 @@ #define MAX_READ_CHUNK 16384 #if CONFIG_SPI_FLASH_ENABLE_COUNTERS -static const char* TAG = "spi_flash"; +static const char *TAG = "spi_flash"; static spi_flash_counters_t s_flash_stats; #define COUNTER_START() uint32_t ts_begin = xthal_get_ccount() @@ -64,20 +64,20 @@ static spi_flash_counters_t s_flash_stats; #endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS -static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc); +static esp_err_t spi_flash_translate_rc(esp_rom_spiflash_result_t rc); const DRAM_ATTR spi_flash_guard_funcs_t g_flash_guard_default_ops = { - .start = spi_flash_disable_interrupts_caches_and_other_cpu, - .end = spi_flash_enable_interrupts_caches_and_other_cpu, - .op_lock = spi_flash_op_lock, - .op_unlock = spi_flash_op_unlock + .start = spi_flash_disable_interrupts_caches_and_other_cpu, + .end = spi_flash_enable_interrupts_caches_and_other_cpu, + .op_lock = spi_flash_op_lock, + .op_unlock = spi_flash_op_unlock }; const DRAM_ATTR spi_flash_guard_funcs_t g_flash_guard_no_os_ops = { - .start = spi_flash_disable_interrupts_caches_and_other_cpu_no_os, - .end = spi_flash_enable_interrupts_caches_no_os, - .op_lock = 0, - .op_unlock = 0 + .start = spi_flash_disable_interrupts_caches_and_other_cpu_no_os, + .end = spi_flash_enable_interrupts_caches_no_os, + .op_lock = 0, + .op_unlock = 0 }; static const spi_flash_guard_funcs_t *s_flash_guard_ops; @@ -90,7 +90,7 @@ void spi_flash_init() #endif } -void IRAM_ATTR spi_flash_guard_set(const spi_flash_guard_funcs_t* funcs) +void IRAM_ATTR spi_flash_guard_set(const spi_flash_guard_funcs_t *funcs) { s_flash_guard_ops = funcs; } @@ -128,19 +128,19 @@ static inline void IRAM_ATTR spi_flash_guard_op_unlock() } } -static SpiFlashOpResult IRAM_ATTR spi_flash_unlock() +static esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock() { static bool unlocked = false; if (!unlocked) { spi_flash_guard_start(); - SpiFlashOpResult rc = SPIUnlock(); + esp_rom_spiflash_result_t rc = esp_rom_spiflash_unlock(); spi_flash_guard_end(); - if (rc != SPI_FLASH_RESULT_OK) { + if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { return rc; } unlocked = true; } - return SPI_FLASH_RESULT_OK; + return ESP_ROM_SPIFLASH_RESULT_OK; } esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec) @@ -163,16 +163,17 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size) size_t end = start + size / SPI_FLASH_SEC_SIZE; const size_t sectors_per_block = BLOCK_ERASE_SIZE / SPI_FLASH_SEC_SIZE; COUNTER_START(); - SpiFlashOpResult rc = spi_flash_unlock(); - if (rc == SPI_FLASH_RESULT_OK) { - for (size_t sector = start; sector != end && rc == SPI_FLASH_RESULT_OK; ) { + esp_rom_spiflash_result_t rc; + rc = spi_flash_unlock(); + if (rc == ESP_ROM_SPIFLASH_RESULT_OK) { + for (size_t sector = start; sector != end && rc == ESP_ROM_SPIFLASH_RESULT_OK; ) { spi_flash_guard_start(); if (sector % sectors_per_block == 0 && end - sector > sectors_per_block) { - rc = SPIEraseBlock(sector / sectors_per_block); + rc = esp_rom_spiflash_erase_block(sector / sectors_per_block); sector += sectors_per_block; COUNTER_ADD_BYTES(erase, sectors_per_block * SPI_FLASH_SEC_SIZE); } else { - rc = SPIEraseSector(sector); + rc = esp_rom_spiflash_erase_sector(sector); ++sector; COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE); } @@ -194,7 +195,7 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size) return ESP_OK; } - SpiFlashOpResult rc = SPI_FLASH_RESULT_OK; + esp_rom_spiflash_result_t rc = ESP_ROM_SPIFLASH_RESULT_OK; COUNTER_START(); const char *srcc = (const char *) srcv; /* @@ -210,16 +211,16 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size) size_t right_off = left_size + mid_size; size_t right_size = size - mid_size - left_size; rc = spi_flash_unlock(); - if (rc != SPI_FLASH_RESULT_OK) { + if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { goto out; } if (left_size > 0) { uint32_t t = 0xffffffff; memcpy(((uint8_t *) &t) + (dst - left_off), srcc, left_size); spi_flash_guard_start(); - rc = SPIWrite(left_off, &t, 4); + rc = esp_rom_spiflash_write(left_off, &t, 4); spi_flash_guard_end(); - if (rc != SPI_FLASH_RESULT_OK) { + if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { goto out; } COUNTER_ADD_BYTES(write, 4); @@ -234,7 +235,7 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size) #else bool direct_write = true; #endif - while(mid_size > 0 && rc == SPI_FLASH_RESULT_OK) { + while(mid_size > 0 && rc == ESP_ROM_SPIFLASH_RESULT_OK) { uint32_t write_buf[8]; uint32_t write_size; const uint32_t *write_src = (const uint32_t *) (srcc + mid_off); @@ -246,13 +247,13 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size) write_src = write_buf; } spi_flash_guard_start(); - rc = SPIWrite(dst + mid_off, write_src, write_size); + rc = esp_rom_spiflash_write(dst + mid_off, (const uint32_t *) (srcc + mid_off), mid_size); spi_flash_guard_end(); COUNTER_ADD_BYTES(write, write_size); mid_size -= write_size; mid_off += write_size; } - if (rc != SPI_FLASH_RESULT_OK) { + if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { goto out; } } @@ -261,9 +262,9 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size) uint32_t t = 0xffffffff; memcpy(&t, srcc + right_off, right_size); spi_flash_guard_start(); - rc = SPIWrite(dst + right_off, &t, 4); + rc = esp_rom_spiflash_write(dst + right_off, &t, 4); spi_flash_guard_end(); - if (rc != SPI_FLASH_RESULT_OK) { + if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { goto out; } COUNTER_ADD_BYTES(write, 4); @@ -289,13 +290,13 @@ esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, } COUNTER_START(); - SpiFlashOpResult rc = spi_flash_unlock(); - - if (rc == SPI_FLASH_RESULT_OK) { - /* SPI_Encrypt_Write encrypts data in RAM as it writes, + esp_rom_spiflash_result_t rc; + rc = spi_flash_unlock(); + if (rc == ESP_ROM_SPIFLASH_RESULT_OK) { + /* esp_rom_spiflash_write_encrypted encrypts data in RAM as it writes, so copy to a temporary buffer - 32 bytes at a time. - Each call to SPI_Encrypt_Write takes a 32 byte "row" of + Each call to esp_rom_spiflash_write_encrypted takes a 32 byte "row" of data to encrypt, and each row is two 16 byte AES blocks that share a key (as derived from flash address). */ @@ -311,25 +312,23 @@ esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, memcpy(encrypt_buf + 16, ssrc + i, 16); /* decrypt the first block from flash, will reencrypt to same bytes */ spi_flash_read_encrypted(row_addr, encrypt_buf, 16); - } - else if (size - i == 16) { + } else if (size - i == 16) { /* 16 bytes left, is first block of a 32 byte row */ row_size = 16; /* copy to first block in buffer */ memcpy(encrypt_buf, ssrc + i, 16); /* decrypt the second block from flash, will reencrypt to same bytes */ spi_flash_read_encrypted(row_addr + 16, encrypt_buf + 16, 16); - } - else { + } else { /* Writing a full 32 byte row (2 blocks) */ row_size = 32; memcpy(encrypt_buf, ssrc + i, 32); } spi_flash_guard_start(); - rc = SPI_Encrypt_Write(row_addr, (uint32_t *)encrypt_buf, 32); + rc = esp_rom_spiflash_write_encrypted(row_addr, (uint32_t *)encrypt_buf, 32); spi_flash_guard_end(); - if (rc != SPI_FLASH_RESULT_OK) { + if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { break; } } @@ -356,7 +355,7 @@ esp_err_t IRAM_ATTR spi_flash_read(size_t src, void *dstv, size_t size) return ESP_OK; } - SpiFlashOpResult rc = SPI_FLASH_RESULT_OK; + esp_rom_spiflash_result_t rc = ESP_ROM_SPIFLASH_RESULT_OK; COUNTER_START(); spi_flash_guard_start(); /* To simplify boundary checks below, we handle small reads separately. */ @@ -365,8 +364,8 @@ esp_err_t IRAM_ATTR spi_flash_read(size_t src, void *dstv, size_t size) uint32_t read_src = src & ~3U; uint32_t left_off = src & 3U; uint32_t read_size = (left_off + size + 3) & ~3U; - rc = SPIRead(read_src, t, read_size); - if (rc != SPI_FLASH_RESULT_OK) { + rc = esp_rom_spiflash_read(read_src, t, read_size); + if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { goto out; } COUNTER_ADD_BYTES(read, read_size); @@ -402,8 +401,8 @@ esp_err_t IRAM_ATTR spi_flash_read(size_t src, void *dstv, size_t size) uint32_t mid_read = 0; while (mid_remaining > 0) { uint32_t read_size = MIN(mid_remaining, MAX_READ_CHUNK); - rc = SPIRead(src + src_mid_off + mid_read, (uint32_t *) (dstc + dst_mid_off + mid_read), read_size); - if (rc != SPI_FLASH_RESULT_OK) { + rc = esp_rom_spiflash_read(src + src_mid_off + mid_read, (uint32_t *) (dstc + dst_mid_off + mid_read), read_size); + if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { goto out; } mid_remaining -= read_size; @@ -426,8 +425,8 @@ esp_err_t IRAM_ATTR spi_flash_read(size_t src, void *dstv, size_t size) } if (pad_left_size > 0) { uint32_t t; - rc = SPIRead(pad_left_src, &t, 4); - if (rc != SPI_FLASH_RESULT_OK) { + rc = esp_rom_spiflash_read(pad_left_src, &t, 4); + if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { goto out; } COUNTER_ADD_BYTES(read, 4); @@ -436,8 +435,8 @@ esp_err_t IRAM_ATTR spi_flash_read(size_t src, void *dstv, size_t size) if (pad_right_size > 0) { uint32_t t[2]; int32_t read_size = (pad_right_size <= 4 ? 4 : 8); - rc = SPIRead(pad_right_src, t, read_size); - if (rc != SPI_FLASH_RESULT_OK) { + rc = esp_rom_spiflash_read(pad_right_src, t, read_size); + if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { goto out; } COUNTER_ADD_BYTES(read, read_size); @@ -461,7 +460,7 @@ esp_err_t IRAM_ATTR spi_flash_read_encrypted(size_t src, void *dstv, size_t size esp_err_t err; const uint8_t *map; spi_flash_mmap_handle_t map_handle; - size_t map_src = src & ~(SPI_FLASH_MMU_PAGE_SIZE-1); + size_t map_src = src & ~(SPI_FLASH_MMU_PAGE_SIZE - 1); size_t map_size = size + (src - map_src); err = spi_flash_mmap(map_src, map_size, SPI_FLASH_MMAP_DATA, (const void **)&map, &map_handle); @@ -474,14 +473,14 @@ esp_err_t IRAM_ATTR spi_flash_read_encrypted(size_t src, void *dstv, size_t size } -static esp_err_t IRAM_ATTR spi_flash_translate_rc(SpiFlashOpResult rc) +static esp_err_t IRAM_ATTR spi_flash_translate_rc(esp_rom_spiflash_result_t rc) { switch (rc) { - case SPI_FLASH_RESULT_OK: + case ESP_ROM_SPIFLASH_RESULT_OK: return ESP_OK; - case SPI_FLASH_RESULT_TIMEOUT: + case ESP_ROM_SPIFLASH_RESULT_TIMEOUT: return ESP_ERR_FLASH_OP_TIMEOUT; - case SPI_FLASH_RESULT_ERR: + case ESP_ROM_SPIFLASH_RESULT_ERR: default: return ESP_ERR_FLASH_OP_FAIL; } @@ -489,13 +488,13 @@ static esp_err_t IRAM_ATTR spi_flash_translate_rc(SpiFlashOpResult rc) #if CONFIG_SPI_FLASH_ENABLE_COUNTERS -static inline void dump_counter(spi_flash_counter_t* counter, const char* name) +static inline void dump_counter(spi_flash_counter_t *counter, const char *name) { ESP_LOGI(TAG, "%s count=%8d time=%8dus bytes=%8d\n", name, counter->count, counter->time, counter->bytes); } -const spi_flash_counters_t* spi_flash_get_counters() +const spi_flash_counters_t *spi_flash_get_counters() { return &s_flash_stats; } diff --git a/components/spi_flash/spi_flash_rom_patch.c b/components/spi_flash/spi_flash_rom_patch.c index 36e5bf823..0664c7482 100644 --- a/components/spi_flash/spi_flash_rom_patch.c +++ b/components/spi_flash/spi_flash_rom_patch.c @@ -11,34 +11,37 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + +#include "rom/ets_sys.h" +#include "rom/gpio.h" #include "rom/spi_flash.h" -#include "soc/spi_reg.h" +#include "sdkconfig.h" -static const uint32_t STATUS_QIE_BIT = (1 << 9); /* Quad Enable */ +#define SPI_IDX 1 +#define OTH_IDX 0 -#define SPI_IDX 1 -#define OTH_IDX 0 +extern esp_rom_spiflash_chip_t g_rom_spiflash_chip; -#ifndef BOOTLOADER_BUILD -#define ATTR IRAM_ATTR -#else -#define ATTR -#endif // BOOTLOADER_BUILD - -extern SpiFlashChip SPI_flashchip_data; - -static void ATTR Wait_SPI_Idle(void) +esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *spi) { - /* Wait for SPI state machine to be idle */ - while((REG_READ(SPI_EXT2_REG(SPI_IDX)) & SPI_ST)) { - } - while(REG_READ(SPI_EXT2_REG(OTH_IDX)) & SPI_ST) { - } + uint32_t status; + + //wait for spi control ready + while ((REG_READ(SPI_EXT2_REG(1)) & SPI_ST)) { + } + while ((REG_READ(SPI_EXT2_REG(0)) & SPI_ST)) { + } + //wait for flash status ready + if ( ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_read_status(spi, &status)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + return ESP_ROM_SPIFLASH_RESULT_OK; } -/* Modified version of SPIUnlock() that replaces version in ROM. - This works around a bug where SPIUnlock sometimes reads the wrong +/* Modified version of esp_rom_spiflash_unlock() that replaces version in ROM. + + This works around a bug where esp_rom_spiflash_unlock sometimes reads the wrong high status byte (RDSR2 result) and then copies it back to the flash status, which can cause the CMP bit or Status Register Protect bit to become set. @@ -48,31 +51,680 @@ static void ATTR Wait_SPI_Idle(void) about interrupts, CPU coordination, flash mapping. However some of the functions in esp_spi_flash.c call it. */ -SpiFlashOpResult ATTR SPIUnlock(void) +esp_rom_spiflash_result_t esp_rom_spiflash_unlock() { - uint32_t status; + uint32_t status; - Wait_SPI_Idle(); + esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip); - if (SPI_read_status_high(&status) != SPI_FLASH_RESULT_OK) { - return SPI_FLASH_RESULT_ERR; - } + if (esp_rom_spiflash_read_statushigh(&g_rom_spiflash_chip, &status) != ESP_ROM_SPIFLASH_RESULT_OK) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } - /* Clear all bits except QIE, if it is set. - (This is different from ROM SPIUnlock, which keeps all bits as-is.) - */ - status &= STATUS_QIE_BIT; + /* Clear all bits except QIE, if it is set. + (This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.) + */ + status &= ESP_ROM_SPIFLASH_QE; - Wait_SPI_Idle(); - REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_WREN); - while(REG_READ(SPI_CMD_REG(SPI_IDX)) != 0) { - } - Wait_SPI_Idle(); + esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip); + REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_WREN); + while (REG_READ(SPI_CMD_REG(SPI_IDX)) != 0) { + } + esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip); - SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B); - if (SPI_write_status(&SPI_flashchip_data, status) != SPI_FLASH_RESULT_OK) { - return SPI_FLASH_RESULT_ERR; - } + SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B); + if (esp_rom_spiflash_write_status(&g_rom_spiflash_chip, status) != ESP_ROM_SPIFLASH_RESULT_OK) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } - return SPI_FLASH_RESULT_OK; + return ESP_ROM_SPIFLASH_RESULT_OK; } + + +#if CONFIG_SPI_FLASH_ROM_DRIVER_PATCH + +extern uint8_t g_rom_spiflash_dummy_len_plus[]; + + +static esp_rom_spiflash_result_t esp_rom_spiflash_enable_write(esp_rom_spiflash_chip_t *spi); +static esp_rom_spiflash_result_t esp_rom_spiflash_enable_qmode(esp_rom_spiflash_chip_t *spi); +static esp_rom_spiflash_result_t esp_rom_spiflash_disable_qmode(esp_rom_spiflash_chip_t *spi); + + +//only support spi1 +static esp_rom_spiflash_result_t esp_rom_spiflash_erase_chip_internal(esp_rom_spiflash_chip_t *spi) +{ + esp_rom_spiflash_wait_idle(spi); + + // Chip erase. + WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_FLASH_CE); + while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0); + + // check erase is finished. + esp_rom_spiflash_wait_idle(spi); + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +//only support spi1 +static esp_rom_spiflash_result_t esp_rom_spiflash_erase_sector_internal(esp_rom_spiflash_chip_t *spi, uint32_t addr) +{ + //check if addr is 4k alignment + if (0 != (addr & 0xfff)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + esp_rom_spiflash_wait_idle(spi); + + // sector erase 4Kbytes erase is sector erase. + WRITE_PERI_REG(PERIPHS_SPI_FLASH_ADDR, addr & 0xffffff); + WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_FLASH_SE); + while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0); + + esp_rom_spiflash_wait_idle(spi); + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +//only support spi1 +static esp_rom_spiflash_result_t esp_rom_spiflash_erase_block_internal(esp_rom_spiflash_chip_t *spi, uint32_t addr) +{ + esp_rom_spiflash_wait_idle(spi); + + // sector erase 4Kbytes erase is sector erase. + WRITE_PERI_REG(PERIPHS_SPI_FLASH_ADDR, addr & 0xffffff); + WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_FLASH_BE); + while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0); + + esp_rom_spiflash_wait_idle(spi); + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +//only support spi1 +static esp_rom_spiflash_result_t esp_rom_spiflash_program_page_internal(esp_rom_spiflash_chip_t *spi, uint32_t spi_addr, + uint32_t *addr_source, int32_t byte_length) +{ + uint32_t temp_addr; + int32_t temp_bl; + uint8_t i; + uint8_t remain_word_num; + + //check 4byte alignment + if (0 != (byte_length & 0x3)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + //check if write in one page + if ((spi->page_size) < ((spi_addr % (spi->page_size)) + byte_length)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + esp_rom_spiflash_wait_idle(spi); + + temp_addr = spi_addr; + temp_bl = byte_length; + + while (temp_bl > 0 ) { + if ( ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_enable_write(spi)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + if ( temp_bl >= ESP_ROM_SPIFLASH_BUFF_BYTE_WRITE_NUM ) { + WRITE_PERI_REG(PERIPHS_SPI_FLASH_ADDR, (temp_addr & 0xffffff) | ( ESP_ROM_SPIFLASH_BUFF_BYTE_WRITE_NUM << ESP_ROM_SPIFLASH_BYTES_LEN )); // 32 byte a block + + for (i = 0; i < (ESP_ROM_SPIFLASH_BUFF_BYTE_WRITE_NUM >> 2); i++) { + WRITE_PERI_REG(PERIPHS_SPI_FLASH_C0 + i * 4, *addr_source++); + } + temp_bl = temp_bl - 32; + temp_addr = temp_addr + 32; + } else { + WRITE_PERI_REG(PERIPHS_SPI_FLASH_ADDR, (temp_addr & 0xffffff) | (temp_bl << ESP_ROM_SPIFLASH_BYTES_LEN )); + + remain_word_num = (0 == (temp_bl & 0x3)) ? (temp_bl >> 2) : (temp_bl >> 2) + 1; + for (i = 0; i < remain_word_num; i++) { + WRITE_PERI_REG(PERIPHS_SPI_FLASH_C0 + i * 4, *addr_source++); + temp_bl = temp_bl - 4; + } + temp_bl = 0; + } + + WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_FLASH_PP); + while ( READ_PERI_REG(PERIPHS_SPI_FLASH_CMD ) != 0 ); + + esp_rom_spiflash_wait_idle(spi); + } + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +//only support spi1 +static esp_rom_spiflash_result_t esp_rom_spiflash_read_data(esp_rom_spiflash_chip_t *spi, uint32_t flash_addr, + uint32_t *addr_dest, int32_t byte_length) +{ + uint32_t temp_addr; + int32_t temp_length; + uint8_t i; + uint8_t remain_word_num; + + //address range check + if ((flash_addr + byte_length) > (spi->chip_size)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + temp_addr = flash_addr; + temp_length = byte_length; + + esp_rom_spiflash_wait_idle(spi); + + while (temp_length > 0) { + if (temp_length >= ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM) { + //WRITE_PERI_REG(PERIPHS_SPI_FLASH_ADDR, temp_addr |(ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM << ESP_ROM_SPIFLASH_BYTES_LEN)); + REG_WRITE(SPI_MISO_DLEN_REG(1), ((ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM << 3) - 1) << SPI_USR_MISO_DBITLEN_S); + WRITE_PERI_REG(PERIPHS_SPI_FLASH_ADDR, temp_addr << 8); + REG_WRITE(PERIPHS_SPI_FLASH_CMD, SPI_USR); + while (REG_READ(PERIPHS_SPI_FLASH_CMD) != 0); + + for (i = 0; i < (ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM >> 2); i++) { + *addr_dest++ = READ_PERI_REG(PERIPHS_SPI_FLASH_C0 + i * 4); + } + temp_length = temp_length - ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM; + temp_addr = temp_addr + ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM; + } else { + //WRITE_PERI_REG(PERIPHS_SPI_FLASH_ADDR, temp_addr |(temp_length << ESP_ROM_SPIFLASH_BYTES_LEN )); + WRITE_PERI_REG(PERIPHS_SPI_FLASH_ADDR, temp_addr << 8); + REG_WRITE(SPI_MISO_DLEN_REG(1), ((ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM << 3) - 1) << SPI_USR_MISO_DBITLEN_S); + REG_WRITE(PERIPHS_SPI_FLASH_CMD, SPI_USR); + while (REG_READ(PERIPHS_SPI_FLASH_CMD) != 0); + + remain_word_num = (0 == (temp_length & 0x3)) ? (temp_length >> 2) : (temp_length >> 2) + 1; + for (i = 0; i < remain_word_num; i++) { + *addr_dest++ = READ_PERI_REG(PERIPHS_SPI_FLASH_C0 + i * 4); + } + temp_length = 0; + } + } + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +esp_rom_spiflash_result_t esp_rom_spiflash_read_status(esp_rom_spiflash_chip_t *spi, uint32_t *status) +{ + uint32_t status_value = ESP_ROM_SPIFLASH_BUSY_FLAG; + + if (g_rom_spiflash_dummy_len_plus[1] == 0) { + while (ESP_ROM_SPIFLASH_BUSY_FLAG == (status_value & ESP_ROM_SPIFLASH_BUSY_FLAG)) { + WRITE_PERI_REG(PERIPHS_SPI_FLASH_STATUS, 0); // clear regisrter + WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_FLASH_RDSR); + while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0); + + status_value = READ_PERI_REG(PERIPHS_SPI_FLASH_STATUS) & (spi->status_mask); + } + } else { + while (ESP_ROM_SPIFLASH_BUSY_FLAG == (status_value & ESP_ROM_SPIFLASH_BUSY_FLAG)) { + esp_rom_spiflash_read_user_cmd(&status_value, 0x05); + } + } + *status = status_value; + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +esp_rom_spiflash_result_t esp_rom_spiflash_read_statushigh(esp_rom_spiflash_chip_t *spi, uint32_t *status) +{ + esp_rom_spiflash_result_t ret; + esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip); + ret = esp_rom_spiflash_read_user_cmd(status, 0x35); + *status = *status << 8; + return ret; +} + +esp_rom_spiflash_result_t esp_rom_spiflash_write_status(esp_rom_spiflash_chip_t *spi, uint32_t status_value) +{ + esp_rom_spiflash_wait_idle(spi); + + // update status value by status_value + WRITE_PERI_REG(PERIPHS_SPI_FLASH_STATUS, status_value); // write status regisrter + WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_FLASH_WRSR); + while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0); + esp_rom_spiflash_wait_idle(spi); + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +static esp_rom_spiflash_result_t esp_rom_spiflash_enable_write(esp_rom_spiflash_chip_t *spi) +{ + uint32_t flash_status = 0; + + esp_rom_spiflash_wait_idle(spi); + + //enable write + WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_FLASH_WREN); // enable write operation + while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0); + + // make sure the flash is ready for writing + while (ESP_ROM_SPIFLASH_WRENABLE_FLAG != (flash_status & ESP_ROM_SPIFLASH_WRENABLE_FLAG)) { + esp_rom_spiflash_read_status(spi, &flash_status); + } + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +static esp_rom_spiflash_result_t esp_rom_spiflash_enable_qmode(esp_rom_spiflash_chip_t *spi) +{ + uint32_t flash_status; + uint32_t status; + //read QE bit, not write if QE + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_read_statushigh(spi, &status)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + if (status & ESP_ROM_SPIFLASH_QE) { + return ESP_ROM_SPIFLASH_RESULT_OK; + } + + //enable 2 byte status writing + SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, ESP_ROM_SPIFLASH_TWO_BYTE_STATUS_EN); + + if ( ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_enable_write(spi)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + esp_rom_spiflash_read_status(spi, &flash_status); + + if ( ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_write_status(spi, flash_status | ESP_ROM_SPIFLASH_QE)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +static esp_rom_spiflash_result_t esp_rom_spiflash_disable_qmode(esp_rom_spiflash_chip_t *spi) +{ + uint32_t flash_status; + uint32_t status; + + //read QE bit, not write if not QE + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_read_statushigh(spi, &status)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + //ets_printf("status %08x, line:%u\n", status, __LINE__); + + if (!(status & ESP_ROM_SPIFLASH_QE)) { + return ESP_ROM_SPIFLASH_RESULT_OK; + } + + //enable 2 byte status writing + SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, ESP_ROM_SPIFLASH_TWO_BYTE_STATUS_EN); + + if ( ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_enable_write(spi)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + esp_rom_spiflash_read_status(spi, &flash_status); + //keep low 8 bit + if ( ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_write_status(spi, flash_status & 0xff)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +static void spi_cache_mode_switch(uint32_t modebit) +{ + if ((modebit & SPI_FREAD_QIO) && (modebit & SPI_FASTRD_MODE)) { + REG_CLR_BIT(SPI_USER_REG(0), SPI_USR_MOSI); + REG_SET_BIT(SPI_USER_REG(0), SPI_USR_MISO | SPI_USR_DUMMY | SPI_USR_ADDR); + REG_SET_FIELD(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN, SPI0_R_QIO_ADDR_BITSLEN); + REG_SET_FIELD(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN, SPI0_R_QIO_DUMMY_CYCLELEN + g_rom_spiflash_dummy_len_plus[0]); + REG_SET_FIELD(SPI_USER2_REG(0), SPI_USR_COMMAND_VALUE, 0xEB); + } else if (modebit & SPI_FASTRD_MODE) { + REG_CLR_BIT(SPI_USER_REG(0), SPI_USR_MOSI); + REG_SET_BIT(SPI_USER_REG(0), SPI_USR_MISO | SPI_USR_DUMMY | SPI_USR_ADDR); + REG_SET_FIELD(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN, SPI0_R_FAST_ADDR_BITSLEN); + if ((modebit & SPI_FREAD_QUAD)) { + REG_SET_FIELD(SPI_USER2_REG(0), SPI_USR_COMMAND_VALUE, 0x6B); + REG_SET_FIELD(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN, SPI0_R_FAST_DUMMY_CYCLELEN + g_rom_spiflash_dummy_len_plus[0]); + } else if ((modebit & SPI_FREAD_DIO)) { + REG_SET_FIELD(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN, SPI0_R_DIO_DUMMY_CYCLELEN + g_rom_spiflash_dummy_len_plus[0]); + REG_SET_FIELD(SPI_USER2_REG(0), SPI_USR_COMMAND_VALUE, 0xBB); + } else if ((modebit & SPI_FREAD_DUAL)) { + REG_SET_FIELD(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN, SPI0_R_FAST_DUMMY_CYCLELEN + g_rom_spiflash_dummy_len_plus[0]); + REG_SET_FIELD(SPI_USER2_REG(0), SPI_USR_COMMAND_VALUE, 0x3B); + } else { + REG_SET_FIELD(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN, SPI0_R_FAST_DUMMY_CYCLELEN + g_rom_spiflash_dummy_len_plus[0]); + REG_SET_FIELD(SPI_USER2_REG(0), SPI_USR_COMMAND_VALUE, 0x0B); + } + } else { + REG_CLR_BIT(SPI_USER_REG(0), SPI_USR_MOSI); + if (g_rom_spiflash_dummy_len_plus[0] == 0) { + REG_CLR_BIT(SPI_USER_REG(0), SPI_USR_DUMMY); + } else { + REG_SET_BIT(SPI_USER_REG(0), SPI_USR_DUMMY); + REG_SET_FIELD(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN, g_rom_spiflash_dummy_len_plus[0] - 1); + } + REG_SET_BIT(SPI_USER_REG(0), SPI_USR_MISO | SPI_USR_ADDR); + REG_SET_FIELD(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN, SPI0_R_SIO_ADDR_BITSLEN); + REG_SET_FIELD(SPI_USER2_REG(0), SPI_USR_COMMAND_VALUE, 0x03); + } + +} + +esp_rom_spiflash_result_t esp_rom_spiflash_lock() +{ + uint32_t status; + + //read QE bit, not write if not QE + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_read_statushigh(&g_rom_spiflash_chip, &status)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + //enable 2 byte status writing + SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, ESP_ROM_SPIFLASH_TWO_BYTE_STATUS_EN); + + if ( ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_enable_write(&g_rom_spiflash_chip)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + if ( ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_write_status(&g_rom_spiflash_chip, status | ESP_ROM_SPIFLASH_WR_PROTECT)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + + +esp_rom_spiflash_result_t esp_rom_spiflash_config_readmode(esp_rom_spiflash_read_mode_t mode, bool legacy) +{ + uint32_t modebit; + + while ((REG_READ(SPI_EXT2_REG(1)) & SPI_ST)) { + } + while ((REG_READ(SPI_EXT2_REG(0)) & SPI_ST)) { + } + //clear old mode bit + CLEAR_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, SPI_FREAD_QIO | SPI_FREAD_QUAD | SPI_FREAD_DIO | SPI_FREAD_DUAL | SPI_FASTRD_MODE); + CLEAR_PERI_REG_MASK(SPI_CTRL_REG(0), SPI_FREAD_QIO | SPI_FREAD_QUAD | SPI_FREAD_DIO | SPI_FREAD_DUAL | SPI_FASTRD_MODE); + //configure read mode + switch (mode) { + case ESP_ROM_SPIFLASH_QIO_MODE : modebit = SPI_FREAD_QIO | SPI_FASTRD_MODE; break; + case ESP_ROM_SPIFLASH_QOUT_MODE : modebit = SPI_FREAD_QUAD | SPI_FASTRD_MODE; break; + case ESP_ROM_SPIFLASH_DIO_MODE : modebit = SPI_FREAD_DIO | SPI_FASTRD_MODE; break; + case ESP_ROM_SPIFLASH_DOUT_MODE : modebit = SPI_FREAD_DUAL | SPI_FASTRD_MODE; break; + case ESP_ROM_SPIFLASH_FASTRD_MODE: modebit = SPI_FASTRD_MODE; break; + case ESP_ROM_SPIFLASH_SLOWRD_MODE: modebit = 0; break; + default : modebit = 0; + } + + if ((ESP_ROM_SPIFLASH_QIO_MODE == mode) || (ESP_ROM_SPIFLASH_QOUT_MODE == mode)) { + esp_rom_spiflash_enable_qmode(&g_rom_spiflash_chip); + } else { + //do not need disable QMode in faster boot + if (legacy) { + esp_rom_spiflash_disable_qmode(&g_rom_spiflash_chip); + } + } + + SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, modebit); + SET_PERI_REG_MASK(SPI_CTRL_REG(0), modebit); + spi_cache_mode_switch(modebit); + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +esp_rom_spiflash_result_t esp_rom_spiflash_erase_chip() +{ + if ( ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_enable_write(&g_rom_spiflash_chip)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_erase_chip_internal(&g_rom_spiflash_chip)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +esp_rom_spiflash_result_t esp_rom_spiflash_erase_block(uint32_t block_num) +{ + // flash write is always 1 line currently + REG_CLR_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_DUMMY); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_ADDR_BITLEN, ESP_ROM_SPIFLASH_W_SIO_ADDR_BITSLEN); + + //check program size + if (block_num >= ((g_rom_spiflash_chip.chip_size) / (g_rom_spiflash_chip.block_size))) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + if ( ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_enable_write(&g_rom_spiflash_chip)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_erase_block_internal(&g_rom_spiflash_chip, block_num * (g_rom_spiflash_chip.block_size))) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +esp_rom_spiflash_result_t esp_rom_spiflash_erase_sector(uint32_t sector_num) +{ + // flash write is always 1 line currently + REG_CLR_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_DUMMY); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_ADDR_BITLEN, ESP_ROM_SPIFLASH_W_SIO_ADDR_BITSLEN); + + //check program size + if (sector_num >= ((g_rom_spiflash_chip.chip_size) / (g_rom_spiflash_chip.sector_size))) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + if ( ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_enable_write(&g_rom_spiflash_chip)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_erase_sector_internal(&g_rom_spiflash_chip, sector_num * (g_rom_spiflash_chip.sector_size))) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +esp_rom_spiflash_result_t esp_rom_spiflash_write(uint32_t target, const uint32_t *src_addr, int32_t len) +{ + uint32_t page_size; + uint32_t pgm_len, pgm_num; + uint8_t i; + + // flash write is always 1 line currently + REG_CLR_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_DUMMY); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_ADDR_BITLEN, ESP_ROM_SPIFLASH_W_SIO_ADDR_BITSLEN); + + //check program size + if ( (target + len) > (g_rom_spiflash_chip.chip_size)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + page_size = g_rom_spiflash_chip.page_size; + pgm_len = page_size - (target % page_size); + if (len < pgm_len) { + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_program_page_internal(&g_rom_spiflash_chip, + target, (uint32_t *)src_addr, len)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + } else { + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_program_page_internal(&g_rom_spiflash_chip, + target, (uint32_t *)src_addr, pgm_len)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + //whole page program + pgm_num = (len - pgm_len) / page_size; + for (i = 0; i < pgm_num; i++) { + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_program_page_internal(&g_rom_spiflash_chip, + target + pgm_len, (uint32_t *)src_addr + (pgm_len >> 2), page_size)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + pgm_len += page_size; + } + + //remain parts to program + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_program_page_internal(&g_rom_spiflash_chip, + target + pgm_len, (uint32_t *)src_addr + (pgm_len >> 2), len - pgm_len)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + } + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +esp_rom_spiflash_result_t esp_rom_spiflash_write_encrypted(uint32_t flash_addr, uint32_t *data, uint32_t len) +{ + esp_rom_spiflash_result_t ret = ESP_ROM_SPIFLASH_RESULT_OK; + uint32_t i; + + if ((flash_addr & 0x1f) || (len & 0x1f)) { //check 32 byte alignment + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + esp_rom_spiflash_write_encrypted_enable(); + + for (i = 0; i < (len >> 5); i++) { + if ((ret = esp_rom_spiflash_prepare_encrypted_data(flash_addr + (i << 5), data + (i << 3))) != ESP_ROM_SPIFLASH_RESULT_OK) { + break; + } + + if ((ret = esp_rom_spiflash_write(flash_addr + (i << 5), data, 32)) != ESP_ROM_SPIFLASH_RESULT_OK) { + break; + } + } + + esp_rom_spiflash_write_encrypted_disable(); + + return ret; +} + + +esp_rom_spiflash_result_t esp_rom_spiflash_read(uint32_t target, uint32_t *dest_addr, int32_t len) +{ + // QIO or SIO, non-QIO regard as SIO + uint32_t modebit; + modebit = READ_PERI_REG(PERIPHS_SPI_FLASH_CTRL); + if ((modebit & SPI_FREAD_QIO) && (modebit & SPI_FASTRD_MODE)) { + REG_CLR_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_MOSI); + REG_SET_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_MISO | SPI_USR_DUMMY | SPI_USR_ADDR); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_ADDR_BITLEN, SPI1_R_QIO_ADDR_BITSLEN); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_DUMMY_CYCLELEN, SPI1_R_QIO_DUMMY_CYCLELEN + g_rom_spiflash_dummy_len_plus[1]); + //REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG2, SPI_USR_COMMAND_VALUE, 0xEB); + REG_WRITE(PERIPHS_SPI_FLASH_USRREG2, (0x7 << SPI_USR_COMMAND_BITLEN_S) | 0xEB); + } else if (modebit & SPI_FASTRD_MODE) { + REG_CLR_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_MOSI); + REG_SET_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_MISO | SPI_USR_ADDR); + if (modebit & SPI_FREAD_DIO) { + if (g_rom_spiflash_dummy_len_plus[1] == 0) { + REG_CLR_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_DUMMY); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_ADDR_BITLEN, SPI1_R_DIO_ADDR_BITSLEN); + REG_WRITE(PERIPHS_SPI_FLASH_USRREG2, (0x7 << SPI_USR_COMMAND_BITLEN_S) | 0xBB); + } else { + REG_SET_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_DUMMY); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_ADDR_BITLEN, SPI1_R_DIO_ADDR_BITSLEN); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_DUMMY_CYCLELEN, g_rom_spiflash_dummy_len_plus[1] - 1); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG2, SPI_USR_COMMAND_VALUE, 0xBB); + } + } else { + if ((modebit & SPI_FREAD_QUAD)) { + //REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG2, SPI_USR_COMMAND_VALUE, 0x6B); + REG_WRITE(PERIPHS_SPI_FLASH_USRREG2, (0x7 << SPI_USR_COMMAND_BITLEN_S) | 0x6B); + } else if ((modebit & SPI_FREAD_DUAL)) { + //REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG2, SPI_USR_COMMAND_VALUE, 0x3B); + REG_WRITE(PERIPHS_SPI_FLASH_USRREG2, (0x7 << SPI_USR_COMMAND_BITLEN_S) | 0x3B); + } else { + //REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG2, SPI_USR_COMMAND_VALUE, 0x0B); + REG_WRITE(PERIPHS_SPI_FLASH_USRREG2, (0x7 << SPI_USR_COMMAND_BITLEN_S) | 0x0B); + } + REG_SET_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_DUMMY); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_ADDR_BITLEN, SPI1_R_FAST_ADDR_BITSLEN); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_DUMMY_CYCLELEN, SPI1_R_FAST_DUMMY_CYCLELEN + g_rom_spiflash_dummy_len_plus[1]); + } + } else { + REG_CLR_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_MOSI); + if (g_rom_spiflash_dummy_len_plus[1] == 0) { + REG_CLR_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_DUMMY); + } else { + REG_SET_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_DUMMY); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_DUMMY_CYCLELEN, g_rom_spiflash_dummy_len_plus[1] - 1); + } + REG_SET_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_MISO | SPI_USR_ADDR); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_ADDR_BITLEN, SPI1_R_SIO_ADDR_BITSLEN); + //REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG2, SPI_USR_COMMAND_VALUE, 0x03); + REG_WRITE(PERIPHS_SPI_FLASH_USRREG2, (0x7 << SPI_USR_COMMAND_BITLEN_S) | 0x03); + } + + if ( ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_read_data(&g_rom_spiflash_chip, target, dest_addr, len)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +esp_rom_spiflash_result_t esp_rom_spiflash_erase_area(uint32_t start_addr, uint32_t area_len) +{ + int32_t total_sector_num; + int32_t head_sector_num; + uint32_t sector_no; + uint32_t sector_num_per_block; + + //set read mode to Fastmode ,not QDIO mode for erase + esp_rom_spiflash_config_readmode(ESP_ROM_SPIFLASH_SLOWRD_MODE, true); + + //check if area is oversize of flash + if ((start_addr + area_len) > g_rom_spiflash_chip.chip_size) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + //start_addr is aligned as sector boundary + if (0 != (start_addr % g_rom_spiflash_chip.sector_size)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + //Unlock flash to enable erase + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_unlock(/*&g_rom_spiflash_chip*/)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + sector_no = start_addr / g_rom_spiflash_chip.sector_size; + sector_num_per_block = g_rom_spiflash_chip.block_size / g_rom_spiflash_chip.sector_size; + total_sector_num = (0 == (area_len % g_rom_spiflash_chip.sector_size)) ? area_len / g_rom_spiflash_chip.sector_size : + 1 + (area_len / g_rom_spiflash_chip.sector_size); + + //check if erase area reach over block boundary + head_sector_num = sector_num_per_block - (sector_no % sector_num_per_block); + + head_sector_num = (head_sector_num >= total_sector_num) ? total_sector_num : head_sector_num; + + //JJJ, BUG of 6.0 erase + //middle part of area is aligned by blocks + total_sector_num -= head_sector_num; + + //head part of area is erased + while (0 != head_sector_num) { + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_erase_sector(sector_no)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + sector_no++; + head_sector_num--; + } + while (total_sector_num > sector_num_per_block) { + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_erase_block(sector_no / sector_num_per_block)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + sector_no += sector_num_per_block; + total_sector_num -= sector_num_per_block; + } + + //tail part of area burn + while (0 < total_sector_num) { + if (ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_erase_sector(sector_no)) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + sector_no++; + total_sector_num--; + } + + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +#endif diff --git a/components/spi_flash/test/test_partitions.c b/components/spi_flash/test/test_partitions.c index 01dd5f445..d859d3dd2 100644 --- a/components/spi_flash/test/test_partitions.c +++ b/components/spi_flash/test/test_partitions.c @@ -23,6 +23,7 @@ #include #include #include +#include TEST_CASE("Test erase partition", "[spi_flash]") { @@ -40,7 +41,7 @@ TEST_CASE("Test erase partition", "[spi_flash]") #endif // put some dummy data on sector boundaries - const char *some_data = "abcdefghijklmn"; + const static DRAM_ATTR char some_data[] = "abcdefghijklmn"; for (int i = 0; i < part->size; i+= 4096) { ESP_ERROR_CHECK( esp_partition_write(part, i, some_data, strlen(some_data)) ); } @@ -64,5 +65,4 @@ TEST_CASE("Test erase partition", "[spi_flash]") TEST_ASSERT_EQUAL_HEX8(0xFF, buf[i]); } } - } diff --git a/components/spi_flash/test/test_read_write.c b/components/spi_flash/test/test_read_write.c index b9dc820b1..147e4c3c9 100644 --- a/components/spi_flash/test/test_read_write.c +++ b/components/spi_flash/test/test_read_write.c @@ -71,18 +71,18 @@ static void IRAM_ATTR test_read(int src_off, int dst_off, int len) { uint32_t src_buf[16]; char dst_buf[64], dst_gold[64]; + fprintf(stderr, "src=%d dst=%d len=%d\n", src_off, dst_off, len); memset(src_buf, 0xAA, sizeof(src_buf)); fill(((char *) src_buf) + src_off, src_off, len); ESP_ERROR_CHECK(spi_flash_erase_sector((start + src_off) / SPI_FLASH_SEC_SIZE)); spi_flash_disable_interrupts_caches_and_other_cpu(); - SpiFlashOpResult rc = SPIWrite(start, src_buf, sizeof(src_buf)); + esp_rom_spiflash_result_t rc = esp_rom_spiflash_write(start, src_buf, sizeof(src_buf)); spi_flash_enable_interrupts_caches_and_other_cpu(); - TEST_ASSERT_EQUAL_INT(rc, SPI_FLASH_RESULT_OK); + TEST_ASSERT_EQUAL_INT(rc, ESP_ROM_SPIFLASH_RESULT_OK); memset(dst_buf, 0x55, sizeof(dst_buf)); memset(dst_gold, 0x55, sizeof(dst_gold)); fill(dst_gold + dst_off, src_off, len); - ESP_ERROR_CHECK(spi_flash_read(start + src_off, dst_buf + dst_off, len)); TEST_ASSERT_EQUAL_INT(cmp_or_dump(dst_buf, dst_gold, sizeof(dst_buf)), 0); } @@ -159,9 +159,9 @@ static void IRAM_ATTR test_write(int dst_off, int src_off, int len) } ESP_ERROR_CHECK(spi_flash_write(start + dst_off, src_buf + src_off, len)); spi_flash_disable_interrupts_caches_and_other_cpu(); - SpiFlashOpResult rc = SPIRead(start, dst_buf, sizeof(dst_buf)); + esp_rom_spiflash_result_t rc = esp_rom_spiflash_read(start, dst_buf, sizeof(dst_buf)); spi_flash_enable_interrupts_caches_and_other_cpu(); - TEST_ASSERT_EQUAL_INT(rc, SPI_FLASH_RESULT_OK); + TEST_ASSERT_EQUAL_INT(rc, ESP_ROM_SPIFLASH_RESULT_OK); TEST_ASSERT_EQUAL_INT(cmp_or_dump(dst_buf, dst_gold, sizeof(dst_buf)), 0); } diff --git a/docs/security/flash-encryption.rst b/docs/security/flash-encryption.rst index 8448f020b..f2f1339d9 100644 --- a/docs/security/flash-encryption.rst +++ b/docs/security/flash-encryption.rst @@ -108,7 +108,7 @@ Where possible, we recommend using the partition write function ``esp_partition_ The ``esp_spi_flash_write`` function will write data when the write_encrypted parameter is set to true. Otherwise, data will be written unencrypted. -The ROM function ``SPI_Encrypt_Write`` will write encrypted data to flash, the ROM function ``SPIWrite`` will write unencrypted to flash. (these function are not supported in esp-idf apps). +The ROM function ``esp_rom_spiflash_write_encrypted`` will write encrypted data to flash, the ROM function ``SPIWrite`` will write unencrypted to flash. (these function are not supported in esp-idf apps). The minimum write size for unencrypted data is 4 bytes (and the alignment is 4 bytes). Because data is encrypted in blocks, the minimum write size for encrypted data is 16 bytes (and the alignment is 16 bytes.)