xtensa/esp32s3: Fix issue of system blocking when SPIRAM is used as stack
1. Fix issue of system blocking due to disable dcache. 2. Support Ext-SRAM-Cache mmu mapping in SMP mode. Signed-off-by: chenwen@espressif.com <chenwen@espressif.com>
This commit is contained in:
parent
5b1486f9ce
commit
638df3329b
@ -32,6 +32,7 @@
|
||||
#include "xtensa.h"
|
||||
#include "esp32s3_spiram.h"
|
||||
#include "esp32s3_himem.h"
|
||||
#include "esp32s3_spiflash_mtd.h"
|
||||
#include "hardware/esp32s3_soc.h"
|
||||
#include "hardware/esp32s3_cache_memory.h"
|
||||
#include "hardware/esp32s3_extmem.h"
|
||||
@ -82,7 +83,6 @@
|
||||
# define SPIRAM_BANKSWITCH_RESERVE 0
|
||||
#endif
|
||||
|
||||
#define MMU_PAGE_SIZE 0x10000
|
||||
#define MMU_PAGE_TO_BYTES(page_num) ((page_num) * MMU_PAGE_SIZE)
|
||||
#define BYTES_TO_MMU_PAGE(bytes) ((bytes) / MMU_PAGE_SIZE)
|
||||
|
||||
@ -129,7 +129,6 @@ extern int cache_dbus_mmu_set(uint32_t ext_ram, uint32_t vaddr,
|
||||
|
||||
static inline bool ramblock_idx_valid(int ramblock_idx);
|
||||
static inline bool rangeblock_idx_valid(int rangeblock_idx);
|
||||
static void set_bank(int virt_bank, int phys_bank, int ct);
|
||||
static uint32_t esp_himem_get_range_start(void);
|
||||
static uint32_t esp_himem_get_range_block(void);
|
||||
static uint32_t esp_himem_get_phy_block(void);
|
||||
@ -209,47 +208,6 @@ static inline bool rangeblock_idx_valid(int rangeblock_idx)
|
||||
return (rangeblock_idx >= 0 && rangeblock_idx < g_rangeblockcnt);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: set_bank
|
||||
*
|
||||
* Description:
|
||||
* Set DCache mmu mapping.
|
||||
*
|
||||
* Input Parameters:
|
||||
* virt_bank - Beginning of the virtual bank
|
||||
* phys_bank - Beginning of the physical bank
|
||||
* ct - Number of banks
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void set_bank(int virt_bank, int phys_bank, int ct)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
/* Suspend DRAM Case during configuration */
|
||||
|
||||
cache_suspend_dcache();
|
||||
ASSERT(cache_dbus_mmu_set(MMU_ACCESS_SPIRAM,
|
||||
SOC_EXTRAM_DATA_LOW +
|
||||
MMU_PAGE_TO_BYTES(virt_bank),
|
||||
MMU_PAGE_TO_BYTES(phys_bank), 64, ct, 0) == 0);
|
||||
|
||||
regval = getreg32(EXTMEM_DCACHE_CTRL1_REG);
|
||||
regval &= ~EXTMEM_DCACHE_SHUT_CORE0_BUS;
|
||||
putreg32(regval, EXTMEM_DCACHE_CTRL1_REG);
|
||||
|
||||
#if defined(CONFIG_SMP)
|
||||
regval = getreg32(EXTMEM_DCACHE_CTRL1_REG);
|
||||
regval &= ~EXTMEM_DCACHE_SHUT_CORE1_BUS;
|
||||
putreg32(regval, EXTMEM_DCACHE_CTRL1_REG);
|
||||
#endif
|
||||
|
||||
cache_resume_dcache(0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp_himem_get_range_start
|
||||
*
|
||||
@ -974,7 +932,7 @@ int esp_himem_map(esp_himem_handle_t handle,
|
||||
{
|
||||
virt_bank = himem_mmu_start + range->block_start + i + range_block;
|
||||
phys_bank = himem_phy_start + handle->block[i + ram_block];
|
||||
set_bank(virt_bank, phys_bank, 1);
|
||||
esp32s3_set_bank(virt_bank, phys_bank, 1);
|
||||
}
|
||||
|
||||
/* Set out pointer */
|
||||
|
@ -39,9 +39,11 @@
|
||||
#include <nuttx/mtd/mtd.h>
|
||||
|
||||
#include "hardware/esp32s3_soc.h"
|
||||
#include "hardware/esp32s3_cache_memory.h"
|
||||
|
||||
#include "xtensa_attr.h"
|
||||
#include "esp32s3_spiflash.h"
|
||||
#include "esp32s3_spiram.h"
|
||||
|
||||
#include "rom/esp32s3_spiflash.h"
|
||||
#include "esp32s3_spiflash_mtd.h"
|
||||
@ -71,6 +73,7 @@ enum spiflash_op_code_e
|
||||
SPIFLASH_OP_CODE_WRITE = 0,
|
||||
SPIFLASH_OP_CODE_READ,
|
||||
SPIFLASH_OP_CODE_ERASE,
|
||||
SPIFLASH_OP_CODE_SET_BANK,
|
||||
SPIFLASH_OP_CODE_ENCRYPT_READ,
|
||||
SPIFLASH_OP_CODE_ENCRYPT_WRITE
|
||||
};
|
||||
@ -99,6 +102,7 @@ struct spiflash_work_arg
|
||||
uint32_t addr;
|
||||
uint8_t *buffer;
|
||||
uint32_t size;
|
||||
uint32_t paddr;
|
||||
} op_arg;
|
||||
|
||||
volatile int ret;
|
||||
@ -144,7 +148,8 @@ static void esp32s3_spiflash_work(void *arg);
|
||||
static int esp32s3_async_op(enum spiflash_op_code_e opcode,
|
||||
uint32_t addr,
|
||||
const uint8_t *buffer,
|
||||
uint32_t size);
|
||||
uint32_t size,
|
||||
uint32_t paddr);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
@ -259,6 +264,12 @@ static void esp32s3_spiflash_work(void *arg)
|
||||
work_arg->ret = spi_flash_erase_range(work_arg->op_arg.addr,
|
||||
work_arg->op_arg.size);
|
||||
}
|
||||
else if (work_arg->op_code == SPIFLASH_OP_CODE_SET_BANK)
|
||||
{
|
||||
work_arg->ret = cache_dbus_mmu_map(work_arg->op_arg.addr,
|
||||
work_arg->op_arg.paddr,
|
||||
work_arg->op_arg.size);
|
||||
}
|
||||
else if (work_arg->op_code == SPIFLASH_OP_CODE_ENCRYPT_READ)
|
||||
{
|
||||
work_arg->ret = spi_flash_read_encrypted(work_arg->op_arg.addr,
|
||||
@ -300,7 +311,8 @@ static void esp32s3_spiflash_work(void *arg)
|
||||
static int esp32s3_async_op(enum spiflash_op_code_e opcode,
|
||||
uint32_t addr,
|
||||
const uint8_t *buffer,
|
||||
uint32_t size)
|
||||
uint32_t size,
|
||||
uint32_t paddr)
|
||||
{
|
||||
int ret;
|
||||
struct spiflash_work_arg work_arg =
|
||||
@ -311,6 +323,7 @@ static int esp32s3_async_op(enum spiflash_op_code_e opcode,
|
||||
.addr = addr,
|
||||
.buffer = (uint8_t *)buffer,
|
||||
.size = size,
|
||||
.paddr = paddr,
|
||||
},
|
||||
.sem = NXSEM_INITIALIZER(0, 0)
|
||||
};
|
||||
@ -370,7 +383,8 @@ static int esp32s3_erase(struct mtd_dev_s *dev, off_t startblock,
|
||||
#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
|
||||
if (stack_is_psram())
|
||||
{
|
||||
ret = esp32s3_async_op(SPIFLASH_OP_CODE_ERASE, offset, NULL, nbytes);
|
||||
ret = esp32s3_async_op(SPIFLASH_OP_CODE_ERASE, offset, NULL,
|
||||
nbytes, 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -438,7 +452,7 @@ static ssize_t esp32s3_read(struct mtd_dev_s *dev, off_t offset,
|
||||
if (stack_is_psram())
|
||||
{
|
||||
ret = esp32s3_async_op(SPIFLASH_OP_CODE_READ, offset,
|
||||
buffer, nbytes);
|
||||
buffer, nbytes, 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -544,7 +558,7 @@ static ssize_t esp32s3_read_decrypt(struct mtd_dev_s *dev,
|
||||
if (stack_is_psram())
|
||||
{
|
||||
ret = esp32s3_async_op(SPIFLASH_OP_CODE_ENCRYPT_READ, offset,
|
||||
buffer, nbytes);
|
||||
buffer, nbytes, 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -656,7 +670,7 @@ static ssize_t esp32s3_write(struct mtd_dev_s *dev, off_t offset,
|
||||
if (stack_is_psram())
|
||||
{
|
||||
ret = esp32s3_async_op(SPIFLASH_OP_CODE_WRITE, offset,
|
||||
buffer, nbytes);
|
||||
buffer, nbytes, 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -720,7 +734,7 @@ static ssize_t esp32s3_bwrite_encrypt(struct mtd_dev_s *dev,
|
||||
if (stack_is_psram())
|
||||
{
|
||||
ret = esp32s3_async_op(SPIFLASH_OP_CODE_ENCRYPT_WRITE, addr,
|
||||
buffer, size);
|
||||
buffer, size, 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -863,6 +877,43 @@ static int esp32s3_ioctl(struct mtd_dev_s *dev, int cmd,
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_set_bank
|
||||
*
|
||||
* Description:
|
||||
* Set Ext-SRAM-Cache mmu mapping.
|
||||
*
|
||||
* Input Parameters:
|
||||
* virt_bank - Beginning of the virtual bank
|
||||
* phys_bank - Beginning of the physical bank
|
||||
* ct - Number of banks
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void esp32s3_set_bank(int virt_bank, int phys_bank, int ct)
|
||||
{
|
||||
int ret;
|
||||
uint32_t vaddr = SOC_EXTRAM_DATA_LOW + MMU_PAGE_SIZE * virt_bank;
|
||||
uint32_t paddr = phys_bank * MMU_PAGE_SIZE;
|
||||
#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
|
||||
if (stack_is_psram())
|
||||
{
|
||||
ret = esp32s3_async_op(SPIFLASH_OP_CODE_SET_BANK, vaddr, NULL, ct,
|
||||
paddr);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ret = cache_dbus_mmu_map(vaddr, paddr, ct);
|
||||
}
|
||||
|
||||
DEBUGASSERT(ret == 0);
|
||||
UNUSED(ret);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_spiflash_alloc_mtdpart
|
||||
*
|
||||
|
@ -46,6 +46,24 @@ extern "C"
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_set_bank
|
||||
*
|
||||
* Description:
|
||||
* Set Ext-SRAM-Cache mmu mapping.
|
||||
*
|
||||
* Input Parameters:
|
||||
* virt_bank - Beginning of the virtual bank
|
||||
* phys_bank - Beginning of the physical bank
|
||||
* ct - Number of banks
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void esp32s3_set_bank(int virt_bank, int phys_bank, int ct);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_spiflash_mtd
|
||||
*
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <sys/param.h>
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
#include <nuttx/init.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "xtensa.h"
|
||||
@ -66,6 +67,22 @@
|
||||
#define SPIRAM_VADDR_MAP_SIZE 0
|
||||
#endif
|
||||
|
||||
/* Max MMU available paddr page num.
|
||||
* `MMU_MAX_PADDR_PAGE_NUM * MMU_PAGE_SIZE` means the max paddr
|
||||
* address supported by the MMU. e.g.: 16384 * 64KB, means MMU can
|
||||
* support 1GB paddr at most
|
||||
*/
|
||||
|
||||
#define MMU_MAX_PADDR_PAGE_NUM 16384
|
||||
|
||||
/* This is the mask used for mapping. e.g.: 0x4200_0000 & MMU_VADDR_MASK */
|
||||
|
||||
#define MMU_VADDR_MASK 0x1FFFFFF
|
||||
|
||||
/* MMU entry num */
|
||||
|
||||
#define MMU_ENTRY_NUM 512
|
||||
|
||||
static bool g_spiram_inited;
|
||||
|
||||
/* These variables are in bytes */
|
||||
@ -109,6 +126,7 @@ extern void cache_resume_dcache(uint32_t val);
|
||||
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_invalidate_addr(uint32_t addr, uint32_t size);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@ -142,10 +160,189 @@ static inline uint32_t mmu_valid_space(uint32_t *start_address)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mmu_check_valid_paddr_region
|
||||
*
|
||||
* Description:
|
||||
* Check if the paddr region is valid.
|
||||
*
|
||||
* Input Parameters:
|
||||
* paddr_start - start of the physical address
|
||||
* len - length, in bytes
|
||||
*
|
||||
* Returned Value:
|
||||
* True for valid.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline bool mmu_check_valid_paddr_region(uint32_t paddr_start,
|
||||
uint32_t len)
|
||||
{
|
||||
return (paddr_start < (MMU_PAGE_SIZE * MMU_MAX_PADDR_PAGE_NUM)) &&
|
||||
(len < (MMU_PAGE_SIZE * MMU_MAX_PADDR_PAGE_NUM)) &&
|
||||
((paddr_start + len - 1) <
|
||||
(MMU_PAGE_SIZE * MMU_MAX_PADDR_PAGE_NUM));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mmu_check_valid_ext_vaddr_region
|
||||
*
|
||||
* Description:
|
||||
* Check if the external memory vaddr region is valid.
|
||||
*
|
||||
* Input Parameters:
|
||||
* vaddr_start - start of the virtual address
|
||||
* len - length, in bytes
|
||||
*
|
||||
* Returned Value:
|
||||
* True for valid.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline bool mmu_check_valid_ext_vaddr_region(uint32_t vaddr_start,
|
||||
uint32_t len)
|
||||
{
|
||||
uint32_t vaddr_end = vaddr_start + len - 1;
|
||||
bool valid = false;
|
||||
valid |= (ADDRESS_IN_IRAM0_CACHE(vaddr_start) &&
|
||||
ADDRESS_IN_IRAM0_CACHE(vaddr_end)) |
|
||||
(ADDRESS_IN_DRAM0_CACHE(vaddr_start) &&
|
||||
ADDRESS_IN_DRAM0_CACHE(vaddr_end));
|
||||
return valid;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp_mmu_map_region
|
||||
*
|
||||
* Description:
|
||||
* To map a virtual address block to a physical memory block.
|
||||
*
|
||||
* Input Parameters:
|
||||
* vaddr - Virtual address in CPU address space
|
||||
* paddr - Physical address in Ext-SRAM
|
||||
* len - Length to be mapped, in bytes
|
||||
* mem_type - MMU target physical memory
|
||||
*
|
||||
* Returned Value:
|
||||
* Actual mapped length.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int IRAM_ATTR esp_mmu_map_region(uint32_t vaddr, uint32_t paddr,
|
||||
uint32_t len, uint32_t mem_type)
|
||||
{
|
||||
DEBUGASSERT(vaddr % MMU_PAGE_SIZE == 0);
|
||||
DEBUGASSERT(paddr % MMU_PAGE_SIZE == 0);
|
||||
DEBUGASSERT(mmu_check_valid_paddr_region(paddr, len));
|
||||
DEBUGASSERT(mmu_check_valid_ext_vaddr_region(vaddr, len));
|
||||
|
||||
uint32_t mmu_val;
|
||||
uint32_t entry_id;
|
||||
uint32_t page_num = (len + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
|
||||
uint32_t ret = page_num * MMU_PAGE_SIZE;
|
||||
mmu_val = paddr >> 16;
|
||||
bool write_back = false;
|
||||
|
||||
while (page_num)
|
||||
{
|
||||
entry_id = (vaddr & MMU_VADDR_MASK) >> 16;
|
||||
DEBUGASSERT(entry_id < MMU_ENTRY_NUM);
|
||||
if (write_back == false && FLASH_MMU_TABLE[entry_id] != MMU_INVALID)
|
||||
{
|
||||
esp_spiram_writeback_cache();
|
||||
write_back = true;
|
||||
}
|
||||
|
||||
FLASH_MMU_TABLE[entry_id] = mmu_val | mem_type;
|
||||
vaddr += MMU_PAGE_SIZE;
|
||||
mmu_val++;
|
||||
page_num--;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cache_dbus_mmu_map
|
||||
*
|
||||
* Description:
|
||||
* Set Ext-SRAM-Cache mmu mapping.
|
||||
*
|
||||
* Input Parameters:
|
||||
* vaddr - Virtual address in CPU address space
|
||||
* paddr - Physical address in Ext-SRAM
|
||||
* num - Pages to be set
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 if success or a negative value if fail.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int IRAM_ATTR cache_dbus_mmu_map(int vaddr, int paddr, int num)
|
||||
{
|
||||
uint32_t regval;
|
||||
irqstate_t flags;
|
||||
uint32_t actual_mapped_len;
|
||||
uint32_t cache_state[CONFIG_SMP_NCPUS];
|
||||
int cpu = up_cpu_index();
|
||||
#ifdef CONFIG_SMP
|
||||
bool smp_start = OSINIT_OS_READY();
|
||||
int other_cpu = cpu ? 0 : 1;
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
* cache_suspend_dcache to make sure the cache is disabled.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* The other CPU might be accessing the cache at the same time, just by
|
||||
* using variables in external RAM.
|
||||
*/
|
||||
|
||||
if (smp_start)
|
||||
{
|
||||
up_cpu_pause(other_cpu);
|
||||
}
|
||||
|
||||
cache_state[other_cpu] = cache_suspend_dcache();
|
||||
#endif
|
||||
cache_state[cpu] = cache_suspend_dcache();
|
||||
|
||||
esp_mmu_map_region(vaddr, paddr, num * MMU_PAGE_SIZE, MMU_ACCESS_SPIRAM);
|
||||
|
||||
regval = getreg32(EXTMEM_DCACHE_CTRL1_REG);
|
||||
regval &= ~EXTMEM_DCACHE_SHUT_CORE0_BUS;
|
||||
putreg32(regval, EXTMEM_DCACHE_CTRL1_REG);
|
||||
|
||||
#if defined(CONFIG_SMP)
|
||||
regval = getreg32(EXTMEM_DCACHE_CTRL1_REG);
|
||||
regval &= ~EXTMEM_DCACHE_SHUT_CORE1_BUS;
|
||||
putreg32(regval, EXTMEM_DCACHE_CTRL1_REG);
|
||||
#endif
|
||||
|
||||
cache_invalidate_addr(vaddr, num * MMU_PAGE_SIZE);
|
||||
|
||||
cache_resume_dcache(cache_state[cpu]);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
cache_resume_dcache(cache_state[other_cpu]);
|
||||
if (smp_start)
|
||||
{
|
||||
up_cpu_resume(other_cpu);
|
||||
}
|
||||
#endif
|
||||
|
||||
leave_critical_section(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initially map all psram physical address to virtual address.
|
||||
* If psram physical size is larger than virtual address range, then only
|
||||
* map the virtual address range.
|
||||
|
@ -34,6 +34,24 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cache_dbus_mmu_map
|
||||
*
|
||||
* Description:
|
||||
* Set Ext-SRAM-Cache mmu mapping.
|
||||
*
|
||||
* Input Parameters:
|
||||
* vaddr - Virtual address in CPU address space
|
||||
* paddr - Physical address in Ext-SRAM
|
||||
* num - Pages to be set
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 if success or a negative value if fail.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int cache_dbus_mmu_map(int vaddr, int paddr, int num);
|
||||
|
||||
/* Initialize spiram interface/hardware. Normally called from
|
||||
* cpu_start.c.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user