diff --git a/cpu/esp32/Kconfig.esp32 b/cpu/esp32/Kconfig.esp32 index a285ed22343d..ad4af827c9e1 100644 --- a/cpu/esp32/Kconfig.esp32 +++ b/cpu/esp32/Kconfig.esp32 @@ -17,6 +17,9 @@ config CPU_FAM_ESP32 select HAS_ESP_BLE_ESP32 select HAS_ESP_HW_COUNTER select HAS_ESP_WIFI_ENTERPRISE + select HAS_PERIPH_FLASHPAGE + select HAS_PERIPH_FLASHPAGE_IN_ADDRESS_SPACE + select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_GPIO_LL select HAS_PERIPH_GPIO_LL_IRQ select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH diff --git a/cpu/esp32/Kconfig.esp32c3 b/cpu/esp32/Kconfig.esp32c3 index ba25dfad0ad0..d7e40fe4849f 100644 --- a/cpu/esp32/Kconfig.esp32c3 +++ b/cpu/esp32/Kconfig.esp32c3 @@ -18,6 +18,9 @@ config CPU_FAM_ESP32C3 select HAS_ESP_BLE select HAS_ESP_BLE_ESP32C3 select HAS_ESP_WIFI_ENTERPRISE + select HAS_PERIPH_FLASHPAGE + select HAS_PERIPH_FLASHPAGE_IN_ADDRESS_SPACE + select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_GPIO_LL select HAS_PERIPH_GPIO_LL_IRQ select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH diff --git a/cpu/esp32/Kconfig.esp32s2 b/cpu/esp32/Kconfig.esp32s2 index 045b71745911..7c0a0c32fe0a 100644 --- a/cpu/esp32/Kconfig.esp32s2 +++ b/cpu/esp32/Kconfig.esp32s2 @@ -13,6 +13,9 @@ config CPU_FAM_ESP32S2 select HAS_CPU_ESP32 select HAS_ESP_HW_COUNTER select HAS_ESP_WIFI_ENTERPRISE + select HAS_PERIPH_FLASHPAGE + select HAS_PERIPH_FLASHPAGE_IN_ADDRESS_SPACE + select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_GPIO_LL select HAS_PERIPH_GPIO_LL_IRQ select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH diff --git a/cpu/esp32/Kconfig.esp32s3 b/cpu/esp32/Kconfig.esp32s3 index 6e4ec9834494..53ff34e8c02f 100644 --- a/cpu/esp32/Kconfig.esp32s3 +++ b/cpu/esp32/Kconfig.esp32s3 @@ -19,6 +19,9 @@ config CPU_FAM_ESP32S3 select HAS_ESP_BLE_ESP32C3 select HAS_ESP_HW_COUNTER select HAS_ESP_WIFI_ENTERPRISE + select HAS_PERIPH_FLASHPAGE + select HAS_PERIPH_FLASHPAGE_IN_ADDRESS_SPACE + select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_GPIO_LL select HAS_PERIPH_GPIO_LL_IRQ select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH diff --git a/cpu/esp32/Makefile.dep b/cpu/esp32/Makefile.dep index 600b94af0a1f..f22aab7c0eff 100644 --- a/cpu/esp32/Makefile.dep +++ b/cpu/esp32/Makefile.dep @@ -128,7 +128,7 @@ ifneq (,$(filter esp_idf_heap,$(USEMODULE))) USEPKG += tlsf endif -ifneq (,$(filter mtd,$(USEMODULE))) +ifneq (,$(filter mtd periph_flashpage,$(USEMODULE))) USEMODULE += esp_idf_spi_flash endif diff --git a/cpu/esp32/Makefile.features b/cpu/esp32/Makefile.features index 6910725a77bd..5f3da5066a5c 100644 --- a/cpu/esp32/Makefile.features +++ b/cpu/esp32/Makefile.features @@ -17,6 +17,9 @@ include $(RIOTCPU)/esp_common/Makefile.features FEATURES_PROVIDED += arch_esp32 FEATURES_PROVIDED += esp_wifi_enterprise +FEATURES_PROVIDED += periph_flashpage +FEATURES_PROVIDED += periph_flashpage_in_address_space +FEATURES_PROVIDED += periph_flashpage_pagewise FEATURES_PROVIDED += periph_gpio_ll FEATURES_PROVIDED += periph_gpio_ll_irq FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high diff --git a/cpu/esp32/Makefile.include b/cpu/esp32/Makefile.include index baef04596926..0a63fe30d702 100644 --- a/cpu/esp32/Makefile.include +++ b/cpu/esp32/Makefile.include @@ -23,6 +23,38 @@ else ifneq (,$(filter esp32s2,$(CPU_FAM))) else $(error Unkwnown ESP32x SoC variant (family)) endif + +ifneq (,$(filter periph_flashpage,$(USEMODULE))) + ifneq (,$(CONFIG_ESP_FLASHPAGE_CAPACITY_64K)) + FLASHFILE_POS = 0x20000 + FLASHPAGE_CAP = 0x10000 + else ifneq (,$(CONFIG_ESP_FLASHPAGE_CAPACITY_128K)) + FLASHFILE_POS = 0x30000 + FLASHPAGE_CAP = 0x20000 + else ifneq (,$(CONFIG_ESP_FLASHPAGE_CAPACITY_256K)) + FLASHFILE_POS = 0x50000 + FLASHPAGE_CAP = 0x40000 + else ifneq (,$(CONFIG_ESP_FLASHPAGE_CAPACITY_512K)) + FLASHFILE_POS = 0x90000 + FLASHPAGE_CAP = 0x80000 + else ifneq (,$(CONFIG_ESP_FLASHPAGE_CAPACITY_1M)) + FLASHFILE_POS = 0x110000 + FLASHPAGE_CAP = 0x100000 + else ifneq (,$(CONFIG_ESP_FLASHPAGE_CAPACITY_2M)) + FLASHFILE_POS = 0x210000 + FLASHPAGE_CAP = 0x200000 + else + # use 512 kByte for periph_flashpage by default + FLASHFILE_POS = 0x90000 + FLASHPAGE_CAP = 0x80000 + CFLAGS += -DCONFIG_ESP_FLASHPAGE_CAPACITY_512K + endif + FLASHPAGE_ADDR_START = 0x10000 + FLASHPAGE_ADDR_END = $(FLASHFILE_POS) + CFLAGS += -DFLASHPAGE_ADDR_START=$(FLASHPAGE_ADDR_START) + CFLAGS += -DFLASHPAGE_ADDR_END=$(FLASHPAGE_ADDR_END) +endif + FLASHFILE_POS ?= 0x10000 ESPTOOL ?= $(RIOTTOOLS)/esptools/esptool_v3.2.py @@ -75,6 +107,7 @@ INCLUDES += -I$(ESP32_SDK_DIR)/components/log/include INCLUDES += -I$(ESP32_SDK_DIR)/components/newlib/platform_include INCLUDES += -I$(ESP32_SDK_DIR)/components/soc/include INCLUDES += -I$(ESP32_SDK_DIR)/components/soc/$(CPU_FAM)/include +INCLUDES += -I$(ESP32_SDK_DIR)/components/spi_flash/include ifneq (,$(filter riscv32%,$(TARGET_ARCH))) INCLUDES += -I$(ESP32_SDK_DIR)/components/riscv/include diff --git a/cpu/esp32/esp-idf/Kconfig b/cpu/esp32/esp-idf/Kconfig index 114701e80984..feff3a103e4d 100644 --- a/cpu/esp32/esp-idf/Kconfig +++ b/cpu/esp32/esp-idf/Kconfig @@ -13,7 +13,7 @@ config MODULE_ESP_IDF default y select MODULE_ESP_IDF_COMMON select MODULE_ESP_IDF_EFUSE - select MODULE_ESP_IDF_SPI_FLASH if MODULE_MTD + select MODULE_ESP_IDF_SPI_FLASH if MODULE_MTD || MODULE_PERIPH_FLASHPAGE select MODULE_ESP_IDF_USB if MODULE_TINYUSB_PORTABLE_ESPRESSIF help Espressif IoT Development Framework. diff --git a/cpu/esp32/include/cpu_conf.h b/cpu/esp32/include/cpu_conf.h index 6268a01a4fdd..54eda06c519e 100644 --- a/cpu/esp32/include/cpu_conf.h +++ b/cpu/esp32/include/cpu_conf.h @@ -22,6 +22,10 @@ #ifndef CPU_CONF_H #define CPU_CONF_H +#if !defined(__ASSEMBLER__) +#include +#endif + /** * @name Stack size configuration * @{ @@ -60,6 +64,41 @@ */ #define PUF_SRAM_ATTRIBUTES __attribute__((used, section(".noinit"))) +/** + * @brief Support of unaligned access + * + * All ESP32x SoCs allow unaligned read/write access to the RAM as well as + * unaligned read access to the constant data in the flash, which is accessible + * via the data bus and mapped by the MMU into the data address space of + * the CPU. + */ +#define CPU_HAS_UNALIGNED_ACCESS 1 + +/** + * @name Flash page configuration + * @{ + */ +#if !DOXYGEN && !defined(__ASSEMBLER__) +/* start address of flash pages in CPU address space as determined by the linker */ +extern uint8_t _fp_mem_start; +#endif + +#define FLASHPAGE_SIZE (4096U) /**< Size of pages (flash sectors) in bytes */ +#define FLASHPAGE_WRITE_BLOCK_SIZE (4U) /**< Minimum write block size */ +#define FLASHPAGE_WRITE_BLOCK_ALIGNMENT (4U) /**< Write block alignment */ + +/** + * @brief Number of pages + */ +#define FLASHPAGE_NUMOF (CONFIG_ESP_FLASHPAGE_CAPACITY / FLASHPAGE_SIZE) + +/** + * @brief CPU base address for flash page access as determined by the linker + */ +#define CPU_FLASH_BASE ((uint32_t)&_fp_mem_start) + +/** @} */ + /* include ESP32x SoC specific compile time configurations */ #if defined(CPU_FAM_ESP32) #include "cpu_conf_esp32.h" diff --git a/cpu/esp32/include/sdkconfig.h b/cpu/esp32/include/sdkconfig.h index d7a91d0d5d3d..ae581d4a2500 100644 --- a/cpu/esp32/include/sdkconfig.h +++ b/cpu/esp32/include/sdkconfig.h @@ -206,6 +206,33 @@ #define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE #define CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER CONFIG_ESP_PHY_MAX_WIFI_TX_POWER +/** + * Flashpage configuration + */ +#ifndef CONFIG_ESP_FLASHPAGE_CAPACITY + +#ifdef MODULE_PERIPH_FLASHPAGE +#if CONFIG_ESP_FLASHPAGE_CAPACITY_64K +#define CONFIG_ESP_FLASHPAGE_CAPACITY 0x10000 +#elif CONFIG_ESP_FLASHPAGE_CAPACITY_128K +#define CONFIG_ESP_FLASHPAGE_CAPACITY 0x20000 +#elif CONFIG_ESP_FLASHPAGE_CAPACITY_256K +#define CONFIG_ESP_FLASHPAGE_CAPACITY 0x40000 +#elif CONFIG_ESP_FLASHPAGE_CAPACITY_512K +#define CONFIG_ESP_FLASHPAGE_CAPACITY 0x80000 +#elif CONFIG_ESP_FLASHPAGE_CAPACITY_1M +#define CONFIG_ESP_FLASHPAGE_CAPACITY 0x100000 +#elif CONFIG_ESP_FLASHPAGE_CAPACITY_2M +#define CONFIG_ESP_FLASHPAGE_CAPACITY 0x200000 +#else +#define CONFIG_ESP_FLASHPAGE_CAPACITY 0x80000 +#endif +#else /* MODULE_PERIPH_FLASHPAGE_IN_ADDRESS_SPACE */ +#define CONFIG_ESP_FLASHPAGE_CAPACITY 0x0 +#endif /* MODULE_PERIPH_FLASHPAGE_IN_ADDRESS_SPACE */ + +#endif /* !CONFIG_ESP_FLASHPAGE_CAPACITY */ + #endif /* DOXYGEN */ /** diff --git a/cpu/esp32/ld/esp32/memory.ld.in b/cpu/esp32/ld/esp32/memory.ld.in index 34f0aa7b5c9a..3bc5a602e39f 100644 --- a/cpu/esp32/ld/esp32/memory.ld.in +++ b/cpu/esp32/ld/esp32/memory.ld.in @@ -84,9 +84,16 @@ MEMORY #ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS /* Flash mapped constant data */ +#ifdef MODULE_PERIPH_FLASHPAGE + drom0_0_seg (R) : org = 0x3F400020, + len = 0x400000 - 0x20 - CONFIG_ESP_FLASHPAGE_CAPACITY + drom0_1_seg (R) : org = ORIGIN(drom0_0_seg) + LENGTH(drom0_0_seg), + len = CONFIG_ESP_FLASHPAGE_CAPACITY +#else drom0_0_seg (R) : org = 0x3F400020, len = 0x400000-0x20 /* (See iram0_2_seg for meaning of 0x20 offset in the above.) */ +#endif /* MODULE_PERIPH_FLASHPAGE */ #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS /* RTC fast memory (executable). Persists over deep sleep. diff --git a/cpu/esp32/ld/esp32/sections.ld.in b/cpu/esp32/ld/esp32/sections.ld.in index 3fbf4bf75ffb..ea116c2fe08c 100644 --- a/cpu/esp32/ld/esp32/sections.ld.in +++ b/cpu/esp32/ld/esp32/sections.ld.in @@ -466,7 +466,6 @@ SECTIONS . = ALIGN(ALIGNOF(.flash.rodata)); } >default_rodata_seg - _rodata_start = ABSOLUTE(.); .flash.rodata : ALIGN(0x10) { _flash_rodata_start = ABSOLUTE(.); @@ -617,6 +616,17 @@ SECTIONS _heap_start = ABSOLUTE(.); _sheap = ABSOLUTE(.); } > dram0_0_seg + +#ifdef MODULE_PERIPH_FLASHPAGE + .flash_writable (NOLOAD) : ALIGN(65536) + { + _fp_mem_start = . ; + KEEP(*(SORT(.flash_writable.*))) + _fp_mem_end = . ; + . = ALIGN(4096); + _end_fw = . ; + } > drom0_1_seg +#endif } ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/cpu/esp32/ld/esp32c3/memory.ld.in b/cpu/esp32/ld/esp32c3/memory.ld.in index d387915f9306..f33d2339bf00 100644 --- a/cpu/esp32/ld/esp32c3/memory.ld.in +++ b/cpu/esp32/ld/esp32c3/memory.ld.in @@ -72,9 +72,16 @@ MEMORY #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS /* Flash mapped constant data */ +#ifdef MODULE_PERIPH_FLASHPAGE + drom0_0_seg (R) : org = 0x3C000020, + len = 0x800000 - 0x20 - CONFIG_ESP_FLASHPAGE_CAPACITY + drom0_1_seg (R) : org = ORIGIN(drom0_0_seg) + LENGTH(drom0_0_seg), + len = CONFIG_ESP_FLASHPAGE_CAPACITY +#else drom0_0_seg (R) : org = 0x3C000020, len = 0x800000-0x20 /* (See iram0_2_seg for meaning of 0x20 offset in the above.) */ +#endif /* MODULE_PERIPH_FLASHPAGE */ #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS /** diff --git a/cpu/esp32/ld/esp32c3/sections.ld.in b/cpu/esp32/ld/esp32c3/sections.ld.in index 5c848e2b2d0f..359b724f8d74 100644 --- a/cpu/esp32/ld/esp32c3/sections.ld.in +++ b/cpu/esp32/ld/esp32c3/sections.ld.in @@ -599,6 +599,16 @@ SECTIONS } > dram0_0_seg _eheap = phy_param_rom; +#ifdef MODULE_PERIPH_FLASHPAGE + .flash_writable (NOLOAD) : ALIGN(65536) + { + _fp_mem_start = . ; + KEEP(*(SORT(.flash_writable.*))) + _fp_mem_end = . ; + . = ALIGN(4096); + _end_fw = . ; + } > drom0_1_seg +#endif } ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/cpu/esp32/ld/esp32s2/memory.ld.in b/cpu/esp32/ld/esp32s2/memory.ld.in index f40fca87a450..8791d4c7031c 100644 --- a/cpu/esp32/ld/esp32s2/memory.ld.in +++ b/cpu/esp32/ld/esp32s2/memory.ld.in @@ -90,9 +90,16 @@ MEMORY #ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS /* Flash mapped constant data */ +#ifdef MODULE_PERIPH_FLASHPAGE + drom0_0_seg (R) : org = 0x3F000020, + len = 0x3f0000-0x20 - CONFIG_ESP_FLASHPAGE_CAPACITY + drom0_1_seg (R) : org = ORIGIN(drom0_0_seg) + LENGTH(drom0_0_seg), + len = CONFIG_ESP_FLASHPAGE_CAPACITY +#else drom0_0_seg (R) : org = 0x3F000020, len = 0x3f0000-0x20 /* (See iram0_2_seg for meaning of 0x20 offset in the above.) */ +#endif /* MODULE_PERIPH_FLASHPAGE */ #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS /* RTC fast memory (executable). Persists over deep sleep. diff --git a/cpu/esp32/ld/esp32s2/sections.ld.in b/cpu/esp32/ld/esp32s2/sections.ld.in index 483429033c53..dac1f641cea4 100644 --- a/cpu/esp32/ld/esp32s2/sections.ld.in +++ b/cpu/esp32/ld/esp32s2/sections.ld.in @@ -592,6 +592,17 @@ SECTIONS . = _heap_end; _eheap = ABSOLUTE(.); + +#ifdef MODULE_PERIPH_FLASHPAGE + .flash_writable (NOLOAD) : ALIGN(65536) + { + _fp_mem_start = . ; + KEEP(*(SORT(.flash_writable.*))) + _fp_mem_end = . ; + . = ALIGN(4096); + _end_fw = . ; + } > drom0_1_seg +#endif } ASSERT(((_iram_text_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/cpu/esp32/ld/esp32s3/memory.ld.in b/cpu/esp32/ld/esp32s3/memory.ld.in index 388f2fb65bcb..0847903076d1 100644 --- a/cpu/esp32/ld/esp32s3/memory.ld.in +++ b/cpu/esp32/ld/esp32s3/memory.ld.in @@ -90,9 +90,16 @@ MEMORY #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS /* Flash mapped constant data */ +#ifdef MODULE_PERIPH_FLASHPAGE + drom0_0_seg (R) : org = 0x3C000020, + len = 0x800000-0x20 - CONFIG_ESP_FLASHPAGE_CAPACITY + drom0_1_seg (R) : org = ORIGIN(drom0_0_seg) + LENGTH(drom0_0_seg), + len = CONFIG_ESP_FLASHPAGE_CAPACITY +#else drom0_0_seg (R) : org = 0x3C000020, len = 0x800000-0x20 /* (See iram0_2_seg for meaning of 0x20 offset in the above.) */ +#endif /* MODULE_PERIPH_FLASHPAGE */ #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS /** diff --git a/cpu/esp32/ld/esp32s3/sections.ld.in b/cpu/esp32/ld/esp32s3/sections.ld.in index d9cbb07cf629..036dbed742d4 100644 --- a/cpu/esp32/ld/esp32s3/sections.ld.in +++ b/cpu/esp32/ld/esp32s3/sections.ld.in @@ -619,6 +619,17 @@ SECTIONS . = _heap_end; _eheap = ABSOLUTE(.); + +#ifdef MODULE_PERIPH_FLASHPAGE + .flash_writable (NOLOAD) : ALIGN(65536) + { + _fp_mem_start = . ; + KEEP(*(SORT(.flash_writable.*))) + _fp_mem_end = . ; + . = ALIGN(4096); + _end_fw = . ; + } > drom0_1_seg +#endif } ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/cpu/esp32/periph/Kconfig b/cpu/esp32/periph/Kconfig index 53a15e4cefd6..ca1f70d91e83 100644 --- a/cpu/esp32/periph/Kconfig +++ b/cpu/esp32/periph/Kconfig @@ -31,4 +31,22 @@ config MODULE_ESP_HW_COUNTER registers that can be used as low-level timer peripherals. Use this option to enable these CCOUNT and CCOMPARE register as low-level timer. +choice ESP_FLASHPAGE_CAPACITY + bool "Flashpage capacity" + default ESP_FLASHPAGE_CAPACITY_512K + depends on MODULE_PERIPH_FLASHPAGE + config ESP_FLASHPAGE_CAPACITY_64K + bool "64 kByte" + config ESP_FLASHPAGE_CAPACITY_128K + bool "128 kByte" + config ESP_FLASHPAGE_CAPACITY_256K + bool "256 kByte" + config ESP_FLASHPAGE_CAPACITY_512K + bool "512 kByte" + config ESP_FLASHPAGE_CAPACITY_1M + bool "1 MByte" + config ESP_FLASHPAGE_CAPACITY_2M + bool "2 MByte" +endchoice + endif # TEST_KCONFIG diff --git a/cpu/esp32/periph/flashpage.c b/cpu/esp32/periph/flashpage.c new file mode 100644 index 000000000000..44e2bc02f972 --- /dev/null +++ b/cpu/esp32/periph/flashpage.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2022 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_esp32 + * @{ + * + * @file + * @brief Implementation of the peripheral flashpage interface + * + * @author Gunar Schorcht + * @} + */ + +#include + +#include "architecture.h" +#include "cpu.h" +#include "irq.h" +#include "periph/flashpage.h" + +#include "irq.h" +#include "log.h" + +#include "esp_flash_partitions.h" +#include "esp_spi_flash.h" +#include "rom/cache.h" +#include "rom/spi_flash.h" +#include "soc/mmu.h" +#include "soc/soc.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#define ESP_PART_TABLE_ADDR 0x8000 /* TODO configurable as used in Makefile.include */ +#define ESP_PART_TABLE_SIZE 0xC00 +#define ESP_PART_ENTRY_SIZE 0x20 +#define ESP_PART_ENTRY_MAGIC ESP_PARTITION_MAGIC + +extern uint8_t _fp_mem_start; /* start address in CPU address space */ +extern uint8_t _fp_mem_end; +extern uint8_t _end_fw; + +static uint32_t _fp_flash_start; /* start address in flash */ + +void IRAM_ATTR esp_flashpage_init(void) +{ + /* CONFIG_ESP_FLASHPAGE_CAPACITY has to be a multiple of SPI_FLASH_MMU_PAGE_SIZE */ + assert((CONFIG_ESP_FLASHPAGE_CAPACITY % SPI_FLASH_MMU_PAGE_SIZE) == 0); + + DEBUG("%s pages in CPU address space @0x%08"PRIx32"...0x%08"PRIx32"\n", __func__, + CPU_FLASH_BASE, CPU_FLASH_BASE + CONFIG_ESP_FLASHPAGE_CAPACITY - 1); + + _fp_flash_start = FLASHPAGE_ADDR_START; + + DEBUG("%s pages in flash @0x%08"PRIx32"...0x%08"PRIx32"\n", __func__, + _fp_flash_start, _fp_flash_start + CONFIG_ESP_FLASHPAGE_CAPACITY - 1); + + uint32_t state = irq_disable(); + + uint32_t p_numof = CONFIG_ESP_FLASHPAGE_CAPACITY / SPI_FLASH_MMU_PAGE_SIZE; + uint32_t p_addr = FLASHPAGE_ADDR_START; + +#if CPU_FAM_ESP32S2 + /* ESP32-S2 requires special handling to enable the MMU pages in Cache + * explicitly */ + + uint32_t autoload = Cache_Suspend_ICache(); + Cache_Invalidate_ICache_All(); + int res = Cache_Ibus_MMU_Set(MMU_ACCESS_FLASH, (uint32_t)&_fp_mem_start, + p_addr, 64, p_numof, 0); + Cache_Resume_ICache(autoload); + + DEBUG("%s DCache MMU set paddr=%08x vaddr=%08x size=%d n=%u\n", __func__, + p_addr, (uint32_t)&_fp_mem_start, CONFIG_ESP_FLASHPAGE_CAPACITY, + p_numof); + + if (res != ESP_OK) { + LOG_TAG_ERROR("flashpage", + "Could not map MMU pages in DCache, error: %d\n", res); + } +#else + uint32_t p_mmu = ((uint32_t)&_fp_mem_start - SOC_DROM_LOW) / SPI_FLASH_MMU_PAGE_SIZE; + + while (p_numof--) { + uint32_t p_flash = p_addr / SPI_FLASH_MMU_PAGE_SIZE; + DEBUG("%s map MMU page %"PRIu32" @0x%08"PRIx32" to " + "flash page %"PRIu32" @0x%08"PRIx32"\n", __func__, + p_mmu, (p_mmu * SPI_FLASH_MMU_PAGE_SIZE) + SOC_DROM_LOW, + p_flash, p_flash * SPI_FLASH_MMU_PAGE_SIZE); + SOC_MMU_DPORT_PRO_FLASH_MMU_TABLE[p_mmu] = SOC_MMU_PAGE_IN_FLASH(p_flash); + p_addr += SPI_FLASH_MMU_PAGE_SIZE; + p_mmu++; + } +#endif + irq_restore(state); + + if (IS_ACTIVE(ENABLE_DEBUG)) { + spi_flash_mmap_dump(); + } +} + +void flashpage_erase(unsigned page) +{ + assert(page < FLASHPAGE_NUMOF); + + uint32_t flash_addr = _fp_flash_start + (page * FLASHPAGE_SIZE); + + DEBUG("%s erase page in flash @0x%08"PRIx32"\n", __func__, flash_addr); + + int res = spi_flash_erase_range(flash_addr, FLASHPAGE_SIZE); + if (res != ESP_OK) { + LOG_TAG_ERROR("flashpage", "Could not erase page %u, error %d\n", + page, res); + } +} + +void flashpage_write(void *target_addr, const void *data, size_t len) +{ + DEBUG("%s write %u byte from @%p to @%p\n", + __func__, len, data, target_addr); + + /* assert multiples of FLASHPAGE_WRITE_BLOCK_SIZE are written */ + assert(!(len % FLASHPAGE_WRITE_BLOCK_SIZE)); + + /* ensure writes to flash are aligned */ + assert(!((unsigned)target_addr % FLASHPAGE_WRITE_BLOCK_ALIGNMENT)); + + /* ensure the length doesn't exceed the actual flash size */ + assert(((unsigned)target_addr + len) <= + (CPU_FLASH_BASE + (FLASHPAGE_SIZE * FLASHPAGE_NUMOF))); + + uint32_t flash_addr = ((uint32_t)target_addr - (uint32_t)&_fp_mem_start) + _fp_flash_start; + + DEBUG("%s write to CPU address @%p (flash @0x%08"PRIx32")\n", + __func__, target_addr, flash_addr); + + int res = spi_flash_write(flash_addr, data, len); + if (res != ESP_OK) { + LOG_TAG_ERROR("flashpage", "Could not write to CPU address @%p " + "(flash @0x%08"PRIx32"), error %d\n", + target_addr, flash_addr, res); + } +} + +unsigned flashpage_first_free(void) +{ + /* _end_fw is page aligned */ + return flashpage_page(&_end_fw); +} + +unsigned flashpage_last_free(void) +{ +// return flashpage_page((const void *)SOC_DROM_HIGH) - 1; + return flashpage_page((void *)(CPU_FLASH_BASE + CONFIG_ESP_FLASHPAGE_CAPACITY)) - 1; +} diff --git a/cpu/esp32/startup.c b/cpu/esp32/startup.c index 9455f4033aeb..7f8bb89c2ee7 100644 --- a/cpu/esp32/startup.c +++ b/cpu/esp32/startup.c @@ -289,6 +289,11 @@ static NORETURN void IRAM system_init (void) print_board_config(); #endif +#if IS_USED(MODULE_PERIPH_FLASHPAGE) + extern void esp_flashpage_init(void); + esp_flashpage_init(); +#endif + #if IS_USED(MODULE_MTD) /* init flash drive */ extern void spi_flash_drive_init (void); diff --git a/cpu/esp_common/Makefile.include b/cpu/esp_common/Makefile.include index 256517041481..4b4d3e3de3d4 100644 --- a/cpu/esp_common/Makefile.include +++ b/cpu/esp_common/Makefile.include @@ -150,12 +150,22 @@ TEST_EXTRA_FILES += $(FLASHFILE) $(BINDIR)/partitions.bin $(BOOTLOADER_BIN) # table setting PARTITION_TABLE_CSV. PARTITION_TABLE_CSV ?= $(BINDIR)/partitions.csv +ifneq (,$(filter periph_flashpage_in_address_space,$(USEMODULE))) $(BINDIR)/partitions.csv: $(FLASHFILE) $(Q)printf "\n" > $(BINDIR)/partitions.csv $(Q)printf "nvs, data, nvs, 0x9000, 0x6000\n" >> $@ $(Q)printf "phy_init, data, phy, 0xf000, 0x1000\n" >> $@ + $(Q)printf "flashpage, data, phy, $(FLASHPAGE_ADDR_START), $(FLASHPAGE_CAP)\n" >> $@ $(Q)printf "factory, app, factory, $(FLASHFILE_POS), " >> $@ $(Q)ls -l $< | awk '{ print $$5 }' >> $@ +else +$(BINDIR)/partitions.csv: $(FLASHFILE) + $(Q)printf "\n" > $(BINDIR)/partitions.csv + $(Q)printf "nvs, data, nvs, 0x9000, 0x6000\n" >> $@ + $(Q)printf "phy_init, data, phy, 0xf000, 0x1000\n" >> $@ + $(Q)printf "factory, app, factory, $(FLASHFILE_POS), " >> $@ + $(Q)ls -l $< | awk '{ print $$5 }' >> $@ +endif $(BINDIR)/partitions.bin: $(PARTITION_TABLE_CSV) $(Q)python3 $(RIOTTOOLS)/esptools/gen_esp32part.py --verify $< $@ diff --git a/tests/periph_flashpage/Makefile b/tests/periph_flashpage/Makefile index cd13ca829289..f105886fbca7 100644 --- a/tests/periph_flashpage/Makefile +++ b/tests/periph_flashpage/Makefile @@ -7,6 +7,7 @@ FEATURES_OPTIONAL += periph_flashpage_pagewise FEATURES_OPTIONAL += periph_flashpage_rwee USEMODULE += od +USEMODULE += od_string USEMODULE += shell # avoid running Kconfig by default diff --git a/tests/periph_flashpage/app.config.test b/tests/periph_flashpage/app.config.test index 20d96a6762ed..845ea3faf283 100644 --- a/tests/periph_flashpage/app.config.test +++ b/tests/periph_flashpage/app.config.test @@ -1,5 +1,6 @@ # this file enables modules defined in Kconfig. Do not use this file for # application configuration. This is only needed during migration. CONFIG_MODULE_OD=y +CONFIG_MODULE_OD_STRING=y CONFIG_MODULE_PERIPH_FLASHPAGE=y CONFIG_MODULE_SHELL=y diff --git a/tests/periph_flashpage/main.c b/tests/periph_flashpage/main.c index 48932cf5ff49..6f8e92d12bc8 100644 --- a/tests/periph_flashpage/main.c +++ b/tests/periph_flashpage/main.c @@ -81,31 +81,9 @@ static int getpage(const char *str) } #ifdef MODULE_PERIPH_FLASHPAGE_PAGEWISE -static void dumpchar(uint8_t mem) -{ - if (mem >= ' ' && mem <= '~') { - printf(" %c ", mem); - } - else { - printf(" ?? "); - } -} - static void memdump(void *addr, size_t len) { - unsigned pos = 0; - uint8_t *mem = (uint8_t *)addr; - - while (pos < (unsigned)len) { - for (unsigned i = 0; i < LINE_LEN; i++) { - printf("0x%02x ", mem[pos + i]); - } - puts(""); - for (unsigned i = 0; i < LINE_LEN; i++) { - dumpchar(mem[pos++]); - } - puts(""); - } + od_hex_dump (addr, len, LINE_LEN); } static void dump_local(void)