From 32168da8d6c1720efb065b5e8c70f1ad4f927d8a Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sat, 7 Jan 2023 13:11:31 +0100 Subject: [PATCH] cpu/esp32: add flashpage support f --- cpu/esp32/Makefile.dep | 2 +- cpu/esp32/Makefile.features | 3 + cpu/esp32/Makefile.include | 1 + cpu/esp32/esp-idf/Kconfig | 2 +- cpu/esp32/periph/flashpage.c | 161 ++++++++++++++++++++++++++++++++ cpu/esp32/startup.c | 5 + cpu/esp_common/Makefile.include | 10 ++ 7 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 cpu/esp32/periph/flashpage.c diff --git a/cpu/esp32/Makefile.dep b/cpu/esp32/Makefile.dep index 600b94af0a..f22aab7c0e 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 6910725a77..5f3da5066a 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 1a5731c7c5..0a63fe30d7 100644 --- a/cpu/esp32/Makefile.include +++ b/cpu/esp32/Makefile.include @@ -107,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 114701e809..feff3a103e 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/periph/flashpage.c b/cpu/esp32/periph/flashpage.c new file mode 100644 index 0000000000..44e2bc02f9 --- /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 9455f4033a..7f8bb89c2e 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 2565170414..4b4d3e3de3 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 $< $@