xtensa/esp32s3: Add SPI RAM/PSRAM Support

This commit is contained in:
Alan C. Assis 2022-03-03 16:29:10 -03:00 committed by Petro Karashchenko
parent 700e09103a
commit dc1b6776b9
10 changed files with 5379 additions and 2 deletions

View File

@ -298,6 +298,11 @@ config ESP32S3_RUN_IRAM
menu "ESP32-S3 Peripheral Selection" menu "ESP32-S3 Peripheral Selection"
config ESP32S3_SPIRAM
bool "SPI RAM Support"
default n
select ARCH_HAVE_HEAP2
config ESP32S3_UART config ESP32S3_UART
bool bool
default n default n
@ -331,6 +336,119 @@ config ESP32S3_UART2
select UART2_SERIALDRIVER select UART2_SERIALDRIVER
select ARCH_HAVE_SERIAL_TERMIOS select ARCH_HAVE_SERIAL_TERMIOS
menu "SPI RAM Config"
depends on ESP32S3_SPIRAM
choice ESP32S3_SPIRAM_MODE
prompt "Mode (QUAD/OCT) of SPI RAM chip"
default ESP32S3_SPIRAM_MODE_QUAD
config ESP32S3_SPIRAM_MODE_QUAD
bool "Quad Mode PSRAM"
config ESP32S3_SPIRAM_MODE_OCT
bool "Octal Mode PSRAM"
endchoice # ESP32S3_SPIRAM_MODE
config ESP32S3_DEFAULT_PSRAM_CLK_IO
int "PSRAM CLK pin"
default 30
config ESP32S3_DEFAULT_PSRAM_CS_IO
int "PSRAM CS pin"
default 26
choice ESP32S3_SPIRAM_TYPE
prompt "Type of SPI RAM chip in use"
default ESP32S3_SPIRAM_TYPE_AUTO
config ESP32S3_SPIRAM_TYPE_AUTO
bool "Auto-detect"
config ESP32S3_SPIRAM_TYPE_ESPPSRAM16
bool "ESP-PSRAM16 or APS1604"
config ESP32S3_SPIRAM_TYPE_ESPPSRAM32
bool "ESP-PSRAM32 or IS25WP032"
config ESP32S3_SPIRAM_TYPE_ESPPSRAM64
bool "ESP-PSRAM64, LY68L6400 or APS6408"
endchoice # ESP32S3_SPIRAM_TYPE
config ESP32S3_SPIRAM_SIZE
int
default -1 if ESP32S3_SPIRAM_TYPE_AUTO
default 2097152 if ESP32S3_SPIRAM_TYPE_ESPPSRAM16
default 4194304 if ESP32S3_SPIRAM_TYPE_ESPPSRAM32
default 8388608 if ESP32S3_SPIRAM_TYPE_ESPPSRAM64
default 16777216 if ESP32S3_SPIRAM_TYPE_ESPPSRAM128
default 33554432 if ESP32S3_SPIRAM_TYPE_ESPPSRAM256
default 0
config ESP32S3_SPIRAM_FETCH_INSTRUCTIONS
bool "Cache fetch instructions from SPI RAM"
default n
---help---
If enabled, instruction in flash will be copied into SPIRAM.
If ESP32S3_SPIRAM_RODATA is also enabled, you can run the instruction
when erasing or programming the flash.
config ESP32S3_SPIRAM_RODATA
bool "Cache load read only data from SPI RAM"
default n
---help---
If enabled, rodata in flash will be copied into SPIRAM.
If ESP32S3_ESP32S2_SPIRAM_FETCH_INSTRUCTIONS is also enabled,
you can run the instruction when erasing or programming the
flash.
choice ESP32S3_SPIRAM_SPEED
prompt "Set RAM clock speed"
default ESP32S3_SPIRAM_SPEED_40M
---help---
Select the speed for the SPI RAM chip.
config ESP32S3_SPIRAM_SPEED_40M
bool "40MHz clock speed"
config ESP32S3_SPIRAM_SPEED_80M
bool "80MHz clock speed"
config ESP32S3_SPIRAM_SPEED_120M
bool "120MHz clock speed"
endchoice # ESP32S3_SPIRAM_SPEED
config ESP32S3_SPIRAM_SPEED
int
default 120 if ESP32S3_SPIRAM_SPEED_120M
default 80 if ESP32S3_SPIRAM_SPEED_80M
default 40 if ESP32S3_SPIRAM_SPEED_40M
config ESP32S3_SPIRAM_BOOT_INIT
bool "Initialize SPI RAM during startup"
depends on ESP32S3_SPIRAM
default y
---help---
If this is enabled, the SPI RAM will be enabled during initial
boot. Unless you have specific requirements, you'll want to leave
this enabled so memory allocated during boot-up can also be
placed in SPI RAM.
config ESP32S3_SPIRAM_IGNORE_NOTFOUND
bool "Ignore PSRAM when not found"
default n
depends on ESP32S3_SPIRAM_BOOT_INIT && !BOOT_SDRAM_DATA
---help---
Normally, if psram initialization is enabled during compile time
but not found at runtime, it is seen as an error making the CPU
panic. If this is enabled, booting will complete but no PSRAM
will be available.
endmenu #SPI RAM Config
config ESP32S3_TIMER0 config ESP32S3_TIMER0
bool "54-bit Timer 0 (Group 0 Timer 0)" bool "54-bit Timer 0 (Group 0 Timer 0)"
default n default n

View File

@ -117,3 +117,7 @@ CHIP_CSRCS += esp32s3_spiflash_mtd.c
endif endif
endif endif
ifeq ($(CONFIG_ESP32S3_SPIRAM),y)
CHIP_CSRCS += esp32s3_spiram.c
CHIP_CSRCS += esp32s3_psram.c
endif

View File

@ -0,0 +1,557 @@
/****************************************************************************
* arch/xtensa/src/esp32s3/esp32s3_psram.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 <stdint.h>
#include <stddef.h>
#include <errno.h>
#include <debug.h>
#include "esp32s3_gpio.h"
#include "esp32s3_psram.h"
#include "rom/esp32s3_spiflash.h"
#include "rom/esp32s3_opi_flash.h"
#include "hardware/esp32s3_spi_mem_reg.h"
#include "hardware/esp32s3_iomux.h"
#include "hardware/esp32s3_gpio_sigmap.h"
/* EFUSE */
#define ESP_ROM_EFUSE_FLASH_DEFAULT_SPI (0)
extern uint32_t esp_rom_efuse_get_flash_gpio_info(void);
extern uint32_t esp_rom_efuse_get_flash_wp_gpio(void);
/* Commands for PSRAM chip */
#define PSRAM_READ 0x03
#define PSRAM_FAST_READ 0x0B
#define PSRAM_FAST_READ_QUAD 0xEB
#define PSRAM_WRITE 0x02
#define PSRAM_QUAD_WRITE 0x38
#define PSRAM_ENTER_QMODE 0x35
#define PSRAM_EXIT_QMODE 0xF5
#define PSRAM_RESET_EN 0x66
#define PSRAM_RESET 0x99
#define PSRAM_SET_BURST_LEN 0xC0
#define PSRAM_DEVICE_ID 0x9F
#define PSRAM_FAST_READ_DUMMY 4
#define PSRAM_FAST_READ_QUAD_DUMMY 6
/* ID */
#define PSRAM_ID_KGD_M 0xff
#define PSRAM_ID_KGD_S 8
#define PSRAM_ID_KGD 0x5d
#define PSRAM_ID_EID_M 0xff
#define PSRAM_ID_EID_S 16
/* Use the [7:5](bit7~bit5) of EID to distinguish the psram size:
*
* BIT7 | BIT6 | BIT5 | SIZE(MBIT)
* -------------------------------------
* 0 | 0 | 0 | 16
* 0 | 0 | 1 | 32
* 0 | 1 | 0 | 64
*/
#define PSRAM_EID_SIZE_M 0x07
#define PSRAM_EID_SIZE_S 5
#define PSRAM_KGD(id) (((id) >> PSRAM_ID_KGD_S) & PSRAM_ID_KGD_M)
#define PSRAM_EID(id) (((id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M)
#define PSRAM_SIZE_ID(id) ((PSRAM_EID(id) >> PSRAM_EID_SIZE_S) & PSRAM_EID_SIZE_M)
#define PSRAM_IS_VALID(id) (PSRAM_KGD(id) == PSRAM_ID_KGD)
#define PSRAM_IS_64MBIT_TRIAL(id) (PSRAM_EID(id) == 0x26)
/* IO-pins for PSRAM.
* WARNING: PSRAM shares all but the CS and CLK pins with the flash, so
* these defines hardcode the flash pins as well, making this code
* incompatible with either a setup that has the flash on non-standard
* pins or ESP32s with built-in flash.
*/
#define FLASH_CLK_IO SPI_CLK_GPIO_NUM
#define FLASH_CS_IO SPI_CS0_GPIO_NUM
/* PSRAM clock and cs IO should be configured based on hardware design. */
#define PSRAM_CLK_IO CONFIG_ESP32S3_DEFAULT_PSRAM_CLK_IO /* Default value is 30 */
#define PSRAM_CS_IO CONFIG_ESP32S3_DEFAULT_PSRAM_CS_IO /* Default value is 26 */
#define PSRAM_SPIQ_SD0_IO SPI_Q_GPIO_NUM
#define PSRAM_SPID_SD1_IO SPI_D_GPIO_NUM
#define PSRAM_SPIWP_SD3_IO SPI_WP_GPIO_NUM
#define PSRAM_SPIHD_SD2_IO SPI_HD_GPIO_NUM
#define CS_PSRAM_SEL SPI_MEM_CS1_DIS_M
#define CS_FLASH_SEL SPI_MEM_CS0_DIS_M
#define SPI1_NUM 1
#define SPI0_NUM 0
typedef enum
{
PSRAM_CMD_QPI,
PSRAM_CMD_SPI,
} psram_cmd_mode_e;
uint32_t g_psram_id;
uint32_t g_psram_size; /* physical psram size in bytes */
static void config_psram_spi_phases(void);
static uint8_t g_psram_cs_io = UINT8_MAX;
/****************************************************************************
* Private Functions
****************************************************************************/
uint8_t psram_get_cs_io(void)
{
return g_psram_cs_io;
}
static void psram_set_op_mode(int spi_num, int mode)
{
if (mode == PSRAM_CMD_QPI)
{
esp_rom_spi_set_op_mode(spi_num, ESP_ROM_SPIFLASH_QIO_MODE);
SET_PERI_REG_MASK(SPI_MEM_CTRL_REG(spi_num), SPI_MEM_FCMD_QUAD_M);
}
else if (mode == PSRAM_CMD_SPI)
{
esp_rom_spi_set_op_mode(spi_num, ESP_ROM_SPIFLASH_SLOWRD_MODE);
}
}
static void _psram_exec_cmd(int spi_num,
uint32_t cmd, int cmd_bit_len,
uint32_t addr, int addr_bit_len,
int dummy_bits, uint8_t *mosi_data,
int mosi_bit_len, uint8_t *miso_data,
int miso_bit_len)
{
esp_rom_spi_cmd_t conf;
uint32_t _addr = addr;
conf.addr = &_addr;
conf.addr_bit_len = addr_bit_len;
conf.cmd = cmd;
conf.cmd_bit_len = cmd_bit_len;
conf.dummy_bit_len = dummy_bits; /* There is a hw approach on chip723 */
conf.tx_data = (uint32_t *) mosi_data;
conf.tx_data_bit_len = mosi_bit_len;
conf.rx_data = (uint32_t *) miso_data;
conf.rx_data_bit_len = miso_bit_len;
esp_rom_spi_cmd_config(spi_num, &conf);
}
void psram_exec_cmd(int spi_num, int mode,
uint32_t cmd, int cmd_bit_len,
uint32_t addr, int addr_bit_len,
int dummy_bits, uint8_t *mosi_data,
int mosi_bit_len, uint8_t *miso_data,
int miso_bit_len, uint32_t cs_mask,
bool is_write_erase_operation)
{
uint32_t backup_usr = READ_PERI_REG(SPI_MEM_USER_REG(spi_num));
uint32_t backup_usr1 = READ_PERI_REG(SPI_MEM_USER1_REG(spi_num));
uint32_t backup_usr2 = READ_PERI_REG(SPI_MEM_USER2_REG(spi_num));
uint32_t backup_ctrl = READ_PERI_REG(SPI_MEM_CTRL_REG(spi_num));
psram_set_op_mode(spi_num, mode);
_psram_exec_cmd(spi_num, cmd, cmd_bit_len, addr,
addr_bit_len, dummy_bits, mosi_data,
mosi_bit_len, miso_data, miso_bit_len);
esp_rom_spi_cmd_start(spi_num, miso_data, miso_bit_len / 8,
cs_mask, is_write_erase_operation);
WRITE_PERI_REG(SPI_MEM_USER_REG(spi_num), backup_usr);
WRITE_PERI_REG(SPI_MEM_USER1_REG(spi_num), backup_usr1);
WRITE_PERI_REG(SPI_MEM_USER2_REG(spi_num), backup_usr2);
WRITE_PERI_REG(SPI_MEM_CTRL_REG(spi_num), backup_ctrl);
}
/* exit QPI mode(set back to SPI mode) */
static void psram_disable_qio_mode(int spi_num)
{
psram_exec_cmd(spi_num, PSRAM_CMD_QPI,
PSRAM_EXIT_QMODE, 8, /* command and command bit len */
0, 0, /* address and address bit len */
0, /* dummy bit len */
NULL, 0, /* tx data and tx bit len */
NULL, 0, /* rx data and rx bit len */
CS_PSRAM_SEL, /* cs bit mask */
false); /* whether is program/erase operation */
}
/* switch psram burst length(32 bytes or 1024 bytes)
* datasheet says it should be 1024 bytes by default
*/
static void psram_set_wrap_burst_length(int spi_num, psram_cmd_mode_e mode)
{
psram_exec_cmd(spi_num, mode,
PSRAM_SET_BURST_LEN, 8, /* command and command bit len */
0, 0, /* address and address bit len */
0, /* dummy bit len */
NULL, 0, /* tx data and tx bit len */
NULL, 0, /* rx data and rx bit len */
CS_PSRAM_SEL, /* cs bit mask */
false); /* whether is program/erase operation */
}
/* send reset command to psram, in spi mode */
static void psram_reset_mode(int spi_num)
{
psram_exec_cmd(spi_num, PSRAM_CMD_SPI,
PSRAM_RESET_EN, 8, /* command and command bit len */
0, 0, /* address and address bit len */
0, /* dummy bit len */
NULL, 0, /* tx data and tx bit len */
NULL, 0, /* rx data and rx bit len */
CS_PSRAM_SEL, /* cs bit mask */
false); /* whether is program/erase operation */
psram_exec_cmd(spi_num, PSRAM_CMD_SPI,
PSRAM_RESET, 8, /* command and command bit len */
0, 0, /* address and address bit len */
0, /* dummy bit len */
NULL, 0, /* tx data and tx bit len */
NULL, 0, /* rx data and rx bit len */
CS_PSRAM_SEL, /* cs bit mask */
false); /* whether is program/erase operation */
}
/****************************************************************************
* Public Functions
****************************************************************************/
int psram_enable_wrap(uint32_t wrap_size)
{
static uint32_t current_wrap_size;
if (current_wrap_size == wrap_size)
{
return OK;
}
switch (wrap_size)
{
case 32:
case 0:
psram_set_wrap_burst_length(1, PSRAM_CMD_QPI);
current_wrap_size = wrap_size;
return OK;
case 16:
case 64:
default:
return -EFAULT;
}
}
bool psram_support_wrap_size(uint32_t wrap_size)
{
switch (wrap_size)
{
case 0:
case 32:
return true;
case 16:
case 64:
default:
return false;
}
}
/* Read ID operation only supports SPI CMD and mode, should issue
* `psram_disable_qio_mode` before calling this
*/
static void psram_read_id(int spi_num, uint32_t *dev_id)
{
psram_exec_cmd(spi_num, PSRAM_CMD_SPI,
PSRAM_DEVICE_ID, 8, /* command and command bit len */
0, 24, /* address and address bit len */
0, /* dummy bit len */
NULL, 0, /* tx data and tx bit len */
(uint8_t *) dev_id, 24, /* rx data and rx bit len */
CS_PSRAM_SEL, /* cs bit mask */
false); /* whether is program/erase operation */
}
/* enter QPI mode */
static void psram_enable_qio_mode(int spi_num)
{
psram_exec_cmd(spi_num, PSRAM_CMD_SPI,
PSRAM_ENTER_QMODE, 8, /* command and command bit len */
0, 0, /* address and address bit len */
0, /* dummy bit len */
NULL, 0, /* tx data and tx bit len */
NULL, 0, /* rx data and rx bit len */
CS_PSRAM_SEL, /* cs bit mask */
false); /* whether is program/erase operation */
}
static void psram_set_cs_timing(void)
{
/* SPI0/1 share the cs_hold / cs_setup, cd_hold_time / cd_setup_time
* registers for PSRAM, so we only need to set SPI0 related registers here
*/
SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0),
SPI_MEM_SPI_SMEM_CS_HOLD_TIME_V, 0,
SPI_MEM_SPI_SMEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0),
SPI_MEM_SPI_SMEM_CS_SETUP_TIME_V, 0,
SPI_MEM_SPI_SMEM_CS_SETUP_TIME_S);
SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_AC_REG(0),
SPI_MEM_SPI_SMEM_CS_HOLD_M |
SPI_MEM_SPI_SMEM_CS_SETUP_M);
}
static void psram_gpio_config(void)
{
/* WP HD */
uint8_t wp_io = PSRAM_SPIWP_SD3_IO;
/* CS1 */
uint8_t cs1_io = PSRAM_CS_IO;
if (cs1_io == SPI_CS1_GPIO_NUM)
{
esp32s3_gpio_matrix_out(cs1_io, SPICS1_OUT_IDX, 0, 0);
}
else
{
esp32s3_configgpio(cs1_io, OUTPUT);
esp32s3_gpio_matrix_out(cs1_io, SIG_GPIO_OUT_IDX, 0, 0);
}
g_psram_cs_io = cs1_io;
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
if (spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI)
{
/* MSPI pins (except wp / hd) are all configured via IO_MUX in 1st
* bootloader.
*/
}
else
{
/* MSPI pins (except wp / hd) are all configured via GPIO matrix in
* 1st bootloader.
*/
wp_io = esp_rom_efuse_get_flash_wp_gpio();
}
/* This ROM function will init both WP and HD pins. */
esp_rom_spiflash_select_qio_pins(wp_io, spiconfig);
}
/* Psram mode init will overwrite original flash speed mode, so that it is
* possible to change psram and flash speed after OTA.
* Flash read mode(QIO/QOUT/DIO/DOUT) will not be changed in app bin.
* It is decided by bootloader, OTA can not change this mode.
*/
int psram_enable(int mode, int vaddrmode)
{
assert(mode < PSRAM_CACHE_MAX && \
"we don't support any other mode for now.");
psram_gpio_config();
psram_set_cs_timing();
/* enter MSPI slow mode to init PSRAM device registers */
/* FIXME: spi_timing_enter_mspi_low_speed_mode(true); */
/* We use SPI1 to init PSRAM */
psram_disable_qio_mode(SPI1_NUM);
psram_read_id(SPI1_NUM, &g_psram_id);
if (!PSRAM_IS_VALID(g_psram_id))
{
/* 16Mbit psram ID read error workaround:
* treat the first read id as a dummy one as the pre-condition,
* Send Read ID command again
*/
psram_read_id(SPI1_NUM, &g_psram_id);
if (!PSRAM_IS_VALID(g_psram_id))
{
merr("PSRAM ID read error: 0x%08x", g_psram_id);
return -EFAULT;
}
}
if (PSRAM_IS_64MBIT_TRIAL(g_psram_id))
{
g_psram_size = PSRAM_SIZE_8MB;
}
else
{
uint8_t density = PSRAM_SIZE_ID(g_psram_id);
switch (density)
{
case 0x0:
g_psram_size = PSRAM_SIZE_2MB;
break;
case 0x1:
g_psram_size = PSRAM_SIZE_4MB;
break;
case 0x2:
g_psram_size = PSRAM_SIZE_8MB;
break;
default:
g_psram_size = 0;
}
}
/* SPI1: send psram reset command */
psram_reset_mode(SPI1_NUM);
/* SPI1: send QPI enable command */
psram_enable_qio_mode(SPI1_NUM);
/* Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the SPI0
* PSRAM timing related registers accordingly
*/
/* FIXME: spi_timing_psram_tuning(); */
/* Configure SPI0 PSRAM related SPI Phases */
config_psram_spi_phases();
/* Back to the high speed mode. Flash/PSRAM clocks are set to the clock
* that user selected. SPI0/1 registers are all set correctly
*/
/* FIXME: spi_timing_enter_mspi_high_speed_mode(true); */
return OK;
}
/* Configure PSRAM SPI0 phase related registers here according
* to the PSRAM chip requirement
*/
static void config_psram_spi_phases(void)
{
/* Config CMD phase */
/* Disable dio mode for cache command */
CLEAR_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_USR_SRAM_DIO_M);
/* Enable qio mode for cache command */
SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_USR_SRAM_QIO_M);
/* Enable cache read command */
SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0),
SPI_MEM_CACHE_SRAM_USR_RCMD_M);
/* Enable cache write command */
SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0),
SPI_MEM_CACHE_SRAM_USR_WCMD_M);
SET_PERI_REG_BITS(SPI_MEM_SRAM_DWR_CMD_REG(0),
SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN, 7,
SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN_S);
SET_PERI_REG_BITS(SPI_MEM_SRAM_DWR_CMD_REG(0),
SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE,
PSRAM_QUAD_WRITE,
SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE_S); /* 0x38 */
SET_PERI_REG_BITS(SPI_MEM_SRAM_DRD_CMD_REG(0),
SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 7,
SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_S);
SET_PERI_REG_BITS(SPI_MEM_SRAM_DRD_CMD_REG(0),
SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_V,
PSRAM_FAST_READ_QUAD,
SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_S); /* 0xEB */
/* Config ADDR phase */
SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0),
SPI_MEM_SRAM_ADDR_BITLEN_V, 23,
SPI_MEM_SRAM_ADDR_BITLEN_S);
/* We set the PSRAM chip required dummy here. If timing tuning is needed,
* the dummy length will be updated in spi_timing_enter_mspi_hs_mode()
*/
/* Enable cache read dummy */
SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0),
SPI_MEM_USR_RD_SRAM_DUMMY_M);
SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0),
SPI_MEM_SRAM_RDUMMY_CYCLELEN_V,
(PSRAM_FAST_READ_QUAD_DUMMY - 1),
SPI_MEM_SRAM_RDUMMY_CYCLELEN_S);
/* ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM */
CLEAR_PERI_REG_MASK(SPI_MEM_MISC_REG(0), SPI_MEM_CS1_DIS_M);
}
int psram_get_physical_size(uint32_t *out_size_bytes)
{
*out_size_bytes = g_psram_size;
return g_psram_size > 0 ? OK : -EINVAL;
}
/* This function is to get the available physical psram size in bytes.
*
* When ECC is enabled, the available size will be reduced.
* On S3 Quad PSRAM, ECC is not enabled for now.
*/
int psram_get_available_size(uint32_t *out_size_bytes)
{
*out_size_bytes = g_psram_size;
return (g_psram_size ? OK : -EINVAL);
}

View File

@ -0,0 +1,130 @@
/****************************************************************************
* arch/xtensa/src/esp32s3/esp32s3_psram.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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#ifndef __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_PSRAM_H
#define __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_PSRAM_H
#define PSRAM_SIZE_2MB (2 * 1024 * 1024)
#define PSRAM_SIZE_4MB (4 * 1024 * 1024)
#define PSRAM_SIZE_8MB (8 * 1024 * 1024)
#define PSRAM_SIZE_16MB (16 * 1024 * 1024)
#define PSRAM_SIZE_32MB (32 * 1024 * 1024)
#define PSRAM_CACHE_S80M 1
#define PSRAM_CACHE_S40M 2
#define PSRAM_CACHE_MAX 3
#define SPIRAM_WRAP_MODE_16B 0
#define SPIRAM_WRAP_MODE_32B 1
#define SPIRAM_WRAP_MODE_64B 2
#define SPIRAM_WRAP_MODE_DISABLE 3
/* See the TRM, chapter PID/MPU/MMU, header 'External RAM' for the
* definitions of these modes. Important is that NORMAL works with the app
* CPU cache disabled, but gives huge cache coherency issues when both app
* and pro CPU are enabled. LOWHIGH and EVENODD do not have these coherency
* issues but cannot be used when the app CPU cache is disabled.
*/
#define PSRAM_VADDR_MODE_NORMAL 0 /* App and Pro CPU use their own flash
* cache for external RAM access
*/
#define PSRAM_VADDR_MODE_LOWHIGH 1 /* App and Pro CPU share external RAM caches:
* pro CPU has low 2M, app CPU has high 2M
*/
#define PSRAM_VADDR_MODE_EVENODD 2 /* App and Pro CPU share external RAM caches:
* pro CPU does even 32yte ranges, app does
* odd ones.
*/
/****************************************************************************
* Public Functions Prototypes
****************************************************************************/
/****************************************************************************
* Name: psram_get_physical_size
*
* Description:
* Get the physical psram size in bytes.
*
****************************************************************************/
int psram_get_physical_size(uint32_t *out_size_bytes);
/****************************************************************************
* Name: psram_get_available_size
*
* Description:
* Get the available physical psram size in bytes.
*
* If ECC is enabled, available PSRAM size will be 15/16 times its
* physical size. If not, it equals to the physical psram size.
* Note: For now ECC is only enabled on ESP32S3 Octal PSRAM
*
* Input Parameters:
* out_size_bytes - availabe physical psram size in bytes.
*
* Returned Value:
* 0 if success or a negative value if fail.
*
****************************************************************************/
int psram_get_available_size(uint32_t *out_size_bytes);
/****************************************************************************
* Name: psram_get_available_size
*
* Description:
* Enable psram cache
*
* Esp-idf uses this to initialize cache for psram, mapping it into the
* main memory address space.
*
* Input Parameters:
* mode - SPI mode to access psram in.
* vaddrmode - Mode the psram cache works in.
*
* Returned Value:
* 0 if success or a negative value if fail.
*
****************************************************************************/
int psram_enable(int mode, int vaddrmode);
/****************************************************************************
* Name: psram_get_cs_io
*
* Description:
* Get the psram CS IO
*
* Returned Value:
* The psram CS IO pin.
*
****************************************************************************/
uint8_t psram_get_cs_io(void);
#endif /* __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_PSRAM_H */

View File

@ -0,0 +1,383 @@
/****************************************************************************
* arch/xtensa/src/esp32s3/esp32s3_spiram.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 <stdlib.h>
#include <stdbool.h>
#include <errno.h>
#include <debug.h>
#include <string.h>
#include <sys/param.h>
#include <nuttx/config.h>
#include <nuttx/spinlock.h>
#include "xtensa.h"
#include "xtensa_attr.h"
#include "esp32s3_psram.h"
#include "esp32s3_spiram.h"
#include "hardware/esp32s3_soc.h"
#include "hardware/esp32s3_cache_memory.h"
#include "hardware/esp32s3_extmem.h"
#include "hardware/esp32s3_iomux.h"
#define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL
#if defined(CONFIG_ESP32S3_SPIRAM)
#if defined(CONFIG_ESP32S3_SPIRAM_SPEED_40M)
# define PSRAM_SPEED PSRAM_CACHE_S40M
#else /* #if CONFIG_ESP32S3_SPIRAM_SPEED_80M */
# define PSRAM_SPEED PSRAM_CACHE_S80M
#endif
static bool g_spiram_inited;
/* These variables are in bytes */
static uint32_t g_allocable_vaddr_start;
static uint32_t g_allocable_vaddr_end;
static DRAM_ATTR uint32_t g_mapped_vaddr_start;
/* Let's export g_mapped_size to export heap */
DRAM_ATTR uint32_t g_mapped_size;
static uint32_t g_instruction_in_spiram;
static uint32_t g_rodata_in_spiram;
#if defined(CONFIG_ESP32S3_SPIRAM_FETCH_INSTRUCTIONS)
static int g_instr_flash2spiram_offs;
static uint32_t g_instr_start_page;
static uint32_t g_instr_end_page;
#endif
#if defined(CONFIG_ESP32S3_SPIRAM_RODATA)
static int g_rodata_flash2spiram_offs;
static uint32_t g_rodata_start_page;
static uint32_t g_rodata_end_page;
#endif
#if defined(CONFIG_ESP32S3_SPIRAM_FETCH_INSTRUCTIONS) || \
defined(CONFIG_ES32S3_SPIRAM_RODATA)
static uint32_t page0_mapped;
static uint32_t page0_page = INVALID_PHY_PAGE;
#endif
/****************************************************************************
* ROM Function Prototypes
****************************************************************************/
extern void cache_writeback_all(void);
extern uint32_t cache_suspend_dcache(void);
extern void cache_resume_dcache(uint32_t val);
extern int cache_dbus_mmu_set(uint32_t ext_ram, uint32_t vaddr,
uint32_t paddr, uint32_t psize,
uint32_t num, uint32_t fixed);
/****************************************************************************
* Public Functions
****************************************************************************/
/* Initially map all psram physical address to virtual address.
* If psram physical size is larger than virtual address range, then only
* map the virtual address range.
*/
void IRAM_ATTR esp_spiram_init_cache(void)
{
uint32_t regval;
int ret = psram_get_available_size(&g_mapped_size);
if (ret != OK)
{
abort();
}
merr("Mapped size = %d\n", g_mapped_size);
if ((SOC_EXTRAM_DATA_HIGH - SOC_EXTRAM_DATA_LOW) < g_mapped_size)
{
/* Decide these logics when there's a real PSRAM with larger size */
merr("Virtual address not enough for PSRAM!");
abort();
}
g_mapped_vaddr_start = SOC_EXTRAM_DATA_HIGH - g_mapped_size;
/* Suspend DRAM Case during configuration */
cache_suspend_dcache();
cache_dbus_mmu_set(MMU_ACCESS_SPIRAM, g_mapped_vaddr_start,
0, 64, g_mapped_size >> 16, 0);
regval = getreg32(EXTMEM_DCACHE_CTRL1_REG);
regval &= ~EXTMEM_DCACHE_SHUT_CORE0_BUS;
putreg32(regval, EXTMEM_DCACHE_CTRL1_REG);
#if defined(CONFIG_SMP)
regval = getreg32(EXTMEM_DCACHE_CTRL1_REG);
regval &= ~EXTMEM_DCACHE_SHUT_CORE1_BUS;
putreg32(regval, EXTMEM_DCACHE_CTRL1_REG);
#endif
cache_resume_dcache(0);
/* Currently no non-heap stuff on ESP32S3 */
g_allocable_vaddr_start = g_mapped_vaddr_start;
g_allocable_vaddr_end = SOC_EXTRAM_DATA_HIGH;
}
/* Simple RAM test. Writes a word every 32 bytes. Takes about a second
* to complete for 4MiB. Returns true when RAM seems OK, false when test
* fails. WARNING: Do not run this before the 2nd cpu has been initialized
* (in a two-core system) or after the heap allocator has taken ownership
* of the memory.
*/
bool esp_spiram_test(void)
{
volatile int *spiram = (volatile int *)g_mapped_vaddr_start;
size_t s = g_mapped_size;
size_t p;
int errct = 0;
int initial_err = -1;
for (p = 0; p < (s / sizeof(int)); p += 8)
{
spiram[p] = p ^ 0xaaaaaaaa;
}
for (p = 0; p < (s / sizeof(int)); p += 8)
{
if (spiram[p] != (p ^ 0xaaaaaaaa))
{
errct++;
if (errct == 1)
{
initial_err = p * sizeof(int);
}
if (errct < 4)
{
merr("SPI SRAM error@%08x:%08x/%08x \n", &spiram[p], spiram[p],
p ^ 0xaaaaaaaa);
}
}
}
if (errct != 0)
{
merr("SPI SRAM memory test fail. %d/%d writes failed, first @ %X\n",
errct, s / 32, initial_err + SOC_EXTRAM_DATA_LOW);
return false;
}
else
{
minfo("SPI SRAM memory test OK!");
return true;
}
}
uint32_t esp_spiram_instruction_access_enabled(void)
{
return g_instruction_in_spiram;
}
uint32_t esp_spiram_rodata_access_enabled(void)
{
return g_rodata_in_spiram;
}
#if defined(CONFIG_ESP32S3_SPIRAM_FETCH_INSTRUCTIONS)
int esp_spiram_enable_instruction_access(void)
{
/* `pages_for_flash` will be overwritten, however it influences the psram
* size to be added to the heap allocator.
*/
abort();
}
#endif
#if defined(CONFIG_ESP32S3_SPIRAM_RODATA)
int esp_spiram_enable_rodata_access(void)
{
/* `pages_for_flash` will be overwritten, however it influences the psram
* size to be added to the heap allocator.
*/
abort();
}
#endif
#if defined(CONFIG_ESP32S3_SPIRAM_FETCH_INSTRUCTIONS)
void instruction_flash_page_info_init(void)
{
uint32_t instr_page_cnt = ((uint32_t)&_instruction_reserved_end -
SOC_IROM_LOW + MMU_PAGE_SIZE - 1) /
MMU_PAGE_SIZE;
g_instr_start_page = *(volatile uint32_t *)(DR_REG_MMU_TABLE +
CACHE_IROM_MMU_START);
g_instr_start_page &= MMU_ADDRESS_MASK;
g_instr_end_page = g_instr_start_page + instr_page_cnt - 1;
}
uint32_t IRAM_ATTR instruction_flash_start_page_get(void)
{
return g_instr_start_page;
}
uint32_t IRAM_ATTR instruction_flash_end_page_get(void)
{
return g_instr_end_page;
}
int IRAM_ATTR instruction_flash2spiram_offset(void)
{
return g_instr_flash2spiram_offs;
}
#endif
#if defined(CONFIG_ESP32_SPIRAM_RODATA)
void rodata_flash_page_info_init(void)
{
uint32_t rodata_page_cnt = ((uint32_t)&_rodata_reserved_end -
((uint32_t)&_rodata_reserved_start &
~ (MMU_PAGE_SIZE - 1)) + MMU_PAGE_SIZE - 1) /
MMU_PAGE_SIZE;
g_rodata_start_page = *(volatile uint32_t *)(DR_REG_MMU_TABLE +
CACHE_DROM_MMU_START);
g_rodata_start_page &= MMU_ADDRESS_MASK;
g_rodata_end_page = g_rodata_start_page + rodata_page_cnt - 1;
}
uint32_t IRAM_ATTR rodata_flash_start_page_get(void)
{
return g_rodata_start_page;
}
uint32_t IRAM_ATTR rodata_flash_end_page_get(void)
{
return g_rodata_end_page;
}
int IRAM_ATTR g_rodata_flash2spiram_offset(void)
{
return g_rodata_flash2spiram_offs;
}
#endif
int esp_spiram_init(void)
{
int r;
uint32_t psram_physical_size = 0;
r = psram_enable(PSRAM_SPEED, PSRAM_MODE);
if (r != OK)
{
merr("SPI RAM enabled but initialization failed. Bailing out.\n");
return r;
}
g_spiram_inited = true;
r = psram_get_physical_size(&psram_physical_size);
if (r != OK)
{
abort();
}
#if defined(CONFIG_ESP32S3_SPIRAM_SIZE) && (CONFIG_ESP32S3_SPIRAM_SIZE != -1)
if (psram_physical_size != CONFIG_ESP32S3_SPIRAM_SIZE)
{
merr("Expected %dMB chip but found %dMB chip. Bailing out..",
(CONFIG_ESP32S3_SPIRAM_SIZE / 1024 / 1024),
(psram_physical_size / 1024 / 1024));
return ;
}
#endif
minfo("Found %dMB SPI RAM device\n", psram_physical_size / (1024 * 1024));
minfo("Speed: %dMHz\n", CONFIG_ESP32S3_SPIRAM_SPEED);
minfo("Initialized, cache is in %s mode.\n",
(PSRAM_MODE == PSRAM_VADDR_MODE_EVENODD) ?
"even/odd (2-core)" :
(PSRAM_MODE == PSRAM_VADDR_MODE_LOWHIGH) ?
"low/high (2-core)" :
(PSRAM_MODE == PSRAM_VADDR_MODE_NORMAL) ?
"normal (1-core)" : "ERROR");
return OK;
}
size_t esp_spiram_get_size(void)
{
if (!g_spiram_inited)
{
merr("SPI RAM not initialized");
abort();
}
uint32_t size = 0; /* in bytes */
int ret = psram_get_available_size(&size);
return ret == OK ? size : 0;
}
/* Before flushing the cache, if psram is enabled as a memory-mapped thing,
* we need to write back the data in the cache to the psram first, otherwise
* it will get lost. For now, we just read 64/128K of random PSRAM memory to
* do this.
*/
void IRAM_ATTR esp_spiram_writeback_cache(void)
{
cache_writeback_all();
}
/**
* @brief If SPI RAM(PSRAM) has been initialized
*
* @return true SPI RAM has been initialized successfully
* @return false SPI RAM hasn't been initialized or initialized failed
*/
bool esp_spiram_is_initialized(void)
{
return g_spiram_inited;
}
uint8_t esp_spiram_get_cs_io(void)
{
return psram_get_cs_io();
}
#endif

View File

@ -0,0 +1,206 @@
/****************************************************************************
* arch/xtensa/src/esp32s3/esp32s3_spiram.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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#ifndef __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_SPIRAM_H
#define __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_SPIRAM_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C"
{
#endif
/* @brief Initialize spiram interface/hardware. Normally called from
* cpu_start.c.
*
* @return ESP_OK on success
*/
int esp_spiram_init(void);
/**
* @brief Configure Cache/MMU for access to external SPI RAM.
*
* Normally this function is called from cpu_start, if
* CONFIG_SPIRAM_BOOT_INIT option is enabled. Applications which need to
* enable SPI RAM at run time can disable CONFIG_SPIRAM_BOOT_INIT, and
* call this function later.
*
* @attention this function must be called with flash cache disabled.
*/
void esp_spiram_init_cache(void);
/**
* @brief Memory test for SPI RAM. Should be called after SPI RAM is
* initialized and (in case of a dual-core system) the app CPU is online.
* This test overwrites the memory with crap, so do not call after e.g. the
* heap allocator has stored important stuff in SPI RAM.
*
* @return true on success, false on failed memory test
*/
bool esp_spiram_test(void);
/**
* @brief Add the initialized SPI RAM to the heap allocator.
*/
int esp_spiram_add_to_heapalloc(void);
/**
* @brief Get the available physical size of the attached SPI RAM chip
*
* @note If ECC is enabled, the available physical size would be smaller
* than the physical size. See `CONFIG_SPIRAM_ECC_ENABLE`
*
* @return Size in bytes, or 0 if no external RAM chip support compiled in.
*/
size_t esp_spiram_get_size(void);
/**
* @brief Force a writeback of the data in the SPI RAM cache. This is to be
* called whenever cache is disabled, because disabling cache on the ESP32
* discards the data in the SPI RAM cache.
*
* This is meant for use from within the SPI flash code.
*/
void esp_spiram_writeback_cache(void);
/**
* @brief If SPI RAM(PSRAM) has been initialized
*
* @return
* - true SPI RAM has been initialized successfully
* - false SPI RAM hasn't been initialized or initialized failed
*/
bool esp_spiram_is_initialized(void);
/**
* @brief get psram CS IO
*
* This interface should be called after PSRAM is enabled, otherwise it will
* return an invalid value -1/0xff.
*
* @return psram CS IO or -1/0xff if psram not enabled
*/
uint8_t esp_spiram_get_cs_io(void);
/**
* @brief Reserve a pool of internal memory for specific DMA/internal
* allocations
*
* @param size Size of reserved pool in bytes
*
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM when no memory available for pool
*/
int esp_spiram_reserve_dma_pool(size_t size);
/**
* @brief If SPI RAM(PSRAM) has been initialized
*
* @return
* - true SPI RAM has been initialized successfully
* - false SPI RAM hasn't been initialized or initialized failed
*/
bool esp_spiram_is_initialized(void);
#if defined(CONFIG_ESP32S3_SPIRAM_FETCH_INSTRUCTIONS)
extern int _instruction_reserved_start;
extern int _instruction_reserved_end;
/**
* @brief Get the start page number of the instruction in SPI flash
*
* @return start page number
*/
uint32_t instruction_flash_start_page_get(void);
/**
* @brief Get the end page number of the instruction in SPI flash
*
* @return end page number
*/
uint32_t instruction_flash_end_page_get(void);
/**
* @brief Get the offset of instruction from SPI flash to SPI RAM
*
* @return instruction offset
*/
int instruction_flash2spiram_offset(void);
#endif
#if defined(CONFIG_SPIRAM_RODATA)
extern int _rodata_reserved_start;
extern int _rodata_reserved_end;
/**
* @brief Get the start page number of the rodata in SPI flash
*
* @return start page number
*/
uint32_t rodata_flash_start_page_get(void);
/**
* @brief Get the end page number of the rodata in SPI flash
*
* @return end page number
*/
uint32_t rodata_flash_end_page_get(void);
/**
* @brief Get the offset number of rodata from SPI flash to SPI RAM
*
* @return rodata offset
*/
int rodata_flash2spiram_offset(void);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -37,6 +37,7 @@
#include "esp32s3_lowputc.h" #include "esp32s3_lowputc.h"
#include "esp32s3_clockconfig.h" #include "esp32s3_clockconfig.h"
#include "esp32s3_region.h" #include "esp32s3_region.h"
#include "esp32s3_spiram.h"
#include "esp32s3_wdt.h" #include "esp32s3_wdt.h"
#include "hardware/esp32s3_cache_memory.h" #include "hardware/esp32s3_cache_memory.h"
#include "hardware/esp32s3_system.h" #include "hardware/esp32s3_system.h"
@ -285,6 +286,22 @@ void noreturn_function IRAM_ATTR __esp32s3_start(void)
showprogress('A'); showprogress('A');
#if defined(CONFIG_ESP32S3_SPIRAM_BOOT_INIT)
if (esp_spiram_init() != OK)
{
# if defined(ESP32S3_SPIRAM_IGNORE_NOTFOUND)
mwarn("SPIRAM Initialization failed!\n");
# else
PANIC();
# endif
}
else
{
esp_spiram_init_cache();
esp_spiram_test();
}
#endif
/* Initialize onboard resources */ /* Initialize onboard resources */
esp32s3_board_initialize(); esp32s3_board_initialize();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,378 @@
/*****************************************************************************
* arch/xtensa/src/esp32s3/rom/esp32s3_opi_flash.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_ESP32S3_ROM_ESP32S3_OPI_FLASH_H
#define __ARCH_XTENSA_SRC_ESP32S3_ROM_ESP32S3_OPI_FLASH_H
/*****************************************************************************
* Included Files
*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct
{
uint8_t mode;
uint8_t cmd_bit_len;
uint16_t cmd;
uint32_t addr;
uint8_t addr_bit_len;
uint8_t dummy_bit_len;
uint8_t data_bit_len;
uint8_t cs_sel: 4;
uint8_t is_pe: 4;
} esp_rom_opiflash_cmd_t;
typedef struct
{
uint8_t addr_bit_len;
uint8_t dummy_bit_len;
uint16_t cmd;
uint8_t cmd_bit_len;
uint8_t var_dummy_en;
} esp_rom_opiflash_spi0rd_t;
typedef struct
{
esp_rom_opiflash_cmd_t rdid;
esp_rom_opiflash_cmd_t rdsr;
esp_rom_opiflash_cmd_t wren;
esp_rom_opiflash_cmd_t se;
esp_rom_opiflash_cmd_t be64k;
esp_rom_opiflash_cmd_t read;
esp_rom_opiflash_cmd_t pp;
esp_rom_opiflash_spi0rd_t cache_rd_cmd;
} esp_rom_opiflash_def_t;
typedef struct
{
uint16_t cmd; /* !< Command value */
uint16_t cmd_bit_len; /* !< Command byte length */
uint32_t *addr; /* !< Point to address value */
uint32_t addr_bit_len; /* !< Address byte length */
uint32_t *tx_data; /* !< Point to send data buffer */
uint32_t tx_data_bit_len; /* !< Send data byte length. */
uint32_t *rx_data; /* !< Point to recevie data buffer */
uint32_t rx_data_bit_len; /* !< Recevie Data byte length. */
uint32_t dummy_bit_len;
} esp_rom_spi_cmd_t;
#define ESP_ROM_OPIFLASH_MUX_TAKE()
#define ESP_ROM_OPIFLASH_MUX_GIVE()
#define ESP_ROM_OPIFLASH_SEL_CS0 (BIT(0))
#define ESP_ROM_OPIFLASH_SEL_CS1 (BIT(1))
/* Definition of MX25UM25645G Octa Flash
* 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
#define FLASH_OP_MODE_RDCMD_DOUT 0x3B
#define ESP_ROM_FLASH_SECTOR_SIZE 0x1000
#define ESP_ROM_FLASH_BLOCK_SIZE_64K 0x10000
#define ESP_ROM_FLASH_PAGE_SIZE 256
/* FLASH commands */
#define ROM_FLASH_CMD_RDID 0x9F
#define ROM_FLASH_CMD_WRSR 0x01
#define ROM_FLASH_CMD_WRSR2 0x31 /* Not all SPI flash uses this command */
#define ROM_FLASH_CMD_WREN 0x06
#define ROM_FLASH_CMD_WRDI 0x04
#define ROM_FLASH_CMD_RDSR 0x05
#define ROM_FLASH_CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
#define ROM_FLASH_CMD_ERASE_SEC 0x20
#define ROM_FLASH_CMD_ERASE_BLK_32K 0x52
#define ROM_FLASH_CMD_ERASE_BLK_64K 0xD8
#define ROM_FLASH_CMD_OTPEN 0x3A /* Enable OTP mode, not all SPI flash uses this command */
#define ROM_FLASH_CMD_RSTEN 0x66
#define ROM_FLASH_CMD_RST 0x99
#define ROM_FLASH_CMD_SE4B 0x21
#define ROM_FLASH_CMD_SE4B_OCT 0xDE21
#define ROM_FLASH_CMD_BE4B 0xDC
#define ROM_FLASH_CMD_BE4B_OCT 0x23DC
#define ROM_FLASH_CMD_RSTEN_OCT 0x9966
#define ROM_FLASH_CMD_RST_OCT 0x6699
#define ROM_FLASH_CMD_FSTRD4B_STR 0x13EC
#define ROM_FLASH_CMD_FSTRD4B_DTR 0x11EE
#define ROM_FLASH_CMD_FSTRD4B 0x0C
#define ROM_FLASH_CMD_PP4B 0x12
#define ROM_FLASH_CMD_PP4B_OCT 0xED12
#define ROM_FLASH_CMD_RDID_OCT 0x609F
#define ROM_FLASH_CMD_WREN_OCT 0xF906
#define ROM_FLASH_CMD_RDSR_OCT 0xFA05
#define ROM_FLASH_CMD_RDCR2 0x71
#define ROM_FLASH_CMD_RDCR2_OCT 0x8E71
#define ROM_FLASH_CMD_WRCR2 0x72
#define ROM_FLASH_CMD_WRCR2_OCT 0x8D72
/* Definitions for GigaDevice GD25LX256E Flash */
#define ROM_FLASH_CMD_RDFSR_GD 0x70
#define ROM_FLASH_CMD_RD_GD 0x03
#define ROM_FLASH_CMD_RD4B_GD 0x13
#define ROM_FLASH_CMD_FSTRD_GD 0x0B
#define ROM_FLASH_CMD_FSTRD4B_GD 0x0C
#define ROM_FLASH_CMD_FSTRD_OOUT_GD 0x8B
#define ROM_FLASH_CMD_FSTRD4B_OOUT_GD 0x7C
#define ROM_FLASH_CMD_FSTRD_OIOSTR_GD 0xCB
#define ROM_FLASH_CMD_FSTRD4B_OIOSTR_GD 0xCC
#define ROM_FLASH_CMD_FSTRD4B_OIODTR_GD 0xFD
#define ROM_FLASH_CMD_PP_GD 0x02
#define ROM_FLASH_CMD_PP4B_GD 0x12
#define ROM_FLASH_CMD_PP_OOUT_GD 0x82
#define ROM_FLASH_CMD_PP4B_OOUT_GD 0x84
#define ROM_FLASH_CMD_PP_OIO_GD 0xC2
#define ROM_FLASH_CMD_PP4B_OIOSTR_GD 0x8E
#define ROM_FLASH_CMD_SE_GD 0x20
#define ROM_FLASH_CMD_SE4B_GD 0x21
#define ROM_FLASH_CMD_BE32K_GD 0x52
#define ROM_FLASH_CMD_BE32K4B_GD 0x5C
#define ROM_FLASH_CMD_BE64K_GD 0xD8
#define ROM_FLASH_CMD_BE64K4B_GD 0xDC
#define ROM_FLASH_CMD_EN4B_GD 0xB7
#define ROM_FLASH_CMD_DIS4B_GD 0xE9
extern const esp_rom_opiflash_def_t *rom_opiflash_cmd_def;
/**
* @brief init legacy driver for Octal Flash
*/
void esp_rom_opiflash_legacy_driver_init(const esp_rom_opiflash_def_t
*flash_cmd_def);
/**
* @brief Config the spi user command
* @param spi_num spi port
* @param pcmd pointer to accept the spi command struct
*/
void esp_rom_spi_cmd_config(int spi_num, esp_rom_spi_cmd_t *pcmd);
/**
* @brief Start a spi user command sequence
* @param spi_num spi port
* @param rx_buf buffer pointer to receive data
* @param rx_len receive data length in byte
* @param cs_en_mask decide which cs to use, 0 for cs0, 1 for cs1
* @param is_write_erase to indicate whether this is a write or erase
* operation, since the CPU would check permission
*/
void esp_rom_spi_cmd_start(int spi_num, uint8_t *rx_buf, uint16_t rx_len,
uint8_t cs_en_mask, bool is_write_erase);
/**
* @brief Config opi flash pads according to efuse settings.
*/
void esp_rom_opiflash_pin_config(void);
/**
* @brief Set SPI read/write operation mode
* @param spi_num spi port
* @param mode Flash Read Mode
*/
void esp_rom_spi_set_op_mode(int spi_num, esp_rom_spiflash_read_mode_t mode);
/**
* @brief Set data swap mode in DTR(DDR) mode
* @param spi_num spi port
* @param wr_swap to decide whether to swap fifo data in dtr write operation
* @param rd_swap to decide whether to swap fifo data in dtr read operation
*/
void esp_rom_spi_set_dtr_swap_mode(int spi, bool wr_swap, bool rd_swap);
/**
* @brief to send reset command in spi/opi-str/opi-dtr mode(for MX25UM25645G)
* @param spi_num spi port
*/
void esp_rom_opiflash_mode_reset(int spi_num);
/**
* @brief To execute a flash operation command
* @param spi_num spi port
* @param mode Flash Read Mode
* @param cmd data to send in command field
* @param cmd_bit_len bit length of command field
* @param addr data to send in address field
* @param addr_bit_len bit length of address field
* @param dummy_bits bit length of dummy field
* @param mosi_data data buffer to be sent in mosi field
* @param mosi_bit_len bit length of data buffer to be sent in mosi field
* @param miso_data data buffer to accept data in miso field
* @param miso_bit_len bit length of data buffer to accept data in miso field
* @param cs_mark decide which cs pin to use. 0: cs0, 1: cs1
* @param is_write_erase_operation to indicate whether this a write or erase
* flash operation
*/
void esp_rom_opiflash_exec_cmd(int spi_num, esp_rom_spiflash_read_mode_t mode,
uint32_t cmd, int cmd_bit_len,
uint32_t addr, int addr_bit_len,
int dummy_bits,
uint8_t *mosi_data, int mosi_bit_len,
uint8_t *miso_data, int miso_bit_len,
uint32_t cs_mask,
bool is_write_erase_operation);
/**
* @brief send reset command to opi flash
* @param spi_num spi port
* @param mode Flash Operation Mode
*/
void esp_rom_opiflash_soft_reset(int spi_num,
esp_rom_spiflash_read_mode_t mode);
/**
* @brief to read opi flash ID
* @note command format would be defined in initialization
* @param[out] out_id buffer to accept id
* @return flash operation result
*/
esp_rom_spiflash_result_t esp_rom_opiflash_read_id(uint8_t *out_id);
/**
* @brief to read opi flash status register
* @note command format would be defined in initialization
* @return opi flash status value
*/
uint8_t esp_rom_opiflash_rdsr(void);
/**
* @brief wait opi flash status register to be idle
* @note command format would be defined in initialization
* @return flash operation result
*/
esp_rom_spiflash_result_t esp_rom_opiflash_wait_idle(void);
/**
* @brief to erase flash sector
* @note command format would be defined in initialization
* @param sector_num the sector to be erased
* @return flash operation result
*/
esp_rom_spiflash_result_t
esp_rom_opiflash_erase_sector(uint32_t sector_num);
/**
* @brief to erase flash block
* @note command format would be defined in initialization
* @param block_num the block to be erased
* @return flash operation result
*/
esp_rom_spiflash_result_t
esp_rom_opiflash_erase_block_64k(uint32_t block_num);
/**
* @brief to erase a flash area define by start address and length
* @note command format would be defined in initialization
* @param start_addr the start address to be erased
* @param area_len the erea length to be erased
* @return flash operation result
*/
esp_rom_spiflash_result_t esp_rom_opiflash_erase_area(uint32_t start_addr,
uint32_t area_len);
/**
* @brief to read data from opi flash
* @note command format would be defined in initialization
* @param flash_addr flash address to read data from
* @param data_addr data buffer to accept the data
* @param len data length to be read
* @return flash operation result
*/
esp_rom_spiflash_result_t esp_rom_opiflash_read(uint32_t flash_addr,
void *data_addr,
int len);
/**
* @brief to write data to opi flash
* @note command format would be defined in initialization
* @param flash_addr flash address to write data to
* @param data_addr data buffer to write to flash
* @param len data length to write
* @return flash operation result
*/
esp_rom_spiflash_result_t esp_rom_opiflash_write(uint32_t flash_addr,
const uint32_t *data_addr,
int len);
/**
* @brief send WREN command
* @note command format would be defined in initialization
* @param arg not used, set to NULL
* @return flash operation result
*/
esp_rom_spiflash_result_t esp_rom_opiflash_wren(void *arg);
/**
* @brief to configure SPI0 read flash command format for cache
* @note command format would be defined in initialization
*
*/
void
esp_rom_opiflash_cache_mode_config(esp_rom_spiflash_read_mode_t mode,
const esp_rom_opiflash_spi0rd_t *cache);
esp_rom_spiflash_result_t esp_rom_opiflash_read_raw(uint32_t flash_addr,
uint8_t *buf, int len);
#ifdef __cplusplus
}
#endif
#endif /* __ARCH_XTENSA_SRC_ESP32S3_ROM_ESP32S3_OPI_FLASH_H */

View File

@ -384,7 +384,7 @@ PROVIDE( Cache_WriteBack_Addr = 0x400016c8 );
PROVIDE( Cache_Invalidate_ICache_All = 0x400016d4 ); PROVIDE( Cache_Invalidate_ICache_All = 0x400016d4 );
PROVIDE( cache_invalidate_dcache_all = 0x400016e0 ); PROVIDE( cache_invalidate_dcache_all = 0x400016e0 );
PROVIDE( Cache_Clean_All = 0x400016ec ); PROVIDE( Cache_Clean_All = 0x400016ec );
PROVIDE( Cache_WriteBack_All = 0x400016f8 ); PROVIDE( cache_writeback_all = 0x400016f8 );
PROVIDE( Cache_Mask_All = 0x40001704 ); PROVIDE( Cache_Mask_All = 0x40001704 );
PROVIDE( Cache_UnMask_Dram0 = 0x40001710 ); PROVIDE( Cache_UnMask_Dram0 = 0x40001710 );
PROVIDE( Cache_Suspend_ICache_Autoload = 0x4000171c ); PROVIDE( Cache_Suspend_ICache_Autoload = 0x4000171c );
@ -442,7 +442,7 @@ PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40001980 );
PROVIDE( Cache_Occupy_DCache_MEMORY = 0x4000198c ); PROVIDE( Cache_Occupy_DCache_MEMORY = 0x4000198c );
PROVIDE( Cache_MMU_Init = 0x40001998 ); PROVIDE( Cache_MMU_Init = 0x40001998 );
PROVIDE( Cache_Ibus_MMU_Set = 0x400019a4 ); PROVIDE( Cache_Ibus_MMU_Set = 0x400019a4 );
PROVIDE( Cache_Dbus_MMU_Set = 0x400019b0 ); PROVIDE( cache_dbus_mmu_set = 0x400019b0 );
PROVIDE( Cache_Count_Flash_Pages = 0x400019bc ); PROVIDE( Cache_Count_Flash_Pages = 0x400019bc );
PROVIDE( Cache_Flash_To_SPIRAM_Copy = 0x400019c8 ); PROVIDE( Cache_Flash_To_SPIRAM_Copy = 0x400019c8 );
PROVIDE( Cache_Travel_Tag_Memory = 0x400019d4 ); PROVIDE( Cache_Travel_Tag_Memory = 0x400019d4 );