arch/xtensa/src/esp32/esp32_spiflash.c: Invalidate the cache and

writeback PSRAM data if the flash address used has a cache mapping.

Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>
This commit is contained in:
Abdelatif Guettouche 2020-12-10 09:15:24 +00:00 committed by Alan Carvalho de Assis
parent 1d438bfb9b
commit 81a9eb190d
2 changed files with 252 additions and 60 deletions

View File

@ -41,10 +41,17 @@
#include "xtensa.h"
#include "xtensa_attr.h"
#include "rom/esp32_spiflash.h"
#include "hardware/esp32_soc.h"
#include "hardware/esp32_spi.h"
#include "hardware/esp32_dport.h"
#include "rom/esp32_spiflash.h"
#ifdef CONFIG_ESP32_SPIRAM
#include "esp32_spiram.h"
#endif
#include "esp32_spiflash.h"
/****************************************************************************
* Pre-processor Definitions
@ -56,7 +63,7 @@
#define SPI_FLASH_WRITE_WORDS (SPI_FLASH_WRITE_BUF_SIZE / 4)
#define SPI_FLASH_READ_WORDS (SPI_FLASH_READ_BUF_SIZE / 4)
#define SPI_FLASH_MAP_PAGE_SIZE (0x10000)
#define SPI_FLASH_MMU_PAGE_SIZE (0x10000)
#define SPI_FLASH_ENCRYPT_UNIT_SIZE (32)
#define SPI_FLASH_ENCRYPT_WORDS (32 / 4)
@ -71,10 +78,13 @@
#define MTD_BLK2SIZE(_priv, _b) (MTD_BLKSIZE(_priv) * (_b))
#define MTD_SIZE2BLK(_priv, _s) ((_s) / MTD_BLKSIZE(_priv))
#define MMU_ADDR2PAGE(_addr) ((_addr) / SPI_FLASH_MAP_PAGE_SIZE)
#define MMU_ADDR2OFF(_addr) ((_addr) % SPI_FLASH_MAP_PAGE_SIZE)
#define MMU_BYTES2PAGES(_n) (((_n) + SPI_FLASH_MAP_PAGE_SIZE - 1) \
/ SPI_FLASH_MAP_PAGE_SIZE)
#define MMU_ADDR2PAGE(_addr) ((_addr) / SPI_FLASH_MMU_PAGE_SIZE)
#define MMU_ADDR2OFF(_addr) ((_addr) % SPI_FLASH_MMU_PAGE_SIZE)
#define MMU_BYTES2PAGES(_n) (((_n) + SPI_FLASH_MMU_PAGE_SIZE - 1) \
/ SPI_FLASH_MMU_PAGE_SIZE)
#define MMU_ALIGNUP_SIZE(_s) (((_s) + SPI_FLASH_MMU_PAGE_SIZE - 1) \
& ~(SPI_FLASH_MMU_PAGE_SIZE - 1))
#define MMU_ALIGNDOWN_SIZE(_s) ((_s) & ~(SPI_FLASH_MMU_PAGE_SIZE - 1))
#ifndef MIN
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
@ -91,6 +101,9 @@
#define APP_MMU_TABLE ((volatile uint32_t *)DPORT_APP_FLASH_MMU_TABLE_REG)
#define PRO_IRAM0_FIRST_PAGE ((SOC_IRAM_LOW - SOC_DRAM_HIGH) /\
(SPI_FLASH_MMU_PAGE_SIZE + IROM0_PAGES_START))
/****************************************************************************
* Private Types
****************************************************************************/
@ -148,13 +161,18 @@ struct spiflash_map_req
uint32_t page_cnt;
};
struct spiflash_cachestate_s
{
int cpu;
irqstate_t flags;
uint32_t val[2];
};
/****************************************************************************
* ROM function prototypes
****************************************************************************/
void Cache_Flush(int cpu);
void Cache_Read_Enable(int cpu);
void Cache_Read_Disable(int cpu);
/****************************************************************************
* Private Functions Prototypes
@ -173,10 +191,13 @@ static inline void spi_reset_regbits(struct esp32_spiflash_s *priv,
/* Misc. helpers */
static inline irqstate_t IRAM_ATTR esp32_spiflash_opstart(
FAR struct esp32_spiflash_s *priv, int *cpu);
static inline void IRAM_ATTR esp32_spiflash_opdone(
FAR struct esp32_spiflash_s *priv, irqstate_t flags, int cpu);
static inline void IRAM_ATTR
esp32_spiflash_opstart(FAR struct spiflash_cachestate_s *state);
static inline void IRAM_ATTR
esp32_spiflash_opdone(FAR const struct spiflash_cachestate_s *state);
static bool IRAM_ATTR spiflash_pagecached(uint32_t phypage);
static void IRAM_ATTR spiflash_flushmapped(size_t start, size_t size);
/* Flash helpers */
@ -376,6 +397,85 @@ 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
*
@ -384,32 +484,29 @@ static inline void spi_reset_regbits(struct esp32_spiflash_s *priv,
*
****************************************************************************/
static inline irqstate_t IRAM_ATTR esp32_spiflash_opstart(
FAR struct esp32_spiflash_s *priv, int *cpu)
static inline void IRAM_ATTR
esp32_spiflash_opstart(FAR struct spiflash_cachestate_s *state)
{
irqstate_t flags;
#ifdef CONFIG_SMP
int other;
#endif
flags = enter_critical_section();
state->flags = enter_critical_section();
*cpu = up_cpu_index();
state->cpu = up_cpu_index();
#ifdef CONFIG_SMP
other = *cpu ? 0 : 1;
other = state->cpu ? 0 : 1;
#endif
DEBUGASSERT(*cpu == 0 || *cpu == 1);
DEBUGASSERT(state->cpu == 0 || state->cpu == 1);
#ifdef CONFIG_SMP
DEBUGASSERT(other == 0 || other == 1);
#endif
Cache_Read_Disable(*cpu);
spi_disable_cache(state->cpu, &state->val[state->cpu]);
#ifdef CONFIG_SMP
Cache_Read_Disable(other);
spi_disable_cache(state->cpu, &state->val[other]);
#endif
return flags;
}
/****************************************************************************
@ -420,30 +517,108 @@ static inline irqstate_t IRAM_ATTR esp32_spiflash_opstart(
*
****************************************************************************/
static inline void IRAM_ATTR esp32_spiflash_opdone(
FAR struct esp32_spiflash_s *priv, irqstate_t flags, int cpu)
static inline void IRAM_ATTR
esp32_spiflash_opdone(FAR const struct spiflash_cachestate_s *state)
{
#ifdef CONFIG_SMP
int other;
#endif
#ifdef CONFIG_SMP
other = cpu ? 0 : 1;
other = state->cpu ? 0 : 1;
#endif
DEBUGASSERT(cpu == 0 || cpu == 1);
DEBUGASSERT(state->cpu == 0 || state->cpu == 1);
#ifdef CONFIG_SMP
DEBUGASSERT(other == 0 || other == 1);
#endif
Cache_Flush(cpu);
Cache_Read_Enable(cpu);
spi_enable_cache(state->cpu, state->val[state->cpu]);
#ifdef CONFIG_SMP
Cache_Flush(other);
Cache_Read_Enable(other);
spi_enable_cache(other, state->val[other]);
#endif
leave_critical_section(flags);
leave_critical_section(state->flags);
}
/****************************************************************************
* Name: spiflash_pagecached
*
* Description:
* Check if the given page is cached.
*
****************************************************************************/
static bool IRAM_ATTR spiflash_pagecached(uint32_t phypage)
{
int start[2];
int end[2];
int i;
int j;
/* Data ROM start and end pages */
start[0] = DROM0_PAGES_START;
end[0] = DROM0_PAGES_END;
/* Instruction RAM start and end pages */
start[1] = PRO_IRAM0_FIRST_PAGE;
end[1] = IROM0_PAGES_END;
for (i = 0; i < 2; i++)
{
for (j = start[i]; j < end[i]; j++)
{
if (PRO_MMU_TABLE[j] == phypage)
{
return true;
}
}
}
return false;
}
/****************************************************************************
* Name: spiflash_flushmapped
*
* Description:
* Writeback PSRAM data and invalidate the cache if the address is mapped.
*
****************************************************************************/
static void IRAM_ATTR spiflash_flushmapped(size_t start, size_t size)
{
uint32_t page_start;
uint32_t addr;
uint32_t page;
page_start = MMU_ALIGNDOWN_SIZE(size);
size += (start - page_start);
size = MMU_ALIGNUP_SIZE(size);
for (addr = page_start; addr < page_start + size;
addr += SPI_FLASH_MMU_PAGE_SIZE)
{
page = addr / SPI_FLASH_MMU_PAGE_SIZE;
if (page >= 256)
{
return;
}
if (spiflash_pagecached(page))
{
#ifdef CONFIG_ESP32_SPIRAM
esp_spiram_writeback_cache();
#endif
Cache_Flush(0);
#ifndef CONFIG_SMP
Cache_Flush(1);
}
#endif
}
}
/****************************************************************************
@ -819,8 +994,7 @@ static int IRAM_ATTR esp32_erasesector(FAR struct esp32_spiflash_s *priv,
uint32_t addr, uint32_t size)
{
uint32_t offset;
int me;
uint32_t flags;
struct spiflash_cachestate_s state;
esp32_set_write_opt(priv);
@ -831,11 +1005,11 @@ static int IRAM_ATTR esp32_erasesector(FAR struct esp32_spiflash_s *priv,
for (offset = 0; offset < size; offset += MTD_ERASESIZE(priv))
{
flags = esp32_spiflash_opstart(priv, &me);
esp32_spiflash_opstart(&state);
if (esp32_enable_write(priv) != OK)
{
esp32_spiflash_opdone(priv, flags, me);
esp32_spiflash_opdone(&state);
return -EIO;
}
@ -848,13 +1022,17 @@ static int IRAM_ATTR esp32_erasesector(FAR struct esp32_spiflash_s *priv,
if (esp32_wait_idle(priv) != OK)
{
esp32_spiflash_opdone(priv, flags, me);
esp32_spiflash_opdone(&state);
return -EIO;
}
esp32_spiflash_opdone(priv, flags, me);
esp32_spiflash_opdone(&state);
}
esp32_spiflash_opstart(&state);
spiflash_flushmapped(addr, size);
esp32_spiflash_opdone(&state);
return 0;
}
@ -953,11 +1131,10 @@ static int IRAM_ATTR esp32_writedata(FAR struct esp32_spiflash_s *priv,
uint32_t size)
{
int ret;
int me;
uint32_t flags;
uint32_t off = 0;
uint32_t bytes;
uint32_t tmp_buf[SPI_FLASH_WRITE_WORDS];
struct spiflash_cachestate_s state;
esp32_set_write_opt(priv);
@ -976,9 +1153,9 @@ static int IRAM_ATTR esp32_writedata(FAR struct esp32_spiflash_s *priv,
memcpy(tmp_buf, &buffer[off], bytes);
flags = esp32_spiflash_opstart(priv, &me);
esp32_spiflash_opstart(&state);
ret = esp32_writeonce(priv, addr, tmp_buf, bytes);
esp32_spiflash_opdone(priv, flags, me);
esp32_spiflash_opdone(&state);
if (ret)
{
@ -990,6 +1167,10 @@ static int IRAM_ATTR esp32_writedata(FAR struct esp32_spiflash_s *priv,
off += bytes;
}
esp32_spiflash_opstart(&state);
spiflash_flushmapped(addr, size);
esp32_spiflash_opdone(&state);
return OK;
}
@ -1020,9 +1201,8 @@ static int IRAM_ATTR esp32_writedata_encrypted(
int i;
int blocks;
int ret = OK;
int me;
uint32_t flags;
uint32_t tmp_buf[SPI_FLASH_ENCRYPT_WORDS];
struct spiflash_cachestate_s state;
if (addr % SPI_FLASH_ENCRYPT_UNIT_SIZE)
{
@ -1044,7 +1224,7 @@ static int IRAM_ATTR esp32_writedata_encrypted(
{
memcpy(tmp_buf, buffer, SPI_FLASH_ENCRYPT_UNIT_SIZE);
flags = esp32_spiflash_opstart(priv, &me);
esp32_spiflash_opstart(&state);
esp_rom_spiflash_write_encrypted_enable();
ret = esp_rom_spiflash_prepare_encrypted_data(addr, tmp_buf);
@ -1063,18 +1243,22 @@ static int IRAM_ATTR esp32_writedata_encrypted(
}
esp_rom_spiflash_write_encrypted_disable();
esp32_spiflash_opdone(priv, flags, me);
esp32_spiflash_opdone(&state);
addr += SPI_FLASH_ENCRYPT_UNIT_SIZE;
buffer += SPI_FLASH_ENCRYPT_UNIT_SIZE;
size -= SPI_FLASH_ENCRYPT_UNIT_SIZE;
}
esp32_spiflash_opstart(&state);
spiflash_flushmapped(addr, size);
esp32_spiflash_opdone(&state);
return 0;
exit:
esp_rom_spiflash_write_encrypted_disable();
esp32_spiflash_opdone(priv, flags, me);
esp32_spiflash_opdone(&state);
return ret;
}
@ -1166,19 +1350,18 @@ static int IRAM_ATTR esp32_readdata(FAR struct esp32_spiflash_s *priv,
uint32_t size)
{
int ret;
int me;
uint32_t flags;
uint32_t off = 0;
uint32_t bytes;
uint32_t tmp_buf[SPI_FLASH_READ_WORDS];
struct spiflash_cachestate_s state;
while (size > 0)
{
bytes = MIN(size, SPI_FLASH_READ_BUF_SIZE);
flags = esp32_spiflash_opstart(priv, &me);
esp32_spiflash_opstart(&state);
ret = esp32_readonce(priv, addr, tmp_buf, bytes);
esp32_spiflash_opdone(priv, flags, me);
esp32_spiflash_opdone(&state);
if (ret)
{
@ -1219,13 +1402,12 @@ static int IRAM_ATTR esp32_mmap(FAR struct esp32_spiflash_s *priv,
{
int ret;
int i;
int me;
int start_page;
int flash_page;
int page_cnt;
uint32_t flags;
struct spiflash_cachestate_s state;
flags = esp32_spiflash_opstart(priv, &me);
esp32_spiflash_opstart(&state);
for (start_page = DROM0_PAGES_START;
start_page < DROM0_PAGES_END;
@ -1257,7 +1439,7 @@ static int IRAM_ATTR esp32_mmap(FAR struct esp32_spiflash_s *priv,
req->start_page = start_page;
req->page_cnt = page_cnt;
req->ptr = (void *)(VADDR0_START_ADDR +
start_page * SPI_FLASH_MAP_PAGE_SIZE +
start_page * SPI_FLASH_MMU_PAGE_SIZE +
MMU_ADDR2OFF(req->src_addr));
ret = 0;
@ -1267,7 +1449,11 @@ static int IRAM_ATTR esp32_mmap(FAR struct esp32_spiflash_s *priv,
ret = -ENOBUFS;
}
esp32_spiflash_opdone(priv, flags, me);
Cache_Flush(0);
#ifdef CONFIG_SMP
Cache_Flush(1);
#endif
esp32_spiflash_opdone(&state);
return ret;
}
@ -1290,11 +1476,10 @@ static int IRAM_ATTR esp32_mmap(FAR struct esp32_spiflash_s *priv,
static void IRAM_ATTR esp32_ummap(FAR struct esp32_spiflash_s *priv,
const struct spiflash_map_req *req)
{
uint32_t flags;
int me;
int i;
struct spiflash_cachestate_s state;
flags = esp32_spiflash_opstart(priv, &me);
esp32_spiflash_opstart(&state);
for (i = req->start_page; i < req->start_page + req->page_cnt; ++i)
{
@ -1304,7 +1489,11 @@ static void IRAM_ATTR esp32_ummap(FAR struct esp32_spiflash_s *priv,
#endif
}
esp32_spiflash_opdone(priv, flags, me);
Cache_Flush(0);
#ifdef CONFIG_SMP
Cache_Flush(1);
#endif
esp32_spiflash_opdone(&state);
}
/****************************************************************************

View File

@ -785,6 +785,9 @@ extern int rom_i2c_writeReg(int block, int block_id, int reg_add,
#define DROM0_PAGES_START 0
#define DROM0_PAGES_END 64
#define IROM0_PAGES_START 64
#define IROM0_PAGES_END 256
/* MMU invaild value */
#define INVALID_MMU_VAL 0x100