This is an automated email from the ASF dual-hosted git repository. aguettouche pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push: new c06d3e1 xtensa/esp32: Add SPI Flash device driver c06d3e1 is described below commit c06d3e1b0a2bd459ea46f5b4946838831c841023 Author: Alan C. Assis <acas...@gmail.com> AuthorDate: Fri Jul 31 11:16:48 2020 -0300 xtensa/esp32: Add SPI Flash device driver ESP32 runs code in a SPI Flash, so users can also use it to store data directly or mount some parts into a filesystem. The SPI Flash usually use SPI0. This driver was implemented by Dong Heng dongh...@espressif.com and modified to fix coding style by Alan Carvalho de Assis. --- arch/xtensa/src/esp32/Kconfig | 31 + arch/xtensa/src/esp32/Make.defs | 4 + arch/xtensa/src/esp32/esp32_spiflash.c | 1194 ++++++++++++++++++++ arch/xtensa/src/esp32/esp32_spiflash.h | 87 ++ arch/xtensa/src/esp32/rom/esp32_spiflash.h | 826 ++++++++++++++ .../xtensa/esp32/esp32-core/scripts/esp32_flash.ld | 3 + .../xtensa/esp32/esp32-core/scripts/esp32_rom.ld | 5 + 7 files changed, 2150 insertions(+) diff --git a/arch/xtensa/src/esp32/Kconfig b/arch/xtensa/src/esp32/Kconfig index de18d2f..f460bb4 100644 --- a/arch/xtensa/src/esp32/Kconfig +++ b/arch/xtensa/src/esp32/Kconfig @@ -82,6 +82,13 @@ config ESP32_SPI bool default n +config ESP32_SPIFLASH + bool + default n + select MTD + select MTD_BYTE_WRITE + select MTD_PARTITION + config ESP32_SPI2 bool "SPI 2" default n @@ -405,4 +412,28 @@ endif # ESP32_SPI3 endmenu # ESP32_SPI +menu "SPI Flash configuration" + depends on ESP32_SPIFLASH + +config ESP32_MTD_OFFSET + hex "MTD base address in SPI Flash" + default 0x180000 + help + MTD base address in SPI Flash. + +config ESP32_MTD_SIZE + hex "MTD size in SPI Flash" + default 0x100000 + help + MTD size in SPI Flash. + +config ESP32_SPIFLASH_DEBUG + bool "Debug SPI Flash" + default n + depends on DEBUG_FS_INFO + help + Enable this option, read and write of SPI Flash + will show input arguments and result. + +endmenu # ESP32_SPIFLASH endif # ARCH_CHIP_ESP32 diff --git a/arch/xtensa/src/esp32/Make.defs b/arch/xtensa/src/esp32/Make.defs index 86998d3..557956d 100644 --- a/arch/xtensa/src/esp32/Make.defs +++ b/arch/xtensa/src/esp32/Make.defs @@ -111,6 +111,10 @@ CHIP_CSRCS += esp32_spi.c endif endif +ifeq ($(CONFIG_ESP32_SPIFLASH),y) +CHIP_CSRCS += esp32_spiflash.c +endif + # Configuration-dependent ESP32 files ifeq ($(CONFIG_SMP),y) diff --git a/arch/xtensa/src/esp32/esp32_spiflash.c b/arch/xtensa/src/esp32/esp32_spiflash.c new file mode 100644 index 0000000..c9402f8 --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_spiflash.c @@ -0,0 +1,1194 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_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_ESP32_SPIFLASH + +#include <stdint.h> +#include <debug.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/errno.h> + +#include <nuttx/mtd/mtd.h> + +#include "xtensa.h" +#include "hardware/esp32_spi.h" +#include "rom/esp32_spiflash.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define SPI_FLASH_WRITE_BUF_SIZE (32) +#define SPI_FLASH_READ_BUF_SIZE (64) + +#define ESP32_MTD_OFFSET CONFIG_ESP32_MTD_OFFSET +#define ESP32_MTD_SIZE CONFIG_ESP32_MTD_SIZE + +#define MTD2PRIV(_dev) ((FAR struct esp32_spiflash_s *)_dev) +#define MTD_SIZE(_priv) ((_priv)->chip->chip_size) +#define MTD_BLKSIZE(_priv) ((_priv)->chip->page_size) +#define MTD_ERASESIZE(_priv) ((_priv)->chip->sector_size) +#define MTD_BLK2SIZE(_priv, _b) (MTD_BLKSIZE(_priv) * (_b)) +#define MTD_SIZE2BLK(_priv, _s) ((_s) / MTD_BLKSIZE(_priv)) + +#ifndef MIN +# define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* SPI Flash device hardware configuration */ + +struct esp32_spiflash_config_s +{ + /* SPI register base address */ + + uint32_t reg_base; +}; + +/* SPI Flash device private data */ + +struct esp32_spiflash_s +{ + struct mtd_dev_s mtd; + + /* Port configuration */ + + const struct esp32_spiflash_config_s *config; + + /* SPI Flash data */ + + esp32_spiflash_chip_t *chip; + + /* SPI Flash communication dummy number */ + + uint8_t *dummies; +}; + +/**************************************************************************** + * Private Functions Prototypes + ****************************************************************************/ + +static int esp32_erase(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks); + +static ssize_t esp32_read(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR uint8_t *buffer); + +static ssize_t esp32_bread(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks, FAR uint8_t *buffer); + +static ssize_t esp32_write(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR const uint8_t *buffer); + +static ssize_t esp32_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks, FAR const uint8_t *buffer); + +static int esp32_ioctl(FAR struct mtd_dev_s *dev, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct esp32_spiflash_config_s s_esp32_spiflash1_config = +{ + .reg_base = REG_SPI_BASE(1) +}; + +static struct esp32_spiflash_s s_esp32_spiflash1 = +{ + .mtd = + { + .erase = esp32_erase, + .bread = esp32_bread, + .bwrite = esp32_bwrite, + .read = esp32_read, + .ioctl = esp32_ioctl, +#if defined(CONFIG_MTD_BYTE_WRITE) + .write = esp32_write, +#endif + .name = "esp32_mainflash" + }, + .config = &s_esp32_spiflash1_config, + .chip = &g_rom_flashchip, + .dummies = g_rom_spiflash_dummy_len_plus +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: spi_set_reg + * + * Description: + * Set the contents 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 + * + ****************************************************************************/ + +static inline void spi_set_reg(struct esp32_spiflash_s *priv, + int offset, uint32_t value) +{ + putreg32(value, priv->config->reg_base + offset); +} + +/**************************************************************************** + * Name: spi_get_reg + * + * Description: + * Get the contents of the SPI register at offset + * + * Input Parameters: + * priv - Private SPI device structure + * offset - Offset to the register of interest + * + * Returned Value: + * The contents of the register + * + ****************************************************************************/ + +static inline uint32_t spi_get_reg(struct esp32_spiflash_s *priv, + int offset) +{ + return getreg32(priv->config->reg_base + offset); +} + +/**************************************************************************** + * 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 + * + ****************************************************************************/ + +static inline void spi_set_regbits(struct esp32_spiflash_s *priv, + int offset, uint32_t bits) +{ + uint32_t tmp = getreg32(priv->config->reg_base + offset); + + putreg32(tmp | bits, priv->config->reg_base + offset); +} + +/**************************************************************************** + * Name: spi_reset_regbits + * + * Description: + * Clear 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 cleared + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void spi_reset_regbits(struct esp32_spiflash_s *priv, + int offset, uint32_t bits) +{ + uint32_t tmp = getreg32(priv->config->reg_base + offset); + + putreg32(tmp & (~bits), priv->config->reg_base + offset); +} + +/**************************************************************************** + * Name: spi_memcpy + * + * Description: + * Copy data from one block of memory to another block of memory. + * The function must be linked in IRAM not in flash, so add this function + * instead of libc memcpy. + * + * Input Parameters: + * d - destination address + * s - source address + * n - data bytes + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void spi_memcpy(void *d, const void *s, uint32_t n) +{ + uint8_t *dest = (uint8_t *)d; + const uint8_t *src = (const uint8_t *)s; + + while (n--) + *dest++ = *src++; +} + +/**************************************************************************** + * Name: esp32_set_read_opt + * + * Description: + * Set SPI Flash to be direct read mode. Due to different SPI I/O mode + * including DIO, QIO and so on. Different command and communication + * timing sequence are needed. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp32_set_read_opt(FAR struct esp32_spiflash_s *priv) +{ + uint32_t regval; + uint32_t ctrl; + uint32_t mode; + uint32_t cmd; + uint32_t cycles = 0; + uint32_t addrbits = 0; + uint32_t dummy = 0; + + ctrl = spi_get_reg(priv, SPI_CTRL_OFFSET); + mode = ctrl & (SPI_FREAD_QIO | SPI_FASTRD_MODE); + if (mode == (SPI_FREAD_QIO | SPI_FASTRD_MODE)) + { + cycles = SPI1_R_QIO_DUMMY_CYCLELEN + priv->dummies[1]; + dummy = 1; + addrbits = SPI1_R_QIO_ADDR_BITSLEN; + cmd = (0x7 << SPI_USR_COMMAND_BITLEN_S) | 0xeb; + } + else if (mode == SPI_FASTRD_MODE) + { + if (ctrl & SPI_FREAD_DIO) + { + if (priv->dummies[1] == 0) + { + addrbits = SPI1_R_DIO_ADDR_BITSLEN; + cmd = (0x7 << SPI_USR_COMMAND_BITLEN_S) | 0xbb; + } + else + { + cycles = priv->dummies[1] - 1; + dummy = 1; + addrbits = SPI1_R_DIO_ADDR_BITSLEN; + cmd = 0xbb; + } + } + else + { + if (ctrl & SPI_FREAD_QUAD) + { + cmd = (0x7 << SPI_USR_COMMAND_BITLEN_S) | 0x6b; + } + else if (ctrl & SPI_FREAD_DUAL) + { + cmd = (0x7 << SPI_USR_COMMAND_BITLEN_S) | 0x3b; + } + else + { + cmd = (0x7 << SPI_USR_COMMAND_BITLEN_S) | 0x0b; + } + + cycles = SPI1_R_FAST_DUMMY_CYCLELEN + priv->dummies[1]; + dummy = 1; + addrbits = SPI1_R_DIO_ADDR_BITSLEN; + } + } + else + { + if (priv->dummies[1] != 0) + { + cycles = priv->dummies[1] - 1; + dummy = 1; + } + + addrbits = SPI1_R_SIO_ADDR_BITSLEN ; + cmd = (0x7 << SPI_USR_COMMAND_BITLEN_S) | 0x03; + } + + regval = spi_get_reg(priv, SPI_USER_OFFSET); + regval &= ~SPI_USR_MOSI; + regval = SPI_USR_MISO | SPI_USR_ADDR; + if (dummy) + { + regval |= SPI_USR_DUMMY; + } + else + { + regval &= ~SPI_USR_DUMMY; + } + + spi_set_regbits(priv, SPI_USER_OFFSET, regval); + + regval = spi_get_reg(priv, SPI_USER1_OFFSET); + regval &= ~SPI_USR_DUMMY_CYCLELEN_M; + regval |= cycles << SPI_USR_DUMMY_CYCLELEN_S; + regval &= ~SPI_USR_ADDR_BITLEN_M; + regval |= addrbits << SPI_USR_ADDR_BITLEN_S; + spi_set_reg(priv, SPI_USER1_OFFSET, regval); + + regval = spi_get_reg(priv, SPI_USER2_OFFSET); + regval &= ~SPI_USR_COMMAND_VALUE; + regval |= cmd; + spi_set_reg(priv, SPI_USER2_OFFSET, regval); +} + +/**************************************************************************** + * Name: esp32_set_read_opt + * + * Description: + * Set SPI Flash to be direct read mode. Due to different SPI I/O mode + * including DIO, QIO and so on. Different command and communication + * timing sequence are needed. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp32_set_write_opt(struct esp32_spiflash_s *priv) +{ + uint32_t addrbits; + uint32_t regval; + + spi_reset_regbits(priv, SPI_USER_OFFSET, SPI_USR_DUMMY); + + addrbits = ESP_ROM_SPIFLASH_W_SIO_ADDR_BITSLEN; + regval = spi_get_reg(priv, SPI_USER1_OFFSET); + regval &= ~SPI_USR_ADDR_BITLEN_M; + regval |= addrbits << SPI_USR_ADDR_BITLEN_S; + spi_set_reg(priv, SPI_USER1_OFFSET, regval); +} + +/**************************************************************************** + * Name: esp32_read_status + * + * Description: + * Read SPI Flash status regitser value. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * status - status buffer pointer + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +static int esp32_read_status(FAR struct esp32_spiflash_s *priv, + uint32_t *status) +{ + esp32_spiflash_chip_t *chip = priv->chip; + uint32_t regval; + uint32_t flags; + bool direct = priv->dummies[1] == 0; + + if (priv->dummies[1] == 0) + { + direct = true; + } + else + { + direct = false; + } + + do + { + if (direct) + { + spi_set_reg(priv, SPI_RD_STATUS_OFFSET, 0); + spi_set_reg(priv, SPI_CMD_OFFSET, SPI_FLASH_RDSR); + while (spi_get_reg(priv, SPI_CMD_OFFSET) != 0) + { + ; + } + + regval = spi_get_reg(priv, SPI_RD_STATUS_OFFSET); + regval &= chip->status_mask; + flags = regval & ESP_ROM_SPIFLASH_BUSY_FLAG; + } + else + { + if (esp_rom_spiflash_read_user_cmd(®val, 0x05)) + { + return -EIO; + } + + flags = regval & ESP_ROM_SPIFLASH_BUSY_FLAG; + } + } + while (flags == ESP_ROM_SPIFLASH_BUSY_FLAG); + + *status = regval; + + return 0; +} + +/**************************************************************************** + * Name: esp32_wait_idle + * + * Description: + * Wait for SPI Flash to be idle state. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +static int esp32_wait_idle(FAR struct esp32_spiflash_s *priv) +{ + uint32_t status; + + while (spi_get_reg(priv, SPI_EXT2_OFFSET) & SPI_ST) + { + ; + } + + while (getreg32(SPI_EXT2_REG(0)) & SPI_ST) + { + ; + } + + if (esp32_read_status(priv, &status)) + { + return -EIO; + } + + return 0; +} + +/**************************************************************************** + * Name: esp32_read_highstatus + * + * Description: + * Read SPI Flash high status regitser value. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * status - status buffer pointer + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +int esp32_read_highstatus(FAR struct esp32_spiflash_s *priv, + uint32_t *status) +{ + uint32_t regval; + + if (esp32_wait_idle(priv)) + { + return -EIO; + } + + if (esp_rom_spiflash_read_user_cmd(®val, 0x35)) + { + return -EIO; + } + + *status = regval << 8; + + return 0; +} + +/**************************************************************************** + * Name: esp32_write_status + * + * Description: + * Write status value to SPI Flash status regitser. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * status - status data + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +int esp32_write_status(FAR struct esp32_spiflash_s *priv, uint32_t status) +{ + if (esp32_wait_idle(priv)) + { + return -EIO; + } + + spi_set_reg(priv, SPI_RD_STATUS_OFFSET, status); + spi_set_reg(priv, SPI_CMD_OFFSET, SPI_FLASH_WRSR); + while (spi_get_reg(priv, SPI_CMD_OFFSET) != 0) + { + ; + } + + if (esp32_wait_idle(priv)) + { + return -EIO; + } + + return 0; +} + +/**************************************************************************** + * Name: esp32_enable_write + * + * Description: + * Drive SPI flash entering into write mode. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +static int esp32_enable_write(FAR struct esp32_spiflash_s *priv) +{ + uint32_t flags; + uint32_t regval; + + if (esp32_wait_idle(priv)) + { + return -EIO; + } + + spi_set_reg(priv, SPI_RD_STATUS_OFFSET, 0); + spi_set_reg(priv, SPI_CMD_OFFSET, SPI_FLASH_WREN); + while (spi_get_reg(priv, SPI_CMD_OFFSET) != 0) + { + ; + } + + do + { + if (esp32_read_status(priv, ®val)) + { + return -EIO; + } + + flags = regval & ESP_ROM_SPIFLASH_WRENABLE_FLAG; + } + while (flags != ESP_ROM_SPIFLASH_WRENABLE_FLAG); + + return 0; +} + +/**************************************************************************** + * Name: esp32_erasesector + * + * Description: + * Erase SPI Flash sector at designated address. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * addr - erasing address + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +static int esp32_erasesector(FAR struct esp32_spiflash_s *priv, + uint32_t addr, uint32_t size) +{ + int ret; + uint32_t offset; + + if (esp32_wait_idle(priv)) + { + return -EIO; + } + + for (offset = 0; offset < size; offset += MTD_ERASESIZE(priv)) + { + ret = esp32_enable_write(priv); + if (ret) + { + return -EIO; + } + + spi_set_reg(priv, SPI_ADDR_OFFSET, (addr + offset) & 0xffffff); + spi_set_reg(priv, SPI_CMD_OFFSET, SPI_FLASH_SE); + while (spi_get_reg(priv, SPI_CMD_OFFSET) != 0) + { + ; + } + + if (esp32_wait_idle(priv)) + { + return -EIO; + } + } + + return 0; +} + +/**************************************************************************** + * Name: esp32_writedata + * + * Description: + * Write data to SPI Flash at designated address. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * addr - target address + * buffer - data buffer pointer + * size - data number + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +static int esp32_writedata(FAR struct esp32_spiflash_s *priv, uint32_t addr, + const uint8_t *buffer, uint32_t size) +{ + uint32_t regval; + uint32_t i; + uint32_t bytes; + uint32_t tmp; + uint32_t res; + + if (esp32_wait_idle(priv)) + { + return -EIO; + } + + while (size > 0) + { + if (esp32_enable_write(priv)) + { + return -EIO; + } + + bytes = MTD_BLKSIZE(priv) - addr % MTD_BLKSIZE(priv) ; + if (!bytes) + { + bytes = MIN(size, SPI_FLASH_WRITE_BUF_SIZE); + } + else + { + bytes = MIN(bytes, size); + bytes = MIN(bytes, SPI_FLASH_WRITE_BUF_SIZE); + } + + regval = addr & 0xffffff; + regval |= bytes << ESP_ROM_SPIFLASH_BYTES_LEN; + spi_set_reg(priv, SPI_ADDR_OFFSET, regval); + + for (i = 0; i < bytes; i += 4) + { + res = MIN(4, bytes - i); + + spi_memcpy(&tmp, buffer, res); + spi_set_reg(priv, SPI_W0_OFFSET + i, tmp); + buffer += res; + } + + spi_set_reg(priv, SPI_RD_STATUS_OFFSET, 0); + spi_set_reg(priv, SPI_CMD_OFFSET, SPI_FLASH_PP); + while (spi_get_reg(priv, SPI_CMD_OFFSET) != 0) + { + ; + } + + if (esp32_wait_idle(priv)) + { + return -EIO; + } + + addr += bytes; + size -= bytes; + } + + return 0; +} + +/**************************************************************************** + * Name: esp32_readdata + * + * Description: + * Read data from SPI Flash at designated address. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * addr - target address + * buffer - data buffer pointer + * size - data number + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +static int esp32_readdata(FAR struct esp32_spiflash_s *priv, uint32_t addr, + uint8_t *buffer, uint32_t size) +{ + uint32_t regval; + uint32_t i; + uint32_t bytes; + uint32_t tmp; + uint32_t res; + + if (esp32_wait_idle(priv)) + { + return -EIO; + } + + while (size > 0) + { + bytes = MIN(size, SPI_FLASH_READ_BUF_SIZE); + regval = ((bytes << 3) - 1) << SPI_USR_MISO_DBITLEN_S; + spi_set_reg(priv, SPI_MISO_DLEN_OFFSET, regval); + + regval = addr << 8; + spi_set_reg(priv, SPI_ADDR_OFFSET, regval); + + spi_set_reg(priv, SPI_RD_STATUS_OFFSET, 0); + spi_set_reg(priv, SPI_CMD_OFFSET, SPI_USR); + while (spi_get_reg(priv, SPI_CMD_OFFSET) != 0) + { + ; + } + + for (i = 0; i < bytes; i += 4) + { + res = MIN(4, bytes - i); + + tmp = spi_get_reg(priv, SPI_W0_OFFSET + i); + spi_memcpy(buffer, &tmp, res); + buffer += res; + } + + addr += bytes; + size -= bytes; + } + + return 0; +} + +/**************************************************************************** + * Name: esp32_erase + * + * Description: + * Erase SPI Flash designated sectors. + * + * Input Parameters: + * dev - ESP32 MTD device data + * startblock - start block number, it is not equal to SPI Flash's block + * nblocks - blocks number + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +static int esp32_erase(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks) +{ + int ret; + uint32_t flags; + FAR struct esp32_spiflash_s *priv = MTD2PRIV(dev); + uint32_t addr = startblock * MTD_ERASESIZE(priv); + uint32_t size = nblocks * MTD_ERASESIZE(priv); + + if ((addr >= MTD_SIZE(priv)) || (addr + size > MTD_SIZE(priv))) + { + return -EINVAL; + } + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_erase(%p, %d, %d)\n", dev, startblock, nblocks); +#endif + + flags = enter_critical_section(); + + esp32_set_write_opt(priv); + ret = esp32_erasesector(priv, addr, size); + + leave_critical_section(flags); + + if (!ret) + { + ret = nblocks; + } + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_erase()=%d\n", ret); +#endif + + return ret; +} + +/**************************************************************************** + * Name: esp32_read + * + * Description: + * Read data from SPI Flash at designated address. + * + * Input Parameters: + * dev - ESP32 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 esp32_read(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR uint8_t *buffer) +{ + int ret; + uint32_t flags; + FAR struct esp32_spiflash_s *priv = MTD2PRIV(dev); + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_read(%p, 0x%x, %d, %p)\n", dev, offset, nbytes, buffer); +#endif + + flags = enter_critical_section(); + + esp32_set_read_opt(priv); + ret = esp32_readdata(priv, offset, buffer, nbytes); + + leave_critical_section(flags); + + if (!ret) + { + ret = nbytes; + } + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_read()=%d\n", ret); +#endif + + return ret; +} + +/**************************************************************************** + * Name: esp32_bread + * + * Description: + * Read data from designated blocks. + * + * Input Parameters: + * dev - ESP32 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 esp32_bread(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks, FAR uint8_t *buffer) +{ + int ret; + FAR struct esp32_spiflash_s *priv = MTD2PRIV(dev); + uint32_t addr = MTD_BLK2SIZE(priv, startblock); + uint32_t size = MTD_BLK2SIZE(priv, nblocks); + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_bread(%p, 0x%x, %d, %p)\n", + dev, startblock, nblocks, buffer); +#endif + + ret = esp32_read(dev, addr, size, buffer); + if (ret == size) + { + ret = nblocks; + } + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_bread()=%d\n", ret); +#endif + + return ret; +} + +/**************************************************************************** + * Name: esp32_write + * + * Description: + * write data to SPI Flash at designated address. + * + * Input Parameters: + * dev - ESP32 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 esp32_write(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR const uint8_t *buffer) +{ + int ret; + uint32_t flags; + FAR struct esp32_spiflash_s *priv = MTD2PRIV(dev); + + ASSERT(buffer); + + if ((offset > MTD_SIZE(priv)) || ((offset + nbytes) > MTD_SIZE(priv))) + { + return -EINVAL; + } + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_write(%p, 0x%x, %d, %p)\n", dev, offset, nbytes, buffer); +#endif + + flags = enter_critical_section(); + + esp32_set_write_opt(priv); + + ret = esp32_writedata(priv, offset, buffer, nbytes); + + leave_critical_section(flags); + + if (!ret) + { + ret = nbytes; + } + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_write()=%d\n", ret); +#endif + + return ret; +} + +/**************************************************************************** + * Name: esp32_bwrite + * + * Description: + * Write data to designated blocks. + * + * Input Parameters: + * dev - ESP32 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 esp32_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks, FAR const uint8_t *buffer) +{ + ssize_t ret; + FAR struct esp32_spiflash_s *priv = MTD2PRIV(dev); + uint32_t addr = MTD_BLK2SIZE(priv, startblock); + uint32_t size = MTD_BLK2SIZE(priv, nblocks); + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_bwrite(%p, 0x%x, %d, %p)\n", + dev, startblock, nblocks, buffer); +#endif + + ret = esp32_write(dev, addr, size, buffer); + if (ret == size) + { + ret = nblocks; + } + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_bwrite()=%d\n", ret); +#endif + + return ret; +} + +/**************************************************************************** + * Name: esp32_ioctl + * + * Description: + * Set/Get option to/from ESP32 SPI Flash MTD device data. + * + * Input Parameters: + * dev - ESP32 MTD device data + * cmd - operation command + * arg - operation argument + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +static int esp32_ioctl(FAR struct mtd_dev_s *dev, int cmd, + unsigned long arg) +{ + int ret = -EINVAL; + FAR struct esp32_spiflash_s *priv = MTD2PRIV(dev); + FAR struct mtd_geometry_s *geo; + + finfo("cmd: %d \n", cmd); + + switch (cmd) + { + case MTDIOC_GEOMETRY: + { + geo = (FAR struct mtd_geometry_s *)arg; + if (geo) + { + geo->blocksize = MTD_BLKSIZE(priv); + geo->erasesize = MTD_ERASESIZE(priv); + geo->neraseblocks = MTD_SIZE(priv) / MTD_ERASESIZE(priv); + ret = OK; + + finfo("blocksize: %d erasesize: %d neraseblocks: %d\n", + geo->blocksize, geo->erasesize, geo->neraseblocks); + } + } + break; + + default: + ret = -ENOTTY; + break; + } + + finfo("return %d\n", ret); + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32_spiflash_alloc_mtdpart + * + * Description: + * Alloc ESP32 SPI Flash MTD + * + * Input Parameters: + * None + * + * Returned Value: + * ESP32 SPI Flash MTD data pointer if success or NULL if fail + * + ****************************************************************************/ + +FAR struct mtd_dev_s *esp32_spiflash_alloc_mtdpart(void) +{ + struct esp32_spiflash_s *priv = &s_esp32_spiflash1; + esp32_spiflash_chip_t *chip = priv->chip; + FAR struct mtd_dev_s *mtd_part; + uint32_t blocks; + uint32_t startblock; + uint32_t size; + + ASSERT((ESP32_MTD_OFFSET + ESP32_MTD_SIZE) <= chip->chip_size); + ASSERT((ESP32_MTD_OFFSET % chip->sector_size) == 0); + ASSERT((ESP32_MTD_SIZE % chip->sector_size) == 0); + + finfo("ESP32 SPI Flash information:\n"); + finfo("\tID = 0x%x\n", chip->device_id); + finfo("\tStatus mask = %x\n", chip->status_mask); + finfo("\tChip size = %d KB\n", chip->chip_size / 1024); + finfo("\tPage size = %d B\n", chip->page_size); + finfo("\tSector size = %d KB\n", chip->sector_size / 1024); + finfo("\tBlock size = %d KB\n", chip->block_size / 1024); + +#if ESP32_MTD_SIZE == 0 + size = chip->chip_size - ESP32_MTD_OFFSET; +#else + size = ESP32_MTD_SIZE; +#endif + + finfo("\tMTD offset = 0x%x\n", ESP32_MTD_OFFSET); + finfo("\tMTD size = 0x%x\n", size); + + startblock = MTD_SIZE2BLK(priv, ESP32_MTD_OFFSET); + blocks = MTD_SIZE2BLK(priv, size); + + mtd_part = mtd_partition(&priv->mtd, startblock, blocks); + if (!mtd_part) + { + ferr("ERROR: create MTD partition"); + return NULL; + } + + return mtd_part; +} + +/**************************************************************************** + * Name: esp32_spiflash_get_mtd + * + * Description: + * Get ESP32 SPI Flash raw MTD. + * + * Input Parameters: + * None + * + * Returned Value: + * ESP32 SPI Flash raw MTD data pointer. + * + ****************************************************************************/ + +FAR struct mtd_dev_s *esp32_spiflash_get_mtd(void) +{ + struct esp32_spiflash_s *priv = &s_esp32_spiflash1; + + return &priv->mtd; +} + +#endif /* CONFIG_ESP32_SPIFLASH */ diff --git a/arch/xtensa/src/esp32/esp32_spiflash.h b/arch/xtensa/src/esp32/esp32_spiflash.h new file mode 100644 index 0000000..1b3702d --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_spiflash.h @@ -0,0 +1,87 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_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_ESP32_ESP32_SPIFLASH_H +#define __ARCH_XTENSA_SRC_ESP32_ESP32_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: esp32_spiflash_init + * + * Description: + * Alloc ESP32 SPI Flash MTD. + * + * Input Parameters: + * None + * + * Returned Value: + * ESP32 SPI Flash MTD data pointer if success or NULL if fail. + * + ****************************************************************************/ + +FAR struct mtd_dev_s *esp32_spiflash_alloc_mtdpart(void); + +/**************************************************************************** + * Name: esp32_spiflash_get_mtd + * + * Description: + * Get ESP32 SPI Flash raw MTD. + * + * Input Parameters: + * None + * + * Returned Value: + * ESP32 SPI Flash raw MTD data pointer. + * + ****************************************************************************/ + +FAR struct mtd_dev_s *esp32_spiflash_get_mtd(void); + +#ifdef __cplusplus +} +#endif +#undef EXTERN + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_XTENSA_SRC_ESP32_ESP32_SPIFLASH_H */ diff --git a/arch/xtensa/src/esp32/rom/esp32_spiflash.h b/arch/xtensa/src/esp32/rom/esp32_spiflash.h new file mode 100644 index 0000000..2e0eb47 --- /dev/null +++ b/arch/xtensa/src/esp32/rom/esp32_spiflash.h @@ -0,0 +1,826 @@ +/***************************************************************************** + * arch/xtensa/src/esp32/rom/esp32_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 _ROM_SPI_FLASH_H_ +#define _ROM_SPI_FLASH_H_ + +/***************************************************************************** + * Included Files + *****************************************************************************/ + +#include <stdint.h> +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* spi_flash_apis, spi flash operation related apis */ + +/***************************************************************************** + * Note + ***************************************************************************** + * 1. ESP32 chip have 4 SPI slave/master, however, SPI0 is + * used as an SPI master to access Flash and ext-SRAM by + * Cache module. It will support Decryto read for Flash, + * read/write for ext-SRAM. And SPI1 is also used as an + * SPI master for Flash read/write and ext-SRAM read/write. + * It will support Encrypto write for Flash. + * 2. As an SPI master, SPI support Highest clock to 80M, + * however, Flash with 80M Clock should be configured + * for different Flash chips. If you want to use 80M + * clock We should use the SPI that is certified by + * Espressif. However, the certification is not started + * at the time, so please use 40M clock at the moment. + * 3. SPI Flash can use 2 lines or 4 lines mode. If you + * use 2 lines mode, you can save two pad SPIHD and + * SPIWP for gpio. ESP32 support configured SPI pad for + * Flash, the configuration is stored in efuse and flash. + * However, the configurations of pads should be certified + * by Espressif. If you use this function, please use 40M + * clock at the moment. + * 4. ESP32 support to use Common SPI command to configure + * Flash to QIO mode, if you failed to configure with fix + * command. With Common SPI Command, ESP32 can also provide + * a way to use same Common SPI command groups on different + * Flash chips. + * 5. This functions are not protected by packeting, Please use the + *****************************************************************************/ + +/***************************************************************************** + * Pre-processor Definitions + *****************************************************************************/ + +#define PERIPHS_SPI_FLASH_CMD SPI_CMD_REG(1) +#define PERIPHS_SPI_FLASH_ADDR SPI_ADDR_REG(1) +#define PERIPHS_SPI_FLASH_CTRL SPI_CTRL_REG(1) +#define PERIPHS_SPI_FLASH_CTRL1 SPI_CTRL1_REG(1) +#define PERIPHS_SPI_FLASH_STATUS SPI_RD_STATUS_REG(1) +#define PERIPHS_SPI_FLASH_USRREG SPI_USER_REG(1) +#define PERIPHS_SPI_FLASH_USRREG1 SPI_USER1_REG(1) +#define PERIPHS_SPI_FLASH_USRREG2 SPI_USER2_REG(1) +#define PERIPHS_SPI_FLASH_C0 SPI_W0_REG(1) +#define PERIPHS_SPI_FLASH_C1 SPI_W1_REG(1) +#define PERIPHS_SPI_FLASH_C2 SPI_W2_REG(1) +#define PERIPHS_SPI_FLASH_C3 SPI_W3_REG(1) +#define PERIPHS_SPI_FLASH_C4 SPI_W4_REG(1) +#define PERIPHS_SPI_FLASH_C5 SPI_W5_REG(1) +#define PERIPHS_SPI_FLASH_C6 SPI_W6_REG(1) +#define PERIPHS_SPI_FLASH_C7 SPI_W7_REG(1) +#define PERIPHS_SPI_FLASH_TX_CRC SPI_TX_CRC_REG(1) + +#define SPI0_R_QIO_DUMMY_CYCLELEN 3 +#define SPI0_R_QIO_ADDR_BITSLEN 31 +#define SPI0_R_FAST_DUMMY_CYCLELEN 7 +#define SPI0_R_DIO_DUMMY_CYCLELEN 1 +#define SPI0_R_DIO_ADDR_BITSLEN 27 +#define SPI0_R_FAST_ADDR_BITSLEN 23 +#define SPI0_R_SIO_ADDR_BITSLEN 23 + +#define SPI1_R_QIO_DUMMY_CYCLELEN 3 +#define SPI1_R_QIO_ADDR_BITSLEN 31 +#define SPI1_R_FAST_DUMMY_CYCLELEN 7 +#define SPI1_R_DIO_DUMMY_CYCLELEN 3 +#define SPI1_R_DIO_ADDR_BITSLEN 31 +#define SPI1_R_FAST_ADDR_BITSLEN 23 +#define SPI1_R_SIO_ADDR_BITSLEN 23 + +#define ESP_ROM_SPIFLASH_W_SIO_ADDR_BITSLEN 23 + +#define ESP_ROM_SPIFLASH_TWO_BYTE_STATUS_EN SPI_WRSR_2B + +/* SPI address register */ + +#define ESP_ROM_SPIFLASH_BYTES_LEN 24 +#define ESP_ROM_SPIFLASH_BUFF_BYTE_WRITE_NUM 32 +#define ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM 64 +#define ESP_ROM_SPIFLASH_BUFF_BYTE_READ_BITS 0x3f + +/* SPI status register */ + +#define ESP_ROM_SPIFLASH_BUSY_FLAG BIT0 +#define ESP_ROM_SPIFLASH_WRENABLE_FLAG BIT1 +#define ESP_ROM_SPIFLASH_BP0 BIT2 +#define ESP_ROM_SPIFLASH_BP1 BIT3 +#define ESP_ROM_SPIFLASH_BP2 BIT4 +#define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|\ + ESP_ROM_SPIFLASH_BP1|\ + ESP_ROM_SPIFLASH_BP2) +#define ESP_ROM_SPIFLASH_QE BIT9 + +/* Extra dummy for flash read */ + +#define ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M 0 +#define ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M 1 +#define ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M 2 + +#define FLASH_ID_GD25LQ32C 0xC86016 + +/***************************************************************************** + * Public Types + *****************************************************************************/ + +typedef enum +{ + ESP_ROM_SPIFLASH_QIO_MODE = 0, + ESP_ROM_SPIFLASH_QOUT_MODE, + ESP_ROM_SPIFLASH_DIO_MODE, + ESP_ROM_SPIFLASH_DOUT_MODE, + ESP_ROM_SPIFLASH_FASTRD_MODE, + ESP_ROM_SPIFLASH_SLOWRD_MODE +} esp_rom_spiflash_read_mode_t; + +typedef enum +{ + ESP_ROM_SPIFLASH_RESULT_OK, + ESP_ROM_SPIFLASH_RESULT_ERR, + ESP_ROM_SPIFLASH_RESULT_TIMEOUT +} esp_rom_spiflash_result_t; + +typedef struct +{ + uint32_t device_id; + uint32_t chip_size; /* chip size in bytes */ + uint32_t block_size; + uint32_t sector_size; + uint32_t page_size; + uint32_t status_mask; +} esp32_spiflash_chip_t; + +typedef struct +{ + uint8_t data_length; + uint8_t read_cmd0; + uint8_t read_cmd1; + uint8_t write_cmd; + uint16_t data_mask; + uint16_t data; +} esp_rom_spiflash_common_cmd_t; + +/***************************************************************************** + * Public Function Prototypes + *****************************************************************************/ + +/***************************************************************************** + * Name: esp_rom_spiflash_fix_dummylen + * + * Description: + * Fix the bug in SPI hardware communication with Flash/Ext-SRAM in High + * Speed. + * + * Please do not call this function in SDK. + * + * Input Parameters: + * uint8_t spi: 0 for SPI0(Cache Access), 1 for SPI1(Flash read/write). + * + * uint8_t freqdiv: Pll is 80M, 4 for 20M, 3 for 26.7M, 2 for 40M, + * 1 for 80M. + * + * Returned Value: + * None + * + *****************************************************************************/ + +void esp_rom_spiflash_fix_dummylen(uint8_t spi, uint8_t freqdiv); + +/***************************************************************************** + * Name: esp_rom_spiflash_select_qiomode + * + * Description: + * Select SPI Flash to QIO mode when WP pad is read from Flash. + * + * Please do not call this function in SDK. + * + * Input Parameters: + * uint8_t wp_gpio_num: WP gpio number. + * + * uint32_t ishspi: 0 for spi, 1 for hspi, flash pad decided by strapping + * else, bit[5:0] spiclk, bit[11:6] spiq, bit[17:12] spid, + * bit[23:18] spics0, bit[29:24] spihd + * + * Returned Value: + * None + *****************************************************************************/ + +void esp_rom_spiflash_select_qiomode(uint8_t wp_gpio_num, + uint32_t ishspi); + +/***************************************************************************** + * Name: esp_rom_spiflash_set_drvs + * + * Description: + * Set SPI Flash pad drivers. + * + * Please do not call this function in SDK. + * + * Input Parameters: + * uint8_t wp_gpio_num: WP gpio number. + * + * uint32_t ishspi: 0 for spi, 1 for hspi, flash pad decided by strapping + * else, bit[5:0] spiclk, bit[11:6] spiq, bit[17:12] spid, + * bit[23:18] spics0, bit[29:24] spihd + * + * uint8_t *drvs: drvs[0]-bit[3:0] for cpiclk, bit[7:4] for spiq, + * drvs[1]-bit[3:0] for spid, drvs[1]-bit[7:4] for spid + * drvs[2]-bit[3:0] for spihd, drvs[2]-bit[7:4] for spiwp. + * Values usually read from flash by rom code, function + * usually callde by rom code. + * if value with bit(3) set, the value is valid, bit[2:0] + * is the real value. + * + * Returned Value: + * None + * + *****************************************************************************/ + +void esp_rom_spiflash_set_drvs(uint8_t wp_gpio_num, + uint32_t ishspi, + uint8_t *drvs); + +/***************************************************************************** + * Name: esp_rom_spiflash_select_padsfunc + * + * Description: + * Select SPI Flash function for pads. + * + * Please do not call this function in SDK. + * + * Input Parameters: + * uint32_t ishspi: 0 for spi, 1 for hspi, flash pad decided by strapping + * else, bit[5:0] spiclk, bit[11:6] spiq, bit[17:12] spid, + * bit[23:18] spics0, bit[29:24] spihd + * + * Returned Value: + * None + * + *****************************************************************************/ + +void esp_rom_spiflash_select_padsfunc(uint32_t ishspi); + +/***************************************************************************** + * Name: esp_rom_spiflash_attach + * + * Description: + * SPI Flash init, clock divisor is 4, use 1 line Slow read mode. + * + * Please do not call this function in SDK. + * + * Input Parameters: + * uint32_t ishspi: 0 for spi, 1 for hspi, flash pad decided by strapping + * else, bit[5:0] spiclk, bit[11:6] spiq, bit[17:12] spid, + * bit[23:18] spics0, bit[29:24] spihd + * + * uint8_t legacy: In legacy mode, more SPI command is used in line. + * + * Returned Value: + * None + * + *****************************************************************************/ + +void esp_rom_spiflash_attach(uint32_t ishspi, bool legacy); + +/***************************************************************************** + * Name: esp_rom_spiflash_read_status + * + * Description: + * SPI Read Flash status register. We use CMD 0x05 (RDSR). + * + * Please do not call this function in SDK. + * + * Input Parameters: + * esp32_spiflash_chip_t *spi : The information for Flash, which is exported + * from ld file. + * + * uint32_t *status : The pointer to which to return the Flash status value. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : read OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : read error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : read timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t +esp_rom_spiflash_read_status(esp32_spiflash_chip_t *spi, + uint32_t *status); + +/***************************************************************************** + * Name: esp32_spiflash_read_statushigh + * + * Description: + * SPI Read Flash status register bits 8-15. We use CMD 0x35 (RDSR2). + * + * Please do not call this function in SDK. + * + * Input Parameters: + * esp32_spiflash_chip_t *spi : The information for Flash, which is exported + * from ld file. + * + * uint32_t *status : The pointer to which to return the Flash status value. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : read OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : read error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : read timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t +esp32_spiflash_read_statushigh(esp32_spiflash_chip_t *spi, + uint32_t *status); + +/***************************************************************************** + * Name: esp32_spiflash_write_status + * + * Description: + * Write status to Falsh status register. + * + * Please do not call this function in SDK. + * + * Input Parameters: + * esp32_spiflash_chip_t *spi : The information for Flash, which is exported + * from ld file. + * + * uint32_t status_value : Value to . + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : write OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : write error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : write timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t +esp32_spiflash_write_status(esp32_spiflash_chip_t *spi, + uint32_t status_value); + +/***************************************************************************** + * Name: esp_rom_spiflash_read_user_cmd + * + * Description: + * Use a command to Read Flash status register. + * + * Please do not call this function in SDK. + * + * Input Parameters: + * esp32_spiflash_chip_t *spi : The information for Flash, which is exported + * from ld file. + * + * uint32_t*status : The pointer to which to return the Flash status value. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : read OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : read error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : read timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t +esp_rom_spiflash_read_user_cmd(uint32_t *status, + uint8_t cmd); + +/***************************************************************************** + * Name: esp_rom_spiflash_config_readmode + * + * Description: + * Config SPI Flash read mode when init. + * + * Please do not call this function in SDK. + * + * Input Parameter: + * esp_rom_spiflash_read_mode_t mode : QIO/QOUT/DIO/DOUT/FastRD/SlowRD. + * + * This function does not try to set the QIO Enable bit in the status + * register, caller is responsible for this. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : config OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : config error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : config timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t +esp_rom_spiflash_config_readmode(esp_rom_spiflash_read_mode_t mode); + +/***************************************************************************** + * Name: esp_rom_spiflash_config_clk + * + * Description: + * Config SPI Flash clock divisor. + * + * Please do not call this function in SDK. + * + * Input Parameters: + * uint8_t freqdiv: clock divisor. + * + * uint8_t spi: 0 for SPI0, 1 for SPI1. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : config OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : config error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : config timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t +esp_rom_spiflash_config_clk(uint8_t freqdiv, + uint8_t spi); + +/***************************************************************************** + * Name: esp_rom_spiflash_common_cmd + * + * Description: + * Send CommonCmd to Flash so that is can go into QIO mode, some Flash use + * different CMD. + * + * Please do not call this function in SDK. + * + * Input Paramater: + * esp_rom_spiflash_common_cmd_t *cmd : A struct to show the action of a + * command. + * + * Returned Value: + * uint16_t 0 : do not send command any more. + * 1 : go to the next command. + * n > 1 : skip (n - 1) commands. + * + *****************************************************************************/ + +uint16_t esp_rom_spiflash_common_cmd(esp_rom_spiflash_common_cmd_t *cmd); + +/***************************************************************************** + * Name: esp_rom_spiflash_unlock + * + * Description: + * Unlock SPI write protect. + * + * Please do not call this function in SDK. + * + * Input Value: + * None. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : Unlock OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Unlock error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Unlock timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t esp_rom_spiflash_unlock(void); + +/***************************************************************************** + * Name: esp_rom_spiflash_lock + * + * Description: + * SPI write protect. + * + * Please do not call this function in SDK. + * + * Input Parameter: + * None. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : Lock OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Lock error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Lock timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t esp_rom_spiflash_lock(void); + +/***************************************************************************** + * Name: esp_rom_spiflash_config_param + * + * Description: + * Update SPI Flash parameter. + * + * Please do not call this function in SDK. + * + * Input Parameters: + * uint32_t deviceId : Device ID read from SPI, the low 32 bit. + * + * uint32_t chip_size : The Flash size. + * + * uint32_t block_size : The Flash block size. + * + * uint32_t sector_size : The Flash sector size. + * + * uint32_t page_size : The Flash page size. + * + * uint32_t status_mask : The Mask used when read status from Flash + * (use single CMD). + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : Update OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Update error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Update timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t +esp_rom_spiflash_config_param(uint32_t deviceid, + uint32_t chip_size, + uint32_t block_size, + uint32_t sector_size, + uint32_t page_size, + uint32_t status_mask); + +/***************************************************************************** + * Name: esp_rom_spiflash_erase_chip + * + * Description: + * Erase whole flash chip. + * + * Please do not call this function in SDK. + * + * Input Parameter: + * None + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : Erase OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Erase error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Erase timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t esp_rom_spiflash_erase_chip(void); + +/***************************************************************************** + * Name: esp_rom_spiflash_erase_block + * + * Description: + * Erase a 64KB block of flash + * Uses SPI flash command D8H. + * + * Please do not call this function in SDK. + * + * Input Parameter: + * uint32_t block_num : Which block to erase. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : Erase OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Erase error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Erase timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t esp_rom_spiflash_erase_block(uint32_t block_num); + +/***************************************************************************** + * Name: esp_rom_spiflash_erase_sector + * + * Description: + * Erase a sector of flash. + * Uses SPI flash command 20H. + * + * Please do not call this function in SDK. + * + * Input Parameters: + * uint32_t sector_num : Which sector to erase. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : Erase OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Erase error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Erase timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t esp_rom_spiflash_erase_sector(uint32_t sector_num); + +/***************************************************************************** + * Name: esp_rom_spiflash_erase_area + * + * Description: + * Erase some sectors. + * + * Please do not call this function in SDK. + * + * Input Parameters: + * uint32_t start_addr : Start addr to erase, should be sector aligned. + * + * uint32_t area_len : Length to erase, should be sector aligned. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : Erase OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Erase error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Erase timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t +esp_rom_spiflash_erase_area(uint32_t start_addr, + uint32_t area_len); + +/***************************************************************************** + * Name: esp_rom_spiflash_write + * + * Description: + * Write Data to Flash, you should Erase it yourself if need. + * + * Please do not call this function in SDK. + * + * Input Parameters: + * uint32_t dest_addr : Address to write, should be 4 bytes aligned. + * + * const uint32_t *src : The pointer to data which is to write. + * + * uint32_t len : Length to write, should be 4 bytes aligned. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : Write OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Write error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Write timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t +esp_rom_spiflash_write(uint32_t dest_addr, + const uint32_t *src, + int32_t len); + +/***************************************************************************** + * Name: esp_rom_spiflash_read + * + * Description: + * Read Data from Flash, you should Erase it yourself if need. + * + * Please do not call this function in SDK. + * + * Input Values: + * uint32_t src_addr : Address to read, should be 4 bytes aligned. + * + * uint32_t *dest : The buf to read the data. + * + * uint32_t len : Length to read, should be 4 bytes aligned. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : Read OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Read error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Read timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t +esp_rom_spiflash_read(uint32_t src_addr, + uint32_t *dest, + int32_t len); + +/***************************************************************************** + * Name: esp_rom_spiflash_write_encrypted_enable + * + * Description: + * SPI1 go into encrypto mode. + * + * Please do not call this function in SDK. + * + *****************************************************************************/ + +void esp_rom_spiflash_write_encrypted_enable(void); + +/***************************************************************************** + * Name: esp_rom_spiflash_prepare_encrypted_data + * + * Description: + * Prepare 32 Bytes data to encrpto writing, you should Erase it yourself + * if need. + * + * Please do not call this function in SDK. + * + * Input Parameters: + * uint32_t flash_addr : Address to write, should be 32 bytes aligned. + * + * uint32_t *data : The pointer to data which is to write. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : Prepare OK. + * ESP_ROM_SPIFLASH_RESULT_ERR : Prepare error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Prepare timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t +esp_rom_spiflash_prepare_encrypted_data(uint32_t flash_addr, + uint32_t *data); + +/***************************************************************************** + * Name: esp_rom_spiflash_write_encrypted_disable + * + * Description: + * SPI1 go out of encrypto mode. + * + * Please do not call this function in SDK. + * + *****************************************************************************/ + +void esp_rom_spiflash_write_encrypted_disable(void); + +/***************************************************************************** + * Name: esp_rom_spiflash_write_encrypted + * + * Description: + * Write data to flash with transparent encryption. + * Sectors to be written should already be erased. + * Please do not call this function in SDK. + * + * Input Parameters: + * uint32_t flash_addr : Address to write, should be 32 byte aligned. + * + * uint32_t *data : The pointer to data to write. Note, this pointer must + * be 32 bit aligned and the content of the data will be + * modified by the encryption function. + * + * uint32_t len : Length to write, should be 32 bytes aligned. + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : Data written successfully. + * ESP_ROM_SPIFLASH_RESULT_ERR : Encryption write error. + * ESP_ROM_SPIFLASH_RESULT_TIMEOUT : Encrypto write timeout. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t +esp_rom_spiflash_write_encrypted(uint32_t flash_addr, + uint32_t *data, + uint32_t len); + +/***************************************************************************** + * Name: esp_rom_spiflash_wait_idle + * + * Description: + * Wait until SPI flash write operation is complete + * + * Please do not call this function in SDK. + * + * Reads the Write In Progress bit of the SPI flash status register, + * repeats until this bit is zero (indicating write complete). + * + * Returned Value: + * ESP_ROM_SPIFLASH_RESULT_OK : Write is complete + * ESP_ROM_SPIFLASH_RESULT_ERR : Error while reading status. + * + *****************************************************************************/ + +esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp32_spiflash_chip_t + *spi); + +/***************************************************************************** + * Name: esp_rom_spiflash_select_qio_pins + * + * Description: + * Enable Quad I/O pin functions + * + * Please do not call this function in SDK. + * + * Sets the HD & WP pin functions for Quad I/O modes, based on the + * efuse SPI pin configuration. + * + * Input Parameters: + * wp_gpio_num - Number of the WP pin to reconfigure for quad I/O. + * spiconfig - Pin configuration, as returned from + * ets_efuse_get_spiconfig(). + * - If this parameter is 0, default SPI pins are used and + * wp_gpio_num parameter is ignored. + * - If this parameter is 1, default HSPI pins are used and + * wp_gpio_num parameter is ignored. + * - For other values, this parameter encodes the HD pin number + * and also the CLK pin number. CLK pin selection is used to + * determine if HSPI or SPI peripheral will be used (use HSPI + * if CLK pin is the HSPI clock pin, otherwise use SPI). + * Both HD & WP pins are configured via GPIO matrix to map to the selected + * peripheral. + * + *****************************************************************************/ + +void esp_rom_spiflash_select_qio_pins(uint8_t wp_gpio_num, + uint32_t spiconfig); + +/* Global esp32_spiflash_chip_t structure used by ROM functions */ + +extern esp32_spiflash_chip_t g_rom_flashchip; + +extern uint8_t g_rom_spiflash_dummy_len_plus[]; + +#ifdef __cplusplus +} +#endif + +#endif /* _ROM_SPI_FLASH_H_ */ diff --git a/boards/xtensa/esp32/esp32-core/scripts/esp32_flash.ld b/boards/xtensa/esp32/esp32-core/scripts/esp32_flash.ld index bccf2aa..1634509 100644 --- a/boards/xtensa/esp32/esp32-core/scripts/esp32_flash.ld +++ b/boards/xtensa/esp32/esp32-core/scripts/esp32_flash.ld @@ -58,6 +58,7 @@ SECTIONS *librtc.a:(.literal .text .literal.* .text.*) *libpp.a:(.literal .text .literal.* .text.*) *libhal.a:(.literal .text .literal.* .text.*) + *libarch.a:esp32_spiflash.*(.literal .text .literal.* .text.*) _iram_text_end = ABSOLUTE(.); /* Module text area starts at the end of iram0_0_seg */ @@ -87,6 +88,7 @@ SECTIONS *(.share.mem) *(.gnu.linkonce.b.*) *(COMMON) + *libarch.a:esp32_spiflash.*(.bss .bss.* COMMON) . = ALIGN(8); _ebss = ABSOLUTE(.); @@ -112,6 +114,7 @@ SECTIONS KEEP (*(.gnu.linkonce.s2.*)) KEEP (*(.jcr)) *(.dram1 .dram1.*) + *libarch.a:esp32_spiflash.*(.rodata .rodata.*) . = ALIGN(4); _edata = ABSOLUTE(.); diff --git a/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld b/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld index 60af005..6541caa 100644 --- a/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld +++ b/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld @@ -1844,3 +1844,8 @@ PROVIDE ( _xtos_syscall_handler = 0x40000790 ); PROVIDE ( _xtos_unhandled_exception = 0x4000c024 ); PROVIDE ( _xtos_unhandled_interrupt = 0x4000c01c ); PROVIDE ( _xtos_vpri_enabled = 0x3ffe0654 ); +PROVIDE ( g_rom_flashchip = 0x3ffae270 ); +PROVIDE ( g_rom_spiflash_dummy_len_plus = 0x3ffae290 ); +PROVIDE ( esp_rom_spiflash_read_user_cmd = 0x400621b0 ); +PROVIDE ( esp_rom_spiflash_write_encrypted_enable = 0x40062df4 ); +PROVIDE ( esp_rom_spiflash_prepare_encrypted_data = 0x40062e1c );