ESP32S2: Add support to SPI Flash

This commit is contained in:
Alan Carvalho de Assis 2023-05-10 19:15:47 -03:00 committed by Xiang Xiao
parent dc08798764
commit 1d88d5a370
15 changed files with 2390 additions and 16 deletions

View File

@ -158,6 +158,10 @@ config ESP32S2_FLASH_8M
bool
default n
config ESP32S2_FLASH_16M
bool
default n
config ESP32S2_PSRAM_2M
bool
default n
@ -749,6 +753,35 @@ config ESP32S2_OTA_SCRATCH_DEVPATH
endif
if ESP32S2_SPIFLASH
comment "General storage MTD configuration"
config ESP32S2_MTD
bool "MTD driver"
default y
select MTD
select MTD_BYTE_WRITE
select MTD_PARTITION
---help---
Initialize an MTD driver for the ESP32-S2 SPI Flash, which will
add an entry at /dev for application access from userspace.
config ESP32S2_SPIFLASH_MTD_BLKSIZE
int "Storage MTD block size"
default 256
depends on ESP32S2_MTD
config ESP32S2_STORAGE_MTD_DEBUG
bool "Storage MTD Debug"
default n
depends on ESP32S2_MTD && DEBUG_FS_INFO
---help---
If this option is enabled, Storage MTD driver read and write functions
will output input parameters and return values (if applicable).
endif # ESP32S2_SPIFLASH
endmenu # SPI Flash Configuration
menu "SPI RAM Configuration"

View File

@ -68,6 +68,22 @@ ifeq ($(CONFIG_ESP32S2_SPI),y)
CHIP_CSRCS += esp32s2_spi.c
endif
#ifeq ($(CONFIG_ESP32S2_SPIFLASH),y)
#CHIP_CSRCS += esp32s2_spicache.c
#CHIP_CSRCS += esp32s2_spiflash.c
#endif
ifeq ($(CONFIG_ESP32S2_SPIFLASH),y)
CHIP_CSRCS += esp32s2_spiflash.c
ifeq ($(CONFIG_ESP32S2_MTD),y)
CHIP_CSRCS += esp32s2_spiflash_mtd.c
endif
endif
ifeq ($(CONFIG_ESP32S2_PARTITION_TABLE),y)
CHIP_CSRCS += esp32_partition.c
endif
ifeq ($(CONFIG_ESP32S2_TIMER),y)
CHIP_CSRCS += esp32s2_tim.c
ifeq ($(CONFIG_TIMER),y)

View File

@ -0,0 +1,876 @@
/****************************************************************************
* arch/xtensa/src/esp32s2/esp32s2_spiflash.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 <nuttx/config.h>
#ifdef CONFIG_ESP32S2_SPIFLASH
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include <stdio.h>
#include <string.h>
#include <sys/param.h>
#include <sys/types.h>
#include <errno.h>
#include <nuttx/arch.h>
#include <nuttx/init.h>
#include <nuttx/mutex.h>
#include <nuttx/mtd/mtd.h>
#include "xtensa.h"
#include "xtensa_attr.h"
#include "hardware/esp32s2_spi_mem_reg.h"
#include "rom/esp32s2_spiflash.h"
#include "rom/esp32s2_opi_flash.h"
#include "esp32s2_irq.h"
#include "esp32s2_spiflash.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Used in spiflash_cachestate_s structure */
#define SPI_FLASH_WRITE_BUF_SIZE (32)
#define SPI_FLASH_READ_BUF_SIZE (64)
#define SPI_FLASH_ERASED_STATE (0xff)
#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_MMU_PAGE_SIZE (0x10000)
/* MMU base virtual mapped address */
#define SPI_FLASH_ENCRYPT_MIN_SIZE (16)
/* Flash MMU table for CPU */
#define MMU_TABLE ((volatile uint32_t *)DR_REG_MMU_TABLE)
#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)
/* SPI port number */
# define SPI_PORT (1)
/* SPI buffer size */
# define SPI_BUFFER_WORDS (16)
# define SPI_BUFFER_BYTES (SPI_BUFFER_WORDS * 4)
/* SPI flash hardware definition */
# define FLASH_SECTOR_SIZE (4096)
/* SPI flash command */
# define FLASH_CMD_WRDI ROM_FLASH_CMD_WRDI
# define FLASH_CMD_WREN ROM_FLASH_CMD_WREN
# define FLASH_CMD_RDSR ROM_FLASH_CMD_RDSR
# define FLASH_CMD_SE4B ROM_FLASH_CMD_SE4B
# define FLASH_CMD_SE ROM_FLASH_CMD_ERASE_SEC
# define FLASH_CMD_PP4B ROM_FLASH_CMD_PP4B
# define FLASH_CMD_PP 0x02
# define FLASH_CMD_FSTRD4B ROM_FLASH_CMD_FSTRD4B
# define FLASH_CMD_FSTRD 0x0B
/* SPI flash SR1 bits */
# define FLASH_SR1_BUSY ESP_ROM_SPIFLASH_BUSY_FLAG
# define FLASH_SR1_WREN ESP_ROM_SPIFLASH_WRENABLE_FLAG
/* SPI flash operation */
#ifdef CONFIG_ESP32S2S_SPI_FLASH_USE_32BIT_ADDRESS
# define ADDR_BITS(addr) (((addr) & 0xff000000) ? 32 : 24)
# define READ_CMD(addr) (ADDR_BITS(addr) == 32 ? FLASH_CMD_FSTRD4B : \
FLASH_CMD_FSTRD)
# define WRITE_CMD(addr) (ADDR_BITS(addr) == 32 ? FLASH_CMD_PP4B : \
FLASH_CMD_PP)
# define ERASE_CMD(addr) (ADDR_BITS(addr) == 32 ? FLASH_CMD_SE4B : \
FLASH_CMD_SE)
# define READ_DUMMY(addr) (8)
#else
# define ADDR_BITS(addr) 24
# define READ_CMD(addr) FLASH_CMD_FSTRD
# define WRITE_CMD(addr) FLASH_CMD_PP
# define ERASE_CMD(addr) FLASH_CMD_SE
# define READ_DUMMY(addr) (8)
#endif
# define SEND_CMD8_TO_FLASH(cmd) \
esp32s2_spi_trans((cmd), 8, \
0, 0, \
NULL, 0, \
NULL, 0, \
0, \
false)
# define READ_SR1_FROM_FLASH(cmd, status) \
esp32s2_spi_trans((cmd), 8, \
0, 0, \
NULL, 0, \
(status), 1, \
0, \
false)
# define ERASE_FLASH_SECTOR(addr) \
esp32s2_spi_trans(ERASE_CMD(addr), 8, \
(addr), ADDR_BITS(addr), \
NULL, 0, \
NULL, 0, \
0, \
true)
# define WRITE_DATA_TO_FLASH(addr, buffer, size) \
esp32s2_spi_trans(WRITE_CMD(addr), 8, \
(addr), ADDR_BITS(addr), \
buffer, size, \
NULL, 0, \
0, \
true)
# define READ_DATA_FROM_FLASH(addr, buffer, size) \
esp32s2_spi_trans(READ_CMD(addr), 8, \
(addr), ADDR_BITS(addr), \
NULL, 0, \
buffer, size, \
READ_DUMMY(addr), \
false)
/****************************************************************************
* Private Types
****************************************************************************/
/* SPI Flash map request data */
struct spiflash_map_req
{
/* Request mapping SPI Flash base address */
uint32_t src_addr;
/* Request mapping SPI Flash size */
uint32_t size;
/* Mapped memory pointer */
void *ptr;
/* Mapped started MMU page index */
uint32_t start_page;
/* Mapped MMU page count */
uint32_t page_cnt;
};
struct spiflash_cachestate_s
{
irqstate_t flags;
uint32_t value;
};
/****************************************************************************
* Private Functions Declaration
****************************************************************************/
extern void cache_flush(int cpu);
extern uint32_t cache_suspend_icache(void);
extern uint32_t cache_suspend_dcache(void);
static inline void IRAM_ATTR
spiflash_start(void);
static inline void IRAM_ATTR
spiflash_end(void);
/****************************************************************************
* Public Functions Declaration
****************************************************************************/
extern uint32_t cache_suspend_icache(void);
extern uint32_t cache_suspend_dcache(void);
extern void cache_resume_icache(uint32_t val);
extern void cache_resume_dcache(uint32_t val);
extern int cache_invalidate_addr(uint32_t addr, uint32_t size);
/****************************************************************************
* Private Data
****************************************************************************/
static struct spiflash_cachestate_s g_state;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: spi_set_reg
*
* Description:
* Set the content of the SPI register at offset
*
* Input Parameters:
* priv - Private SPI device structure
* offset - Offset to the register of interest
* value - Value to be written
*
* Returned Value:
* None
*
****************************************************************************/
/****************************************************************************
* Name: spi_set_regbits
*
* Description:
* Set the bits of the SPI register at offset
*
* Input Parameters:
* priv - Private SPI device structure
* offset - Offset to the register of interest
* bits - Bits to be set
*
* Returned Value:
* None
*
****************************************************************************/
/****************************************************************************
* Name: spiflash_start
*
* Description:
* Prepare for an SPIFLASH operartion.
*
****************************************************************************/
static inline void IRAM_ATTR
spiflash_start(void)
{
g_state.flags = enter_critical_section();
g_state.value = cache_suspend_icache() << 16;
g_state.value |= cache_suspend_dcache();
}
/****************************************************************************
* Name: spiflash_end
*
* Description:
* Undo all the steps of start.
*
****************************************************************************/
static inline void IRAM_ATTR
spiflash_end(void)
{
cache_resume_icache(g_state.value >> 16);
cache_resume_dcache(g_state.value & 0xffff);
leave_critical_section(g_state.flags);
}
/****************************************************************************
* Name: esp32s2_spi_trans
*
* Description:
* Transmit given command, address and data.
*
* Input Parameters:
* command - command value
* command_bits - command bits
* address - address value
* address_bits - address bits
* tx_buffer - write buffer
* tx_bytes - write buffer size
* rx_buffer - read buffer
* rx_bytes - read buffer size
* dummy_bits - dummy bits
* is_program - true if operation is program or erase
*
* Returned Value:
* 0 if success or a negative value if fail.
*
****************************************************************************/
static IRAM_ATTR void esp32s2_spi_trans(uint32_t command,
uint32_t command_bits,
uint32_t address,
uint32_t address_bits,
uint32_t *tx_buffer,
uint32_t tx_bytes,
uint32_t *rx_buffer,
uint32_t rx_bytes,
uint32_t dummy_bits,
bool is_program)
{
uint32_t regval;
uint32_t cmd_reg;
uint32_t user1_reg = getreg32(SPI_MEM_USER1_REG(SPI_PORT));
uint32_t user_reg = getreg32(SPI_MEM_USER_REG(SPI_PORT));
/* Initiliaze SPI user register */
user_reg &= ~(SPI_MEM_USR_ADDR_M | SPI_MEM_USR_DUMMY_M |
SPI_MEM_USR_MOSI_M | SPI_MEM_USR_MISO_M);
user_reg |= SPI_MEM_USR_COMMAND_M;
/* Wait until SPI is idle */
do
{
cmd_reg = getreg32(SPI_MEM_CMD_REG(SPI_PORT));
}
while ((cmd_reg & SPI_MEM_USR_M) != 0);
/* Set command bits and value, and command is always needed */
regval = getreg32(SPI_MEM_USER2_REG(SPI_PORT));
regval &= ~(SPI_MEM_USR_COMMAND_BITLEN_M | SPI_MEM_USR_COMMAND_VALUE_M);
regval |= ((command_bits - 1) << SPI_MEM_USR_COMMAND_BITLEN_S) |
(command << SPI_MEM_USR_COMMAND_VALUE_S);
putreg32(regval, SPI_MEM_USER2_REG(SPI_PORT));
/* Set address bits and value */
if (address_bits)
{
user1_reg &= ~SPI_MEM_USR_ADDR_BITLEN_M;
user1_reg |= (address_bits - 1) << SPI_MEM_USR_ADDR_BITLEN_S;
putreg32(address, SPI_MEM_ADDR_REG(SPI_PORT));
user_reg |= SPI_MEM_USR_ADDR_M;
regval = getreg32(SPI_MEM_CACHE_FCTRL_REG(SPI_PORT));
if (address_bits > 24)
{
regval |= SPI_MEM_CACHE_USR_CMD_4BYTE_M;
}
else
{
regval &= ~SPI_MEM_CACHE_USR_CMD_4BYTE_M;
}
putreg32(regval, SPI_MEM_CACHE_FCTRL_REG(SPI_PORT));
}
/* Set dummy */
if (dummy_bits)
{
user1_reg &= ~SPI_MEM_USR_DUMMY_CYCLELEN_M;
user1_reg |= (dummy_bits - 1) << SPI_MEM_USR_DUMMY_CYCLELEN_S;
user_reg |= SPI_MEM_USR_DUMMY_M;
}
/* Set TX data */
if (tx_bytes)
{
putreg32(tx_bytes * 8 - 1, SPI_MEM_MOSI_DLEN_REG(SPI_PORT));
for (uint32_t i = 0; i < tx_bytes; i += 4)
{
putreg32(tx_buffer[i / 4], SPI_MEM_W0_REG(SPI_PORT) + i);
}
user_reg |= SPI_MEM_USR_MOSI_M;
}
/* Set RX data */
if (rx_bytes)
{
putreg32(rx_bytes * 8 - 1, SPI_MEM_MISO_DLEN_REG(SPI_PORT));
user_reg |= SPI_MEM_USR_MISO_M;
}
putreg32(user_reg, SPI_MEM_USER_REG(SPI_PORT));
putreg32(user1_reg, SPI_MEM_USER1_REG(SPI_PORT));
/* Set I/O mode */
regval = getreg32(SPI_MEM_CTRL_REG(SPI_PORT));
regval &= ~(SPI_MEM_FREAD_QIO_M | SPI_MEM_FREAD_DIO_M |
SPI_MEM_FREAD_QUAD_M | SPI_MEM_FREAD_DUAL_M |
SPI_MEM_FCMD_OCT_M | SPI_MEM_FCMD_QUAD_M |
SPI_MEM_FCMD_DUAL_M | SPI_MEM_FADDR_OCT_M |
SPI_MEM_FDIN_OCT_M | SPI_MEM_FDOUT_OCT_M |
SPI_MEM_FDUMMY_OUT_M | SPI_MEM_RESANDRES_M |
SPI_MEM_WP_REG_M | SPI_MEM_WRSR_2B_M);
regval |= SPI_MEM_FASTRD_MODE_M;
putreg32(regval, SPI_MEM_CTRL_REG(SPI_PORT));
/* Set clock and delay */
/* FIXME */
regval = SPI_MEM_FLASH_PES_EN_M |
SPI_MEM_FLASH_PES_EN_M;
putreg32(regval, SPI_MEM_FLASH_SUS_CMD_REG(SPI_PORT));
putreg32(0, SPI_MEM_CLOCK_GATE_REG(SPI_PORT));
/* Set if this is program or erase operation */
if (is_program)
{
cmd_reg |= SPI_MEM_FLASH_PE_M;
}
/* Start transmision */
cmd_reg |= SPI_MEM_USR_M;
putreg32(cmd_reg, SPI_MEM_CMD_REG(SPI_PORT));
/* Wait until transmission is done */
while ((getreg32(SPI_MEM_CMD_REG(SPI_PORT)) & SPI_MEM_USR_M) != 0)
{
;
}
/* Get read data */
if (rx_bytes)
{
for (uint32_t i = 0; i < rx_bytes; i += 4)
{
rx_buffer[i / 4] = getreg32(SPI_MEM_W0_REG(SPI_PORT) + i);
}
}
}
/****************************************************************************
* Name: wait_flash_idle
*
* Description:
* Wait until flash enters idle state
*
* Returned Value:
* None.
*
****************************************************************************/
static IRAM_ATTR void wait_flash_idle(void)
{
uint32_t status;
do
{
READ_SR1_FROM_FLASH(FLASH_CMD_RDSR, &status);
if ((status & FLASH_SR1_BUSY) == 0)
{
break;
}
}
while (1);
}
/****************************************************************************
* Name: enable_flash_write
*
* Description:
* Enable Flash write mode
*
* Returned Value:
* None.
*
****************************************************************************/
static IRAM_ATTR void enable_flash_write(void)
{
uint32_t status;
do
{
SEND_CMD8_TO_FLASH(FLASH_CMD_WREN);
READ_SR1_FROM_FLASH(FLASH_CMD_RDSR, &status);
if ((status & FLASH_SR1_WREN) != 0)
{
break;
}
}
while (1);
}
/****************************************************************************
* Name: disable_flash_write
*
* Description:
* Disable Flash write mode
*
* Returned Value:
* None.
*
****************************************************************************/
static IRAM_ATTR void disable_flash_write(void)
{
uint32_t status;
do
{
SEND_CMD8_TO_FLASH(FLASH_CMD_WRDI);
READ_SR1_FROM_FLASH(FLASH_CMD_RDSR, &status);
if ((status & FLASH_SR1_WREN) == 0)
{
break;
}
}
while (1);
}
/****************************************************************************
* Name: esp32s2_mmap
*
* Description:
* Mapped SPI Flash address to ESP32S2's address bus, so that software
* can read SPI Flash data by reading data from memory access.
*
* If SPI Flash hardware encryption is enable, the read from mapped
* address is decrypted.
*
* Input Parameters:
* req - SPI Flash mapping requesting parameters
*
* Returned Value:
* 0 if success or a negative value if fail.
*
****************************************************************************/
static int IRAM_ATTR esp32s2_mmap(struct spiflash_map_req *req)
{
int ret;
int i;
int start_page;
int flash_page;
int page_cnt;
spiflash_start();
for (start_page = DROM0_PAGES_START;
start_page < DROM0_PAGES_END;
++start_page)
{
if (MMU_TABLE[start_page] == INVALID_MMU_VAL)
{
break;
}
}
flash_page = MMU_ADDR2PAGE(req->src_addr);
page_cnt = MMU_BYTES2PAGES(MMU_ADDR2OFF(req->src_addr) + req->size);
if (start_page + page_cnt < DROM0_PAGES_END)
{
for (i = 0; i < page_cnt; i++)
{
MMU_TABLE[start_page + i] = flash_page + i;
}
req->start_page = start_page;
req->page_cnt = page_cnt;
req->ptr = (void *)(VADDR0_START_ADDR +
start_page * SPI_FLASH_MMU_PAGE_SIZE +
MMU_ADDR2OFF(req->src_addr));
ret = 0;
}
else
{
ret = -ENOBUFS;
}
spiflash_end();
return ret;
}
/****************************************************************************
* Name: esp32s2_ummap
*
* Description:
* Unmap SPI Flash address in ESP32S2's address bus, and free resource.
*
* Input Parameters:
* spi - ESP32S2 SPI Flash chip data
* req - SPI Flash mapping requesting parameters
*
* Returned Value:
* None.
*
****************************************************************************/
static IRAM_ATTR void esp32s2_ummap(const struct spiflash_map_req *req)
{
int i;
spiflash_start();
for (i = req->start_page; i < req->start_page + req->page_cnt; ++i)
{
MMU_TABLE[i] = INVALID_MMU_VAL;
}
spiflash_end();
}
/****************************************************************************
* Name: spi_flash_read_encrypted
*
* Description:
* Read decrypted data from SPI Flash at designated address when
* enable SPI Flash hardware encryption.
*
* Input Parameters:
* spi - ESP32S2 SPI Flash chip data
* addr - target address
* buffer - data buffer pointer
* size - data number
*
* Returned Value:
* OK if success or a negative value if fail.
*
****************************************************************************/
int spi_flash_read_encrypted(uint32_t addr, void *buffer, uint32_t size)
{
int ret;
struct spiflash_map_req req =
{
.src_addr = addr,
.size = size
};
ret = esp32s2_mmap(&req);
if (ret)
{
return ret;
}
memcpy(buffer, req.ptr, size);
esp32s2_ummap(&req);
return OK;
}
/****************************************************************************
* Name: spi_flash_erase_sector
*
* Description:
* Erase the Flash sector.
*
* Parameters:
* sector - Sector number, the count starts at sector 0, 4KB per sector.
*
* Returned Values: esp_err_t
* Zero (OK) is returned or a negative error.
*
****************************************************************************/
IRAM_ATTR int spi_flash_erase_sector(uint32_t sector)
{
int ret = OK;
uint32_t addr = sector * FLASH_SECTOR_SIZE;
spiflash_start();
wait_flash_idle();
enable_flash_write();
ERASE_FLASH_SECTOR(addr);
wait_flash_idle();
disable_flash_write();
spiflash_end();
return ret;
}
/****************************************************************************
* Name: spi_flash_erase_range
*
* Description:
* Erase a range of flash sectors
*
* Parameters:
* start_address - Address where erase operation has to start.
* Must be 4kB-aligned
* size - Size of erased range, in bytes. Must be divisible by
* 4kB.
*
* Returned Values:
* Zero (OK) is returned or a negative error.
*
****************************************************************************/
IRAM_ATTR int spi_flash_erase_range(uint32_t start_address, uint32_t size)
{
int ret = OK;
uint32_t addr = start_address;
spiflash_start();
for (uint32_t i = 0; i < size; i += FLASH_SECTOR_SIZE)
{
wait_flash_idle();
enable_flash_write();
ERASE_FLASH_SECTOR(addr);
addr += FLASH_SECTOR_SIZE;
}
wait_flash_idle();
disable_flash_write();
spiflash_end();
return ret;
}
/****************************************************************************
* Name: spi_flash_write
*
* Description:
* Write data to Flash.
*
* Parameters:
* dest_addr - Destination address in Flash.
* src - Pointer to the source buffer.
* size - Length of data, in bytes.
*
* Returned Values:
* Zero (OK) is returned or a negative error.
*
****************************************************************************/
IRAM_ATTR int spi_flash_write(uint32_t dest_addr,
const void *buffer,
uint32_t size)
{
int ret = OK;
const uint8_t *tx_buf = (const uint8_t *)buffer;
uint32_t tx_bytes = size;
uint32_t tx_addr = dest_addr;
spiflash_start();
for (int i = 0; i < size; i += SPI_BUFFER_BYTES)
{
uint32_t spi_buffer[SPI_BUFFER_WORDS];
uint32_t n = MIN(tx_bytes, SPI_BUFFER_BYTES);
memcpy(spi_buffer, tx_buf, n);
wait_flash_idle();
enable_flash_write();
WRITE_DATA_TO_FLASH(tx_addr, spi_buffer, n);
tx_bytes -= n;
tx_buf += n;
tx_addr += n;
}
wait_flash_idle();
disable_flash_write();
spiflash_end();
return ret;
}
/****************************************************************************
* Name: spi_flash_read
*
* Description:
* Read data from Flash.
*
* Parameters:
* src_addr - source address of the data in Flash.
* dest - pointer to the destination buffer
* size - length of data
*
* Returned Values:
* Zero (OK) is returned or a negative error.
*
****************************************************************************/
IRAM_ATTR int spi_flash_read(uint32_t src_addr, void *dest, uint32_t size)
{
int ret = OK;
uint8_t *rx_buf = (uint8_t *)dest;
uint32_t rx_bytes = size;
uint32_t rx_addr = src_addr;
spiflash_start();
for (uint32_t i = 0; i < size; i += SPI_BUFFER_BYTES)
{
uint32_t spi_buffer[SPI_BUFFER_WORDS];
uint32_t n = MIN(rx_bytes, SPI_BUFFER_BYTES);
READ_DATA_FROM_FLASH(rx_addr, spi_buffer, n);
memcpy(rx_buf, spi_buffer, n);
rx_bytes -= n;
rx_buf += n;
rx_addr += n;
}
spiflash_end();
return ret;
}
/****************************************************************************
* Name: esp32s2_spiflash_init
*
* Description:
* Initialize ESP32-S2 SPI flash driver.
*
* Returned Value:
* OK if success or a negative value if fail.
*
****************************************************************************/
int esp32s2_spiflash_init(void)
{
return OK;
}
#endif /* CONFIG_ESP32S2_SPIFLASH */

View File

@ -0,0 +1,94 @@
/****************************************************************************
* arch/xtensa/src/esp32s2/esp32s2_spiflash.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_ESP32S2_ESP32S2_SPIFLASH_H
#define __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_SPIFLASH_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <nuttx/mtd/mtd.h>
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: spi_flash_read_encrypted
*
* Description:
*
* Read data from Encrypted Flash.
*
* If flash encryption is enabled, this function will transparently
* decrypt data as it is read.
* If flash encryption is not enabled, this function behaves the same as
* spi_flash_read().
*
* See esp_flash_encryption_enabled() for a function to check if flash
* encryption is enabled.
*
* Parameters:
* addr - source address of the data in Flash.
* buffer - pointer to the destination buffer
* size - length of data
*
* Returned Values: esp_err_t
*
****************************************************************************/
int spi_flash_read_encrypted(uint32_t addr, void *buffer, uint32_t size);
/****************************************************************************
* Name: esp32s2_spiflash_init
*
* Description:
* Initialize ESP32-S3 SPI flash driver.
*
* Returned Value:
* OK if success or a negative value if fail.
*
****************************************************************************/
int esp32s2_spiflash_init(void);
#ifdef __cplusplus
}
#endif
#undef EXTERN
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_SPIFLASH_H */

View File

@ -0,0 +1,792 @@
/****************************************************************************
* arch/xtensa/src/esp32s2/esp32s2_spiflash_mtd.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 <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <inttypes.h>
#include <errno.h>
#include <nuttx/arch.h>
#include <nuttx/init.h>
#include <nuttx/mutex.h>
#include <nuttx/mtd/mtd.h>
#include "hardware/esp32s2_soc.h"
#include "xtensa_attr.h"
#include "esp32s2_spiflash.h"
#include "rom/esp32s2_spiflash.h"
#include "esp32s2_spiflash_mtd.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define MTD_BLK_SIZE CONFIG_ESP32S2_SPIFLASH_MTD_BLKSIZE
#define MTD_ERASE_SIZE 4096
#define MTD_ERASED_STATE (0xff)
#define MTD2PRIV(_dev) ((struct esp32s2_mtd_dev_s *)_dev)
#define MTD_SIZE(_priv) ((_priv)->chip->chip_size)
#define MTD_BLK2SIZE(_priv, _b) (MTD_BLK_SIZE * (_b))
#define MTD_SIZE2BLK(_priv, _s) ((_s) / MTD_BLK_SIZE)
/****************************************************************************
* Private Types
****************************************************************************/
/* ESP32-S3 SPI Flash device private data */
struct esp32s2_mtd_dev_s
{
struct mtd_dev_s mtd;
/* SPI Flash data */
esp32s2_spiflash_chip_t *chip;
};
/****************************************************************************
* Private Functions Prototypes
****************************************************************************/
/* MTD driver methods */
static int esp32s2_erase(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks);
static ssize_t esp32s2_read(struct mtd_dev_s *dev, off_t offset,
size_t nbytes, uint8_t *buffer);
static ssize_t esp32s2_read_decrypt(struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
uint8_t *buffer);
static ssize_t esp32s2_bread(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, uint8_t *buffer);
static ssize_t esp32s2_bread_decrypt(struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
uint8_t *buffer);
static ssize_t esp32s2_write(struct mtd_dev_s *dev, off_t offset,
size_t nbytes, const uint8_t *buffer);
static ssize_t esp32s2_bwrite(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, const uint8_t *buffer);
static ssize_t esp32s2_bwrite_encrypt(struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
const uint8_t *buffer);
static int esp32s2_ioctl(struct mtd_dev_s *dev, int cmd,
unsigned long arg);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct esp32s2_mtd_dev_s g_esp32s2_spiflash =
{
.mtd =
{
.erase = esp32s2_erase,
.bread = esp32s2_bread,
.bwrite = esp32s2_bwrite,
.read = esp32s2_read,
.ioctl = esp32s2_ioctl,
#ifdef CONFIG_MTD_BYTE_WRITE
.write = esp32s2_write,
#endif
.name = "esp32s2_spiflash"
},
.chip = &g_rom_flashchip,
};
static const struct esp32s2_mtd_dev_s g_esp32s2_spiflash_encrypt =
{
.mtd =
{
.erase = esp32s2_erase,
.bread = esp32s2_bread_decrypt,
.bwrite = esp32s2_bwrite_encrypt,
.read = esp32s2_read_decrypt,
.ioctl = esp32s2_ioctl,
#ifdef CONFIG_MTD_BYTE_WRITE
.write = NULL,
#endif
.name = "esp32s2_spiflash_encrypt"
},
.chip = &g_rom_flashchip,
};
/* Ensure exclusive access to the driver */
static mutex_t g_lock = NXMUTEX_INITIALIZER;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: esp32s2_erase
*
* Description:
* Erase SPI Flash designated sectors.
*
* Input Parameters:
* dev - MTD device data
* startblock - start block number, it is not equal to SPI Flash's block
* nblocks - Number of blocks
*
* Returned Value:
* Erased blocks if success or a negative value if fail.
*
****************************************************************************/
static int esp32s2_erase(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks)
{
ssize_t ret;
uint32_t offset = startblock * MTD_ERASE_SIZE;
uint32_t nbytes = nblocks * MTD_ERASE_SIZE;
struct esp32s2_mtd_dev_s *priv = (struct esp32s2_mtd_dev_s *)dev;
if ((offset > MTD_SIZE(priv)) || ((offset + nbytes) > MTD_SIZE(priv)))
{
return -EINVAL;
}
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s(%p, 0x%x, %d)\n", __func__, dev, startblock, nblocks);
finfo("spi_flash_erase_range(0x%x, %d)\n", offset, nbytes);
#endif
ret = nxmutex_lock(&g_lock);
if (ret < 0)
{
return ret;
}
ret = spi_flash_erase_range(offset, nbytes);
nxmutex_unlock(&g_lock);
if (ret == OK)
{
ret = nblocks;
}
else
{
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("Failed to erase the flash range!\n");
#endif
ret = -1;
}
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s()=%d\n", __func__, ret);
#endif
return ret;
}
/****************************************************************************
* Name: esp32s2_read
*
* Description:
* Read data from SPI Flash at designated address.
*
* Input Parameters:
* dev - MTD device data
* offset - target address offset
* nbytes - data number
* buffer - data buffer pointer
*
* Returned Value:
* Read data bytes if success or a negative value if fail.
*
****************************************************************************/
static ssize_t esp32s2_read(struct mtd_dev_s *dev, off_t offset,
size_t nbytes, uint8_t *buffer)
{
ssize_t ret;
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, offset, nbytes, buffer);
finfo("spi_flash_read(0x%x, %p, %d)\n", offset, buffer, nbytes);
#endif
/* Acquire the mutex. */
ret = nxmutex_lock(&g_lock);
if (ret < 0)
{
return ret;
}
ret = spi_flash_read(offset, buffer, nbytes);
nxmutex_unlock(&g_lock);
if (ret == OK)
{
ret = nbytes;
}
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s()=%d\n", __func__, ret);
#endif
return ret;
}
/****************************************************************************
* Name: esp32s2_bread
*
* Description:
* Read data from designated blocks.
*
* Input Parameters:
* dev - MTD device data
* startblock - start block number, it is not equal to SPI Flash's block
* nblocks - blocks number
* buffer - data buffer pointer
*
* Returned Value:
* Read block number if success or a negative value if fail.
*
****************************************************************************/
static ssize_t esp32s2_bread(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, uint8_t *buffer)
{
ssize_t ret;
uint32_t addr = startblock * MTD_BLK_SIZE;
uint32_t size = nblocks * MTD_BLK_SIZE;
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, startblock, nblocks,
buffer);
finfo("spi_flash_read(0x%x, %p, %d)\n", addr, buffer, size);
#endif
ret = nxmutex_lock(&g_lock);
if (ret < 0)
{
return ret;
}
ret = spi_flash_read(addr, buffer, size);
nxmutex_unlock(&g_lock);
if (ret == OK)
{
ret = nblocks;
}
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s()=%d\n", __func__, ret);
#endif
return ret;
}
/****************************************************************************
* Name: esp32s2_read_decrypt
*
* Description:
* Read encrypted data and decrypt automatically from SPI Flash
* at designated address.
*
* Input Parameters:
* dev - MTD device data
* offset - target address offset
* nbytes - data number
* buffer - data buffer pointer
*
* Returned Value:
* Read data bytes if success or a negative value if fail.
*
****************************************************************************/
static ssize_t esp32s2_read_decrypt(struct mtd_dev_s *dev,
off_t offset,
size_t nbytes,
uint8_t *buffer)
{
ssize_t ret;
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, offset, nbytes, buffer);
finfo("spi_flash_read_encrypted(0x%x, %p, %d)\n", offset, buffer,
nbytes);
#endif
/* Acquire the mutex. */
ret = nxmutex_lock(&g_lock);
if (ret < 0)
{
return ret;
}
ret = spi_flash_read_encrypted(offset, buffer, nbytes);
nxmutex_unlock(&g_lock);
if (ret == OK)
{
ret = nbytes;
}
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s()=%d\n", __func__, ret);
#endif
return ret;
}
/****************************************************************************
* Name: esp32s2_bread_decrypt
*
* Description:
* Read encrypted data and decrypt automatically from designated blocks.
*
* Input Parameters:
* dev - MTD device data
* startblock - start block number, it is not equal to SPI Flash's block
* nblocks - blocks number
* buffer - data buffer pointer
*
* Returned Value:
* Read block number if success or a negative value if fail.
*
****************************************************************************/
static ssize_t esp32s2_bread_decrypt(struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
uint8_t *buffer)
{
ssize_t ret;
uint32_t addr = startblock * MTD_BLK_SIZE;
uint32_t size = nblocks * MTD_BLK_SIZE;
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, startblock, nblocks,
buffer);
finfo("spi_flash_read_encrypted(0x%x, %p, %d)\n", addr, buffer, size);
#endif
ret = nxmutex_lock(&g_lock);
if (ret < 0)
{
return ret;
}
ret = spi_flash_read_encrypted(addr, buffer, size);
nxmutex_unlock(&g_lock);
if (ret == OK)
{
ret = nblocks;
}
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s()=%d\n", __func__, ret);
#endif
return ret;
}
/****************************************************************************
* Name: esp32s2_write
*
* Description:
* write data to SPI Flash at designated address.
*
* Input Parameters:
* dev - MTD device data
* offset - target address offset
* nbytes - data number
* buffer - data buffer pointer
*
* Returned Value:
* Writen bytes if success or a negative value if fail.
*
****************************************************************************/
static ssize_t esp32s2_write(struct mtd_dev_s *dev, off_t offset,
size_t nbytes, const uint8_t *buffer)
{
ssize_t ret;
struct esp32s2_mtd_dev_s *priv = (struct esp32s2_mtd_dev_s *)dev;
ASSERT(buffer);
if ((offset > MTD_SIZE(priv)) || ((offset + nbytes) > MTD_SIZE(priv)))
{
return -EINVAL;
}
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, offset, nbytes, buffer);
finfo("spi_flash_write(0x%x, %p, %d)\n", offset, buffer, nbytes);
#endif
/* Acquire the mutex. */
ret = nxmutex_lock(&g_lock);
if (ret < 0)
{
return ret;
}
ret = spi_flash_write(offset, buffer, nbytes);
nxmutex_unlock(&g_lock);
if (ret == OK)
{
ret = nbytes;
}
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s()=%d\n", __func__, ret);
#endif
return ret;
}
/****************************************************************************
* Name: esp32s2_bwrite_encrypt
*
* Description:
* Write data to designated blocks by SPI Flash hardware encryption.
*
* Input Parameters:
* dev - MTD device data
* startblock - start MTD block number,
* it is not equal to SPI Flash's block
* nblocks - blocks number
* buffer - data buffer pointer
*
* Returned Value:
* Writen block number if success or a negative value if fail.
*
****************************************************************************/
static ssize_t esp32s2_bwrite_encrypt(struct mtd_dev_s *dev,
off_t startblock,
size_t nblocks,
const uint8_t *buffer)
{
ssize_t ret;
uint32_t addr = startblock * MTD_BLK_SIZE;
uint32_t size = nblocks * MTD_BLK_SIZE;
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, startblock,
nblocks, buffer);
finfo("spi_flash_write_encrypted(0x%x, %p, %d)\n", addr, buffer, size);
#endif
ret = nxmutex_lock(&g_lock);
if (ret < 0)
{
return ret;
}
ret = spi_flash_write_encrypted(addr, buffer, size);
nxmutex_unlock(&g_lock);
if (ret == OK)
{
ret = nblocks;
}
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s()=%d\n", __func__, ret);
#endif
return ret;
}
/****************************************************************************
* Name: esp32s2_bwrite
*
* Description:
* Write data to designated blocks.
*
* Input Parameters:
* dev - MTD device data
* startblock - start MTD block number,
* it is not equal to SPI Flash's block
* nblocks - blocks number
* buffer - data buffer pointer
*
* Returned Value:
* Writen block number if success or a negative value if fail.
*
****************************************************************************/
static ssize_t esp32s2_bwrite(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, const uint8_t *buffer)
{
ssize_t ret;
uint32_t addr = startblock * MTD_BLK_SIZE;
uint32_t size = nblocks * MTD_BLK_SIZE;
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, startblock,
nblocks, buffer);
finfo("spi_flash_write(0x%x, %p, %d)\n", addr, buffer, size);
#endif
ret = nxmutex_lock(&g_lock);
if (ret < 0)
{
return ret;
}
ret = spi_flash_write(addr, buffer, size);
nxmutex_unlock(&g_lock);
if (ret == OK)
{
ret = nblocks;
}
#ifdef CONFIG_ESP32S2_STORAGE_MTD_DEBUG
finfo("%s()=%d\n", __func__, ret);
#endif
return ret;
}
/****************************************************************************
* Name: esp32s2_ioctl
*
* Description:
* Set/Get option to/from ESP32-S3 SPI Flash MTD device data.
*
* Input Parameters:
* dev - ESP32-S3 MTD device data
* cmd - operation command
* arg - operation argument
*
* Returned Value:
* 0 if success or a negative value if fail.
*
****************************************************************************/
static int esp32s2_ioctl(struct mtd_dev_s *dev, int cmd,
unsigned long arg)
{
int ret = OK;
finfo("cmd: %d\n", cmd);
switch (cmd)
{
case MTDIOC_GEOMETRY:
{
struct esp32s2_mtd_dev_s *priv = (struct esp32s2_mtd_dev_s *)dev;
struct mtd_geometry_s *geo = (struct mtd_geometry_s *)arg;
if (geo)
{
memset(geo, 0, sizeof(*geo));
geo->blocksize = MTD_BLK_SIZE;
geo->erasesize = MTD_ERASE_SIZE;
geo->neraseblocks = MTD_SIZE(priv) / MTD_ERASE_SIZE;
ret = OK;
finfo("blocksize: %" PRId32 " erasesize: %" PRId32 \
" neraseblocks: %" PRId32 "\n",
geo->blocksize, geo->erasesize, geo->neraseblocks);
}
}
break;
case BIOC_PARTINFO:
{
struct esp32s2_mtd_dev_s *priv = (struct esp32s2_mtd_dev_s *)dev;
struct partition_info_s *info = (struct partition_info_s *)arg;
if (info != NULL)
{
info->numsectors = MTD_SIZE(priv) / MTD_BLK_SIZE;
info->sectorsize = MTD_BLK_SIZE;
info->startsector = 0;
info->parent[0] = '\0';
}
}
break;
case MTDIOC_ERASESTATE:
{
uint8_t *result = (uint8_t *)arg;
*result = MTD_ERASED_STATE;
ret = OK;
}
break;
default:
ret = -ENOTTY;
break;
}
finfo("return %d\n", ret);
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp32s2_spiflash_alloc_mtdpart
*
* Description:
* Allocate an MTD partition from the ESP32-S3 SPI Flash.
*
* Input Parameters:
* mtd_offset - MTD Partition offset from the base address in SPI Flash.
* mtd_size - Size for the MTD partition.
* encrypted - Flag indicating whether the newly allocated partition will
* have its content encrypted.
*
* Returned Value:
* ESP32-S3 SPI Flash MTD data pointer if success or NULL if fail.
*
****************************************************************************/
struct mtd_dev_s *esp32s2_spiflash_alloc_mtdpart(uint32_t mtd_offset,
uint32_t mtd_size,
bool encrypted)
{
const struct esp32s2_mtd_dev_s *priv;
const esp32s2_spiflash_chip_t *chip;
struct mtd_dev_s *mtd_part;
uint32_t blocks;
uint32_t startblock;
uint32_t size;
if (encrypted)
{
priv = &g_esp32s2_spiflash_encrypt;
}
else
{
priv = &g_esp32s2_spiflash;
}
chip = priv->chip;
finfo("ESP32-S2 SPI Flash information:\n");
finfo("\tID = 0x%" PRIx32 "\n", chip->device_id);
finfo("\tStatus mask = 0x%" PRIx32 "\n", chip->status_mask);
finfo("\tChip size = %" PRId32 " KB\n", chip->chip_size / 1024);
finfo("\tPage size = %" PRId32 " B\n", chip->page_size);
finfo("\tSector size = %" PRId32 " KB\n", chip->sector_size / 1024);
finfo("\tBlock size = %" PRId32 " KB\n", chip->block_size / 1024);
ASSERT((mtd_offset + mtd_size) <= chip->chip_size);
ASSERT((mtd_offset % chip->sector_size) == 0);
ASSERT((mtd_size % chip->sector_size) == 0);
if (mtd_size == 0)
{
size = chip->chip_size - mtd_offset;
}
else
{
size = mtd_size;
}
finfo("\tMTD offset = 0x%" PRIx32 "\n", mtd_offset);
finfo("\tMTD size = 0x%" PRIx32 "\n", size);
startblock = MTD_SIZE2BLK(priv, mtd_offset);
blocks = MTD_SIZE2BLK(priv, size);
mtd_part = mtd_partition((struct mtd_dev_s *)&priv->mtd, startblock,
blocks);
if (!mtd_part)
{
ferr("ERROR: Failed to create MTD partition\n");
return NULL;
}
return mtd_part;
}
/****************************************************************************
* Name: esp32s2_spiflash_mtd
*
* Description:
* Get SPI Flash MTD.
*
* Input Parameters:
* None
*
* Returned Value:
* ESP32-S3 SPI Flash MTD pointer.
*
****************************************************************************/
struct mtd_dev_s *esp32s2_spiflash_mtd(void)
{
struct esp32s2_mtd_dev_s *priv =
(struct esp32s2_mtd_dev_s *)&g_esp32s2_spiflash;
return &priv->mtd;
}
/****************************************************************************
* Name: esp32s2_spiflash_encrypt_mtd
*
* Description:
* Get SPI Flash encryption MTD.
*
* Input Parameters:
* None
*
* Returned Value:
* SPI Flash encryption MTD pointer.
*
****************************************************************************/
struct mtd_dev_s *esp32s2_spiflash_encrypt_mtd(void)
{
struct esp32s2_mtd_dev_s *priv =
(struct esp32s2_mtd_dev_s *)&g_esp32s2_spiflash_encrypt;
return &priv->mtd;
}

View File

@ -0,0 +1,108 @@
/****************************************************************************
* arch/xtensa/src/esp32s2/esp32s2_spiflash_mtd.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_ESP32S2_ESP32S2_SPIFLASH_MTD_H
#define __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_SPIFLASH_MTD_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <nuttx/mtd/mtd.h>
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: esp32s2_spiflash_mtd
*
* Description:
* Get SPI Flash MTD.
*
* Input Parameters:
* None
*
* Returned Value:
* ESP32-S3 SPI Flash MTD pointer.
*
****************************************************************************/
struct mtd_dev_s *esp32s2_spiflash_mtd(void);
/****************************************************************************
* Name: esp32s2_spiflash_encrypt_mtd
*
* Description:
* Get SPI Flash encryption MTD.
*
* Input Parameters:
* None
*
* Returned Value:
* SPI Flash encryption MTD pointer.
*
****************************************************************************/
struct mtd_dev_s *esp32s2_spiflash_encrypt_mtd(void);
/****************************************************************************
* Name: esp32s2_spiflash_alloc_mtdpart
*
* Description:
* Allocate an MTD partition from the ESP32-S3 SPI Flash.
*
* Input Parameters:
* mtd_offset - MTD Partition offset from the base address in SPI Flash.
* mtd_size - Size for the MTD partition.
* encrypted - Flag indicating whether the newly allocated partition will
* have its content encrypted.
*
* Returned Value:
* SPI Flash MTD data pointer if success or NULL if fail.
*
****************************************************************************/
struct mtd_dev_s *esp32s2_spiflash_alloc_mtdpart(uint32_t mtd_offset,
uint32_t mtd_size,
bool encrypted);
#ifdef __cplusplus
}
#endif
#undef EXTERN
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_SPIFLASH_MTD_H */

View File

@ -34,6 +34,8 @@ extern "C"
#define REG_SPI_MEM_BASE(i) (DR_REG_SPI0_BASE - (i) * 0x1000)
#define SPI_MEM_CMD_REG(i) (REG_SPI_MEM_BASE(i) + 0x0)
/* SPI_MEM_FLASH_READ : R/W/SC ;bitpos:[31] ;default: 1'b0 ; */
/* Description: Read flash enable. Read flash operation will be triggered

View File

@ -115,6 +115,13 @@
#define SYSTEM_CLK_EN_DEDICATED_GPIO_V 0x00000001
#define SYSTEM_CLK_EN_DEDICATED_GPIO_S 7
/* SYSTEM_CLK_EN_ASSIST_DEBUG : R/W ;bitpos:[6] ;default: 0 */
#define SYSTEM_CLK_EN_ASSIST_DEBUG (BIT(6))
#define SYSTEM_CLK_EN_ASSIST_DEBUG_M (BIT(6))
#define SYSTEM_CLK_EN_ASSIST_DEBUG_V 0x1
#define SYSTEM_CLK_EN_ASSIST_DEBUG_S 6
/* SYSTEM_CPU_PERI_RST_EN_REG register
* CPU peripheral reset register
*/
@ -130,6 +137,13 @@
#define SYSTEM_RST_EN_DEDICATED_GPIO_V 0x00000001
#define SYSTEM_RST_EN_DEDICATED_GPIO_S 7
/* SYSTEM_RST_EN_ASSIST_DEBUG : R/W ;bitpos:[6] ;default: 1 ; */
#define SYSTEM_RST_EN_ASSIST_DEBUG (BIT(6))
#define SYSTEM_RST_EN_ASSIST_DEBUG_M (BIT(6))
#define SYSTEM_RST_EN_ASSIST_DEBUG_V 0x1
#define SYSTEM_RST_EN_ASSIST_DEBUG_S 6
/* SYSTEM_CPU_PER_CONF_REG register
* CPU peripheral clock configuration register
*/
@ -1101,6 +1115,20 @@
#define SYSTEM_LPCLK_SEL_RTC_SLOW_V 0x00000001
#define SYSTEM_LPCLK_SEL_RTC_SLOW_S 24
/* SYSTEM_BT_LPCK_DIV_A : R/W ;bitpos:[23:12] ;default: 1 */
#define SYSTEM_BT_LPCK_DIV_A 0x00000FFF
#define SYSTEM_BT_LPCK_DIV_A_M ((SYSTEM_BT_LPCK_DIV_A_V)<<(SYSTEM_BT_LPCK_DIV_A_S))
#define SYSTEM_BT_LPCK_DIV_A_V 0xFFF
#define SYSTEM_BT_LPCK_DIV_A_S 12
/* SYSTEM_BT_LPCK_DIV_B : R/W ;bitpos:[11:0] ;default: 1 */
#define SYSTEM_BT_LPCK_DIV_B 0x00000FFF
#define SYSTEM_BT_LPCK_DIV_B_M ((SYSTEM_BT_LPCK_DIV_B_V)<<(SYSTEM_BT_LPCK_DIV_B_S))
#define SYSTEM_BT_LPCK_DIV_B_V 0xFFF
#define SYSTEM_BT_LPCK_DIV_B_S 0
/* SYSTEM_CPU_INTR_FROM_CPU_0_REG register
* CPU interrupt controlling register 0
*/
@ -1200,6 +1228,7 @@
#define SYSTEM_RSA_MEM_PD_M (SYSTEM_RSA_MEM_PD_V << SYSTEM_RSA_MEM_PD_S)
#define SYSTEM_RSA_MEM_PD_V 0x00000001
#define SYSTEM_RSA_MEM_PD_S 0
#define SYSTEM_RSA_PD SYSTEM_RSA_MEM_PD
/* SYSTEM_BUSTOEXTMEM_ENA_REG register
* EDMA enable register

View File

@ -143,17 +143,6 @@ typedef struct
uint16_t data;
} esp_rom_spiflash_common_cmd_t;
/**
* Global ROM spiflash data, as used by legacy SPI flash functions
*/
struct spiflash_legacy_data_s
{
esp32s2_spiflash_chip_t chip;
uint8_t dummy_len_plus[3];
uint8_t sig_matrix;
};
/**
* Structure holding SPI flash access critical sections management functions.
*
@ -484,7 +473,7 @@ esp_rom_spiflash_config_clk(uint8_t freqdiv,
*
* Please do not call this function in SDK.
*
* Input Paramater:
* Input Parameter:
* esp_rom_spiflash_common_cmd_t *cmd : A struct to show the action of a
* command.
*
@ -1011,7 +1000,10 @@ void spi_flash_enable_cache(uint32_t cpuid);
* Public Data
*****************************************************************************/
extern const struct spiflash_legacy_data_s *rom_spiflash_legacy_data;
/* Global esp32s2_spiflash_chip_t structure used by ROM functions */
extern esp32s2_spiflash_chip_t g_rom_flashchip;
extern uint8_t g_rom_spiflash_dummy_len_plus[];
#ifdef __cplusplus
}

View File

@ -12,6 +12,47 @@ config ESP32S2_MERGE_BINS
This is only useful when the path to binary files (e.g. bootloader)
is provided via the ESPTOOL_BINDIR variable.
choice ESP32S2_SPIFLASH_FS
prompt "Mount SPI Flash MTD on bring-up"
default ESP32S2_SPIFLASH_SMARTFS
depends on ESP32S2_SPIFLASH
optional
---help---
Mount the SPI Flash MTD with the selected File System format on board
bring-up.
If not selected, the MTD will be registered as a device node on /dev.
config ESP32S2_SPIFLASH_SMARTFS
bool "SmartFS"
select FS_SMARTFS
select MTD_SMART
depends on !ESP32S2_SECURE_FLASH_ENC_ENABLED
comment "SmartFS not supported with Flash Encryption"
depends on ESP32S2_SECURE_FLASH_ENC_ENABLED
config ESP32S2_SPIFLASH_NXFFS
bool "NXFFS"
select FS_NXFFS
depends on !ESP32S2_SECURE_FLASH_ENC_ENABLED
comment "NXFFS not supported with Flash Encryption"
depends on ESP32S2_SECURE_FLASH_ENC_ENABLED
config ESP32S2_SPIFLASH_SPIFFS
bool "SPIFFS"
select FS_SPIFFS
depends on !ESP32S2_SECURE_FLASH_ENC_ENABLED
comment "SPIFFS not supported with Flash Encryption"
depends on ESP32S2_SECURE_FLASH_ENC_ENABLED
config ESP32S2_SPIFLASH_LITTLEFS
bool "LittleFS"
select FS_LITTLEFS
endchoice
config ESP32S2_LCD_OVERCLOCK
bool "Run LCD at higher clock speed than allowed"
default n

View File

@ -76,7 +76,7 @@ PROVIDE ( Cache_Lock_ICache_Items = 0x40018950 );
PROVIDE ( Cache_Mask_All = 0x40018458 );
PROVIDE ( cache_memory_baseaddrs = 0x3ffaf020 );
PROVIDE ( Cache_MMU_Init = 0x40018dd8 );
PROVIDE ( Cache_Resume_DCache = 0x40018d3c );
PROVIDE ( cache_resume_dcache = 0x40018d3c );
PROVIDE ( Cache_Resume_DCache_Autoload = 0x4001850c );
PROVIDE ( cache_resume_icache = 0x40018cdc );
PROVIDE ( Cache_Resume_ICache_Autoload = 0x400184c4 );
@ -85,7 +85,7 @@ PROVIDE ( Cache_Set_Default_Mode = 0x4001810c );
PROVIDE ( cache_set_icache_mode = 0x4001803c );
PROVIDE ( Cache_Start_DCache_Preload = 0x400185c4 );
PROVIDE ( Cache_Start_ICache_Preload = 0x40018530 );
PROVIDE ( Cache_Suspend_DCache = 0x40018d04 );
PROVIDE ( cache_suspend_dcache = 0x40018d04 );
PROVIDE ( Cache_Suspend_DCache_Autoload = 0x400184e0 );
PROVIDE ( cache_suspend_icache = 0x40018ca4 );
PROVIDE ( Cache_Suspend_ICache_Autoload = 0x40018498 );
@ -348,7 +348,7 @@ PROVIDE ( ets_write_char_uart = 0x4000f998 );
PROVIDE ( exc_cause_table = 0x3ffacbe8 );
PROVIDE ( FilePacketSendDeflatedReqMsgProc = 0x40011ed8 );
PROVIDE ( FilePacketSendReqMsgProc = 0x40011bd8 );
PROVIDE ( flashchip = 0x3ffffd38 );
PROVIDE ( g_rom_flashchip = 0x3ffffd38 );
PROVIDE ( FlashDwnLdDeflatedStartMsgProc = 0x40011e80 );
PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x40011cc0 );
PROVIDE ( FlashDwnLdStartMsgProc = 0x40011b74 );

View File

@ -24,6 +24,10 @@ ifeq ($(CONFIG_WATCHDOG),y)
CSRCS += esp32s2_board_wdt.c
endif
ifeq ($(CONFIG_ESP32S2_SPIFLASH),y)
CSRCS += esp32s2_board_spiflash.c
endif
ifeq ($(CONFIG_SENSORS_MAX6675),y)
CSRCS += esp32s2_max6675.c
endif

View File

@ -0,0 +1,367 @@
/****************************************************************************
* boards/xtensa/esp32s2/common/src/esp32s2_board_spiflash.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 <nuttx/config.h>
#include <sys/mount.h>
#include "inttypes.h"
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/kmalloc.h>
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
#include <nuttx/fs/nxffs.h>
#ifdef CONFIG_BCH
#include <nuttx/drivers/drivers.h>
#endif
#include "esp32s2_spiflash.h"
#include "esp32s2_spiflash_mtd.h"
#include "esp32s2-saola-1.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef CONFIG_ESP32S2_STORAGE_MTD_OFFSET
# define CONFIG_ESP32S2_STORAGE_MTD_OFFSET 0x10000
#endif
#ifndef CONFIG_ESP32S2_STORAGE_MTD_SIZE
# define CONFIG_ESP32S2_STORAGE_MTD_SIZE 0x100000
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: setup_smartfs
*
* Description:
* Provide a block driver wrapper around MTD partition and mount a
* SMART FS over it.
*
* Parameters:
* smartn - Number used to register the mtd partition: /dev/smartx, where
* x = smartn.
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESP32S2_SPIFLASH_SMARTFS)
static int setup_smartfs(int smartn, struct mtd_dev_s *mtd,
const char *mnt_pt)
{
int ret = OK;
char path[22];
ret = smart_initialize(smartn, mtd, NULL);
if (ret < 0)
{
finfo("smart_initialize failed, Trying to erase first...\n");
ret = mtd->ioctl(mtd, MTDIOC_BULKERASE, 0);
if (ret < 0)
{
ferr("ERROR: ioctl(BULKERASE) failed: %d\n", ret);
return ret;
}
finfo("Erase successful, initializing it again.\n");
ret = smart_initialize(smartn, mtd, NULL);
if (ret < 0)
{
ferr("ERROR: smart_initialize failed: %d\n", ret);
return ret;
}
}
if (mnt_pt != NULL)
{
snprintf(path, sizeof(path), "/dev/smart%d", smartn);
ret = nx_mount(path, mnt_pt, "smartfs", 0, NULL);
if (ret < 0)
{
ferr("ERROR: Failed to mount the FS volume: %d\n", ret);
return ret;
}
}
return ret;
}
#endif
/****************************************************************************
* Name: setup_littlefs
*
* Description:
* Register a mtd driver and mount a Little FS over it.
*
* Parameters:
* path - Path name used to register the mtd driver.
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
* priv - Privileges
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESP32S2_SPIFLASH_LITTLEFS)
static int setup_littlefs(const char *path, struct mtd_dev_s *mtd,
const char *mnt_pt, int priv)
{
int ret = OK;
ret = register_mtddriver(path, mtd, priv, NULL);
if (ret < 0)
{
ferr("ERROR: Failed to register MTD: %d\n", ret);
return ERROR;
}
if (mnt_pt != NULL)
{
ret = nx_mount(path, mnt_pt, "littlefs", 0, NULL);
if (ret < 0)
{
ret = nx_mount(path, mnt_pt, "littlefs", 0, "forceformat");
if (ret < 0)
{
ferr("ERROR: Failed to mount the FS volume: %d\n", ret);
return ret;
}
}
}
return OK;
}
#endif
/****************************************************************************
* Name: setup_spiffs
*
* Description:
* Register a mtd driver and mount a SPIFFS over it.
*
* Parameters:
* path - Path name used to register the mtd driver.
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
* priv - Privileges
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESP32S2_SPIFLASH_SPIFFS)
static int setup_spiffs(const char *path, struct mtd_dev_s *mtd,
const char *mnt_pt, int priv)
{
int ret = OK;
ret = register_mtddriver(path, mtd, priv, NULL);
if (ret < 0)
{
ferr("ERROR: Failed to register MTD: %d\n", ret);
return ERROR;
}
if (mnt_pt != NULL)
{
ret = nx_mount(path, mnt_pt, "spiffs", 0, NULL);
if (ret < 0)
{
ferr("ERROR: Failed to mount the FS volume: %d\n", ret);
return ret;
}
}
return ret;
}
#endif
/****************************************************************************
* Name: setup_nxffs
*
* Description:
* Register a mtd driver and mount a SPIFFS over it.
*
* Parameters:
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESP32S2_SPIFLASH_NXFFS)
static int setup_nxffs(struct mtd_dev_s *mtd, const char *mnt_pt)
{
int ret = OK;
ret = nxffs_initialize(mtd);
if (ret < 0)
{
ferr("ERROR: NXFFS init failed: %d\n", ret);
return ret;
}
if (mnt_pt != NULL)
{
ret = nx_mount(NULL, mnt_pt, "nxffs", 0, NULL);
if (ret < 0)
{
ferr("ERROR: Failed to mount the FS volume: %d\n", ret);
return ret;
}
}
return ret;
}
#endif
/****************************************************************************
* Name: init_storage_partition
*
* Description:
* Initialize partition that is dedicated to general use.
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
static int init_storage_partition(void)
{
int ret = OK;
struct mtd_dev_s *mtd;
mtd = esp32s2_spiflash_alloc_mtdpart(CONFIG_ESP32S2_STORAGE_MTD_OFFSET,
CONFIG_ESP32S2_STORAGE_MTD_SIZE,
false);
if (!mtd)
{
ferr("ERROR: Failed to alloc MTD partition of SPI Flash\n");
return ERROR;
}
#if defined (CONFIG_ESP32S2_SPIFLASH_SMARTFS)
ret = setup_smartfs(0, mtd, "/data");
if (ret < 0)
{
ferr("ERROR: Failed to setup smartfs\n");
return ret;
}
#elif defined (CONFIG_ESP32S2_SPIFLASH_NXFFS)
ret = setup_nxffs(mtd, "/data");
if (ret < 0)
{
ferr("ERROR: Failed to setup nxffs\n");
return ret;
}
#elif defined (CONFIG_ESP32S2_SPIFLASH_LITTLEFS)
const char *path = "/dev/esp32s2flash";
ret = setup_littlefs(path, mtd, "/data", 0755);
if (ret < 0)
{
ferr("ERROR: Failed to setup littlefs\n");
return ret;
}
#elif defined (CONFIG_ESP32S2_SPIFLASH_SPIFFS)
const char *path = "/dev/esp32s2flash";
ret = setup_spiffs(path, mtd, "/data", 0755);
if (ret < 0)
{
ferr("ERROR: Failed to setup spiffs\n");
return ret;
}
#else
ret = register_mtddriver("/dev/esp32s2flash", mtd, 0755, NULL);
if (ret < 0)
{
ferr("ERROR: Failed to register MTD: %d\n", ret);
return ret;
}
#endif
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: board_spiflash_init
*
* Description:
* Initialize the SPIFLASH and register the MTD device.
*
****************************************************************************/
int board_spiflash_init(void)
{
int ret = OK;
ret = esp32s2_spiflash_init();
if (ret < 0)
{
return ret;
}
ret = init_storage_partition();
if (ret < 0)
{
return ret;
}
return ret;
}

View File

@ -81,6 +81,18 @@
int esp32s2_bringup(void);
/****************************************************************************
* Name: board_spiflash_init
*
* Description:
* Initialize the SPIFLASH and register the MTD device.
*
****************************************************************************/
#ifdef CONFIG_ESP32S2_SPIFLASH
int board_spiflash_init(void);
#endif
/****************************************************************************
* Name: esp32s2_gpio_init
*

View File

@ -145,6 +145,14 @@ int esp32s2_bringup(void)
}
#endif /* CONFIG_ESP32S2_LEDC */
#ifdef CONFIG_ESP32S2_SPIFLASH
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
}
#endif
#ifdef CONFIG_DEV_GPIO
ret = esp32s2_gpio_init();
if (ret < 0)