From 66308774dba62b401faa3f78f1b4a90add46f618 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 6 Apr 2017 16:17:23 +1000 Subject: [PATCH 1/4] esptool: Update to include ESP32-D2WD support (and other SPI flash remapping) --- components/esptool_py/esptool | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esptool_py/esptool b/components/esptool_py/esptool index 907273664..96698a3da 160000 --- a/components/esptool_py/esptool +++ b/components/esptool_py/esptool @@ -1 +1 @@ -Subproject commit 907273664ada32fc33f3fbfeba99550512c67e4d +Subproject commit 96698a3da9acc6e357741663830f97524b688ade From 85e76a7cfccbfab7d6686ee339ad6a2721d0097d Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 12 Apr 2017 11:31:26 +1000 Subject: [PATCH 2/4] spiflash ROM functions: Remove Quad I/O mode enable/disable code from flash ROM functions Confusion here is that original ROM has two functions: * SPIReadModeCnfig() - sets mode, calls enable_qio_mode/disable_qio_mode * SPIMasterReadModeCnfig() - As above, but doesn't set QIO mode in status register However we never want to use the ROM method to set/clear QIO mode flag, as not all flash chips work this way. Instead we do it in flash_qio_mode.c in bootloader. So in both cases (ROM or "patched ROM") we now call SPIMasterReadModeCnfig(), which is now named esp_rom_spiflash_config_readmode(). --- .../bootloader/src/main/flash_qio_mode.c | 3 +- components/esp32/include/rom/spi_flash.h | 16 +--- components/esp32/ld/esp32.rom.spiflash.ld | 2 +- components/spi_flash/spi_flash_rom_patch.c | 78 ++----------------- 4 files changed, 10 insertions(+), 89 deletions(-) diff --git a/components/bootloader/src/main/flash_qio_mode.c b/components/bootloader/src/main/flash_qio_mode.c index 4b2ec3088..55c618654 100644 --- a/components/bootloader/src/main/flash_qio_mode.c +++ b/components/bootloader/src/main/flash_qio_mode.c @@ -180,7 +180,8 @@ static void enable_qio_mode(read_status_fn_t read_status_fn, #else mode = ESP_ROM_SPIFLASH_QIO_MODE; #endif - esp_rom_spiflash_master_config_readmode(mode); + esp_rom_spiflash_config_readmode(mode); + } static unsigned read_status_8b_rdsr() diff --git a/components/esp32/include/rom/spi_flash.h b/components/esp32/include/rom/spi_flash.h index bb2da748b..97efccc36 100644 --- a/components/esp32/include/rom/spi_flash.h +++ b/components/esp32/include/rom/spi_flash.h @@ -279,25 +279,13 @@ esp_rom_spiflash_result_t esp_rom_spiflash_read_user_cmd(uint32_t *status, uint8 * * @param esp_rom_spiflash_read_mode_t mode : QIO/QOUT/DIO/DOUT/FastRD/SlowRD. * - * @param uint8_t legacy: In legacy mode, more SPI command is used in line. + * This function does not try to set the QIO Enable bit in the status register, caller is responsible for this. * * @return ESP_ROM_SPIFLASH_RESULT_OK : config OK. * ESP_ROM_SPIFLASH_RESULT_ERR : config error. * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : config timeout. */ -esp_rom_spiflash_result_t esp_rom_spiflash_config_readmode(esp_rom_spiflash_read_mode_t mode, bool legacy); - -/** - * @brief Config SPI Flash read mode when Flash is running in some mode. - * Please do not call this function in SDK. - * - * @param esp_rom_spiflash_read_mode_t mode : QIO/QOUT/DIO/DOUT/FastRD/SlowRD. - * - * @return ESP_ROM_SPIFLASH_RESULT_OK : config OK. - * ESP_ROM_SPIFLASH_RESULT_ERR : config error. - * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : config timeout. - */ -esp_rom_spiflash_result_t esp_rom_spiflash_master_config_readmode(esp_rom_spiflash_read_mode_t mode); +esp_rom_spiflash_result_t esp_rom_spiflash_config_readmode(esp_rom_spiflash_read_mode_t mode); /** * @brief Config SPI Flash clock divisor. diff --git a/components/esp32/ld/esp32.rom.spiflash.ld b/components/esp32/ld/esp32.rom.spiflash.ld index 64af6a4b9..709b35811 100644 --- a/components/esp32/ld/esp32.rom.spiflash.ld +++ b/components/esp32/ld/esp32.rom.spiflash.ld @@ -10,7 +10,7 @@ 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_config_readmode = 0x40062b64 ); /* SPIMasterReadModeCnfig */ PROVIDE ( esp_rom_spiflash_read_status = 0x4006226c ); PROVIDE ( esp_rom_spiflash_read_statushigh = 0x40062448 ); PROVIDE ( esp_rom_spiflash_write = 0x40062d50 ); diff --git a/components/spi_flash/spi_flash_rom_patch.c b/components/spi_flash/spi_flash_rom_patch.c index 0664c7482..ec59a1ff1 100644 --- a/components/spi_flash/spi_flash_rom_patch.c +++ b/components/spi_flash/spi_flash_rom_patch.c @@ -87,9 +87,6 @@ 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) @@ -309,65 +306,6 @@ static esp_rom_spiflash_result_t esp_rom_spiflash_enable_write(esp_rom_spiflash_ 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)) { @@ -431,7 +369,7 @@ esp_rom_spiflash_result_t esp_rom_spiflash_lock() } -esp_rom_spiflash_result_t esp_rom_spiflash_config_readmode(esp_rom_spiflash_read_mode_t mode, bool legacy) +esp_rom_spiflash_result_t esp_rom_spiflash_config_readmode(esp_rom_spiflash_read_mode_t mode) { uint32_t modebit; @@ -453,15 +391,6 @@ esp_rom_spiflash_result_t esp_rom_spiflash_config_readmode(esp_rom_spiflash_read 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); @@ -668,7 +597,10 @@ esp_rom_spiflash_result_t esp_rom_spiflash_erase_area(uint32_t start_addr, uint3 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); + // + // TODO: this is probably a bug as it doesn't re-enable QIO mode, not serious as this + // function is not used in IDF. + esp_rom_spiflash_config_readmode(ESP_ROM_SPIFLASH_SLOWRD_MODE); //check if area is oversize of flash if ((start_addr + area_len) > g_rom_spiflash_chip.chip_size) { From f7793840e1b3e3092c845eea246597af307ffb7f Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 13 Apr 2017 17:08:53 +1000 Subject: [PATCH 3/4] bootloader: Add QIO support for ESP32-D2WD SPI flash --- .../bootloader/src/main/bootloader_start.c | 10 +++++ .../bootloader/src/main/flash_qio_mode.c | 37 ++++++++++++++++++- components/esp32/include/rom/efuse.h | 15 +++++--- components/esp32/include/rom/spi_flash.h | 18 +++++++++ components/esp32/ld/esp32.rom.ld | 1 + 5 files changed, 75 insertions(+), 6 deletions(-) diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index 536077af4..28446c264 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -19,6 +19,7 @@ #include "esp_log.h" #include "rom/cache.h" +#include "rom/efuse.h" #include "rom/ets_sys.h" #include "rom/spi_flash.h" #include "rom/crc.h" @@ -258,6 +259,15 @@ 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 ); + +#ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH + const uint32_t spiconfig = ets_efuse_get_spiconfig(); + if(spiconfig != EFUSE_SPICONFIG_SPI_DEFAULTS && spiconfig != EFUSE_SPICONFIG_HSPI_DEFAULTS) { + ESP_LOGE(TAG, "SPI flash pins are overridden. \"Enable SPI flash ROM driver patched functions\" must be enabled in menuconfig"); + return; + } +#endif + esp_rom_spiflash_unlock(); ESP_LOGI(TAG, "Enabling RNG early entropy source..."); diff --git a/components/bootloader/src/main/flash_qio_mode.c b/components/bootloader/src/main/flash_qio_mode.c index 55c618654..cd288290c 100644 --- a/components/bootloader/src/main/flash_qio_mode.c +++ b/components/bootloader/src/main/flash_qio_mode.c @@ -16,7 +16,9 @@ #include "flash_qio_mode.h" #include "esp_log.h" #include "rom/spi_flash.h" +#include "rom/efuse.h" #include "soc/spi_struct.h" +#include "soc/efuse_reg.h" #include "sdkconfig.h" /* SPI flash controller */ @@ -33,6 +35,9 @@ #define CMD_RDSR 0x05 #define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */ + +#define ESP32_D2WD_WP_GPIO 7 /* ESP32-D2WD has this GPIO wired to WP pin of flash */ + static const char *TAG = "qio_mode"; typedef unsigned (*read_status_fn_t)(); @@ -77,7 +82,7 @@ static void write_status_16b_wrsr(unsigned new_status); const static qio_info_t chip_data[] = { /* Manufacturer, mfg_id, flash_id, id mask, Read Status, Write Status, QIE Bit */ { "MXIC", 0xC2, 0x2000, 0xFF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, - { "ISSI", 0x9D, 0x4000, 0xFF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, + { "ISSI", 0x9D, 0x4000, 0xCF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, /* IDs 0x40xx, 0x70xx */ { "WinBond", 0xEF, 0x4000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 }, /* Final entry is default entry, if no other IDs have matched. @@ -102,6 +107,9 @@ static void enable_qio_mode(read_status_fn_t read_status_fn, */ static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len); +/* dummy_len_plus values defined in ROM for SPI flash configuration */ +extern uint8_t g_rom_spiflash_dummy_len_plus[]; + void bootloader_enable_qio_mode(void) { uint32_t raw_flash_id; @@ -149,6 +157,20 @@ static void enable_qio_mode(read_status_fn_t read_status_fn, uint8_t status_qio_bit) { uint32_t status; + const uint32_t spiconfig = ets_efuse_get_spiconfig(); + + if (spiconfig != EFUSE_SPICONFIG_SPI_DEFAULTS && spiconfig != EFUSE_SPICONFIG_HSPI_DEFAULTS) { + // spiconfig specifies a custom efuse pin configuration. This config defines all pins -except- WP. + // + // For now, in this situation we only support Quad I/O mode for ESP32-D2WD where WP pin is known. + uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_RESERVE); + uint32_t pkg_ver = chip_ver & 0x7; + const uint32_t PKG_VER_ESP32_D2WD = 2; // TODO: use chip detection API once available + if (pkg_ver != PKG_VER_ESP32_D2WD) { + ESP_LOGE(TAG, "Quad I/O is only supported for standard pin numbers or ESP32-D2WD. Falling back to Dual I/O."); + return; + } + } esp_rom_spiflash_wait_idle(&g_rom_flashchip); @@ -180,8 +202,10 @@ static void enable_qio_mode(read_status_fn_t read_status_fn, #else mode = ESP_ROM_SPIFLASH_QIO_MODE; #endif + esp_rom_spiflash_config_readmode(mode); + esp_rom_spiflash_select_qio_pins(ESP32_D2WD_WP_GPIO, spiconfig); } static unsigned read_status_8b_rdsr() @@ -223,6 +247,17 @@ static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8 SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0; SPIFLASH.data_buf[0] = mosi_data; + if (g_rom_spiflash_dummy_len_plus[1]) { + /* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */ + if (miso_len > 0) { + SPIFLASH.user.usr_dummy = 1; + SPIFLASH.user1.usr_dummy_cyclelen = g_rom_spiflash_dummy_len_plus[1] - 1; + } else { + SPIFLASH.user.usr_dummy = 0; + SPIFLASH.user1.usr_dummy_cyclelen = 0; + } + } + SPIFLASH.cmd.usr = 1; while(SPIFLASH.cmd.usr != 0) { } diff --git a/components/esp32/include/rom/efuse.h b/components/esp32/include/rom/efuse.h index 58cfdb20b..337227ab0 100644 --- a/components/esp32/include/rom/efuse.h +++ b/components/esp32/include/rom/efuse.h @@ -60,15 +60,20 @@ void ets_efuse_program_op(void); uint32_t ets_efuse_get_8M_clock(void); /** - * @brief Read spi pad configuration, show gpio number of flash pad, includes 5 pads. + * @brief Read spi flash pin configuration from Efuse * - * @param null - * - * @return uint32_t: 0, invalid, flash pad decided by strapping - * else, bit[5:0] spiclk, bit[11:6] spiq, bit[17:12] spid, bit[23:18] spics0, bit[29:24] spihd + * @return + * - 0 for default SPI pins. + * - 1 for default HSPI pins. + * - Other values define a custom pin configuration mask. Pins are encoded as per the EFUSE_SPICONFIG_RET_SPICLK, + * EFUSE_SPICONFIG_RET_SPIQ, EFUSE_SPICONFIG_RET_SPID, EFUSE_SPICONFIG_RET_SPICS0, EFUSE_SPICONFIG_RET_SPIHD macros. + * WP pin (for quad I/O modes) is not saved in efuse and not returned by this function. */ uint32_t ets_efuse_get_spiconfig(void); +#define EFUSE_SPICONFIG_SPI_DEFAULTS 0 +#define EFUSE_SPICONFIG_HSPI_DEFAULTS 1 + #define EFUSE_SPICONFIG_RET_SPICLK_MASK 0x3f #define EFUSE_SPICONFIG_RET_SPICLK_SHIFT 0 #define EFUSE_SPICONFIG_RET_SPICLK(ret) (((ret) >> EFUSE_SPICONFIG_RET_SPICLK_SHIFT) & EFUSE_SPICONFIG_RET_SPICLK_MASK) diff --git a/components/esp32/include/rom/spi_flash.h b/components/esp32/include/rom/spi_flash.h index 97efccc36..35d010d79 100644 --- a/components/esp32/include/rom/spi_flash.h +++ b/components/esp32/include/rom/spi_flash.h @@ -512,6 +512,24 @@ esp_rom_spiflash_result_t esp_rom_spiflash_write_encrypted(uint32_t flash_addr, esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *spi); +/** @brief Enable Quad I/O pin functions + * + * @note Please do not call this function in SDK. + * + * Sets the HD & WP pin functions for Quad I/O modes, based on the + * efuse SPI pin configuration. + * + * @param wp_gpio_num - Number of the WP pin to reconfigure for quad I/O. + * + * @param spiconfig - Pin configuration, as returned from ets_efuse_get_spiconfig(). + * - If this parameter is 0, default SPI pins are used and wp_gpio_num parameter is ignored. + * - If this parameter is 1, default HSPI pins are used and wp_gpio_num parameter is ignored. + * - For other values, this parameter encodes the HD pin number and also the CLK pin number. CLK pin selection is used + * to determine if HSPI or SPI peripheral will be used (use HSPI if CLK pin is the HSPI clock pin, otherwise use SPI). + * Both HD & WP pins are configured via GPIO matrix to map to the selected peripheral. + */ +void esp_rom_spiflash_select_qio_pins(uint8_t wp_gpio_num, uint32_t spiconfig); + /** @brief Global esp_rom_spiflash_chip_t structure used by ROM functions * */ diff --git a/components/esp32/ld/esp32.rom.ld b/components/esp32/ld/esp32.rom.ld index 6529e31df..3b81f2cec 100644 --- a/components/esp32/ld/esp32.rom.ld +++ b/components/esp32/ld/esp32.rom.ld @@ -1537,6 +1537,7 @@ 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 ( esp_rom_spiflash_select_qio_pins = 0x40061ddc ); PROVIDE ( g_rom_spiflash_chip = 0x3ffae270 ); /* From b99d5df9228e2f4f48b43cedcfc14ec339f2bf93 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 13 Apr 2017 17:37:35 +1000 Subject: [PATCH 4/4] unit tests: Shrink unit test partition table so tests can run on 2MB of flash --- tools/unit-test-app/partition_table_unit_test_app.csv | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/unit-test-app/partition_table_unit_test_app.csv b/tools/unit-test-app/partition_table_unit_test_app.csv index b6e57b4ed..129d0d3f6 100644 --- a/tools/unit-test-app/partition_table_unit_test_app.csv +++ b/tools/unit-test-app/partition_table_unit_test_app.csv @@ -6,7 +6,9 @@ nvs, data, nvs, 0x9000, 0x4000 otadata, data, ota, 0xd000, 0x2000 phy_init, data, phy, 0xf000, 0x1000 factory, 0, 0, 0x10000, 1M -ota_0, 0, ota_0, , 1M -ota_1, 0, ota_1, , 1M +# these OTA partitions are used for tests, but can't fit real OTA apps in them +# (done this way so tests can run in 2MB of flash.) +ota_0, 0, ota_0, , 128K +ota_1, 0, ota_1, , 128K # flash_test partition used for SPI flash tests flash_test, 0x55, 0x55, , 512K