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:37 UTC

[incubator-nuttx] 02/04: risc-v/esp32c3: 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 3c63cb522ca310da61602a14f6f00afc84b3a489
Author: Gustavo Henrique Nihei <gu...@espressif.com>
AuthorDate: Fri Sep 10 13:29:22 2021 -0300

    risc-v/esp32c3: Enable booting from MCUboot bootloader
    
    Signed-off-by: Gustavo Henrique Nihei <gu...@espressif.com>
---
 arch/risc-v/src/esp32c3/Kconfig                    | 158 +++++++++--
 arch/risc-v/src/esp32c3/esp32c3_start.c            | 174 +++++++++++-
 .../src/esp32c3/hardware/esp32c3_cache_memory.h    | 110 ++++++++
 arch/risc-v/src/esp32c3/hardware/extmem_reg.h      |  23 +-
 .../esp32c3/esp32c3-devkit/scripts/Make.defs       |   6 +-
 .../esp32c3-devkit/scripts/esp32c3.template.ld     |  70 ++++-
 .../esp32c3-devkit/scripts/esp32c3_mcuboot.ld      | 308 +++++++++++++++++++++
 .../esp32c3/esp32c3-devkit/scripts/esp32c3_rom.ld  |   6 +-
 .../esp32c3/esp32c3-devkit/src/esp32c3_spiflash.c  | 112 ++++++++
 tools/esp32c3/Config.mk                            | 108 ++++++--
 10 files changed, 1010 insertions(+), 65 deletions(-)

diff --git a/arch/risc-v/src/esp32c3/Kconfig b/arch/risc-v/src/esp32c3/Kconfig
index f91e39d..f307375 100644
--- a/arch/risc-v/src/esp32c3/Kconfig
+++ b/arch/risc-v/src/esp32c3/Kconfig
@@ -516,13 +516,6 @@ config ESP32C3_UART1_CTSPIN
 
 endif # ESP32C3_UART1
 
-config ESP32C3_PARTITION
-	bool "ESP32-C3 Partition"
-	default n
-	select ESP32C3_SPIFLASH
-	---help---
-		Decode partition file and initialize partition as MTD.
-
 endmenu
 
 menu "Real-Time Timer"
@@ -760,7 +753,8 @@ config ESP32C3_WIFI_FS_MOUNTPT
 
 config ESP32C3_WIFI_MTD_OFFSET
 	hex "Wi-Fi MTD partition offset"
-	default 0x280000
+	default 0x280000 if !ESP32C3_HAVE_OTA_PARTITION
+	default 0x350000 if ESP32C3_HAVE_OTA_PARTITION
 	depends on ESP32C3_WIFI_SAVE_PARAM
 	---help---
 		This is the base address of the Wi-Fi MTD partition.
@@ -840,9 +834,50 @@ endmenu # BLE Configuration
 menu "SPI Flash configuration"
 	depends on ESP32C3_SPIFLASH
 
+if ESP32C3_HAVE_OTA_PARTITION
+
+comment "Application Image OTA Update support"
+
+config ESP32C3_OTA_PRIMARY_SLOT_OFFSET
+	hex "Application image primary slot offset"
+	default "0x10000"
+
+config ESP32C3_OTA_PRIMARY_SLOT_DEVPATH
+	string "Application image primary slot device path"
+	default "/dev/ota0"
+
+config ESP32C3_OTA_SECONDARY_SLOT_OFFSET
+	hex "Application image secondary slot offset"
+	default "0x110000"
+
+config ESP32C3_OTA_SECONDARY_SLOT_DEVPATH
+	string "Application image secondary slot device path"
+	default "/dev/ota1"
+
+config ESP32C3_OTA_SLOT_SIZE
+	hex "Application image slot size (in bytes)"
+	default "0x100000"
+
+config ESP32C3_OTA_SCRATCH_OFFSET
+	hex "Scratch partition offset"
+	default "0x210000"
+
+config ESP32C3_OTA_SCRATCH_SIZE
+	hex "Scratch partition size"
+	default "0x40000"
+
+config ESP32C3_OTA_SCRATCH_DEVPATH
+	string "Scratch partition device path"
+	default "/dev/otascratch"
+
+endif
+
+comment "General MTD configuration"
+
 config ESP32C3_MTD_OFFSET
 	hex "MTD base address in SPI Flash"
-	default 0x180000
+	default 0x180000 if !ESP32C3_HAVE_OTA_PARTITION
+	default 0x250000 if ESP32C3_HAVE_OTA_PARTITION
 	---help---
 		MTD base address in SPI Flash.
 
@@ -860,20 +895,7 @@ config ESP32C3_SPIFLASH_DEBUG
 		If this option is enabled, SPI Flash driver read and write functions
 		will output input parameters and return values (if applicable).
 
-endmenu # ESP32C3_SPIFLASH
-
-menu "Partition Configuration"
-	depends on ESP32C3_PARTITION
-
-config ESP32C3_PARTITION_OFFSET
-	hex "Partition offset"
-	default "0x8000"
-
-config ESP32C3_PARTITION_MOUNT
-	string "Partition mount point"
-	default "/dev/esp/partition/"
-
-endmenu # ESP32C3_PARTITION
+endmenu # SPI Flash configuration
 
 menu "GDMA Configuration"
 	depends on ESP32C3_DMA
@@ -909,6 +931,96 @@ config ESP32C3_TICKLESS
 	select ARCH_HAVE_TICKLESS
 	select SCHED_TICKLESS
 
+config ESP32C3_HAVE_OTA_PARTITION
+	bool
+	default n
+
+menu "Application Image Configuration"
+
+choice
+	prompt "Application Image Format"
+	default ESP32C3_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 ESP32C3_APP_FORMAT_LEGACY
+	bool "Legacy format"
+	---help---
+		This is the legacy application image format, as supported by the ESP-IDF
+		2nd stage bootloader.
+
+config ESP32C3_APP_FORMAT_MCUBOOT
+	bool "MCUboot-bootable format"
+	select ESP32C3_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 ESP32C3_ESPTOOL_TARGET_PRIMARY
+	depends on ESP32C3_HAVE_OTA_PARTITION
+	---help---
+		Slot to which ESPTOOL will flash the generated binary image.
+
+config ESP32C3_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 ESP32C3_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 ESP32C3_APP_MCUBOOT_HEADER_SIZE
+	int "Application image header size (in bytes)"
+	default 32
+	depends on ESP32C3_APP_FORMAT_MCUBOOT
+
+endmenu # Application Image Configuration
+
+if ESP32C3_APP_FORMAT_LEGACY
+
+config ESP32C3_PARTITION
+	bool "ESP32-C3 Partition"
+	default n
+	select ESP32C3_SPIFLASH
+	---help---
+		Decode partition file and initialize partition as MTD.
+
+menu "Partition Configuration"
+	depends on ESP32C3_PARTITION
+
+config ESP32C3_PARTITION_OFFSET
+	hex "Partition offset"
+	default "0x8000"
+
+config ESP32C3_PARTITION_MOUNT
+	string "Partition mount point"
+	default "/dev/esp/partition/"
+
+endmenu # Partition Configuration
+
+endif
+
 menu "AES accelerator"
 	depends on ESP32C3_AES_ACCELERATOR
 
diff --git a/arch/risc-v/src/esp32c3/esp32c3_start.c b/arch/risc-v/src/esp32c3/esp32c3_start.c
index d83cf82..07e7016 100644
--- a/arch/risc-v/src/esp32c3/esp32c3_start.c
+++ b/arch/risc-v/src/esp32c3/esp32c3_start.c
@@ -35,17 +35,83 @@
 #include "esp32c3_lowputc.h"
 #include "esp32c3_start.h"
 #include "esp32c3_wdt.h"
+#include "hardware/esp32c3_cache_memory.h"
+#include "hardware/extmem_reg.h"
 
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
 
 #ifdef CONFIG_DEBUG_FEATURES
-#  define showprogress(c) riscv_lowputc(c)
+#  define showprogress(c)     riscv_lowputc(c)
 #else
 #  define showprogress(c)
 #endif
 
+#ifdef CONFIG_ESP32C3_APP_FORMAT_MCUBOOT
+
+#define PRIMARY_SLOT_OFFSET   CONFIG_ESP32C3_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_ESP32C3_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_ESP32C3_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_dbus_mmu_set(uint32_t ext_ram, uint32_t vaddr,
+                              uint32_t paddr, uint32_t psize, uint32_t num,
+                              uint32_t fixed);
+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_ESP32C3_APP_FORMAT_MCUBOOT
+IRAM_ATTR noreturn_function void __start(void);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32C3_APP_FORMAT_MCUBOOT
+HDR_ATTR static void (*_entry_point)(void) = &__start;
+#endif
+
 /****************************************************************************
  * Public Data
  ****************************************************************************/
@@ -57,6 +123,101 @@ uint8_t g_idlestack[CONFIG_IDLETHREAD_STACKSIZE]
 uint32_t g_idle_topstack = ESP32C3_IDLESTACK_TOP;
 
 /****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * 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_ESP32C3_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_ESP32C3_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_dbus_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);
+  rc |= cache_ibus_mmu_set(MMU_ACCESS_FLASH, irom_vma_aligned,
+                           irom_lma_aligned, 64, (int)irom_page_count, 0);
+
+  regval  = getreg32(EXTMEM_ICACHE_CTRL1_REG);
+  regval &= ~(EXTMEM_ICACHE_SHUT_IBUS_M | EXTMEM_ICACHE_SHUT_DBUS_M);
+  putreg32(regval, EXTMEM_ICACHE_CTRL1_REG);
+
+  cache_resume_icache(autoload);
+
+  return (int)rc;
+}
+#endif
+
+/****************************************************************************
  * Public Functions
  ****************************************************************************/
 
@@ -66,7 +227,14 @@ uint32_t g_idle_topstack = ESP32C3_IDLESTACK_TOP;
 
 void __esp32c3_start(void)
 {
-  uint32_t *dest;
+#ifdef CONFIG_ESP32C3_APP_FORMAT_MCUBOOT
+  if (map_rom_segments() != 0)
+    {
+      ets_printf("Failed to setup XIP, aborting\n");
+      while (true);
+    }
+
+#endif
 
   /* Set CPU frequency */
 
@@ -88,7 +256,7 @@ void __esp32c3_start(void)
    * 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;
     }
diff --git a/arch/risc-v/src/esp32c3/hardware/esp32c3_cache_memory.h b/arch/risc-v/src/esp32c3/hardware/esp32c3_cache_memory.h
new file mode 100644
index 0000000..cf3e0aa
--- /dev/null
+++ b/arch/risc-v/src/esp32c3/hardware/esp32c3_cache_memory.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+ * arch/risc-v/src/esp32c3/hardware/esp32c3_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_RISCV_SRC_ESP32C3_HARDWARE_ESP32C3_CACHE_MEMORY_H_
+#define __ARCH_RISCV_SRC_ESP32C3_HARDWARE_ESP32C3_CACHE_MEMORY_H_
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* IRAM0 is connected with Cache IBUS0 */
+
+#define IRAM0_ADDRESS_LOW               0x40000000
+#define IRAM0_ADDRESS_HIGH              0x44000000
+#define IRAM0_CACHE_ADDRESS_LOW         0x42000000
+#define IRAM0_CACHE_ADDRESS_HIGH        0x42800000
+
+/* DRAM0 is connected with Cache DBUS0 */
+
+#define DRAM0_ADDRESS_LOW               0x3c000000
+#define DRAM0_ADDRESS_HIGH              0x40000000
+#define DRAM0_CACHE_ADDRESS_LOW         0x3c000000
+#define DRAM0_CACHE_ADDRESS_HIGH        0x3c800000
+#define DRAM0_CACHE_OPERATION_HIGH      DRAM0_CACHE_ADDRESS_HIGH
+#define ESP_CACHE_TEMP_ADDR             0x3c000000
+
+#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_DRAM0(vaddr)         ADDRESS_IN_BUS(DRAM0, vaddr)
+#define ADDRESS_IN_DRAM0_CACHE(vaddr)   ADDRESS_IN_BUS(DRAM0_CACHE, vaddr)
+
+#define BUS_IRAM0_CACHE_SIZE    BUS_SIZE(IRAM0_CACHE)
+#define BUS_DRAM0_CACHE_SIZE    BUS_SIZE(DRAM0_CACHE)
+
+#define CACHE_IBUS              0
+#define CACHE_IBUS_MMU_START    0
+#define CACHE_IBUS_MMU_END      0x200
+
+#define CACHE_DBUS              1
+#define CACHE_DBUS_MMU_START    0
+#define CACHE_DBUS_MMU_END      0x200
+
+#define CACHE_IROM_MMU_START    0
+#define CACHE_IROM_MMU_END      Cache_Get_IROM_MMU_End()
+#define CACHE_IROM_MMU_SIZE     (CACHE_IROM_MMU_END - CACHE_IROM_MMU_START)
+
+#define CACHE_DROM_MMU_START    CACHE_IROM_MMU_END
+#define CACHE_DROM_MMU_END      Cache_Get_DROM_MMU_End()
+#define CACHE_DROM_MMU_SIZE     (CACHE_DROM_MMU_END - CACHE_DROM_MMU_START)
+
+#define CACHE_DROM_MMU_MAX_END  0x200
+
+#define ICACHE_MMU_SIZE         0x200
+#define DCACHE_MMU_SIZE         0x200
+
+#define MMU_BUS_START(i)        0
+#define MMU_BUS_SIZE(i)         0x200
+
+#define MMU_INVALID             BIT(8)
+#define MMU_TYPE                0
+#define MMU_ACCESS_FLASH        0
+
+#define CACHE_MAX_SYNC_NUM      0x400000
+#define CACHE_MAX_LOCK_NUM      0x8000
+
+#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   0x100
+#define MMU_ADDRESS_MASK        0xff
+#define MMU_PAGE_SIZE           0x10000
+#define INVALID_PHY_PAGE        0xffff
+
+#define BUS_ADDR_SIZE           0x800000
+#define BUS_ADDR_MASK           (BUS_ADDR_SIZE - 1)
+
+#define CACHE_ICACHE_LOW_SHIFT      0
+#define CACHE_ICACHE_HIGH_SHIFT     2
+#define CACHE_DCACHE_LOW_SHIFT      4
+#define CACHE_DCACHE_HIGH_SHIFT     6
+
+#define CACHE_MEMORY_IBANK0_ADDR    0x4037c000
+
+#endif /* __ARCH_RISCV_SRC_ESP32C3_HARDWARE_ESP32C3_CACHE_MEMORY_H_ */
diff --git a/arch/risc-v/src/esp32c3/hardware/extmem_reg.h b/arch/risc-v/src/esp32c3/hardware/extmem_reg.h
index 88ce7f7..d44cdcb 100644
--- a/arch/risc-v/src/esp32c3/hardware/extmem_reg.h
+++ b/arch/risc-v/src/esp32c3/hardware/extmem_reg.h
@@ -31,8 +31,29 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-#define EXTMEM_CACHE_MMU_POWER_CTRL_REG     (DR_REG_EXTMEM_BASE + 0x0AC)
+#define EXTMEM_ICACHE_CTRL1_REG             (DR_REG_EXTMEM_BASE + 0x004)
 #define EXTMEM_ICACHE_TAG_POWER_CTRL_REG    (DR_REG_EXTMEM_BASE + 0x008)
+#define EXTMEM_CACHE_MMU_POWER_CTRL_REG     (DR_REG_EXTMEM_BASE + 0x0ac)
+
+/* EXTMEM_ICACHE_SHUT_DBUS : R/W ;bitpos:[1] ;default: 1'b1 ;
+ * description: The bit is used to disable core1 ibus
+ * 0: enable  1: disable
+ */
+
+#define EXTMEM_ICACHE_SHUT_DBUS             (BIT(1))
+#define EXTMEM_ICACHE_SHUT_DBUS_M           (BIT(1))
+#define EXTMEM_ICACHE_SHUT_DBUS_V           0x1
+#define EXTMEM_ICACHE_SHUT_DBUS_S           1
+
+/* EXTMEM_ICACHE_SHUT_IBUS : R/W ;bitpos:[0] ;default: 1'b1 ;
+ * description: The bit is used to disable core0 ibus
+ * 0: enable  1: disable
+ */
+
+#define EXTMEM_ICACHE_SHUT_IBUS             (BIT(0))
+#define EXTMEM_ICACHE_SHUT_IBUS_M           (BIT(0))
+#define EXTMEM_ICACHE_SHUT_IBUS_V           0x1
+#define EXTMEM_ICACHE_SHUT_IBUS_S           0
 
 /* EXTMEM_CACHE_MMU_MEM_FORCE_ON : R/W ;bitpos:[0] ;default: 1'b1.
  * The bit is used to enable clock gating to save
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/scripts/Make.defs b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/Make.defs
index 4449874..257b015 100644
--- a/boards/risc-v/esp32c3/esp32c3-devkit/scripts/Make.defs
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/Make.defs
@@ -24,7 +24,11 @@ include $(TOPDIR)/tools/esp32c3/Config.mk
 include $(TOPDIR)/arch/risc-v/src/rv32im/Toolchain.defs
 
 LDSCRIPT1 = $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32c3_out.ld
-LDSCRIPT2 = $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32c3.ld
+ifeq ($(CONFIG_ESP32C3_APP_FORMAT_MCUBOOT),y)
+  LDSCRIPT2 = $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32c3_mcuboot.ld
+else
+  LDSCRIPT2 = $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32c3.ld
+endif
 LDSCRIPT3 = $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32c3_rom.ld
 
 ifeq ($(CONFIG_CYGWIN_WINTOOL),y)
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/scripts/esp32c3.template.ld b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/esp32c3.template.ld
index 5923840..82a3398 100644
--- a/boards/risc-v/esp32c3/esp32c3-devkit/scripts/esp32c3.template.ld
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/esp32c3.template.ld
@@ -47,26 +47,55 @@
 
 #define I_D_SRAM_SIZE       SRAM_DRAM_END - SRAM_DRAM_ORG
 
+#ifdef CONFIG_ESP32C3_FLASH_2M
+#  define FLASH_SIZE        0x200000
+#elif defined (CONFIG_ESP32C3_FLASH_4M)
+#  define FLASH_SIZE        0x400000
+#elif defined (CONFIG_ESP32C3_FLASH_8M)
+#  define FLASH_SIZE        0x800000
+#elif defined (CONFIG_ESP32C3_FLASH_16M)
+#  define FLASH_SIZE        0x1000000
+#endif
+
 MEMORY
 {
-  /* All these values assume the flash cache is on, and have the blocks it
+#ifdef CONFIG_ESP32C3_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_ESP32C3_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_ESP32C3_APP_MCUBOOT_HEADER_SIZE, len = 0x20
+  ROM (RX) :             org = CONFIG_ESP32C3_APP_MCUBOOT_HEADER_SIZE + 0x20,
+                         len = FLASH_SIZE - (CONFIG_ESP32C3_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 byte-wise access.
+   * port' dram/drom regions map to the same iram/irom regions but are
+   * connected to the data port of the CPU and e.g. allow bytewise access.
    */
 
   iram0_0_seg (RX) :      org = SRAM_IRAM_ORG, len = I_D_SRAM_SIZE
 
-  /* Flash mapped instruction data.
-   *
-   * The 0x20 offset is a convenience for the app binary image generation.
+  /* Flash mapped instruction data. */
+
+#ifdef CONFIG_ESP32C3_APP_FORMAT_MCUBOOT
+  irom0_0_seg (RX) :      org = 0x42000000, 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).
    */
 
-  irom0_0_seg (RX) :      org = 0x42000020, len = 0x8000000 - 0x20
+  irom0_0_seg (RX) :      org = 0x42000020, len = FLASH_SIZE - 0x20
+#endif
 
   /* Shared data RAM, excluding memory reserved for ROM bss/data/stack. */
 
@@ -74,7 +103,32 @@ MEMORY
 
   /* Flash mapped constant data */
 
-  drom0_0_seg (R) :       org = 0x3c000020, len = 0x8000000 - 0x20
+#ifdef CONFIG_ESP32C3_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 = 0x3c000000 + (CONFIG_ESP32C3_APP_MCUBOOT_HEADER_SIZE + 0x20),
+                         len = FLASH_SIZE - (CONFIG_ESP32C3_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 = 0x3c000020, len = FLASH_SIZE - 0x20
+#endif
 
   /* RTC fast memory. Persists over deep sleep. */
 
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/scripts/esp32c3_mcuboot.ld b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/esp32c3_mcuboot.ld
new file mode 100644
index 0000000..94077d6
--- /dev/null
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/esp32c3_mcuboot.ld
@@ -0,0 +1,308 @@
+/****************************************************************************
+ * boards/risc-v/esp32c3/esp32c3-devkit/scripts/esp32c3_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: */
+
+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.text))
+    LONG(LOADADDR(.iram0.text))
+    LONG(SIZEOF(.iram0.text))
+
+    /* 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 (*libarch.a:esp32c3_spiflash.* esp32c3_head.* esp32c3_start.*) .rodata)
+    *(EXCLUDE_FILE (*libarch.a:esp32c3_spiflash.* esp32c3_head.* esp32c3_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)
+    . = (. + 3) & ~ 3;
+    __eh_frame = ABSOLUTE(.);
+    KEEP(*(.eh_frame))
+    . = (. + 7) & ~ 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
+
+  .iram0.text :
+  {
+    _iram_start = ABSOLUTE(.);
+
+    /* Vectors go to start of IRAM */
+
+    KEEP(*(.exception_vectors.text));
+    . = ALIGN(4);
+
+    *(.iram1)
+    *(.iram1.*)
+    *libarch.a:esp32c3_spiflash.*(.literal .text .literal.* .text.*)
+    esp32c3_head.*(.literal .text .literal.* .text.*)
+    esp32c3_start.*(.literal .text .literal.* .text.*)
+    *(.wifi0iram .wifi0iram.*)
+    *(.wifirxiram .wifirxiram.*)
+    *(.wifislpiram .wifislpiram.*)
+    *(.wifislprxiram .wifislprxiram.*)
+  } >iram0_0_seg AT>ROM
+
+  .dram0.dummy (NOLOAD):
+  {
+    /* 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 */
+
+  .dram0.bss (NOLOAD) :
+  {
+    /* .bss initialized on power-up */
+
+    . = ALIGN (8);
+    _sbss = ABSOLUTE(.);
+    *(.dynsbss)
+    *(.sbss)
+    *(.sbss.*)
+    *(.gnu.linkonce.sb.*)
+    *(.scommon)
+    *(.sbss2)
+    *(.sbss2.*)
+    *(.gnu.linkonce.sb2.*)
+    *(.dynbss)
+    KEEP (*(.bss))
+    *(.bss.*)
+    *(.share.mem)
+    *(.gnu.linkonce.b.*)
+    *(COMMON)
+    . = ALIGN(8);
+    _ebss = ABSOLUTE(.);
+  } >dram0_0_seg
+
+  .noinit (NOLOAD):
+  {
+    /* This section contains data that is not initialized during load,
+     * or during the application's initialization sequence.
+     */
+
+    . = ALIGN(8);
+    *(.noinit)
+    *(.noinit.*)
+    . = ALIGN(8);
+  } >dram0_0_seg
+
+  .dram0.data :
+  {
+    /* .data initialized on power-up in ROMed configurations. */
+
+    _sdata = ABSOLUTE(.);
+    KEEP (*(.data))
+    KEEP (*(.data.*))
+    KEEP (*(.gnu.linkonce.d.*))
+    KEEP (*(.data1))
+    __global_pointer$ = . + 0x800;
+    KEEP (*(.sdata))
+    KEEP (*(.sdata.*))
+    KEEP (*(.gnu.linkonce.s.*))
+    KEEP (*(.sdata2))
+    KEEP (*(.sdata2.*))
+    KEEP (*(.gnu.linkonce.s2.*))
+    KEEP (*(.jcr))
+    *(.dram1 .dram1.*)
+    *libarch.a:esp32c3_spiflash.*(.rodata .rodata.*)
+    esp32c3_head.*(.rodata .rodata.*)
+    esp32c3_start.*(.rodata .rodata.*)
+    _edata = ABSOLUTE(.);
+    . = ALIGN(4);
+
+    /* Heap starts at the end of .data */
+
+    _sheap = ABSOLUTE(.);
+  } >dram0_0_seg AT>ROM
+
+  /* Marks the end of IRAM code segment */
+
+  .iram0.text_end (NOLOAD) :
+  {
+    . = ALIGN (16);
+  } >iram0_0_seg
+
+  .iram0.data :
+  {
+    . = ALIGN(16);
+    *(.iram.data)
+    *(.iram.data*)
+  } >iram0_0_seg AT>ROM
+
+  .iram0.bss (NOLOAD) :
+  {
+    . = ALIGN(16);
+    *(.iram.bss)
+    *(.iram.bss*)
+
+    . = ALIGN(16);
+    _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.
+     */
+
+    . = SIZEOF(.flash.rodata);
+  } >irom0_0_seg
+
+  .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)
+    . = ALIGN(4);
+
+    _etext = .;
+  } >irom0_0_seg AT>ROM
+
+  .rtc.text :
+  {
+    . = ALIGN(4);
+    *(.rtc.literal .rtc.text)
+  } >rtc_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_seg
+
+  /* RTC BSS section. */
+
+  .rtc.bss (NOLOAD) :
+  {
+    *(.rtc.bss)
+  } >rtc_seg
+
+  .rtc.data :
+  {
+    *(.rtc.data)
+    *(.rtc.rodata)
+
+   /* Whatever is left from the RTC memory is used as a special heap. */
+
+    . = ALIGN (4);
+    _srtcheap = ABSOLUTE(.);
+  } >rtc_seg AT>ROM
+}
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/scripts/esp32c3_rom.ld b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/esp32c3_rom.ld
index f282eef..d251f5e 100644
--- a/boards/risc-v/esp32c3/esp32c3-devkit/scripts/esp32c3_rom.ld
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/esp32c3_rom.ld
@@ -297,7 +297,7 @@ PROVIDE( ROM_Boot_Cache_Init = 0x400004c8 );
 PROVIDE( Cache_Invalidate_ICache_Items = 0x400004cc );
 PROVIDE( Cache_Op_Addr = 0x400004d0 );
 PROVIDE( cache_invalidate_addr = 0x400004d4 );
-PROVIDE( Cache_Invalidate_ICache_All = 0x400004d8 );
+PROVIDE( cache_invalidate_icache_all = 0x400004d8 );
 PROVIDE( Cache_Mask_All = 0x400004dc );
 PROVIDE( Cache_UnMask_Dram0 = 0x400004e0 );
 PROVIDE( Cache_Suspend_ICache_Autoload = 0x400004e4 );
@@ -331,8 +331,8 @@ PROVIDE( Cache_Get_DROM_MMU_End = 0x40000550 );
 PROVIDE( Cache_Owner_Init = 0x40000554 );
 PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40000558 );
 PROVIDE( Cache_MMU_Init = 0x4000055c );
-PROVIDE( Cache_Ibus_MMU_Set = 0x40000560 );
-PROVIDE( Cache_Dbus_MMU_Set = 0x40000564 );
+PROVIDE( cache_ibus_mmu_set = 0x40000560 );
+PROVIDE( cache_dbus_mmu_set = 0x40000564 );
 PROVIDE( Cache_Count_Flash_Pages = 0x40000568 );
 PROVIDE( Cache_Travel_Tag_Memory = 0x4000056c );
 PROVIDE( Cache_Get_Virtual_Addr = 0x40000570 );
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_spiflash.c b/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_spiflash.c
index 15678c4..cef2237 100644
--- a/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_spiflash.c
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_spiflash.c
@@ -38,6 +38,9 @@
 #include <nuttx/spi/spi.h>
 #include <nuttx/mtd/mtd.h>
 #include <nuttx/fs/nxffs.h>
+#ifdef CONFIG_BCH
+#include <nuttx/drivers/drivers.h>
+#endif
 
 #include "esp32c3_spiflash.h"
 #include "esp32c3-devkit.h"
@@ -46,11 +49,112 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+#define ARRAYSIZE(x)                (sizeof((x)) / sizeof((x)[0]))
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32C3_HAVE_OTA_PARTITION
+
+struct ota_partition_s
+{
+  uint32_t    offset;          /* Partition offset from the beginning of MTD */
+  uint32_t    size;            /* Partition size in bytes */
+  const char *devpath;         /* Partition device path */
+};
+
+#endif
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32C3_HAVE_OTA_PARTITION
+static int init_ota_partitions(void);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32C3_HAVE_OTA_PARTITION
+static const struct ota_partition_s g_ota_partition_table[] =
+{
+  {
+    .offset  = CONFIG_ESP32C3_OTA_PRIMARY_SLOT_OFFSET,
+    .size    = CONFIG_ESP32C3_OTA_SLOT_SIZE,
+    .devpath = CONFIG_ESP32C3_OTA_PRIMARY_SLOT_DEVPATH
+  },
+  {
+    .offset  = CONFIG_ESP32C3_OTA_SECONDARY_SLOT_OFFSET,
+    .size    = CONFIG_ESP32C3_OTA_SLOT_SIZE,
+    .devpath = CONFIG_ESP32C3_OTA_SECONDARY_SLOT_DEVPATH
+  },
+  {
+    .offset  = CONFIG_ESP32C3_OTA_SCRATCH_OFFSET,
+    .size    = CONFIG_ESP32C3_OTA_SCRATCH_SIZE,
+    .devpath = CONFIG_ESP32C3_OTA_SCRATCH_DEVPATH
+  }
+};
+#endif
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
 
 /****************************************************************************
+ * Name: init_ota_partitions
+ *
+ * Description:
+ *   Initialize partitions that are dedicated to firmware OTA update.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32C3_HAVE_OTA_PARTITION
+static int init_ota_partitions(void)
+{
+  FAR struct mtd_dev_s *mtd;
+#ifdef CONFIG_BCH
+  char blockdev[18];
+#endif
+  int ret = OK;
+
+  for (int i = 0; i < ARRAYSIZE(g_ota_partition_table); ++i)
+    {
+      const struct ota_partition_s *part = &g_ota_partition_table[i];
+      mtd = esp32c3_spiflash_alloc_mtdpart(part->offset, part->size);
+
+      ret = ftl_initialize(i, mtd);
+      if (ret < 0)
+        {
+          ferr("ERROR: Failed to initialize the FTL layer: %d\n", ret);
+          return ret;
+        }
+
+#ifdef CONFIG_BCH
+      snprintf(blockdev, 18, "/dev/mtdblock%d", i);
+
+      ret = bchdev_register(blockdev, part->devpath, false);
+      if (ret < 0)
+        {
+          ferr("ERROR: bchdev_register %s failed: %d\n", part->devpath, ret);
+          return ret;
+        }
+#endif
+    }
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
  * Name: setup_smartfs
  *
  * Description:
@@ -403,6 +507,14 @@ int esp32c3_spiflash_init(void)
 {
   int ret = OK;
 
+#ifdef CONFIG_ESP32C3_HAVE_OTA_PARTITION
+  ret = init_ota_partitions();
+  if (ret < 0)
+    {
+      return ret;
+    }
+#endif
+
 #ifdef CONFIG_ESP32C3_WIFI_SAVE_PARAM
   ret = init_wifi_partition();
   if (ret < 0)
diff --git a/tools/esp32c3/Config.mk b/tools/esp32c3/Config.mk
index 440becb..4550c6f 100644
--- a/tools/esp32c3/Config.mk
+++ b/tools/esp32c3/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       := 0x0
-	PT_OFFSET       := 0x8000
-	BOOTLOADER      := $(ESPTOOL_BINDIR)/bootloader-esp32c3.bin
-	PARTITION_TABLE := $(ESPTOOL_BINDIR)/partition-table-esp32c3.bin
-	FLASH_BL        := $(BL_OFFSET) $(BOOTLOADER)
-	FLASH_PT        := $(PT_OFFSET) $(PARTITION_TABLE)
-	ESPTOOL_BINS    := $(FLASH_BL) $(FLASH_PT)
+	ifeq ($(CONFIG_ESP32C3_APP_FORMAT_LEGACY),y)
+		BL_OFFSET       := 0x0
+		PT_OFFSET       := 0x8000
+		BOOTLOADER      := $(ESPTOOL_BINDIR)/bootloader-esp32c3.bin
+		PARTITION_TABLE := $(ESPTOOL_BINDIR)/partition-table-esp32c3.bin
+		FLASH_BL        := $(BL_OFFSET) $(BOOTLOADER)
+		FLASH_PT        := $(PT_OFFSET) $(PARTITION_TABLE)
+		ESPTOOL_BINS    := $(FLASH_BL) $(FLASH_PT)
+	else ifeq ($(CONFIG_ESP32C3_APP_FORMAT_MCUBOOT),y)
+		BL_OFFSET       := 0x0
+		BOOTLOADER      := $(ESPTOOL_BINDIR)/mcuboot-esp32c3.bin
+		FLASH_BL        := $(BL_OFFSET) $(BOOTLOADER)
+		ESPTOOL_BINS    := $(FLASH_BL)
+	endif
 endif
 
-ESPTOOL_BINS += 0x10000 nuttx.bin
+ifeq ($(CONFIG_ESP32C3_APP_FORMAT_LEGACY),y)
+	APP_OFFSET     := 0x10000
+	APP_IMAGE      := nuttx.bin
+	FLASH_APP      := $(APP_OFFSET) $(APP_IMAGE)
+else ifeq ($(CONFIG_ESP32C3_APP_FORMAT_MCUBOOT),y)
+	ifeq ($(CONFIG_ESP32C3_ESPTOOL_TARGET_PRIMARY),y)
+		VERIFIED   := --confirm
+		APP_OFFSET := $(CONFIG_ESP32C3_OTA_PRIMARY_SLOT_OFFSET)
+	else ifeq ($(CONFIG_ESP32C3_ESPTOOL_TARGET_SECONDARY),y)
+		VERIFIED   :=
+		APP_OFFSET := $(CONFIG_ESP32C3_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-C3 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-C3 chip."; \
-		exit 1; \
-	fi
-	esptool.py -c esp32c3 elf2image $(ESPTOOL_FLASH_OPTS) -o nuttx.bin nuttx
-	$(Q) echo "Generated: nuttx.bin (ESP32-C3 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_ESP32C3_APP_FORMAT_MCUBOOT),y)
+define SIGNBIN
+	$(Q) echo "MKIMAGE: ESP32-C3 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_ESP32C3_APP_MCUBOOT_HEADER_SIZE) --pad-header \
+		-S $(CONFIG_ESP32C3_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_ESP32C3_APP_FORMAT_LEGACY),y)
+define ELF2IMAGE
+	$(Q) echo "MKIMAGE: ESP32-C3 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-C3 chip."; \
+		exit 1; \
+	fi
+	esptool.py -c esp32c3 elf2image $(ESPTOOL_FLASH_OPTS) -o nuttx.bin nuttx
+	$(Q) echo "Generated: nuttx.bin (ESP32-C3 compatible)"
+endef
+endif
+
 # POSTBUILD -- Perform post build operations
 
+ifeq ($(CONFIG_ESP32C3_APP_FORMAT_MCUBOOT),y)
+define POSTBUILD
+	$(call SIGNBIN)
+	$(call MERGEBIN)
+endef
+else ifeq ($(CONFIG_ESP32C3_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