diff --git a/components/bootloader/Makefile.projbuild b/components/bootloader/Makefile.projbuild index 91be3a6d6e..50c95f9fec 100644 --- a/components/bootloader/Makefile.projbuild +++ b/components/bootloader/Makefile.projbuild @@ -8,7 +8,7 @@ # basically runs Make in the src/ directory but it needs to zero some variables # the ESP-IDF project.mk makefile exports first, to not let them interfere. # -ifeq ("$(IS_BOOTLOADER_BUILD)","") +ifndef IS_BOOTLOADER_BUILD BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH) BOOTLOADER_BUILD_DIR=$(abspath $(BUILD_DIR_BASE)/bootloader) diff --git a/components/bootloader/src/Makefile b/components/bootloader/src/Makefile index f30e314a5f..add9c15d61 100644 --- a/components/bootloader/src/Makefile +++ b/components/bootloader/src/Makefile @@ -4,12 +4,13 @@ # PROJECT_NAME := bootloader -COMPONENTS := esptool_py bootloader log +COMPONENTS := esptool_py bootloader log spi_flash # The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included. # # IS_BOOTLOADER_BUILD tells the component Makefile.projbuild to be a no-op IS_BOOTLOADER_BUILD := 1 +export IS_BOOTLOADER_BUILD #We cannot include the esp32 component directly but we need its includes. #This is fixed by adding CFLAGS from Makefile.projbuild diff --git a/components/bootloader/src/main/bootloader_config.h b/components/bootloader/src/main/bootloader_config.h index 709ff41b16..f99a1c94e5 100644 --- a/components/bootloader/src/main/bootloader_config.h +++ b/components/bootloader/src/main/bootloader_config.h @@ -51,7 +51,7 @@ enum { SPI_SPEED_20M, SPI_SPEED_80M = 0xF }; -/*suppport flash size in esp32 */ +/*supported flash sizes*/ enum { SPI_SIZE_1MB = 0, SPI_SIZE_2MB, diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index a61ea77d59..e87f579f42 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -58,6 +58,7 @@ void IRAM_ATTR set_cache_and_start_app(uint32_t drom_addr, uint32_t irom_load_addr, uint32_t irom_size, uint32_t entry_addr); +static void update_flash_config(struct flash_hdr* pfhdr); void IRAM_ATTR call_start_cpu0() @@ -258,7 +259,7 @@ void bootloader_main() memset(&bs, 0, sizeof(bs)); ESP_LOGI(TAG, "compile time " __TIME__ ); - /* close watch dog here */ + /* 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(); @@ -269,6 +270,8 @@ void bootloader_main() print_flash_info(&fhdr); + update_flash_config(&fhdr); + if (!load_partition_table(&bs, PARTITION_ADD)) { ESP_LOGE(TAG, "load partition table error!"); return; @@ -364,7 +367,7 @@ void unpack_load_app(const partition_pos_t* partition) uint32_t irom_size = 0; /* Reload the RTC memory sections whenever a non-deepsleep reset - is occuring */ + is occurring */ bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET; ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic, @@ -482,6 +485,36 @@ void IRAM_ATTR set_cache_and_start_app( (*entry)(); } +static void update_flash_config(struct flash_hdr* pfhdr) +{ + uint32_t size; + switch(pfhdr->spi_size) { + case SPI_SIZE_1MB: + size = 1; + break; + case SPI_SIZE_2MB: + size = 2; + break; + case SPI_SIZE_4MB: + size = 4; + break; + case SPI_SIZE_8MB: + size = 8; + break; + case SPI_SIZE_16MB: + size = 16; + break; + default: + size = 2; + } + Cache_Read_Disable( 0 ); + // Set flash chip size + SPIParamCfg(g_rom_flashchip.deviceId, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); + // TODO: set mode + // TODO: set frequency + Cache_Flush(0); + Cache_Read_Enable( 0 ); +} void print_flash_info(struct flash_hdr* pfhdr) { diff --git a/components/esp32/include/rom/spi_flash.h b/components/esp32/include/rom/spi_flash.h index ba8eebc2ce..1f14c6617a 100644 --- a/components/esp32/include/rom/spi_flash.h +++ b/components/esp32/include/rom/spi_flash.h @@ -218,7 +218,7 @@ void SelectSpiFunction(uint32_t ishspi); void spi_flash_attach(uint32_t ishspi, bool legacy); /** - * @brief SPI Read Flash status register. We use CMD 0x05. + * @brief SPI Read Flash status register. We use CMD 0x05 (RDSR). * Please do not call this function in SDK. * * @param SpiFlashChip *spi : The information for Flash, which is exported from ld file. @@ -232,7 +232,7 @@ void spi_flash_attach(uint32_t ishspi, bool legacy); SpiFlashOpResult SPI_read_status(SpiFlashChip *spi, uint32_t *status); /** - * @brief SPI Read Flash status register high 16 bit. We use CMD 0x35. + * @brief SPI Read Flash status register bits 8-15. We use CMD 0x35 (RDSR2). * Please do not call this function in SDK. * * @param SpiFlashChip *spi : The information for Flash, which is exported from ld file. @@ -243,7 +243,7 @@ SpiFlashOpResult SPI_read_status(SpiFlashChip *spi, uint32_t *status); * SPI_FLASH_RESULT_ERR : read error. * SPI_FLASH_RESULT_TIMEOUT : read timeout. */ -SpiFlashOpResult SPI_read_status_high(SpiFlashChip *spi, uint32_t *status); +SpiFlashOpResult SPI_read_status_high(uint32_t *status); /** * @brief Write status to Falsh status register. @@ -503,6 +503,12 @@ void SPI_Write_Encrypt_Disable(void); */ SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, uint32_t *data, uint32_t len); + +/** @brief Global SpiFlashChip structure used by ROM functions + * + */ +extern SpiFlashChip g_rom_flashchip; + /** * @} */ diff --git a/components/esp32/ld/esp32.rom.ld b/components/esp32/ld/esp32.rom.ld index cc14d3258a..5266a679be 100644 --- a/components/esp32/ld/esp32.rom.ld +++ b/components/esp32/ld/esp32.rom.ld @@ -286,6 +286,7 @@ PROVIDE ( _global_impure_ptr = 0x3ffae0b0 ); PROVIDE ( gmtime = 0x40059848 ); PROVIDE ( gmtime_r = 0x40059868 ); PROVIDE ( g_phyFuns_instance = 0x3ffae0c4 ); +PROVIDE ( g_rom_flashchip = 0x3ffae270 ); PROVIDE ( gpio_init = 0x40009c20 ); PROVIDE ( gpio_input_get = 0x40009b88 ); PROVIDE ( gpio_input_get_high = 0x40009b9c ); @@ -1584,6 +1585,8 @@ 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 ); @@ -1595,9 +1598,8 @@ PROVIDE ( SPIReadModeCnfig = 0x40062944 ); PROVIDE ( SPI_read_status = 0x4006226c ); /* This is static function, but can be used, not generated by script*/ PROVIDE ( SPI_read_status_high = 0x40062448 ); -PROVIDE ( SPIUnlock = 0x400628b0 ); PROVIDE ( SPI_user_command_read = 0x400621b0 ); -PROVIDE ( spi_w25q16 = 0x3ffae270 ); +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 ); diff --git a/components/esptool_py/Kconfig.projbuild b/components/esptool_py/Kconfig.projbuild index 3da802296a..8bab51225e 100644 --- a/components/esptool_py/Kconfig.projbuild +++ b/components/esptool_py/Kconfig.projbuild @@ -94,4 +94,31 @@ config ESPTOOLPY_FLASHFREQ default "26m" if ESPTOOLPY_FLASHFREQ_26M default "20m" if ESPTOOLPY_FLASHFREQ_20M + +choice ESPTOOLPY_FLASHSIZE + prompt "Flash size" + default ESPTOOLPY_FLASHSIZE_2MB + help + SPI flash size, in megabytes + +config ESPTOOLPY_FLASHSIZE_1MB + bool "1 MB" +config ESPTOOLPY_FLASHSIZE_2MB + bool "2 MB" +config ESPTOOLPY_FLASHSIZE_4MB + bool "4 MB" +config ESPTOOLPY_FLASHSIZE_8MB + bool "8 MB" +config ESPTOOLPY_FLASHSIZE_16MB + bool "16 MB" +endchoice + +config ESPTOOLPY_FLASHSIZE + string + default "1MB" if ESPTOOLPY_FLASHSIZE_1MB + default "2MB" if ESPTOOLPY_FLASHSIZE_2MB + default "4MB" if ESPTOOLPY_FLASHSIZE_4MB + default "8MB" if ESPTOOLPY_FLASHSIZE_8MB + default "16MB" if ESPTOOLPY_FLASHSIZE_16MB + endmenu diff --git a/components/esptool_py/Makefile.projbuild b/components/esptool_py/Makefile.projbuild index 4d0dd1b3e5..69c01e1e7f 100644 --- a/components/esptool_py/Makefile.projbuild +++ b/components/esptool_py/Makefile.projbuild @@ -4,6 +4,7 @@ ESPPORT ?= $(CONFIG_ESPTOOLPY_PORT) ESPBAUD ?= $(CONFIG_ESPTOOLPY_BAUD) ESPFLASHMODE ?= $(CONFIG_ESPTOOLPY_FLASHMODE) ESPFLASHFREQ ?= $(CONFIG_ESPTOOLPY_FLASHFREQ) +ESPFLASHSIZE ?= $(CONFIG_ESPTOOLPY_FLASHSIZE) PYTHON ?= $(call dequote,$(CONFIG_PYTHON)) @@ -15,13 +16,15 @@ ESPTOOLPY_SRC := $(COMPONENT_PATH)/esptool/esptool.py ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32 ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD) +ESPTOOL_FLASH_OPTIONS := --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) --flash_size $(ESPFLASHSIZE) + # the no-stub argument is temporary until esptool.py fully supports compressed uploads -ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) +ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) $(ESPTOOL_FLASH_OPTIONS) ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN) $(APP_BIN): $(APP_ELF) $(ESPTOOLPY_SRC) - $(Q) $(ESPTOOLPY) elf2image --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) -o $@ $< + $(Q) $(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) -o $@ $< flash: all_binaries $(ESPTOOLPY_SRC) @echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..." diff --git a/components/esptool_py/esptool b/components/esptool_py/esptool index 197ba605fe..5c6962e894 160000 --- a/components/esptool_py/esptool +++ b/components/esptool_py/esptool @@ -1 +1 @@ -Subproject commit 197ba605fe0c05e16bf4c5ec07b726adc8d86abc +Subproject commit 5c6962e894e0a118c9a4b5760876433493449260 diff --git a/components/spi_flash/component.mk b/components/spi_flash/component.mk index ef497a7ecb..459da06419 100755 --- a/components/spi_flash/component.mk +++ b/components/spi_flash/component.mk @@ -1,3 +1,8 @@ COMPONENT_ADD_INCLUDEDIRS := include +ifdef IS_BOOTLOADER_BUILD +# Bootloader needs updated SPIUnlock from this file +COMPONENT_OBJS := spi_flash_rom_patch.o +endif + include $(IDF_PATH)/make/component_common.mk diff --git a/components/spi_flash/spi_flash_rom_patch.c b/components/spi_flash/spi_flash_rom_patch.c new file mode 100644 index 0000000000..7e23beaea2 --- /dev/null +++ b/components/spi_flash/spi_flash_rom_patch.c @@ -0,0 +1,72 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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/spi_flash.h" +#include "soc/spi_reg.h" + +static const uint32_t STATUS_QIE_BIT = (1 << 9); /* Quad Enable */ + +#define SPI_IDX 1 +#define OTH_IDX 0 + +extern SpiFlashChip SPI_flashchip_data; + +static void IRAM_ATTR Wait_SPI_Idle(void) +{ + /* 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) { + } +} + +/* Modified version of SPIUnlock() that replaces version in ROM. + + This works around a bug where SPIUnlock 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. + + Like other ROM SPI functions, this function is not designed to be + called directly from an RTOS environment without taking precautions + about interrupts, CPU coordination, flash mapping. However some of + the functions in esp_spi_flash.c call it. + */ +SpiFlashOpResult IRAM_ATTR SPIUnlock(void) +{ + uint32_t status; + + Wait_SPI_Idle(); + + if (SPI_read_status_high(&status) != SPI_FLASH_RESULT_OK) { + return SPI_FLASH_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; + + 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(); + + 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; + } + + return SPI_FLASH_RESULT_OK; +}