From 671787a966d2d5bc2061db82ee0cf3471a287184 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Tue, 7 Mar 2017 18:38:27 +0800 Subject: [PATCH] After rebasing, it was found out that flushing the cache drops the writeback-pending psram cache lines on the ground. We now evict these by reading 64/128K of memory before flushing the cache. Also fixes a snafu in psram cache mode (inverted hi/lo and even/odd selectors) as well as an option to not let the heap allocator touch the psram. --- components/esp32/Kconfig | 17 +++++++++- components/esp32/cpu_start.c | 8 +++-- components/esp32/heap_alloc_caps.c | 2 +- components/esp32/include/esp_psram.h | 10 ++++++ components/esp32/psram.c | 49 ++++++++++++++++++++++++++-- components/spi_flash/flash_mmap.c | 7 ++++ 6 files changed, 85 insertions(+), 8 deletions(-) diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index bafb280ee..618f14e76 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -173,8 +173,17 @@ config MEMMAP_SPIRAM_SIZE help Size of external SPI RAM +config MEMMAP_SPIRAM_NO_HEAPALLOC + bool "Initialize PSRAM memory but do not add to heap allocator" + default "n" + help + This initializes the PSRAM as normal, but does not make the heap allocator aware of the + memory region. You can use the memory region from 0x3F800000-0x3FBFFFFF freely, but + need to do your own memory management there. + config MEMMAP_SPIRAM_TEST bool "On SPI RAM init, do a quick memory test" + depends on !MEMMAP_SPIRAM_NO_HEAPALLOC default "n" help This does a quick memory test on boot-up. This takes about a second for 4MiB of SPI RAM. @@ -191,7 +200,13 @@ config MEMMAP_SPIRAM_ENABLE_MALLOC config MEMMAP_SPIRAM_ALLOC_LIMIT_INTERNAL int "Always put malloc()s smaller than this size, in bytes, in internal RAM" depends on MEMMAP_SPIRAM_ENABLE_MALLOC - default 1024 + range 4096 4194304 + default 4096 + help + Always tries to allocate heap allocation requests smaller than defined here in + internal RAM instead of PSRAM; allocations larger than this will initially + go to PSRAM. If either of these initial allocations fails, allocation in the + other memory region will be attempted as a backup option. endif diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 08229605d..246fc6653 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -95,10 +95,10 @@ extern volatile int port_xSchedulerRunning[2]; static const char* TAG = "cpu_start"; -#if CONFIG_MEMMAP_SMP -#define PSRAM_MODE PSRAM_VADDR_MODE_EVENODD -#else +#if CONFIG_FREERTOS_UNICORE #define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL +#else +#define PSRAM_MODE PSRAM_VADDR_MODE_EVENODD #endif /* @@ -147,6 +147,8 @@ void IRAM_ATTR call_start_cpu0() if ( psram_enable(PSRAM_CACHE_F40M_S40M, PSRAM_MODE) != ESP_OK) { ESP_EARLY_LOGE(TAG, "PSRAM enabled but initialization failed. Bailing out."); abort(); + } else { + ESP_EARLY_LOGI(TAG, "PSRAM initialized, cache is in %s mode.", (PSRAM_MODE==PSRAM_VADDR_MODE_EVENODD)?"even/odd (2-core)":"normal (1-core"); } #endif diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 703f0c119..fbde06614 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -272,7 +272,7 @@ void heap_alloc_caps_init() { #endif #endif -#if CONFIG_MEMMAP_SPIRAM_ENABLE +#if CONFIG_MEMMAP_SPIRAM_ENABLE && !CONFIG_MEMMAP_SPIRAM_NO_HEAPALLOC if (CONFIG_MEMMAP_SPIRAM_SIZE < 0x400000) { disable_mem_region((void*)0x3f800000+CONFIG_MEMMAP_SPIRAM_SIZE, (void*)0x3fc00000); //Disable unused SPI SRAM region } diff --git a/components/esp32/include/esp_psram.h b/components/esp32/include/esp_psram.h index 38f9fc740..d449fa403 100644 --- a/components/esp32/include/esp_psram.h +++ b/components/esp32/include/esp_psram.h @@ -51,4 +51,14 @@ typedef enum { */ esp_err_t psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode); + +/** + * @brief Write back all psram data contained in the cache + * + * Before the flash/psram cache is flushed (=invalidated on esp32), the psram + * data that resides there needs to be written back This routine does that. + */ +void esp_psram_writeback_cache(); + + #endif diff --git a/components/esp32/psram.c b/components/esp32/psram.c index 93d1f99d2..c0a63439e 100644 --- a/components/esp32/psram.c +++ b/components/esp32/psram.c @@ -550,11 +550,11 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra CLEAR_PERI_REG_MASK(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_DRAM_HL|DPORT_PRO_DRAM_SPLIT); CLEAR_PERI_REG_MASK(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_DRAM_HL|DPORT_APP_DRAM_SPLIT); if (vaddrmode == PSRAM_VADDR_MODE_LOWHIGH) { - SET_PERI_REG_MASK(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_DRAM_SPLIT); - SET_PERI_REG_MASK(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_DRAM_SPLIT); - } else if (vaddrmode == PSRAM_VADDR_MODE_EVENODD) { SET_PERI_REG_MASK(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_DRAM_HL); SET_PERI_REG_MASK(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_DRAM_HL); + } else if (vaddrmode == PSRAM_VADDR_MODE_EVENODD) { + SET_PERI_REG_MASK(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_DRAM_SPLIT); + SET_PERI_REG_MASK(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_DRAM_SPLIT); } CLEAR_PERI_REG_MASK(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DRAM1|DPORT_PRO_CACHE_MASK_OPSDRAM); //use Dram1 to visit ext sram. @@ -566,3 +566,46 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra CLEAR_PERI_REG_MASK(SPI_PIN_REG(0), SPI_CS1_DIS_M); //ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM) } +/* + Before flushing the cache, if psram is enabled, we need to write back the data in the cache to the psram first, + otherwise it will get lost. For now, we just read 64/128K of random PSRAM memory to do this. Yes, we should be + able to optimize this. Later. +*/ +void IRAM_ATTR esp_psram_writeback_cache() +{ + int x; + volatile int i=0; + volatile uint8_t *psram=(volatile uint8_t*)0x3F800000; + int cacheWasDisabled=0; + + //We need cache enabled for this to work. Re-enable it if needed; make sure we + //disable it again on exit as well. + if (REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE)==0) { + cacheWasDisabled|=(1<<0); + SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 1, DPORT_PRO_CACHE_ENABLE_S); + } +#ifndef CONFIG_FREERTOS_UNICORE + if (REG_GET_BIT(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_CACHE_ENABLE)==0) { + cacheWasDisabled|=(1<<1); + SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 1, DPORT_APP_CACHE_ENABLE_S); + } +#endif + +#if CONFIG_FREERTOS_UNICORE + for (x=0; x<1024*64; x+=32) { + i+=psram[x]; + } +#else + for (x=0; x<1024*64; x+=32) { + i+=psram[x]; + i+=psram[x+(1024*1024*2)+(1024*64)]; //address picked to also clear cache of app cpu in low/high mode + } + ets_printf("%x\n", i); +#endif + + if (cacheWasDisabled&(1<<0)) SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 0, DPORT_PRO_CACHE_ENABLE_S); +#ifndef CONFIG_FREERTOS_UNICORE + if (cacheWasDisabled&(1<<1)) SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 0, DPORT_APP_CACHE_ENABLE_S); +#endif +} + diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index 221d2ced6..62e617950 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -31,6 +31,7 @@ #include "esp_flash_encrypt.h" #include "esp_log.h" #include "cache_utils.h" +#include "esp_psram.h" #ifndef NDEBUG // Enable built-in checks in queue.h in debug builds @@ -193,6 +194,9 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_ entire cache. */ if (!did_flush && need_flush) { +#if CONFIG_MEMMAP_SPIRAM_ENABLE + esp_psram_writeback_cache(); +#endif Cache_Flush(0); Cache_Flush(1); } @@ -298,6 +302,9 @@ static inline IRAM_ATTR bool update_written_pages(size_t start_addr, size_t leng tricky because mmaped memory can be used on un-pinned cores, or the pointer passed between CPUs. */ +#if CONFIG_MEMMAP_SPIRAM_ENABLE + esp_psram_writeback_cache(); +#endif Cache_Flush(0); #ifndef CONFIG_FREERTOS_UNICORE Cache_Flush(1);