From c4f87977dc7e9a682c58f2916dc9eba730a20455 Mon Sep 17 00:00:00 2001 From: "Alan C. Assis" Date: Tue, 2 Feb 2021 20:29:22 -0300 Subject: [PATCH] xtensa/esp32: Fix cache issue detected by DEBUG_ASSERTION --- arch/xtensa/src/esp32/Make.defs | 8 + arch/xtensa/src/esp32/esp32_spicache.c | 140 ++++++++++++++++++ arch/xtensa/src/esp32/esp32_spicache.h | 91 ++++++++++++ arch/xtensa/src/esp32/esp32_spiflash.c | 80 +--------- arch/xtensa/src/esp32/esp32_spiflash.h | 2 + arch/xtensa/src/esp32/esp32_spiram.c | 134 +++++++++++++++++ arch/xtensa/src/esp32/esp32_spiram.h | 39 +++++ .../esp32/esp32-devkitc/scripts/esp32_rom.ld | 1 - .../esp32-ethernet-kit/scripts/esp32_rom.ld | 1 - .../esp32-wrover-kit/scripts/esp32_rom.ld | 1 - 10 files changed, 415 insertions(+), 82 deletions(-) create mode 100644 arch/xtensa/src/esp32/esp32_spicache.c create mode 100644 arch/xtensa/src/esp32/esp32_spicache.h diff --git a/arch/xtensa/src/esp32/Make.defs b/arch/xtensa/src/esp32/Make.defs index 01165b1d5a..a721eb1103 100644 --- a/arch/xtensa/src/esp32/Make.defs +++ b/arch/xtensa/src/esp32/Make.defs @@ -118,6 +118,14 @@ CHIP_CSRCS += esp32_spi.c endif endif +# SPIFLASH and SPIRAM need spicache.c + +ifeq ($(CONFIG_ESP32_SPIFLASH),y) +CHIP_CSRCS += esp32_spicache.c +else ifeq ($(CONFIG_ESP32_SPIRAM),y) +CHIP_CSRCS += esp32_spicache.c +endif + ifeq ($(CONFIG_ESP32_SPIFLASH),y) CHIP_CSRCS += esp32_spiflash.c endif diff --git a/arch/xtensa/src/esp32/esp32_spicache.c b/arch/xtensa/src/esp32/esp32_spicache.c new file mode 100644 index 0000000000..65fca75aea --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_spicache.c @@ -0,0 +1,140 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_spicache.c + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_ESP32_SPIRAM) || defined(CONFIG_ESP32_SPIFLASH) + +#include +#include +#include +#include +#include +#include + +#include "xtensa.h" +#include "xtensa_attr.h" + +#include "hardware/esp32_soc.h" +#include "hardware/esp32_spi.h" +#include "hardware/esp32_dport.h" + +#ifdef CONFIG_ESP32_SPIRAM +#include "esp32_spiram.h" +#endif + +#include "esp32_spicache.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: spiflash_disable_cache + ****************************************************************************/ + +void IRAM_ATTR spi_disable_cache(int cpu, uint32_t *state) +{ + const uint32_t cache_mask = 0x3f; /* Caches' bits in CTRL1_REG */ + uint32_t regval; + uint32_t ret = 0; + + if (cpu == 0) + { + ret |= (getreg32(DPORT_PRO_CACHE_CTRL1_REG) & cache_mask); + while (((getreg32(DPORT_PRO_DCACHE_DBUG0_REG) >> + DPORT_PRO_CACHE_STATE_S) & DPORT_PRO_CACHE_STATE) != 1) + { + ; + } + + regval = getreg32(DPORT_PRO_CACHE_CTRL_REG); + regval &= ~DPORT_PRO_CACHE_ENABLE_M; + putreg32(regval, DPORT_PRO_CACHE_CTRL_REG); + } +#ifdef CONFIG_SMP + else + { + ret |= (getreg32(DPORT_APP_CACHE_CTRL1_REG) & cache_mask); + while (((getreg32(DPORT_APP_DCACHE_DBUG0_REG) >> + DPORT_APP_CACHE_STATE_S) & DPORT_APP_CACHE_STATE) != 1) + { + ; + } + + regval = getreg32(DPORT_APP_CACHE_CTRL_REG); + regval &= ~DPORT_APP_CACHE_ENABLE_M; + putreg32(regval, DPORT_APP_CACHE_CTRL_REG); + } + +#endif + *state = ret; +} + +/**************************************************************************** + * Name: spiflash_enable_cache + ****************************************************************************/ + +void IRAM_ATTR spi_enable_cache(int cpu, uint32_t state) +{ + const uint32_t cache_mask = 0x3f; /* Caches' bits in CTRL1_REG */ + uint32_t regval; + uint32_t ctrlreg; + uint32_t ctrl1reg; + uint32_t ctrlmask; + + if (cpu == 0) + { + ctrlreg = DPORT_PRO_CACHE_CTRL_REG; + ctrl1reg = DPORT_PRO_CACHE_CTRL1_REG; + ctrlmask = DPORT_PRO_CACHE_ENABLE_M; + } +#ifdef CONFIG_SMP + else + { + ctrlreg = DPORT_APP_CACHE_CTRL_REG; + ctrl1reg = DPORT_APP_CACHE_CTRL1_REG; + ctrlmask = DPORT_APP_CACHE_ENABLE_M; + } +#endif + + regval = getreg32(ctrlreg); + regval |= ctrlmask; + putreg32(regval, ctrlreg); + + regval = getreg32(ctrl1reg); + regval &= ~cache_mask; + regval |= state; + putreg32(regval, ctrl1reg); +} + +#endif /* CONFIG_ESP32_SPICACHE */ diff --git a/arch/xtensa/src/esp32/esp32_spicache.h b/arch/xtensa/src/esp32/esp32_spicache.h new file mode 100644 index 0000000000..3cdd00397f --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_spicache.h @@ -0,0 +1,91 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_spicache.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_ESP32_ESP32_SPICACHE_H +#define __ARCH_XTENSA_SRC_ESP32_ESP32_SPICACHE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "xtensa_attr.h" + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: spi_disable_cache + * + * Description: + * Disable cache for SPI FLASH on a CPU + * + * Input Parameters: + * - cpu: ID of CPU to disable cache + * - state: pointer to cache reg state that will be returned + * + * Returned Value: + * None (the return will be over *state) + * + ****************************************************************************/ + +void IRAM_ATTR spi_disable_cache(int cpu, uint32_t *state); + +/**************************************************************************** + * Name: spi_enable_cache + * + * Description: + * Enable cache for SPI FLASH on a CPU + * + * Input Parameters: + * - cpu: ID of CPU to enable cache + * - state: the cache reg state to be set + * + * Returned Value: + * None + * + ****************************************************************************/ + +void IRAM_ATTR spi_enable_cache(int cpu, uint32_t state); + +#ifdef __cplusplus +} +#endif +#undef EXTERN + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_XTENSA_SRC_ESP32_ESP32_SPICACHE_H */ diff --git a/arch/xtensa/src/esp32/esp32_spiflash.c b/arch/xtensa/src/esp32/esp32_spiflash.c index f019f0157d..b0ef6c5a3d 100644 --- a/arch/xtensa/src/esp32/esp32_spiflash.c +++ b/arch/xtensa/src/esp32/esp32_spiflash.c @@ -51,6 +51,7 @@ #include "esp32_spiram.h" #endif +#include "esp32_spicache.h" #include "esp32_spiflash.h" /**************************************************************************** @@ -397,85 +398,6 @@ static inline void spi_reset_regbits(struct esp32_spiflash_s *priv, putreg32(tmp & (~bits), priv->config->reg_base + offset); } -/**************************************************************************** - * Name: spiflash_disable_cache - ****************************************************************************/ - -static void IRAM_ATTR spi_disable_cache(int cpu, uint32_t *state) -{ - const uint32_t cache_mask = 0x3f; /* Caches' bits in CTRL1_REG */ - uint32_t regval; - uint32_t ret = 0; - - if (cpu == 0) - { - ret |= (getreg32(DPORT_PRO_CACHE_CTRL1_REG) & cache_mask); - while (((getreg32(DPORT_PRO_DCACHE_DBUG0_REG) >> - DPORT_PRO_CACHE_STATE_S) & DPORT_PRO_CACHE_STATE) != 1) - { - ; - } - - regval = getreg32(DPORT_PRO_CACHE_CTRL_REG); - regval &= ~DPORT_PRO_CACHE_ENABLE_M; - putreg32(regval, DPORT_PRO_CACHE_CTRL_REG); - } -#ifdef CONFIG_SMP - else - { - ret |= (getreg32(DPORT_APP_CACHE_CTRL1_REG) & cache_mask); - while (((getreg32(DPORT_APP_DCACHE_DBUG0_REG) >> - DPORT_APP_CACHE_STATE_S) & DPORT_APP_CACHE_STATE) != 1) - { - ; - } - - regval = getreg32(DPORT_APP_CACHE_CTRL_REG); - regval &= ~DPORT_APP_CACHE_ENABLE_M; - putreg32(regval, DPORT_APP_CACHE_CTRL_REG); - } - -#endif - *state = ret; -} - -/**************************************************************************** - * Name: spiflash_enable_cache - ****************************************************************************/ - -static void IRAM_ATTR spi_enable_cache(int cpu, uint32_t state) -{ - const uint32_t cache_mask = 0x3f; /* Caches' bits in CTRL1_REG */ - uint32_t regval; - uint32_t ctrlreg; - uint32_t ctrl1reg; - uint32_t ctrlmask; - - if (cpu == 0) - { - ctrlreg = DPORT_PRO_CACHE_CTRL_REG; - ctrl1reg = DPORT_PRO_CACHE_CTRL1_REG; - ctrlmask = DPORT_PRO_CACHE_ENABLE_M; - } -#ifdef CONFIG_SMP - else - { - ctrlreg = DPORT_APP_CACHE_CTRL_REG; - ctrl1reg = DPORT_APP_CACHE_CTRL1_REG; - ctrlmask = DPORT_APP_CACHE_ENABLE_M; - } -#endif - - regval = getreg32(ctrlreg); - regval |= ctrlmask; - putreg32(regval, ctrlreg); - - regval = getreg32(ctrl1reg); - regval &= ~cache_mask; - regval |= state; - putreg32(regval, ctrl1reg); -} - /**************************************************************************** * Name: esp32_spiflash_opstart * diff --git a/arch/xtensa/src/esp32/esp32_spiflash.h b/arch/xtensa/src/esp32/esp32_spiflash.h index 3c9099aa1a..cda155d8f1 100644 --- a/arch/xtensa/src/esp32/esp32_spiflash.h +++ b/arch/xtensa/src/esp32/esp32_spiflash.h @@ -31,6 +31,8 @@ #include #include +#include "xtensa_attr.h" + #ifndef __ASSEMBLY__ #undef EXTERN diff --git a/arch/xtensa/src/esp32/esp32_spiram.c b/arch/xtensa/src/esp32/esp32_spiram.c index 9880a8b9b1..bb41e00f9d 100644 --- a/arch/xtensa/src/esp32/esp32_spiram.c +++ b/arch/xtensa/src/esp32/esp32_spiram.c @@ -33,8 +33,10 @@ #include #include #include +#include #include "esp32_spiram.h" +#include "esp32_spicache.h" #include "esp32_psram.h" #include "xtensa.h" #include "xtensa_attr.h" @@ -97,6 +99,138 @@ size_t __attribute__((weak)) esp_himem_reserved_area_size(void) * Public Functions ****************************************************************************/ +unsigned int IRAM_ATTR cache_sram_mmu_set(int cpu_no, int pid, + unsigned int vaddr, + unsigned int paddr, + int psize, int num) +{ + uint32_t regval; + uint32_t statecpu0; +#ifdef CONFIG_SMP + uint32_t statecpu1; +#endif + unsigned int i; + unsigned int shift; + unsigned int mask_s; + unsigned int mmu_addr; + unsigned int mmu_table_val; + irqstate_t flags; + + /* address check */ + + if ((ADDRESS_CHECK(vaddr, psize)) || (ADDRESS_CHECK(paddr, psize))) + { + return MMU_SET_ADDR_ALIGNED_ERROR; + } + + /* psize check */ + + if (psize == 32) + { + shift = 15; + mask_s = 0; + } + else if (psize == 16) + { + shift = 14; + mask_s = 1; + } + else if (psize == 8) + { + shift = 13; + mask_s = 2; + } + else if (psize == 4) + { + shift = 12; + mask_s = 3; + } + else if (psize == 2) + { + shift = 11; + mask_s = 4; + } + else + { + return MMU_SET_PAGE_SIZE_ERROR; + } + + /* mmu value */ + + mmu_table_val = paddr >> shift; + + /* mmu_addr */ + + if (pid == 0 || pid == 1) + { + if (vaddr >= PRO_DRAM1_START_ADDR && vaddr < PRO_DRAM1_END_ADDR(psize)) + { + mmu_addr = 1152 + ((vaddr & (0x3fffff >> mask_s)) >> shift); + } + else + { + return MMU_SET_VADDR_OUT_RANGE; + } + } + else + { + if (vaddr >= PRO_DRAM1_START_ADDR && vaddr < PRO_DRAM1_END_ADDR(psize)) + { + mmu_addr = (1024 + (pid << 7)) + + ((vaddr & (0x3fffff >> mask_s)) >> shift); + } + else + { + return MMU_SET_VADDR_OUT_RANGE; + } + } + + /* The MMU registers are implemented in such a way that lookups from the + * cache subsystem may collide with CPU access to the MMU registers. We use + * the flash guards to make sure the cache is disabled. + */ + + flags = spin_lock_irqsave(); + + spi_disable_cache(0, &statecpu0); + +#ifdef CONFIG_SMP + spi_disable_cache(1, &statecpu1); +#endif + + /* mmu change */ + + for (i = 0; i < num; i++) + { + *(volatile unsigned int *)(CACHE_MMU_ADDRESS_BASE(cpu_no) + + mmu_addr * 4) = mmu_table_val + i; /* write table */ + mmu_addr++; + } + + if (cpu_no == 0) + { + regval = getreg32(DPORT_PRO_CACHE_CTRL1_REG); + regval &= ~DPORT_PRO_CMMU_SRAM_PAGE_MODE; + regval |= mask_s; + putreg32(regval, DPORT_PRO_CACHE_CTRL1_REG); + } + else + { + regval = getreg32(DPORT_APP_CACHE_CTRL1_REG); + regval &= ~DPORT_APP_CMMU_SRAM_PAGE_MODE; + regval |= mask_s; + putreg32(regval, DPORT_APP_CACHE_CTRL1_REG); + } + + spi_enable_cache(0, statecpu0); +#ifdef CONFIG_SMP + spi_enable_cache(1, statecpu1); +#endif + + spin_unlock_irqrestore(flags); + return 0; +} + void IRAM_ATTR esp_spiram_init_cache(void) { #ifdef CONFIG_SMP diff --git a/arch/xtensa/src/esp32/esp32_spiram.h b/arch/xtensa/src/esp32/esp32_spiram.h index 346fceff3c..28734a9f16 100644 --- a/arch/xtensa/src/esp32/esp32_spiram.h +++ b/arch/xtensa/src/esp32/esp32_spiram.h @@ -35,6 +35,45 @@ #define ESP_SPIRAM_SIZE_64MBITS 2 /* SPI RAM size is 64 MBits */ #define ESP_SPIRAM_SIZE_INVALID 3 /* SPI RAM size is invalid */ +/* Errors that can be returned by cache_sram_* */ + +#define MMU_SET_ADDR_ALIGNED_ERROR 1 +#define MMU_SET_PAGE_SIZE_ERROR 3 +#define MMU_SET_VADDR_OUT_RANGE 5 + +#define PROCACHE_MMU_ADDR_BASE 0x3FF10000 +#define APPCACHE_MMU_ADDR_BASE 0x3FF12000 + +/* sram address */ + +#define PRO_DRAM1_START_ADDR 0x3F800000 +#define PRO_DRAM1_END_ADDR(psize) (PRO_DRAM1_START_ADDR + ((psize) << 17)) + +/* cache mmu register file address */ + +#define CACHE_MMU_ADDRESS_BASE(cpu_no) ((cpu_no) ? (APPCACHE_MMU_ADDR_BASE) :\ + (PROCACHE_MMU_ADDR_BASE)) + +/* virtual address, physical address check */ + +#define ADDRESS_CHECK(addr,psize) (((addr) & (0xFFFF >>((64/(psize))-1))) != 0) + +/* CPU number check */ + +#define CPU_NUMBER_CHECK(cpu_no) (((cpu_no)<0) || ((cpu_no)>1)) + +/* PID check */ + +#define PID_CHECK(pid) (((pid)<0) || ((pid)>7)) + +/* flash MMU edge check (flash size default : 16*1024 K) */ + +#define FLASH_MMU_EDGE_CHECK(mmu_val,num) (((mmu_val) + (num)) > 256) + +/* sram MMU edge check (sram size default : 8*1024 K) */ + +#define SRAM_MMU_EDGE_CHECK(mmu_val,num,psize) (((mmu_val) + (num)) > ((8*1024)/(psize))) + /* Description: get SPI RAM size * return * - ESP_SPIRAM_SIZE_INVALID if SPI RAM not enabled or not valid diff --git a/boards/xtensa/esp32/esp32-devkitc/scripts/esp32_rom.ld b/boards/xtensa/esp32/esp32-devkitc/scripts/esp32_rom.ld index dd68edead4..f8f1cf813a 100644 --- a/boards/xtensa/esp32/esp32-devkitc/scripts/esp32_rom.ld +++ b/boards/xtensa/esp32/esp32-devkitc/scripts/esp32_rom.ld @@ -64,7 +64,6 @@ PROVIDE ( Cache_Flush = 0x40009a14 ); PROVIDE ( Cache_Read_Disable = 0x40009ab8 ); PROVIDE ( Cache_Read_Enable = 0x40009a84 ); PROVIDE ( Cache_Read_Init = 0x40009950 ); -PROVIDE ( cache_sram_mmu_set = 0x400097f4 ); /* This is static function, but can be used, not generated by script*/ PROVIDE ( calc_rtc_memory_crc = 0x40008170 ); PROVIDE ( calloc = 0x4000bee4 ); diff --git a/boards/xtensa/esp32/esp32-ethernet-kit/scripts/esp32_rom.ld b/boards/xtensa/esp32/esp32-ethernet-kit/scripts/esp32_rom.ld index dd68edead4..f8f1cf813a 100644 --- a/boards/xtensa/esp32/esp32-ethernet-kit/scripts/esp32_rom.ld +++ b/boards/xtensa/esp32/esp32-ethernet-kit/scripts/esp32_rom.ld @@ -64,7 +64,6 @@ PROVIDE ( Cache_Flush = 0x40009a14 ); PROVIDE ( Cache_Read_Disable = 0x40009ab8 ); PROVIDE ( Cache_Read_Enable = 0x40009a84 ); PROVIDE ( Cache_Read_Init = 0x40009950 ); -PROVIDE ( cache_sram_mmu_set = 0x400097f4 ); /* This is static function, but can be used, not generated by script*/ PROVIDE ( calc_rtc_memory_crc = 0x40008170 ); PROVIDE ( calloc = 0x4000bee4 ); diff --git a/boards/xtensa/esp32/esp32-wrover-kit/scripts/esp32_rom.ld b/boards/xtensa/esp32/esp32-wrover-kit/scripts/esp32_rom.ld index dd68edead4..f8f1cf813a 100644 --- a/boards/xtensa/esp32/esp32-wrover-kit/scripts/esp32_rom.ld +++ b/boards/xtensa/esp32/esp32-wrover-kit/scripts/esp32_rom.ld @@ -64,7 +64,6 @@ PROVIDE ( Cache_Flush = 0x40009a14 ); PROVIDE ( Cache_Read_Disable = 0x40009ab8 ); PROVIDE ( Cache_Read_Enable = 0x40009a84 ); PROVIDE ( Cache_Read_Init = 0x40009950 ); -PROVIDE ( cache_sram_mmu_set = 0x400097f4 ); /* This is static function, but can be used, not generated by script*/ PROVIDE ( calc_rtc_memory_crc = 0x40008170 ); PROVIDE ( calloc = 0x4000bee4 );