You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/09/28 01:22:01 UTC

[incubator-nuttx] 01/03: xtensa/esp32s2: Enable booting from MCUboot bootloader

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 800678ca789eb96b1fe07f06e44130cbeda4dca2
Author: Gustavo Henrique Nihei <gu...@espressif.com>
AuthorDate: Mon Sep 13 13:56:55 2021 -0300

    xtensa/esp32s2: Enable booting from MCUboot bootloader
    
    Signed-off-by: Gustavo Henrique Nihei <gu...@espressif.com>
---
 arch/xtensa/src/esp32s2/Kconfig                    | 132 +++++++++-
 arch/xtensa/src/esp32s2/esp32s2_start.c            | 265 ++++++++++++++++++---
 .../src/esp32s2/hardware/esp32s2_cache_memory.h    | 153 ++++++++++++
 arch/xtensa/src/esp32s2/hardware/esp32s2_extmem.h  |  69 ++++++
 .../esp32s2/esp32s2-saola-1/scripts/Make.defs      |  10 +-
 .../esp32s2-saola-1/scripts/esp32s2.template.ld    |  73 +++++-
 .../esp32s2-saola-1/scripts/esp32s2_flash.ld       |   2 +-
 .../{esp32s2_flash.ld => esp32s2_mcuboot.ld}       | 241 +++++++++++++------
 .../esp32s2/esp32s2-saola-1/scripts/esp32s2_rom.ld |   8 +-
 tools/esp32s2/Config.mk                            | 108 +++++++--
 10 files changed, 911 insertions(+), 150 deletions(-)

diff --git a/arch/xtensa/src/esp32s2/Kconfig b/arch/xtensa/src/esp32s2/Kconfig
index c529b52..09bc35e 100644
--- a/arch/xtensa/src/esp32s2/Kconfig
+++ b/arch/xtensa/src/esp32s2/Kconfig
@@ -176,14 +176,6 @@ config ESP32S2_RT_TIMER
 	select ESP32S2_TIMER
 	default n
 
-config ESP32S2_PARTITION
-	bool "ESP32S2 Partition"
-	default n
-	select ESP32S2_SPIFLASH
-	---help---
-		Decode esp-idf's partition file and initialize
-		partition by nuttx MTD.
-
 config ESP32S2_RUN_IRAM
 	bool "Run from IRAM"
 	default n
@@ -620,9 +612,50 @@ endmenu # ESP32S2_SPI
 menu "SPI Flash configuration"
 	depends on ESP32S2_SPIFLASH
 
+if ESP32S2_HAVE_OTA_PARTITION
+
+comment "Application Image OTA Update support"
+
+config ESP32S2_OTA_PRIMARY_SLOT_OFFSET
+	hex "Application image primary slot offset"
+	default "0x10000"
+
+config ESP32S2_OTA_PRIMARY_SLOT_DEVPATH
+	string "Application image primary slot device path"
+	default "/dev/ota0"
+
+config ESP32S2_OTA_SECONDARY_SLOT_OFFSET
+	hex "Application image secondary slot offset"
+	default "0x110000"
+
+config ESP32S2_OTA_SECONDARY_SLOT_DEVPATH
+	string "Application image secondary slot device path"
+	default "/dev/ota1"
+
+config ESP32S2_OTA_SLOT_SIZE
+	hex "Application image slot size (in bytes)"
+	default "0x100000"
+
+config ESP32S2_OTA_SCRATCH_OFFSET
+	hex "Scratch partition offset"
+	default "0x210000"
+
+config ESP32S2_OTA_SCRATCH_SIZE
+	hex "Scratch partition size"
+	default "0x40000"
+
+config ESP32S2_OTA_SCRATCH_DEVPATH
+	string "Scratch partition device path"
+	default "/dev/otascratch"
+
+endif
+
+comment "General MTD configuration"
+
 config ESP32S2_MTD_OFFSET
 	hex "MTD base address in SPI Flash"
-	default 0x180000
+	default 0x180000 if !ESP32S2_HAVE_OTA_PARTITION
+	default 0x250000 if ESP32S2_HAVE_OTA_PARTITION
 	---help---
 		MTD base address in SPI Flash.
 
@@ -640,7 +673,7 @@ config ESP32S2_SPIFLASH_DEBUG
 		Enable this option, read and write of SPI Flash
 		will show input arguments and result.
 
-endmenu # ESP32S2_SPIFLASH
+endmenu # SPI Flash configuration
 
 menu "SPI RAM Config"
 	depends on ESP32S2_SPIRAM
@@ -866,6 +899,81 @@ config ESP32S2_FREERUN
 endmenu # Timer/counter Configuration
 endif # ESP32S2_TIMER
 
+config ESP32S2_HAVE_OTA_PARTITION
+	bool
+	default n
+
+menu "Application Image Configuration"
+
+choice
+	prompt "Application Image Format"
+	default ESP32S2_APP_FORMAT_LEGACY
+	---help---
+		Depending on the chosen 2nd stage bootloader, the application may
+		be required to be perform a specific startup routine. Furthermore,
+		the image binary must be formatted according to the definition from
+		the 2nd stage bootloader.
+
+config ESP32S2_APP_FORMAT_LEGACY
+	bool "Legacy format"
+	---help---
+		This is the legacy application image format, as supported by the ESP-IDF
+		2nd stage bootloader.
+
+config ESP32S2_APP_FORMAT_MCUBOOT
+	bool "MCUboot-bootable format"
+	select ESP32S2_HAVE_OTA_PARTITION
+	depends on EXPERIMENTAL
+	---help---
+		The Espressif port of MCUboot supports the loading of unsegmented firmware
+		images.
+
+comment "MCUboot support depends on CONFIG_EXPERIMENTAL"
+	depends on !EXPERIMENTAL
+
+endchoice # Application Image Format
+
+choice
+	prompt "Target slot for image flashing"
+	default ESP32S2_ESPTOOL_TARGET_PRIMARY
+	depends on ESP32S2_HAVE_OTA_PARTITION
+	---help---
+		Slot to which ESPTOOL will flash the generated binary image.
+
+config ESP32S2_ESPTOOL_TARGET_PRIMARY
+	bool "Application image primary slot"
+	---help---
+		This assumes that the generated image is already pre-validated.
+		This is the recommended option for the initial stages of the
+		application firmware image development.
+
+config ESP32S2_ESPTOOL_TARGET_SECONDARY
+	bool "Application image secondary slot"
+	---help---
+		The application needs to confirm the generated image as valid,
+		otherwise the bootloader may consider it invalid and perform the
+		rollback of the update after a reset.
+		This is the choice most suitable for the development and verification
+		of a secure firmware update workflow.
+
+endchoice
+
+config ESP32S2_APP_MCUBOOT_HEADER_SIZE
+	int "Application image header size (in bytes)"
+	default 32
+	depends on ESP32S2_APP_FORMAT_MCUBOOT
+
+endmenu # Application Image Configuration
+
+if ESP32S2_APP_FORMAT_LEGACY
+
+config ESP32S2_PARTITION
+	bool "ESP32-S2 Partition"
+	default n
+	select ESP32S2_SPIFLASH
+	---help---
+		Decode partition file and initialize partition as MTD.
+
 menu "Partition Configuration"
 	depends on ESP32S2_PARTITION
 
@@ -877,7 +985,9 @@ config ESP32S2_PARTITION_MOUNT
 	string "Partition mount point"
 	default "/dev/esp/partition/"
 
-endmenu # ESP32S2_PARTITION
+endmenu # Partition Configuration
+
+endif
 
 menu "AES accelerate"
 	depends on ESP32S2_AES_ACCELERATOR
diff --git a/arch/xtensa/src/esp32s2/esp32s2_start.c b/arch/xtensa/src/esp32s2/esp32s2_start.c
index a6a883a..18dfe34 100644
--- a/arch/xtensa/src/esp32s2/esp32s2_start.c
+++ b/arch/xtensa/src/esp32s2/esp32s2_start.c
@@ -33,7 +33,8 @@
 #include "xtensa.h"
 #include "xtensa_attr.h"
 
-#include "hardware/esp32s2_rtccntl.h"
+#include "hardware/esp32s2_cache_memory.h"
+#include "hardware/esp32s2_extmem.h"
 #include "esp32s2_clockconfig.h"
 #include "esp32s2_region.h"
 #include "esp32s2_start.h"
@@ -50,6 +51,67 @@
 #  define showprogress(c)
 #endif
 
+#ifdef CONFIG_ESP32S2_APP_FORMAT_MCUBOOT
+
+#define PRIMARY_SLOT_OFFSET   CONFIG_ESP32S2_OTA_PRIMARY_SLOT_OFFSET
+
+#define HDR_ATTR              __attribute__((section(".entry_addr"))) \
+                                __attribute__((used))
+
+/* Cache MMU block size */
+
+#define MMU_BLOCK_SIZE        0x00010000  /* 64 KB */
+
+/* Cache MMU address mask (MMU tables ignore bits which are zero) */
+
+#define MMU_FLASH_MASK        (~(MMU_BLOCK_SIZE - 1))
+
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_APP_FORMAT_MCUBOOT
+extern uint32_t _image_irom_vma;
+extern uint32_t _image_irom_lma;
+extern uint32_t _image_irom_size;
+
+extern uint32_t _image_drom_vma;
+extern uint32_t _image_drom_lma;
+extern uint32_t _image_drom_size;
+#endif
+
+/****************************************************************************
+ * ROM Function Prototypes
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_APP_FORMAT_MCUBOOT
+extern int ets_printf(const char *fmt, ...);
+extern uint32_t cache_suspend_icache(void);
+extern void cache_resume_icache(uint32_t val);
+extern void cache_invalidate_icache_all(void);
+extern int cache_ibus_mmu_set(uint32_t ext_ram, uint32_t vaddr,
+                              uint32_t paddr, uint32_t psize, uint32_t num,
+                              uint32_t fixed);
+#endif
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_APP_FORMAT_MCUBOOT
+noreturn_function void __start(void);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_APP_FORMAT_MCUBOOT
+HDR_ATTR static void (*_entry_point)(void) = &__start;
+#endif
+
 /****************************************************************************
  * Public Data
  ****************************************************************************/
@@ -60,29 +122,28 @@ uint32_t g_idlestack[IDLETHREAD_STACKWORDS]
   aligned_data(16) locate_data(".noinit");
 
 /****************************************************************************
- * Public Functions
+ * Private Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: __start
+ * Name: __esp32s2_start
  *
  * Description:
- *   We arrive here after the bootloader finished loading the program from
- *   flash. The hardware is mostly uninitialized, and the app CPU is in
- *   reset. We do have a stack, so we can do the initialization in C.
+ *   Perform base configuration of the chip for code execution.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
  *
  ****************************************************************************/
 
-void IRAM_ATTR __start(void)
+void IRAM_ATTR __esp32s2_start(void)
 {
-  uint32_t *dest;
   uint32_t regval;
   uint32_t sp;
 
-  /* Disable any wdt enabled by bootloader */
-
-  esp32s2_wdt_early_deinit();
-
   regval  = getreg32(DR_REG_BB_BASE + 0x48); /* DR_REG_BB_BASE+48 */
   regval &= ~(1 << 14);
   putreg32(regval, DR_REG_BB_BASE + 0x48);
@@ -95,18 +156,6 @@ void IRAM_ATTR __start(void)
 
   up_irq_disable();
 
-  /* Set CPU frequency configured in board.h */
-
-  esp32s2_clockconfig();
-
-  esp32s2_lowsetup();
-
-#ifdef USE_EARLYSERIALINIT
-  /* Perform early serial initialization */
-
-  xtensa_earlyserialinit();
-#endif
-
   /* Move the stack to a known location.  Although we were given a stack
    * pointer at start-up, we don't know where that stack pointer is
    * positioned with respect to our memory map.  The only safe option is to
@@ -124,29 +173,187 @@ void IRAM_ATTR __start(void)
 
   __asm__ __volatile__ ("wsr %0, vecbase\n"::"r" (&_init_start));
 
-  showprogress('A');
-
   /* Set .bss to zero */
 
   /* Clear .bss.  We'll do this inline (vs. calling memset) just to be
    * certain that there are no issues with the state of global variables.
    */
 
-  for (dest = &_sbss; dest < &_ebss; dest++)
+  for (uint32_t *dest = &_sbss; dest < &_ebss; dest++)
     {
       *dest = 0;
     }
 
-  showprogress('B');
+  /* The 2nd stage bootloader enables RTC WDT to check on startup sequence
+   * related issues in application. Hence disable that as we are about to
+   * start the NuttX environment.
+   */
+
+  esp32s2_wdt_early_deinit();
+
+  /* Set CPU frequency configured in board.h */
+
+  esp32s2_clockconfig();
+
+#ifndef CONFIG_SUPPRESS_UART_CONFIG
+  /* Configure the UART so we can get debug output */
+
+  esp32s2_lowsetup();
+#endif
+
+#ifdef USE_EARLYSERIALINIT
+  /* Perform early serial initialization */
+
+  xtensa_earlyserialinit();
+#endif
+
+  showprogress('A');
 
   /* Initialize onboard resources */
 
   esp32s2_board_initialize();
 
-  showprogress('C');
+  showprogress('B');
 
   /* Bring up NuttX */
 
   nx_start();
   for (; ; ); /* Should not return */
 }
+
+/****************************************************************************
+ * Name: calc_mmu_pages
+ *
+ * Description:
+ *   Calculate the number of cache pages to map.
+ *
+ * Input Parameters:
+ *   size  - Size of data to map
+ *   vaddr - Virtual address where data will be mapped
+ *
+ * Returned Value:
+ *   Number of cache MMU pages required to do the mapping.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_APP_FORMAT_MCUBOOT
+static inline uint32_t calc_mmu_pages(uint32_t size, uint32_t vaddr)
+{
+  return (size + (vaddr - (vaddr & MMU_FLASH_MASK)) + MMU_BLOCK_SIZE - 1) /
+    MMU_BLOCK_SIZE;
+}
+#endif
+
+/****************************************************************************
+ * Name: map_rom_segments
+ *
+ * Description:
+ *   Configure the MMU and Cache peripherals for accessing ROM code and data.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_APP_FORMAT_MCUBOOT
+static int map_rom_segments(void)
+{
+  uint32_t rc = 0;
+  uint32_t regval;
+  uint32_t drom_lma_aligned;
+  uint32_t drom_vma_aligned;
+  uint32_t drom_page_count;
+  uint32_t irom_lma_aligned;
+  uint32_t irom_vma_aligned;
+  uint32_t irom_page_count;
+
+  size_t partition_offset = PRIMARY_SLOT_OFFSET;
+  uint32_t app_irom_lma = partition_offset + (uint32_t)&_image_irom_lma;
+  uint32_t app_irom_size = (uint32_t)&_image_irom_size;
+  uint32_t app_irom_vma = (uint32_t)&_image_irom_vma;
+  uint32_t app_drom_lma = partition_offset + (uint32_t)&_image_drom_lma;
+  uint32_t app_drom_size = (uint32_t)&_image_drom_size;
+  uint32_t app_drom_vma = (uint32_t)&_image_drom_vma;
+
+  uint32_t autoload = cache_suspend_icache();
+  cache_invalidate_icache_all();
+
+  /* Clear the MMU entries that are already set up, so the new app only has
+   * the mappings it creates.
+   */
+
+  for (size_t i = 0; i < FLASH_MMU_TABLE_SIZE; i++)
+    {
+      FLASH_MMU_TABLE[i] = MMU_TABLE_INVALID_VAL;
+    }
+
+  drom_lma_aligned = app_drom_lma & MMU_FLASH_MASK;
+  drom_vma_aligned = app_drom_vma & MMU_FLASH_MASK;
+  drom_page_count = calc_mmu_pages(app_drom_size, app_drom_vma);
+  rc = cache_ibus_mmu_set(MMU_ACCESS_FLASH, drom_vma_aligned,
+                           drom_lma_aligned, 64, (int)drom_page_count, 0);
+
+  irom_lma_aligned = app_irom_lma & MMU_FLASH_MASK;
+  irom_vma_aligned = app_irom_vma & MMU_FLASH_MASK;
+  irom_page_count = calc_mmu_pages(app_irom_size, app_irom_vma);
+
+  if (app_irom_lma + app_irom_size > IRAM1_ADDRESS_LOW)
+    {
+      rc |= cache_ibus_mmu_set(MMU_ACCESS_FLASH, IRAM0_ADDRESS_LOW, 0, 64,
+                               64, 1);
+      rc |= cache_ibus_mmu_set(MMU_ACCESS_FLASH, IRAM1_ADDRESS_LOW, 0, 64,
+                               64, 1);
+
+      regval  = getreg32(EXTMEM_PRO_ICACHE_CTRL1_REG);
+      regval &= ~(EXTMEM_PRO_ICACHE_MASK_IRAM1);
+      putreg32(regval, EXTMEM_PRO_ICACHE_CTRL1_REG);
+    }
+
+  rc |= cache_ibus_mmu_set(MMU_ACCESS_FLASH, irom_vma_aligned,
+                           irom_lma_aligned, 64, (int)irom_page_count, 0);
+
+  regval  = getreg32(EXTMEM_PRO_ICACHE_CTRL1_REG);
+  regval &= ~(EXTMEM_PRO_ICACHE_MASK_IRAM0 |
+              EXTMEM_PRO_ICACHE_MASK_DROM0);
+  putreg32(regval, EXTMEM_PRO_ICACHE_CTRL1_REG);
+
+  cache_resume_icache(autoload);
+
+  return (int)rc;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: __start
+ *
+ * Description:
+ *   We arrive here after the bootloader finished loading the program from
+ *   flash. The hardware is mostly uninitialized, and the app CPU is in
+ *   reset. We do have a stack, so we can do the initialization in C.
+ *
+ *   The app CPU will remain in reset unless CONFIG_SMP is selected and
+ *   up_cpu_start() is called later in the bring-up sequence.
+ *
+ ****************************************************************************/
+
+void __start(void)
+{
+#ifdef CONFIG_ESP32S2_APP_FORMAT_MCUBOOT
+  if (map_rom_segments() != 0)
+    {
+      ets_printf("Failed to setup XIP, aborting\n");
+      while (true);
+    }
+
+#endif
+  __esp32s2_start();
+
+  while (true); /* Should not return */
+}
diff --git a/arch/xtensa/src/esp32s2/hardware/esp32s2_cache_memory.h b/arch/xtensa/src/esp32s2/hardware/esp32s2_cache_memory.h
new file mode 100644
index 0000000..2812646
--- /dev/null
+++ b/arch/xtensa/src/esp32s2/hardware/esp32s2_cache_memory.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/hardware/esp32s2_cache_memory.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_CACHE_MEMORY_H_
+#define __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_CACHE_MEMORY_H_
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+
+#include "esp32s2_soc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* IRAM0 is connected with Cache IBUS0 */
+
+#define IRAM0_ADDRESS_LOW               0x40000000
+#define IRAM0_ADDRESS_HIGH              0x40400000
+#define IRAM0_CACHE_ADDRESS_LOW         0x40080000
+#define IRAM0_CACHE_ADDRESS_HIGH        0x40400000
+
+/* IRAM1 is connected with Cache IBUS1 */
+
+#define IRAM1_ADDRESS_LOW               0x40400000
+#define IRAM1_ADDRESS_HIGH              0x40800000
+
+/* DROM0 is connected with Cache IBUS2 */
+
+#define DROM0_ADDRESS_LOW               0x3f000000
+#define DROM0_ADDRESS_HIGH              0x3f400000
+
+/* DRAM0 is connected with Cache DBUS0 */
+
+#define DRAM0_ADDRESS_LOW               0x3fc00000
+#define DRAM0_ADDRESS_HIGH              0x40000000
+#define DRAM0_CACHE_ADDRESS_LOW         0x3fc00000
+#define DRAM0_CACHE_ADDRESS_HIGH        0x3ff80000
+
+/* DRAM1 is connected with Cache DBUS1 */
+
+#define DRAM1_ADDRESS_LOW               0x3f800000
+#define DRAM1_ADDRESS_HIGH              0x3fc00000
+
+/* DPORT is connected with Cache DBUS2 */
+
+#define DPORT_ADDRESS_LOW               0x3f400000
+#define DPORT_ADDRESS_HIGH              0x3f800000
+#define DPORT_CACHE_ADDRESS_LOW         0x3f500000
+#define DPORT_CACHE_ADDRESS_HIGH        0x3f800000
+
+#define BUS_SIZE(bus_name)              (bus_name##_ADDRESS_HIGH - \
+                                            bus_name##_ADDRESS_LOW)
+#define ADDRESS_IN_BUS(bus_name, vaddr) ((vaddr) >= bus_name##_ADDRESS_LOW \
+                                            && (vaddr) < \
+                                                bus_name##_ADDRESS_HIGH)
+
+#define ADDRESS_IN_IRAM0(vaddr)         ADDRESS_IN_BUS(IRAM0, vaddr)
+#define ADDRESS_IN_IRAM0_CACHE(vaddr)   ADDRESS_IN_BUS(IRAM0_CACHE, vaddr)
+#define ADDRESS_IN_IRAM1(vaddr)         ADDRESS_IN_BUS(IRAM1, vaddr)
+#define ADDRESS_IN_DROM0(vaddr)         ADDRESS_IN_BUS(DROM0, vaddr)
+#define ADDRESS_IN_DRAM0(vaddr)         ADDRESS_IN_BUS(DRAM0, vaddr)
+#define ADDRESS_IN_DRAM0_CACHE(vaddr)   ADDRESS_IN_BUS(DRAM0_CACHE, vaddr)
+#define ADDRESS_IN_DRAM1(vaddr)         ADDRESS_IN_BUS(DRAM1, vaddr)
+#define ADDRESS_IN_DPORT(vaddr)         ADDRESS_IN_BUS(DPORT, vaddr)
+#define ADDRESS_IN_DPORT_CACHE(vaddr)   ADDRESS_IN_BUS(DPORT_CACHE, vaddr)
+
+#define BUS_IRAM0_CACHE_SIZE            BUS_SIZE(IRAM0_CACHE)
+#define BUS_IRAM1_CACHE_SIZE            BUS_SIZE(IRAM1)
+#define BUS_IROM0_CACHE_SIZE            BUS_SIZE(IROM0)
+#define BUS_DROM0_CACHE_SIZE            BUS_SIZE(DROM0)
+#define BUS_DRAM0_CACHE_SIZE            BUS_SIZE(DRAM0_CACHE)
+#define BUS_DRAM1_CACHE_SIZE            BUS_SIZE(DRAM1)
+#define BUS_DPORT_CACHE_SIZE            BUS_SIZE(DPORT)
+
+#define PRO_CACHE_IBUS0                 0
+#define PRO_CACHE_IBUS0_MMU_START       0
+#define PRO_CACHE_IBUS0_MMU_END         0x100
+
+#define PRO_CACHE_IBUS1                 1
+#define PRO_CACHE_IBUS1_MMU_START       0x100
+#define PRO_CACHE_IBUS1_MMU_END         0x200
+
+#define PRO_CACHE_IBUS2                 2
+#define PRO_CACHE_IBUS2_MMU_START       0x200
+#define PRO_CACHE_IBUS2_MMU_END         0x300
+
+#define PRO_CACHE_DBUS0                 3
+#define PRO_CACHE_DBUS0_MMU_START       0x300
+#define PRO_CACHE_DBUS0_MMU_END         0x400
+
+#define PRO_CACHE_DBUS1                 4
+#define PRO_CACHE_DBUS1_MMU_START       0x400
+#define PRO_CACHE_DBUS1_MMU_END         0x500
+
+#define PRO_CACHE_DBUS2                 5
+#define PRO_CACHE_DBUS2_MMU_START       0x500
+#define PRO_CACHE_DBUS2_MMU_END         0x600
+
+#define ICACHE_MMU_SIZE                 0x300
+#define DCACHE_MMU_SIZE                 0x300
+
+#define MMU_BUS_START(i)                ((i) * 0x100)
+#define MMU_BUS_SIZE                    0x100
+
+#define MMU_INVALID                     BIT(14)
+#define MMU_ACCESS_FLASH                BIT(15)
+#define MMU_ACCESS_SPIRAM               BIT(16)
+
+#define FLASH_MMU_TABLE             ((volatile uint32_t *)DR_REG_MMU_TABLE)
+#define FLASH_MMU_TABLE_SIZE        (ICACHE_MMU_SIZE / sizeof(uint32_t))
+
+#define MMU_TABLE_INVALID_VAL           0x4000
+#define FLASH_MMU_TABLE_INVALID_VAL     DPORT_MMU_TABLE_INVALID_VAL
+#define MMU_ADDRESS_MASK                0x3fff
+#define MMU_PAGE_SIZE                   0x10000
+
+#define BUS_ADDR_SIZE                   0x400000
+#define BUS_ADDR_MASK                   (BUS_ADDR_SIZE - 1)
+#define BUS_NUM_MASK                    0x3
+
+#define CACHE_MEMORY_BANK_SIZE          8192
+#define CACHE_MEMORY_BANK_NUM           4
+#define CACHE_MEMORY_BANK_NUM_MASK      0x3
+#define CACHE_MEMORY_LAYOUT_SHIFT       4
+#define CACHE_MEMORY_LAYOUT_SHIFT0      0
+#define CACHE_MEMORY_LAYOUT_SHIFT1      4
+#define CACHE_MEMORY_LAYOUT_SHIFT2      8
+#define CACHE_MEMORY_LAYOUT_SHIFT3      12
+#define CACHE_MEMORY_LAYOUT_MASK        0xf
+#define CACHE_MEMORY_BANK0_ADDR         0x3ffb0000
+#define CACHE_MEMORY_BANK1_ADDR         0x3ffb2000
+#define CACHE_MEMORY_BANK2_ADDR         0x3ffb4000
+#define CACHE_MEMORY_BANK3_ADDR         0x3ffb6000
+
+#endif /* __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_CACHE_MEMORY_H_ */
diff --git a/arch/xtensa/src/esp32s2/hardware/esp32s2_extmem.h b/arch/xtensa/src/esp32s2/hardware/esp32s2_extmem.h
new file mode 100644
index 0000000..5fdd8e2
--- /dev/null
+++ b/arch/xtensa/src/esp32s2/hardware/esp32s2_extmem.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/hardware/esp32s2_extmem.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_EXTMEM_H_
+#define __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_EXTMEM_H_
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include "esp32s2_soc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define EXTMEM_PRO_ICACHE_CTRL1_REG         (DR_REG_EXTMEM_BASE + 0x044)
+
+/* EXTMEM_PRO_ICACHE_MASK_BUS2 : R/W ;bitpos:[2] ;default: 1'b1 ;
+ * description: The bit is used to disable ibus2
+ * 0: enable  1: disable
+ */
+
+#define EXTMEM_PRO_ICACHE_MASK_BUS2         (BIT(2))
+#define EXTMEM_PRO_ICACHE_MASK_BUS2_M       (BIT(2))
+#define EXTMEM_PRO_ICACHE_MASK_BUS2_V       0x1
+#define EXTMEM_PRO_ICACHE_MASK_BUS2_S       2
+
+/* EXTMEM_PRO_ICACHE_MASK_BUS1 : R/W ;bitpos:[1] ;default: 1'b1 ;
+ * description: The bit is used to disable ibus1
+ * 0: enable  1: disable
+ */
+
+#define EXTMEM_PRO_ICACHE_MASK_BUS1         (BIT(1))
+#define EXTMEM_PRO_ICACHE_MASK_BUS1_M       (BIT(1))
+#define EXTMEM_PRO_ICACHE_MASK_BUS1_V       0x1
+#define EXTMEM_PRO_ICACHE_MASK_BUS1_S       1
+
+/* EXTMEM_PRO_ICACHE_MASK_BUS0 : R/W ;bitpos:[0] ;default: 1'b1 ;
+ * description: The bit is used to disable ibus0
+ * 0: enable  1: disable
+ */
+
+#define EXTMEM_PRO_ICACHE_MASK_BUS0         (BIT(0))
+#define EXTMEM_PRO_ICACHE_MASK_BUS0_M       (BIT(0))
+#define EXTMEM_PRO_ICACHE_MASK_BUS0_V       0x1
+#define EXTMEM_PRO_ICACHE_MASK_BUS0_S       0
+#define EXTMEM_PRO_ICACHE_MASK_IRAM0        EXTMEM_PRO_ICACHE_MASK_BUS0
+#define EXTMEM_PRO_ICACHE_MASK_IRAM1        EXTMEM_PRO_ICACHE_MASK_BUS1
+#define EXTMEM_PRO_ICACHE_MASK_DROM0        EXTMEM_PRO_ICACHE_MASK_BUS2
+
+#endif /* __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_EXTMEM_H_ */
diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/Make.defs b/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/Make.defs
index addad88..b757289 100644
--- a/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/Make.defs
+++ b/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/Make.defs
@@ -27,10 +27,14 @@ LDSCRIPT1 = $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32s2_out.ld
 LDSCRIPT3 = $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32s2_rom.ld
 LDSCRIPT4 = $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32s2_peripherals.ld
 
-ifeq ($(CONFIG_ESP32S2_RUN_IRAM),y)
-  LDSCRIPT2 = $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32s2_iram.ld
+ifeq ($(CONFIG_ESP32S2_APP_FORMAT_MCUBOOT),y)
+  LDSCRIPT2 = $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32s2_mcuboot.ld
 else
-  LDSCRIPT2 = $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32s2_flash.ld
+  ifeq ($(CONFIG_ESP32S2_RUN_IRAM),y)
+    LDSCRIPT2 = $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32s2_iram.ld
+  else
+    LDSCRIPT2 = $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32s2_flash.ld
+  endif
 endif
 
 ifeq ($(CONFIG_CYGWIN_WINTOOL),y)
diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2.template.ld b/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2.template.ld
index 3617280..f4811bb 100644
--- a/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2.template.ld
+++ b/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2.template.ld
@@ -46,9 +46,34 @@
 
 #define I_D_RAM_SIZE   DATA_RAM_END - DRAM_ORG
 
+#ifdef CONFIG_ESP32S2_FLASH_2M
+#  define FLASH_SIZE        0x200000
+#elif defined (CONFIG_ESP32S2_FLASH_4M)
+#  define FLASH_SIZE        0x400000
+#elif defined (CONFIG_ESP32S2_FLASH_8M)
+#  define FLASH_SIZE        0x800000
+#elif defined (CONFIG_ESP32S2_FLASH_16M)
+#  define FLASH_SIZE        0x1000000
+#endif
+
 MEMORY
 {
-  /* All these values assume the flash cache is on, and have the blocks this
+#ifdef CONFIG_ESP32S2_APP_FORMAT_MCUBOOT
+  /* The origin values for "metadata" and "ROM" memory regions are the actual
+   * load addresses.
+   *
+   * NOTE: The memory region starting from 0x0 with length represented by
+   * CONFIG_ESP32S2_APP_MCUBOOT_HEADER_SIZE is reserved for the MCUboot header,
+   * which will be prepended to the binary file by the "imgtool" during the
+   * signing of firmware image.
+   */
+
+  metadata (RX) :        org = CONFIG_ESP32S2_APP_MCUBOOT_HEADER_SIZE, len = 0x20
+  ROM (RX) :             org = CONFIG_ESP32S2_APP_MCUBOOT_HEADER_SIZE + 0x20,
+                         len = FLASH_SIZE - (CONFIG_ESP32S2_APP_MCUBOOT_HEADER_SIZE + 0x20)
+#endif
+
+  /* Below values assume the flash cache is on, and have the blocks this
    * uses subtracted from the length of the various regions. The 'data access
    * port' dram/drom regions map to the same iram/irom regions but are
    * connected to the data port of the CPU and eg allow bytewise access.
@@ -58,26 +83,57 @@ MEMORY
 
   iram0_0_seg (RX) :                 org = IRAM_ORG, len = I_D_RAM_SIZE
 
-  /* Even though the segment name is iram, it is actually mapped to flash */
+  /* Flash mapped instruction data. */
 
-  iram0_2_seg (RX) :                 org = 0x40080020, len = 0x780000-0x20
-
-  /* (0x20 offset above is a convenience for the app binary image generation.
+#ifdef CONFIG_ESP32S2_APP_FORMAT_MCUBOOT
+  irom0_0_seg (RX) :                 org = 0x40080020, len = FLASH_SIZE
+#else
+  /* The 0x20 offset is a convenience for the app binary image generation.
    * Flash cache has 64KB pages. The .bin file which is flashed to the chip
    * has a 0x18 byte file header, and each segment has a 0x08 byte segment
    * header. Setting this offset makes it simple to meet the flash cache MMU's
-   * constraint that (paddr % 64KB == vaddr % 64KB).)
+   * constraint that (paddr % 64KB == vaddr % 64KB).
    */
 
+  irom0_0_seg (RX) :                 org = 0x40080020, len = FLASH_SIZE - 0x20
+#endif
+
   /* Shared data RAM, excluding memory reserved for bootloader and ROM
    * bss/data/stack.
    */
 
   dram0_0_seg (RW) :                 org = DRAM_ORG, len = I_D_RAM_SIZE
 
+
+
   /* Flash mapped constant data */
 
-  drom0_0_seg (R) :                  org = 0x3f000020, len = 0x3f0000-0x20
+#ifdef CONFIG_ESP32S2_APP_FORMAT_MCUBOOT
+  /* The DROM segment origin is offset by 0x40 for mirroring the actual ROM
+   * image layout:
+   *    0x0  - 0x1F : MCUboot header
+   *    0x20 - 0x3F : Application image metadata section
+   *    0x40 onwards: ROM code and data
+   * This is required to meet the following constraint from the external
+   * flash MMU:
+   *    VMA % 64KB == LMA % 64KB
+   * i.e. the lower 16 bits of both the virtual address (address seen by the
+   * CPU) and the load address (physical address of the external flash) must
+   * be equal.
+   */
+
+  drom0_0_seg (R) :      org = 0x3f000000 + (CONFIG_ESP32S2_APP_MCUBOOT_HEADER_SIZE + 0x20),
+                         len = FLASH_SIZE - (CONFIG_ESP32S2_APP_MCUBOOT_HEADER_SIZE + 0x20)
+#else
+  /* The 0x20 offset is a convenience for the app binary image generation.
+   * Flash cache has 64KB pages. The .bin file which is flashed to the chip
+   * has a 0x18 byte file header, and each segment has a 0x08 byte segment
+   * header. Setting this offset makes it simple to meet the flash cache MMU's
+   * constraint that (paddr % 64KB == vaddr % 64KB).
+   */
+
+  drom0_0_seg (R) :                  org = 0x3f000020, len = FLASH_SIZE - 0x20
+#endif
 
   /* RTC fast memory (executable). Persists over deep sleep. */
 
@@ -90,5 +146,8 @@ MEMORY
 
   rtc_slow_seg(RW)  :    org = 0x50000000 + CONFIG_ESP32S2_ULP_COPROC_RESERVE_MEM,
                          len = 0x2000 - CONFIG_ESP32S2_ULP_COPROC_RESERVE_MEM
+
+  /* RTC fast memory (same block as above), viewed from data bus */
+  rtc_data_seg(RW)  :                 org = 0x3ff9e000, len = 0x2000
 }
 
diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_flash.ld b/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_flash.ld
index 74acf2f..fa4823e 100644
--- a/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_flash.ld
+++ b/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_flash.ld
@@ -198,7 +198,7 @@ SECTIONS
     . += 16;
 
     _etext = .;
-  } >iram0_2_seg
+  } >irom0_0_seg
 
   .rtc.text :
   {
diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_flash.ld b/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_mcuboot.ld
similarity index 50%
copy from boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_flash.ld
copy to boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_mcuboot.ld
index 74acf2f..a459692 100644
--- a/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_flash.ld
+++ b/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_mcuboot.ld
@@ -1,5 +1,21 @@
 /****************************************************************************
- * boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_flash.ld
+ * boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_mcuboot.ld
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you 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.
+ *
  ****************************************************************************/
 
 /* Default entry point: */
@@ -8,6 +24,95 @@ ENTRY(__start);
 
 SECTIONS
 {
+  .metadata :
+  {
+    /* Magic for load header */
+
+    LONG(0xace637d3)
+
+    /* Application entry point address */
+
+    KEEP(*(.entry_addr))
+
+    /* IRAM metadata:
+     * - Destination address (VMA) for IRAM region
+     * - Flash offset (LMA) for start of IRAM region
+     * - Size of IRAM region
+     */
+
+    LONG(ADDR(.iram0.vectors))
+    LONG(LOADADDR(.iram0.vectors))
+    LONG(LOADADDR(.iram0.text) + SIZEOF(.iram0.text) - LOADADDR(.iram0.vectors))
+
+    /* DRAM metadata:
+     * - Destination address (VMA) for DRAM region
+     * - Flash offset (LMA) for start of DRAM region
+     * - Size of DRAM region
+     */
+
+    LONG(ADDR(.dram0.data))
+    LONG(LOADADDR(.dram0.data))
+    LONG(SIZEOF(.dram0.data))
+  } >metadata
+
+  _image_drom_vma = ADDR(.flash.rodata);
+  _image_drom_lma = LOADADDR(.flash.rodata);
+  _image_drom_size = LOADADDR(.flash.rodata) + SIZEOF(.flash.rodata) - _image_drom_lma;
+
+  .flash.rodata :
+  {
+    _srodata = ABSOLUTE(.);
+    *(EXCLUDE_FILE (esp32s2_start.*) .rodata)
+    *(EXCLUDE_FILE (esp32s2_start.*) .rodata.*)
+
+    *(.srodata.*)
+
+    *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
+    *(.gnu.linkonce.r.*)
+    *(.rodata1)
+    __XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
+    *(.xt_except_table)
+    *(.gcc_except_table .gcc_except_table.*)
+    *(.gnu.linkonce.e.*)
+    *(.gnu.version_r)
+    KEEP(*(.eh_frame))
+    . = (. + 3) & ~ 3;
+
+    /* C++ constructor and destructor tables, properly ordered: */
+
+    _sinit = ABSOLUTE(.);
+    KEEP (*crtbegin.o(.ctors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+    _einit = ABSOLUTE(.);
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+
+    /* C++ exception handlers table: */
+
+    __XT_EXCEPTION_DESCS_ = ABSOLUTE(.);
+    *(.xt_except_desc)
+    *(.gnu.linkonce.h.*)
+    __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
+    *(.xt_except_desc_end)
+    *(.dynamic)
+    *(.gnu.version_d)
+    . = ALIGN(4);               /* This table MUST be 4-byte aligned */
+    _erodata = ABSOLUTE(.);
+
+    /* Literals are also RO data. */
+
+    _lit4_start = ABSOLUTE(.);
+    *(*.lit4)
+    *(.lit4.*)
+    *(.gnu.linkonce.lit4.*)
+    _lit4_end = ABSOLUTE(.);
+    . = ALIGN(4);
+  } >drom0_0_seg AT>ROM
+
   /* Send .iram0 code to iram */
 
   .iram0.vectors :
@@ -47,24 +152,30 @@ SECTIONS
     *(.entry.text)
     *(.init.literal)
     *(.init)
-  } > iram0_0_seg
+    _init_end = ABSOLUTE(.);
+  } >iram0_0_seg AT>ROM
 
   .iram0.text :
   {
     /* Code marked as running out of IRAM */
 
     *(.iram1 .iram1.*)
+    esp32s2_start.*(.literal .text .literal.* .text.*)
 
     /* align + add 16B for CPU dummy speculative instr. fetch */
 
     . = ALIGN(4) + 16;
     _iram_text = ABSOLUTE(.);
-  } > iram0_0_seg
+  } >iram0_0_seg AT>ROM
 
-  .dram0_reserved_for_iram (NOLOAD):
+  .dram0.dummy (NOLOAD):
   {
-    . = ORIGIN(dram0_0_seg) + _iram_text - _iram_start;
-  } > dram0_0_seg
+    /* This section is required to skip .iram0.text area because iram0_0_seg
+     * and dram0_0_seg reflect the same address space on different buses.
+     */
+
+    . = ORIGIN(dram0_0_seg) + _iram_end - _iram_start;
+  } >dram0_0_seg
 
   /* Shared RAM */
 
@@ -100,6 +211,7 @@ SECTIONS
 
     . = ALIGN(4);
     *(.noinit)
+    *(.noinit.*)
     . = ALIGN(4);
   } >dram0_0_seg
 
@@ -120,95 +232,86 @@ SECTIONS
     KEEP (*(.gnu.linkonce.s2.*))
     KEEP (*(.jcr))
     *(.dram1 .dram1.*)
-    . = ALIGN(4);
+    esp32s2_start.*(.rodata .rodata.*)
     _edata = ABSOLUTE(.);
+    . = ALIGN(4);
 
     /* Heap starts at the end of .data */
 
     _sheap = ABSOLUTE(.);
-  } >dram0_0_seg
-
-  .flash.rodata :
-  {
-    _srodata = ABSOLUTE(.);
-    *(.rodata)
-    *(.rodata.*)
-    *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
-    *(.gnu.linkonce.r.*)
-    *(.rodata1)
-    __XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
-    *(.xt_except_table)
-    *(.gcc_except_table)
-    *(.gcc_except_table.*)
-    *(.gnu.linkonce.e.*)
-    *(.gnu.version_r)
-    *(.eh_frame)
+  } >dram0_0_seg AT>ROM
 
-    . = (. + 3) & ~ 3;
+  /* Marks the end of IRAM code segment */
 
-    /* C++ constructor and destructor tables, properly ordered: */
-
-    _sinit = ABSOLUTE(.);
-    KEEP (*crtbegin.o(.ctors))
-    KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
-    KEEP (*(SORT(.ctors.*)))
-    KEEP (*(.ctors))
-    _einit = ABSOLUTE(.);
-    KEEP (*crtbegin.o(.dtors))
-    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
-    KEEP (*(SORT(.dtors.*)))
-    KEEP (*(.dtors))
-
-    /* C++ exception handlers table: */
-
-    __XT_EXCEPTION_DESCS_ = ABSOLUTE(.);
-    *(.xt_except_desc)
-    *(.gnu.linkonce.h.*)
-    __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
-    *(.xt_except_desc_end)
-    *(.dynamic)
-    *(.gnu.version_d)
-    _erodata = ABSOLUTE(.);
-
-    /* Literals are also RO data. */
+  .iram0.text_end (NOLOAD) :
+  {
+    . = ALIGN (4);
+    _iram_end = ABSOLUTE(.);
+  } >iram0_0_seg
+
+  _image_irom_vma = ADDR(.flash.text);
+  _image_irom_lma = LOADADDR(.flash.text);
+  _image_irom_size = LOADADDR(.flash.text) + SIZEOF(.flash.text) - _image_irom_lma;
+
+  /* The alignment of the ".flash.text" output section is forced to
+   * 0x0000FFFF (64KB) to ensure that it will be allocated at the beginning
+   * of the next available Flash block.
+   * This is required to meet the following constraint from the external
+   * flash MMU:
+   *    VMA % 64KB == LMA % 64KB
+   * i.e. the lower 16 bits of both the virtual address (address seen by the
+   * CPU) and the load address (physical address of the external flash) must
+   * be equal.
+   */
+
+  .flash_text_dummy (NOLOAD) : ALIGN(0x0000FFFF)
+  {
+    /* This section is required to skip .flash.rodata area because irom0_0_seg
+     * and drom0_0_seg reflect the same address space on different buses.
+     */
 
-    _lit4_start = ABSOLUTE(.);
-    *(*.lit4)
-    *(.lit4.*)
-    *(.gnu.linkonce.lit4.*)
-    _lit4_end = ABSOLUTE(.);
-    . = ALIGN(4);
-  } >drom0_0_seg
+    . = SIZEOF(.flash.rodata);
+  } >irom0_0_seg
 
-  .flash.text :
+  .flash.text : ALIGN(0x0000FFFF)
   {
     _stext = .;
+
     *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
     *(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */
     *(.fini.literal)
     *(.fini)
     *(.gnu.version)
-
-    /* CPU will try to prefetch up to 16 bytes of instructions.
-     * This means that any configuration (e.g. MMU, PMS) must allow
-     * safe access to up to 16 bytes after the last real instruction, add
-     * dummy bytes to ensure this
-     */
-
-    . += 16;
+    . = ALIGN(4);
 
     _etext = .;
-  } >iram0_2_seg
+  } >irom0_0_seg AT>ROM
 
   .rtc.text :
   {
     . = ALIGN(4);
     *(.rtc.literal .rtc.text)
-  } >rtc_iram_seg
+  } >rtc_iram_seg AT>ROM
+
+  .rtc.dummy (NOLOAD) :
+  {
+    /* This section is required to skip .rtc.text area because the text and
+     * data segments reflect the same address space on different buses.
+     */
+
+    . = SIZEOF(.rtc.text);
+  } >rtc_data_seg
+
+  /* RTC BSS section. */
+
+  .rtc.bss (NOLOAD) :
+  {
+    *(.rtc.bss)
+  } >rtc_data_seg
 
   .rtc.data :
   {
     *(.rtc.data)
     *(.rtc.rodata)
-  } > rtc_slow_seg
+  } >rtc_data_seg AT>ROM
 }
diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_rom.ld b/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_rom.ld
index d6d6e1b..61d252a 100644
--- a/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_rom.ld
+++ b/boards/xtensa/esp32s2/esp32s2-saola-1/scripts/esp32s2_rom.ld
@@ -43,12 +43,12 @@ PROVIDE ( Cache_Get_Memory_BaseAddr = 0x40019244 );
 PROVIDE ( Cache_Get_Memory_value = 0x400192d8 );
 PROVIDE ( Cache_Get_Mode = 0x40017ff0 );
 PROVIDE ( Cache_Get_Virtual_Addr = 0x40019210 );
-PROVIDE ( Cache_Ibus_MMU_Set = 0x40018df4 );
+PROVIDE ( cache_ibus_mmu_set = 0x40018df4 );
 PROVIDE ( Cache_ICache_Preload_Done = 0x4001859c );
 PROVIDE ( Cache_Invalidate_Addr = 0x400182e4 );
 PROVIDE ( Cache_Invalidate_DCache_All = 0x4001842c );
 PROVIDE ( Cache_Invalidate_DCache_Items = 0x40018208 );
-PROVIDE ( Cache_Invalidate_ICache_All = 0x40018420 );
+PROVIDE ( cache_invalidate_icache_all = 0x40018420 );
 PROVIDE ( Cache_Invalidate_ICache_Items = 0x400181b8 );
 PROVIDE ( Cache_Lock_Addr = 0x40018b10 );
 PROVIDE ( Cache_Lock_DCache_Items = 0x40018a80 );
@@ -58,7 +58,7 @@ PROVIDE ( cache_memory_baseaddrs = 0x3ffaf020 );
 PROVIDE ( Cache_MMU_Init = 0x40018dd8 );
 PROVIDE ( Cache_Resume_DCache = 0x40018d3c );
 PROVIDE ( Cache_Resume_DCache_Autoload = 0x4001850c );
-PROVIDE ( Cache_Resume_ICache = 0x40018cdc );
+PROVIDE ( cache_resume_icache = 0x40018cdc );
 PROVIDE ( Cache_Resume_ICache_Autoload = 0x400184c4 );
 PROVIDE ( Cache_Set_DCache_Mode = 0x40018074 );
 PROVIDE ( Cache_Set_Default_Mode = 0x4001810c );
@@ -67,7 +67,7 @@ PROVIDE ( Cache_Start_DCache_Preload = 0x400185c4 );
 PROVIDE ( Cache_Start_ICache_Preload = 0x40018530 );
 PROVIDE ( Cache_Suspend_DCache = 0x40018d04 );
 PROVIDE ( Cache_Suspend_DCache_Autoload = 0x400184e0 );
-PROVIDE ( Cache_Suspend_ICache = 0x40018ca4 );
+PROVIDE ( cache_suspend_icache = 0x40018ca4 );
 PROVIDE ( Cache_Suspend_ICache_Autoload = 0x40018498 );
 PROVIDE ( Cache_Travel_Tag_Memory = 0x4001908c );
 PROVIDE ( Cache_Unlock_Addr = 0x40018b9c );
diff --git a/tools/esp32s2/Config.mk b/tools/esp32s2/Config.mk
index 51d38f2..9e39b88 100644
--- a/tools/esp32s2/Config.mk
+++ b/tools/esp32s2/Config.mk
@@ -60,36 +60,43 @@ endif
 
 ESPTOOL_FLASH_OPTS := -fs $(FLASH_SIZE) -fm $(FLASH_MODE) -ff $(FLASH_FREQ)
 
+# Configure the variables according to build environment
+
 ifdef ESPTOOL_BINDIR
-	BL_OFFSET       := 0x1000
-	PT_OFFSET       := 0x8000
-	BOOTLOADER      := $(ESPTOOL_BINDIR)/bootloader-esp32s2.bin
-	PARTITION_TABLE := $(ESPTOOL_BINDIR)/partition-table-esp32s2.bin
-	FLASH_BL        := $(BL_OFFSET) $(BOOTLOADER)
-	FLASH_PT        := $(PT_OFFSET) $(PARTITION_TABLE)
-	ESPTOOL_BINS    := $(FLASH_BL) $(FLASH_PT)
+	ifeq ($(CONFIG_ESP32S2_APP_FORMAT_LEGACY),y)
+		BL_OFFSET       := 0x1000
+		PT_OFFSET       := 0x8000
+		BOOTLOADER      := $(ESPTOOL_BINDIR)/bootloader-esp32s2.bin
+		PARTITION_TABLE := $(ESPTOOL_BINDIR)/partition-table-esp32s2.bin
+		FLASH_BL        := $(BL_OFFSET) $(BOOTLOADER)
+		FLASH_PT        := $(PT_OFFSET) $(PARTITION_TABLE)
+		ESPTOOL_BINS    := $(FLASH_BL) $(FLASH_PT)
+	else ifeq ($(CONFIG_ESP32S2_APP_FORMAT_MCUBOOT),y)
+		BL_OFFSET       := 0x1000
+		BOOTLOADER      := $(ESPTOOL_BINDIR)/mcuboot-esp32s2.bin
+		FLASH_BL        := $(BL_OFFSET) $(BOOTLOADER)
+		ESPTOOL_BINS    := $(FLASH_BL)
+	endif
 endif
 
-ESPTOOL_BINS += 0x10000 nuttx.bin
+ifeq ($(CONFIG_ESP32S2_APP_FORMAT_LEGACY),y)
+	APP_OFFSET     := 0x10000
+	APP_IMAGE      := nuttx.bin
+	FLASH_APP      := $(APP_OFFSET) $(APP_IMAGE)
+else ifeq ($(CONFIG_ESP32S2_APP_FORMAT_MCUBOOT),y)
+	ifeq ($(CONFIG_ESP32S2_ESPTOOL_TARGET_PRIMARY),y)
+		VERIFIED   := --confirm
+		APP_OFFSET := $(CONFIG_ESP32S2_OTA_PRIMARY_SLOT_OFFSET)
+	else ifeq ($(CONFIG_ESP32S2_ESPTOOL_TARGET_SECONDARY),y)
+		VERIFIED   :=
+		APP_OFFSET := $(CONFIG_ESP32S2_OTA_SECONDARY_SLOT_OFFSET)
+	endif
+
+	APP_IMAGE      := nuttx.signed.bin
+	FLASH_APP      := $(APP_OFFSET) $(APP_IMAGE)
+endif
 
-# ELF2IMAGE -- Convert an ELF file into a binary file in Espressif application image format
-
-define ELF2IMAGE
-	$(Q) echo "MKIMAGE: ESP32-S2 binary"
-	$(Q) if ! esptool.py version 1>/dev/null 2>&1; then \
-		echo ""; \
-		echo "esptool.py not found.  Please run: \"pip install esptool\""; \
-		echo ""; \
-		echo "Run make again to create the nuttx.bin image."; \
-		exit 1; \
-	fi
-	$(Q) if [ -z $(FLASH_SIZE) ]; then \
-		echo "Missing Flash memory size configuration for the ESP32-S2 chip."; \
-		exit 1; \
-	fi
-	esptool.py -c esp32s2 elf2image $(ESPTOOL_FLASH_OPTS) -o nuttx.bin nuttx
-	$(Q) echo "Generated: nuttx.bin (ESP32-S2 compatible)"
-endef
+ESPTOOL_BINS += $(FLASH_APP)
 
 # MERGEBIN -- Merge raw binary files into a single file
 
@@ -114,12 +121,61 @@ define MERGEBIN
 endef
 endif
 
+# SIGNBIN -- Sign the binary image file
+
+ifeq ($(CONFIG_ESP32S2_APP_FORMAT_MCUBOOT),y)
+define SIGNBIN
+	$(Q) echo "MKIMAGE: ESP32-S2 binary"
+	$(Q) if ! imgtool version 1>/dev/null 2>&1; then \
+		echo ""; \
+		echo "imgtool not found.  Please run: \"pip install imgtool\""; \
+		echo ""; \
+		echo "Run make again to create the nuttx.signed.bin image."; \
+		exit 1; \
+	fi
+	imgtool sign --pad --pad-sig $(VERIFIED) --align 4 -v 0 \
+		-H $(CONFIG_ESP32S2_APP_MCUBOOT_HEADER_SIZE) --pad-header \
+		-S $(CONFIG_ESP32S2_OTA_SLOT_SIZE) \
+		nuttx.bin nuttx.signed.bin
+	$(Q) echo nuttx.signed.bin >> nuttx.manifest
+	$(Q) echo "Generated: nuttx.signed.bin (MCUboot compatible)"
+endef
+endif
+
+# ELF2IMAGE -- Convert an ELF file into a binary file in Espressif application image format
+
+ifeq ($(CONFIG_ESP32S2_APP_FORMAT_LEGACY),y)
+define ELF2IMAGE
+	$(Q) echo "MKIMAGE: ESP32-S2 binary"
+	$(Q) if ! esptool.py version 1>/dev/null 2>&1; then \
+		echo ""; \
+		echo "esptool.py not found.  Please run: \"pip install esptool\""; \
+		echo ""; \
+		echo "Run make again to create the nuttx.bin image."; \
+		exit 1; \
+	fi
+	$(Q) if [ -z $(FLASH_SIZE) ]; then \
+		echo "Missing Flash memory size configuration for the ESP32-S2 chip."; \
+		exit 1; \
+	fi
+	esptool.py -c esp32s2 elf2image $(ESPTOOL_FLASH_OPTS) -o nuttx.bin nuttx
+	$(Q) echo "Generated: nuttx.bin (ESP32-S2 compatible)"
+endef
+endif
+
 # POSTBUILD -- Perform post build operations
 
+ifeq ($(CONFIG_ESP32S2_APP_FORMAT_MCUBOOT),y)
+define POSTBUILD
+	$(call SIGNBIN)
+	$(call MERGEBIN)
+endef
+else ifeq ($(CONFIG_ESP32S2_APP_FORMAT_LEGACY),y)
 define POSTBUILD
 	$(call ELF2IMAGE)
 	$(call MERGEBIN)
 endef
+endif
 
 # ESPTOOL_BAUD -- Serial port baud rate used when flashing/reading via esptool.py