Merge branch 'feature/add_opi_flash_psram_support' into 'master'

spi flash: opi flash psram support and spi timing tuning  support on 727

Closes IDF-3097

See merge request espressif/esp-idf!12946
pull/7307/head
Michael (XIAO Xufeng) 2021-06-28 01:59:19 +00:00
commit afc2bc94b3
26 zmienionych plików z 1752 dodań i 145 usunięć

Wyświetl plik

@ -21,6 +21,9 @@
#define FLASH_IO_MATRIX_DUMMY_40M 0 #define FLASH_IO_MATRIX_DUMMY_40M 0
#define FLASH_IO_MATRIX_DUMMY_80M 0 #define FLASH_IO_MATRIX_DUMMY_80M 0
#define FLASH_IO_DRIVE_GD_WITH_1V8PSRAM 3 #define FLASH_IO_DRIVE_GD_WITH_1V8PSRAM 3
#define FLASH_CS_SETUP_TIME 3
#define FLASH_CS_HOLD_TIME 3
#define FLASH_CS_HOLD_DELAY 2
void bootloader_flash_update_id() void bootloader_flash_update_id()
{ {
@ -30,12 +33,18 @@ void bootloader_flash_update_id()
void IRAM_ATTR bootloader_flash_cs_timing_config() void IRAM_ATTR bootloader_flash_cs_timing_config()
{ {
// SPI0/1 share the cs_hold / cs_setup, cd_hold_time / cd_setup_time, cs_hold_delay registers for FLASH/PSRAM, so we only need to set SPI0 related registers here
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M); SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S); SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, FLASH_CS_HOLD_TIME, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S); SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, FLASH_CS_SETUP_TIME, SPI_MEM_CS_SETUP_TIME_S);
SET_PERI_REG_MASK(SPI_MEM_USER_REG(1), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_HOLD_TIME_V, 1, SPI_MEM_CS_HOLD_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);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S); SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_TIME_V, FLASH_CS_HOLD_TIME, 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, FLASH_CS_SETUP_TIME, SPI_MEM_SPI_SMEM_CS_SETUP_TIME_S);
// cs high time
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_DELAY_V, FLASH_CS_HOLD_DELAY, SPI_MEM_CS_HOLD_DELAY_S);
SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_V, FLASH_CS_HOLD_DELAY, SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_S);
} }
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr) void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)

Wyświetl plik

@ -16,7 +16,7 @@ else()
"esp_crypto_lock.c" "esp_crypto_lock.c"
"memprot.c" "memprot.c"
"spiram.c" "spiram.c"
"spiram_psram.c") "spi_timing_config.c")
set(include_dirs "include") set(include_dirs "include")
set(requires driver efuse soc xtensa) #unfortunately rom/uart uses SOC registers directly set(requires driver efuse soc xtensa) #unfortunately rom/uart uses SOC registers directly
@ -27,6 +27,12 @@ else()
set(priv_requires app_trace app_update bootloader_support log mbedtls nvs_flash pthread set(priv_requires app_trace app_update bootloader_support log mbedtls nvs_flash pthread
spi_flash vfs espcoredump esp_common perfmon esp_timer esp_ipc) spi_flash vfs espcoredump esp_common perfmon esp_timer esp_ipc)
if(CONFIG_SPIRAM_MODE_QUAD)
list(APPEND srcs "spiram_psram.c")
elseif(CONFIG_SPIRAM_MODE_OCT)
list(APPEND srcs "opiram_psram.c")
endif()
idf_component_register(SRCS "${srcs}" idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${include_dirs}" INCLUDE_DIRS "${include_dirs}"
REQUIRES "${requires}" REQUIRES "${requires}"

Wyświetl plik

@ -169,8 +169,19 @@ menu "ESP32S3-Specific"
menu "SPI RAM config" menu "SPI RAM config"
depends on ESP32S3_SPIRAM_SUPPORT depends on ESP32S3_SPIRAM_SUPPORT
choice SPIRAM_MODE
prompt "Mode (QUAD/OCT) of SPI RAM chip in use"
default SPIRAM_MODE_QUAD
config SPIRAM_MODE_QUAD
bool "Quad Mode PSRAM"
config SPIRAM_MODE_OCT
bool "Octal Mode PSRAM"
endchoice
choice SPIRAM_TYPE choice SPIRAM_TYPE
prompt "Type of SPI RAM chip in use" prompt "Type of SPIRAM chip in use"
default SPIRAM_TYPE_AUTO default SPIRAM_TYPE_AUTO
config SPIRAM_TYPE_AUTO config SPIRAM_TYPE_AUTO
@ -178,12 +189,14 @@ menu "ESP32S3-Specific"
config SPIRAM_TYPE_ESPPSRAM16 config SPIRAM_TYPE_ESPPSRAM16
bool "ESP-PSRAM16 or APS1604" bool "ESP-PSRAM16 or APS1604"
depends on SPIRAM_MODE_QUAD
config SPIRAM_TYPE_ESPPSRAM32 config SPIRAM_TYPE_ESPPSRAM32
bool "ESP-PSRAM32 or IS25WP032" bool "ESP-PSRAM32 or IS25WP032"
depends on SPIRAM_MODE_QUAD
config SPIRAM_TYPE_ESPPSRAM64 config SPIRAM_TYPE_ESPPSRAM64
bool "ESP-PSRAM64 or LY68L6400" bool "ESP-PSRAM64 , LY68L6400 or APS6408"
endchoice endchoice
config SPIRAM_SIZE config SPIRAM_SIZE
@ -192,6 +205,8 @@ menu "ESP32S3-Specific"
default 2097152 if SPIRAM_TYPE_ESPPSRAM16 default 2097152 if SPIRAM_TYPE_ESPPSRAM16
default 4194304 if SPIRAM_TYPE_ESPPSRAM32 default 4194304 if SPIRAM_TYPE_ESPPSRAM32
default 8388608 if SPIRAM_TYPE_ESPPSRAM64 default 8388608 if SPIRAM_TYPE_ESPPSRAM64
default 16777216 if SPIRAM_TYPE_ESPPSRAM128
default 33554432 if SPIRAM_TYPE_ESPPSRAM256
default 0 default 0
menu "PSRAM Clock and CS IO for ESP32S3" menu "PSRAM Clock and CS IO for ESP32S3"
@ -235,10 +250,6 @@ menu "ESP32S3-Specific"
bool "80MHz clock speed" bool "80MHz clock speed"
config SPIRAM_SPEED_40M config SPIRAM_SPEED_40M
bool "40Mhz clock speed" bool "40Mhz clock speed"
config SPIRAM_SPEED_26M
bool "26Mhz clock speed"
config SPIRAM_SPEED_20M
bool "20Mhz clock speed"
endchoice endchoice
# insert non-chip-specific items here # insert non-chip-specific items here

Wyświetl plik

@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
//Octal FLASH: core clock 160M, module clock 40M, DTR mode
#define MSPI_TIMING_FLASH_CONFIG_TABLE_CORE_CLK_160M_MODULE_CLK_40M_DTR_MODE {{1, 0, 0}, {0, 0, 0}, {2, 1, 1}, {2, 0, 1}, {2, 2, 2}, {2, 1, 2}, {1, 0, 1}, {0, 0, 1}}
#define MSPI_TIMING_FLASH_CONFIG_NUM_CORE_CLK_160M_MODULE_CLK_40M_DTR_MODE 8
#define MSPI_TIMING_FLASH_DEFAULT_CONFIG_ID_CORE_CLK_160M_MODULE_CLK_40M_DTR_MODE 2
//Octal FLASH: core clock 160M, module clock 80M, DTR mode
#define MSPI_TIMING_FLASH_CONFIG_TABLE_CORE_CLK_160M_MODULE_CLK_80M_DTR_MODE {{0, 0, 0}, {4, 2, 2}, {2, 1, 2}, {4, 1, 2}, {1, 0, 1}, {4, 0, 2}, {0, 0, 1}, {4, 2, 3}, {2, 1, 3}, {4, 1, 3}, {1, 0, 2}, {4, 0, 3}, {0, 0, 2}, {4, 2, 4}}
#define MSPI_TIMING_FLASH_CONFIG_NUM_CORE_CLK_160M_MODULE_CLK_80M_DTR_MODE 14
#define MSPI_TIMING_FLASH_DEFAULT_CONFIG_ID_CORE_CLK_160M_MODULE_CLK_80M_DTR_MODE 1
//Octal FLASH: core clock 240M, module clock 120M, DTR mode
#define MSPI_TIMING_FLASH_CONFIG_TABLE_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE {{0, 0, 0}, {4, 1, 2}, {1, 0, 1}, {4, 0, 2}, {0, 0, 1}, {4, 1, 3}, {1, 0, 2}, {4, 0, 3}, {0, 0, 2}, {4, 1, 4}, {1, 0, 3}, {4, 0, 4}, {0, 0, 3}, {4, 1, 5}}
#define MSPI_TIMING_FLASH_CONFIG_NUM_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE 14
#define MSPI_TIMING_FLASH_DEFAULT_CONFIG_ID_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE 1
//Octal FLASH: core clock 160M, module clock 80M, STR mode
#define MSPI_TIMING_FLASH_CONFIG_TABLE_CORE_CLK_160M_MODULE_CLK_80M_STR_MODE {{1, 0, 0}, {0, 0, 0}, {2, 1, 1}, {2, 0, 1}, {2, 2, 2}, {2, 1, 2}, {1, 0, 1}, {0, 0, 1}}
#define MSPI_TIMING_FLASH_CONFIG_NUM_CORE_CLK_160M_MODULE_CLK_80M_STR_MODE 8
#define MSPI_TIMING_FLASH_DEFAULT_CONFIG_ID_CORE_CLK_160M_MODULE_CLK_80M_STR_MODE 2
//Octal FLASH: core clock 120M, module clock 120M, STR mode
#define MSPI_TIMING_FLASH_CONFIG_TABLE_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE {{2, 0, 1}, {0, 0, 0}, {2, 2, 2}, {1, 0, 1}, {2, 0, 2}, {0, 0, 1}, {2, 2, 3}, {1, 0, 2}, {2, 0, 3}, {0, 0, 2}, {2, 2, 4}, {1, 0, 3}}
#define MSPI_TIMING_FLASH_CONFIG_NUM_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 12
#define MSPI_TIMING_FLASH_DEFAULT_CONFIG_ID_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 2
//Octal PSRAM: core clock 80M, module clock 40M, DTR mode
#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_80M_MODULE_CLK_40M_DTR_MODE {{1, 0, 0}, {2, 1, 1}, {2, 0, 1}, {0, 0, 0}, {3, 1, 1}, {3, 0, 1}, {1, 0, 1}, {2, 1, 2}, {2, 0, 2}, {0, 0, 1}, {3, 1, 2}, {3, 0, 2}}
#define MSPI_TIMING_PSRAM_CONFIG_NUM_CORE_CLK_80M_MODULE_CLK_40M_DTR_MODE 12
#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_80M_MODULE_CLK_40M_DTR_MODE 4
//Octal PSRAM: core clock 160M, module clock 80M, DTR mode
#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_160M_MODULE_CLK_80M_DTR_MODE {{1, 0, 0}, {0, 0, 0}, {3, 0, 1}, {1, 0, 1}, {0, 0, 1}, {3, 0, 2}, {1, 0, 2}, {0, 0, 2}, {3, 0, 3}, {1, 0, 3}, {0, 0, 3}, {3, 0, 4}, {1, 0, 4}, {0, 0, 4}}
#define MSPI_TIMING_PSRAM_CONFIG_NUM_CORE_CLK_160M_MODULE_CLK_80M_DTR_MODE 14
#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_160M_MODULE_CLK_80M_DTR_MODE 1

Wyświetl plik

@ -0,0 +1,172 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_flash_partitions.h"
#include "esp32s3/rom/spi_flash.h"
#include "esp32s3/rom/opi_flash.h"
#include "esp32s3/mspi_timing_tuning_configs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SPI_TIMING_CONFIG_NUM_DEFAULT 20 //This should be larger than the max available timing config num
#define SPI_TIMING_TEST_DATA_LEN 64
#define SPI_TIMING_PSRAM_TEST_DATA_ADDR 0
#define SPI_TIMING_FLASH_TEST_DATA_ADDR ESP_BOOTLOADER_OFFSET
//-------------------------------------------FLASH Operation Mode and Corresponding Timing Tuning Parameter Table --------------------------------------//
#define SPI_TIMING_FLASH_DTR_MODE (CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR || CONFIG_ESPTOOLPY_FLASHMODE_OIO_DTR)
#define SPI_TIMING_FLASH_STR_MODE (CONFIG_ESPTOOLPY_FLASHMODE_OPI_STR || CONFIG_ESPTOOLPY_FLASHMODE_OIO_STR || CONFIG_ESPTOOLPY_FLASHMODE_OOUT_STR)
/* Determine A feasible core clock below: SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ and SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ*/
//OCTAL FLASH
#if CONFIG_ESPTOOLPY_OCT_FLASH
// OCT FLASH 40M DTR
#if SPI_TIMING_FLASH_DTR_MODE && CONFIG_ESPTOOLPY_FLASHFREQ_40M
_Static_assert(!CONFIG_ESPTOOLPY_FLASHFREQ_40M, "Octal FLASH 40MHz DDR is not supported. TODO: IDF-1630");
#define SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 160
#endif
//OCT FLASH 80M DTR
#if SPI_TIMING_FLASH_DTR_MODE && CONFIG_ESPTOOLPY_FLASHFREQ_80M
#define SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 160
#endif
//OCT FLASH 120M DTR
#if SPI_TIMING_FLASH_DTR_MODE && CONFIG_ESPTOOLPY_FLASHFREQ_120M
#define SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 240
#endif
//OCT FLASH 80M STR
#if SPI_TIMING_FLASH_STR_MODE && CONFIG_ESPTOOLPY_FLASHFREQ_80M
#define SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 160
#endif
//OCT FLASH 120M STR
#if SPI_TIMING_FLASH_STR_MODE && CONFIG_ESPTOOLPY_FLASHFREQ_120M
#define SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 120
#endif
#endif //#if CONFIG_ESPTOOLPY_OCT_FLASH
/* QUAD FLASH Operation Mode should be added here if needed */
//---------------------------------------PSRAM Operation Mode and Corresponding Timing Tuning Parameter Table--------------------------------------//
#define SPI_TIMING_PSRAM_DTR_MODE 1 //Currently we only support DTR Octal PSRAM
#define SPI_TIMING_PSRAM_STR_MODE 0
//OCTAL PSRAM
#if CONFIG_SPIRAM_MODE_OCT
//OCT 40M PSRAM
#if SPI_TIMING_PSRAM_DTR_MODE && CONFIG_SPIRAM_SPEED_40M
#define SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 80
#endif
//OCT 80M PSRAM
#if SPI_TIMING_PSRAM_DTR_MODE && CONFIG_SPIRAM_SPEED_80M
#define SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 160
#endif
#endif //#if CONFIG_SPIRAM_MODE_OCT
/* QUAD PSRAM Operation Mode should be added here if needed */
//------------------------------------------Get the timing tuning config-----------------------------------------------//
#ifdef SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ
//FLASH needs tuning, and it expects this core clock: SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ
#define SPI_TIMING_FLASH_NEEDS_TUNING 1
#endif
#ifdef SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ
//PSRAM needs tuning, and it expects this core clock: SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ
#define SPI_TIMING_PSRAM_NEEDS_TUNING 1
#endif
//If both FLASH and PSRAM need tuning, the core clock should be same
#if SPI_TIMING_FLASH_NEEDS_TUNING && SPI_TIMING_PSRAM_NEEDS_TUNING
_Static_assert(SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ == SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ, "FLASH and PSRAM Mode configuration are not supported");
#define SPI_TIMING_CORE_CLOCK_MHZ SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ
//If only FLASH needs tuning, the core clock could be as FLASH expected
#elif SPI_TIMING_FLASH_NEEDS_TUNING && !SPI_TIMING_PSRAM_NEEDS_TUNING
#define SPI_TIMING_CORE_CLOCK_MHZ SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ
//If only PSRAM needs tuning, the core clock could be as PSRAM expected
#elif !SPI_TIMING_FLASH_NEEDS_TUNING && SPI_TIMING_PSRAM_NEEDS_TUNING
#define SPI_TIMING_CORE_CLOCK_MHZ SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ
#else
#define SPI_TIMING_CORE_CLOCK_MHZ 80
#endif
//------------------------------------------Helper Macros to get FLASH/PSRAM tuning configs-----------------------------------------------//
#define __GET_TUNING_CONFIG(type, core_clock, module_clock, mode) \
(spi_timing_config_t) { .tuning_config_table = MSPI_TIMING_##type##_CONFIG_TABLE_CORE_CLK_##core_clock##M_MODULE_CLK_##module_clock##M_##mode, \
.available_config_num = MSPI_TIMING_##type##_CONFIG_NUM_CORE_CLK_##core_clock##M_MODULE_CLK_##module_clock##M_##mode, \
.default_config_id = MSPI_TIMING_##type##_DEFAULT_CONFIG_ID_CORE_CLK_##core_clock##M_MODULE_CLK_##module_clock##M_##mode }
#define _GET_TUNING_CONFIG(type, core_clock, module_clock, mode) __GET_TUNING_CONFIG(type, core_clock, module_clock, mode)
#define SPI_TIMING_FLASH_GET_TUNING_CONFIG(core_clock_mhz, module_clock_mhz, mode) _GET_TUNING_CONFIG(FLASH, core_clock_mhz, module_clock_mhz, mode)
#define SPI_TIMING_PSRAM_GET_TUNING_CONFIG(core_clock_mhz, module_clock_mhz, mode) _GET_TUNING_CONFIG(PSRAM, core_clock_mhz, module_clock_mhz, mode)
/**
* SPI timing tuning registers. The macro `SPI_TIMING_FLASH_CONFIG_TABLE` below is the corresponding register value table.
* Upper layer rely on these 3 registers to tune the timing.
*/
typedef struct {
uint8_t spi_din_mode; /*!< input signal delay mode*/
uint8_t spi_din_num; /*!< input signal delay number */
uint8_t extra_dummy_len; /*!< extra dummy length*/
} spi_timing_tuning_param_t;
typedef struct {
spi_timing_tuning_param_t tuning_config_table[SPI_TIMING_CONFIG_NUM_DEFAULT]; //available timing tuning configs
uint32_t available_config_num;
uint32_t default_config_id; //If tuning fails, we use this one as default
} spi_timing_config_t;
/**
* The SPI FLASH module clock and SPI PSRAM module clock is divided from the SPI core clock, core clock is from system clock:
*
* PLL ----| |---- FLASH Module Clock
* XTAL ----|----> Core Clock ---->|
* RTC8M ----| |---- PSRAM Module Clock
*
*/
typedef enum {
SPI_TIMING_CONFIG_CORE_CLOCK_80M,
SPI_TIMING_CONFIG_CORE_CLOCK_120M,
SPI_TIMING_CONFIG_CORE_CLOCK_160M,
SPI_TIMING_CONFIG_CORE_CLOCK_240M
} spi_timing_config_core_clock_t;
spi_timing_config_core_clock_t spi_timing_config_get_core_clock(void);
void spi_timing_config_set_core_clock(uint8_t spi_num, spi_timing_config_core_clock_t core_clock);
void spi_timing_config_set_flash_clock(uint8_t spi_num, uint32_t freqdiv);
void spi_timing_config_flash_set_din_mode_num(uint8_t spi_num, uint8_t din_mode, uint8_t din_num);
void spi_timing_config_flash_set_extra_dummy(uint8_t spi_num, uint8_t extra_dummy);
void spi_timing_config_flash_read_data(uint8_t spi_num, uint8_t *buf, uint32_t addr, uint32_t len);
void spi_timing_config_set_psram_clock(uint8_t spi_num, uint32_t freqdiv);
void spi_timing_config_psram_set_din_mode_num(uint8_t spi_num, uint8_t din_mode, uint8_t din_num);
void spi_timing_config_psram_set_extra_dummy(uint8_t spi_num, uint8_t extra_dummy);
void spi_timing_config_psram_write_data(uint8_t spi_num, uint8_t *buf, uint32_t addr, uint32_t len);
void spi_timing_config_psram_read_data(uint8_t spi_num,uint8_t *buf, uint32_t addr, uint32_t len);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -0,0 +1,291 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "string.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_types.h"
#include "esp_log.h"
#include "spiram_psram.h"
#include "esp32s3/rom/ets_sys.h"
#include "esp32s3/rom/spi_flash.h"
#include "esp32s3/rom/opi_flash.h"
#include "esp32s3/rom/gpio.h"
#include "esp32s3/rom/cache.h"
#include "soc/io_mux_reg.h"
#include "soc/dport_reg.h"
#include "soc/apb_ctrl_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/efuse_reg.h"
#include "driver/gpio.h"
#include "driver/spi_common.h"
#include "driver/periph_ctrl.h"
#if CONFIG_SPIRAM_MODE_OCT
#include "soc/rtc.h"
#include "spi_flash_private.h"
#define OPI_PSRAM_SYNC_READ 0x0000
#define OPI_PSRAM_SYNC_WRITE 0x8080
#define OPI_PSRAM_REG_READ 0x4040
#define OPI_PSRAM_REG_WRITE 0xC0C0
#define OCT_PSRAM_RD_CMD_BITLEN 16
#define OCT_PSRAM_WR_CMD_BITLEN 16
#define OCT_PSRAM_ADDR_BITLEN 32
#define OCT_PSRAM_RD_DUMMY_BITLEN (2*(10-1))
#define OCT_PSRAM_WR_DUMMY_BITLEN (2*(5-1))
#define OCT_PSRAM_CS1_IO 26
typedef struct {
union {
struct {
uint8_t drive_str: 2;
uint8_t read_latency: 3;
uint8_t lt: 1;
uint8_t rsvd0_1: 2;
};
uint8_t val;
} mr0;
union {
struct {
uint8_t vendor_id: 5;
uint8_t rsvd0_2: 3;
};
uint8_t val;
} mr1;
union {
struct {
uint8_t density: 3;
uint8_t dev_id: 2;
uint8_t rsvd1_2: 2;
uint8_t gb: 1;
};
uint8_t val;
} mr2;
union {
struct {
uint8_t rsvd3_7: 5;
uint8_t srf: 1;
uint8_t vcc: 1;
uint8_t rsvd0: 1;
};
uint8_t val;
} mr3;
union {
struct {
uint8_t pasr: 3;
uint8_t rf: 1;
uint8_t rsvd3: 1;
uint8_t wr_latency: 3;
};
uint8_t val;
} mr4;
union {
struct {
uint8_t bl: 2;
uint8_t bt: 1;
uint8_t rsvd0_4: 5;
};
uint8_t val;
} mr8;
} opi_psram_mode_reg_t;
static const char* TAG = "opi psram";
static DRAM_ATTR psram_size_t s_psram_size;
static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psram_vaddr_mode_t vaddrmode);
/**
* Initialise mode registers of the PSRAM
*/
static void IRAM_ATTR s_init_psram_mode_reg(int spi_num, opi_psram_mode_reg_t *mode_reg_config)
{
esp_rom_spiflash_read_mode_t mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
int cmd_len = 16;
uint32_t addr = 0x0;
int addr_bit_len = 32;
int dummy = OCT_PSRAM_RD_DUMMY_BITLEN;
opi_psram_mode_reg_t mode_reg = {0};
int data_bit_len = 16;
//read
esp_rom_opiflash_exec_cmd(spi_num, mode,
OPI_PSRAM_REG_READ, cmd_len,
addr, addr_bit_len,
dummy,
NULL, 0,
&mode_reg.mr0.val, data_bit_len,
BIT(1),
false);
//modify
mode_reg.mr0.lt = mode_reg_config->mr0.lt;
mode_reg.mr0.read_latency = mode_reg_config->mr0.read_latency;
mode_reg.mr0.drive_str = mode_reg_config->mr0.drive_str;
//write
esp_rom_opiflash_exec_cmd(spi_num, mode,
OPI_PSRAM_REG_WRITE, cmd_len,
addr, addr_bit_len,
0,
&mode_reg.mr0.val, 16,
NULL, 0,
BIT(1),
false);
}
static void IRAM_ATTR s_get_psram_mode_reg(int spi_num, opi_psram_mode_reg_t *out_reg)
{
esp_rom_spiflash_read_mode_t mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
int cmd_len = 16;
int addr_bit_len = 32;
int dummy = OCT_PSRAM_RD_DUMMY_BITLEN;
int data_bit_len = 16;
//Read MR0 register
esp_rom_opiflash_exec_cmd(spi_num, mode,
OPI_PSRAM_REG_READ, cmd_len,
0x0, addr_bit_len,
dummy,
NULL, 0,
&out_reg->mr0.val, data_bit_len,
BIT(1),
false);
//Read MR2 register
esp_rom_opiflash_exec_cmd(spi_num, mode,
OPI_PSRAM_REG_READ, cmd_len,
0x2, addr_bit_len,
dummy,
NULL, 0,
&out_reg->mr2.val, data_bit_len,
BIT(1),
false);
//Read MR4 register
esp_rom_opiflash_exec_cmd(spi_num, mode,
OPI_PSRAM_REG_READ, cmd_len,
0x4, addr_bit_len,
dummy,
NULL, 0,
&out_reg->mr4.val, data_bit_len,
BIT(1),
false);
//Read MR8 register
esp_rom_opiflash_exec_cmd(spi_num, mode,
OPI_PSRAM_REG_READ, cmd_len,
0x8, addr_bit_len,
dummy,
NULL, 0,
&out_reg->mr8.val, data_bit_len,
BIT(1),
false);
}
static void IRAM_ATTR s_print_psram_info(opi_psram_mode_reg_t *reg_val)
{
ESP_EARLY_LOGI(TAG, "vendor id : 0x%02x (%s)", reg_val->mr1.vendor_id, reg_val->mr1.vendor_id == 0x0d ? "AP" : "UNKNOWN");
ESP_EARLY_LOGI(TAG, "dev id : 0x%02x (generation %d)", reg_val->mr2.dev_id, reg_val->mr2.dev_id + 1);
ESP_EARLY_LOGI(TAG, "density : 0x%02x (%d Mbit)", reg_val->mr2.density, reg_val->mr2.density == 0x1 ? 32 :
reg_val->mr2.density == 0X3 ? 64 :
reg_val->mr2.density == 0x5 ? 128 :
reg_val->mr2.density == 0x7 ? 256 : 0);
ESP_EARLY_LOGI(TAG, "good-die : 0x%02x (%s)", reg_val->mr2.gb, reg_val->mr2.gb == 1 ? "Pass" : "Fail");
ESP_EARLY_LOGI(TAG, "Latency : 0x%02x (%s)", reg_val->mr0.lt, reg_val->mr0.lt == 1 ? "Fixed" : "Variable");
ESP_EARLY_LOGI(TAG, "VCC : 0x%02x (%s)", reg_val->mr3.vcc, reg_val->mr3.vcc == 1 ? "3V" : "1.8V");
ESP_EARLY_LOGI(TAG, "SRF : 0x%02x (%s Refresh)", reg_val->mr3.srf, reg_val->mr3.srf == 0x1 ? "Fast" : "Slow");
ESP_EARLY_LOGI(TAG, "BurstType : 0x%02x (%s Wrap)", reg_val->mr8.bt, reg_val->mr8.bt == 1 && reg_val->mr8.bl != 3 ? "Hybrid" : "");
ESP_EARLY_LOGI(TAG, "BurstLen : 0x%02x (%d Byte)", reg_val->mr8.bl, reg_val->mr8.bl == 0x00 ? 16 :
reg_val->mr8.bl == 0x01 ? 32 :
reg_val->mr8.bl == 0x10 ? 64 : 1024);
ESP_EARLY_LOGI(TAG, "Readlatency : 0x%02x (%d cycles@%s)", reg_val->mr0.read_latency, reg_val->mr0.read_latency * 2 + 6,
reg_val->mr0.lt == 1 ? "Fixed" : "Variable");
ESP_EARLY_LOGI(TAG, "DriveStrength: 0x%02x (1/%d)", reg_val->mr0.drive_str, reg_val->mr0.drive_str == 0x00 ? 1 :
reg_val->mr0.drive_str == 0x01 ? 2 :
reg_val->mr0.drive_str == 0x02 ? 4 : 8);
}
esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode)
{
// enable CS signal
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[OCT_PSRAM_CS1_IO], FUNC_SPICS1_SPICS1);
//enter MSPI slow mode to init PSRAM device registers
spi_timing_enter_mspi_low_speed_mode();
//set to variable dummy mode
SET_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY);
#if CONFIG_ESPTOOLPY_FLASH_VENDOR_MXIC && CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR
esp_rom_spi_set_dtr_swap_mode(1, false, false);
#endif
//Set PSRAM read latency and drive strength
static DRAM_ATTR opi_psram_mode_reg_t mode_reg = {0};
mode_reg.mr0.lt = 1;
mode_reg.mr0.read_latency = 2;
mode_reg.mr0.drive_str = 0;
s_init_psram_mode_reg(1, &mode_reg);
//Print PSRAM info
s_get_psram_mode_reg(1, &mode_reg);
s_print_psram_info(&mode_reg);
s_psram_size = mode_reg.mr2.density == 0x1 ? PSRAM_SIZE_32MBITS :
mode_reg.mr2.density == 0X3 ? PSRAM_SIZE_64MBITS :
mode_reg.mr2.density == 0x5 ? PSRAM_SIZE_128MBITS :
mode_reg.mr2.density == 0x7 ? PSRAM_SIZE_256MBITS : 0;
#if CONFIG_ESPTOOLPY_FLASH_VENDOR_MXIC && CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR
esp_rom_spi_set_dtr_swap_mode(1, true, true);
#endif
spi_timing_psram_tuning();
spi_timing_enter_mspi_high_speed_mode();
/**
* Tuning may change SPI1 regs, whereas legacy spi_flash APIs rely on these regs.
* This function is to restore SPI1 init state.
*/
spi_flash_set_rom_required_regs();
psram_cache_init(mode, vaddrmode);
return ESP_OK;
}
//register initialization for sram cache params and r/w commands
static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psram_vaddr_mode_t vaddrmode)
{
//Config Write CMD phase for SPI0 to access PSRAM
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, OCT_PSRAM_WR_CMD_BITLEN - 1, 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, OPI_PSRAM_SYNC_WRITE, SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE_S);
//Config Read CMD phase for SPI0 to access PSRAM
SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_CACHE_SRAM_USR_RCMD_M);
SET_PERI_REG_BITS(SPI_MEM_SRAM_DRD_CMD_REG(0), SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_V, OCT_PSRAM_RD_CMD_BITLEN - 1, 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, OPI_PSRAM_SYNC_READ, SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_S);
//Config ADDR phase
SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_ADDR_BITLEN_V, OCT_PSRAM_ADDR_BITLEN - 1, SPI_MEM_SRAM_ADDR_BITLEN_S);
SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_CACHE_USR_SCMD_4BYTE_M);
//Config RD/WR Dummy phase
SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_USR_RD_SRAM_DUMMY_M | SPI_MEM_USR_WR_SRAM_DUMMY_M);
SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_RDUMMY_CYCLELEN_V, OCT_PSRAM_RD_DUMMY_BITLEN - 1, SPI_MEM_SRAM_RDUMMY_CYCLELEN_S);
SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_DDR_REG(0), SPI_MEM_SPI_SMEM_VAR_DUMMY_M);
SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_WDUMMY_CYCLELEN_V, OCT_PSRAM_WR_DUMMY_BITLEN - 1, SPI_MEM_SRAM_WDUMMY_CYCLELEN_S);
CLEAR_PERI_REG_MASK(SPI_MEM_SPI_SMEM_DDR_REG(0), SPI_MEM_SPI_SMEM_DDR_WDAT_SWP_M | SPI_MEM_SPI_SMEM_DDR_RDAT_SWP_M);
SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_DDR_REG(0), SPI_MEM_SPI_SMEM_DDR_EN_M);
SET_PERI_REG_MASK(SPI_MEM_SRAM_CMD_REG(0), SPI_MEM_SDUMMY_OUT_M | SPI_MEM_SCMD_OCT_M | SPI_MEM_SADDR_OCT_M | SPI_MEM_SDOUT_OCT_M | SPI_MEM_SDIN_OCT_M);
SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_OCT_M);
Cache_Resume_DCache(0);
}
psram_size_t psram_get_size()
{
return s_psram_size;
}
#endif //#if CONFIG_SPIRAM_MODE_OCT

Wyświetl plik

@ -0,0 +1,197 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "string.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_types.h"
#include "esp_log.h"
#include "soc/spi_mem_reg.h"
#include "esp32s3/spi_timing_config.h"
#define OPI_PSRAM_SYNC_READ 0x0000
#define OPI_PSRAM_SYNC_WRITE 0x8080
#define OCT_PSRAM_RD_DUMMY_NUM (2*(10-1))
#define OCT_PSRAM_WR_DUMMY_NUM (2*(5-1))
/////////////////////////////////////////TIMING TUNING IS NEEDED//////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING //If one of the FLASH / PSRAM or both of them need timing tuning, we should build following code
spi_timing_config_core_clock_t IRAM_ATTR spi_timing_config_get_core_clock(void)
{
switch (SPI_TIMING_CORE_CLOCK_MHZ) {
case 80:
return SPI_TIMING_CONFIG_CORE_CLOCK_80M;
case 120:
return SPI_TIMING_CONFIG_CORE_CLOCK_120M;
case 160:
return SPI_TIMING_CONFIG_CORE_CLOCK_160M;
case 240:
return SPI_TIMING_CONFIG_CORE_CLOCK_240M;
default:
abort();
}
}
void IRAM_ATTR spi_timing_config_set_core_clock(uint8_t spi_num, spi_timing_config_core_clock_t core_clock)
{
uint32_t reg_val = 0;
switch (core_clock) {
case SPI_TIMING_CONFIG_CORE_CLOCK_80M:
reg_val = 0;
break;
case SPI_TIMING_CONFIG_CORE_CLOCK_120M:
reg_val = 1;
break;
case SPI_TIMING_CONFIG_CORE_CLOCK_160M:
reg_val = 2;
break;
case SPI_TIMING_CONFIG_CORE_CLOCK_240M:
reg_val = 3;
break;
default:
abort();
}
REG_SET_FIELD(SPI_MEM_CORE_CLK_SEL_REG(spi_num), SPI_MEM_CORE_CLK_SEL, reg_val);
}
//-------------------------------------FLASH timing tuning-------------------------------------//
void IRAM_ATTR spi_timing_config_set_flash_clock(uint8_t spi_num, uint32_t freqdiv)
{
assert(freqdiv > 0);
if (freqdiv == 1) {
WRITE_PERI_REG(SPI_MEM_CLOCK_REG(spi_num), SPI_MEM_CLK_EQU_SYSCLK);
} else {
uint32_t freqbits = (((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)) | (((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)) | ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S);
WRITE_PERI_REG(SPI_MEM_CLOCK_REG(spi_num), freqbits);
}
}
void IRAM_ATTR spi_timing_config_flash_set_din_mode_num(uint8_t spi_num, uint8_t din_mode, uint8_t din_num)
{
uint32_t reg_val = 0;
reg_val = (REG_READ(SPI_MEM_DIN_MODE_REG(spi_num)) & (~(SPI_MEM_DIN0_MODE_M | SPI_MEM_DIN1_MODE_M | SPI_MEM_DIN2_MODE_M | SPI_MEM_DIN3_MODE_M | SPI_MEM_DIN4_MODE_M | SPI_MEM_DIN5_MODE_M | SPI_MEM_DIN6_MODE_M | SPI_MEM_DIN7_MODE_M | SPI_MEM_DINS_MODE_M)))
| (din_mode << SPI_MEM_DIN0_MODE_S) | (din_mode << SPI_MEM_DIN1_MODE_S) | (din_mode << SPI_MEM_DIN2_MODE_S) | (din_mode << SPI_MEM_DIN3_MODE_S)
| (din_mode << SPI_MEM_DIN4_MODE_S) | (din_mode << SPI_MEM_DIN5_MODE_S) | (din_mode << SPI_MEM_DIN6_MODE_S) | (din_mode << SPI_MEM_DIN7_MODE_S) | (din_mode << SPI_MEM_DINS_MODE_S);
REG_WRITE(SPI_MEM_DIN_MODE_REG(spi_num), reg_val);
reg_val = (REG_READ(SPI_MEM_DIN_NUM_REG(spi_num)) & (~(SPI_MEM_DIN0_NUM_M | SPI_MEM_DIN1_NUM_M | SPI_MEM_DIN2_NUM_M | SPI_MEM_DIN3_NUM_M | SPI_MEM_DIN4_NUM_M | SPI_MEM_DIN5_NUM_M | SPI_MEM_DIN6_NUM_M | SPI_MEM_DIN7_NUM_M | SPI_MEM_DINS_NUM_M)))
| (din_num << SPI_MEM_DIN0_NUM_S) | (din_num << SPI_MEM_DIN1_NUM_S) | (din_num << SPI_MEM_DIN2_NUM_S) | (din_num << SPI_MEM_DIN3_NUM_S)
| (din_num << SPI_MEM_DIN4_NUM_S) | (din_num << SPI_MEM_DIN5_NUM_S) | (din_num << SPI_MEM_DIN6_NUM_S) | (din_num << SPI_MEM_DIN7_NUM_S) | (din_num << SPI_MEM_DINS_NUM_S);
REG_WRITE(SPI_MEM_DIN_NUM_REG(spi_num), reg_val);
}
void IRAM_ATTR spi_timing_config_flash_set_extra_dummy(uint8_t spi_num, uint8_t extra_dummy)
{
if (extra_dummy > 0) {
SET_PERI_REG_MASK(SPI_MEM_TIMING_CALI_REG(spi_num), SPI_MEM_TIMING_CALI_M);
SET_PERI_REG_BITS(SPI_MEM_TIMING_CALI_REG(spi_num), SPI_MEM_EXTRA_DUMMY_CYCLELEN_V, extra_dummy,
SPI_MEM_EXTRA_DUMMY_CYCLELEN_S);
} else {
CLEAR_PERI_REG_MASK(SPI_MEM_TIMING_CALI_REG(spi_num), SPI_MEM_TIMING_CALI_M);
SET_PERI_REG_BITS(SPI_MEM_TIMING_CALI_REG(spi_num), SPI_MEM_EXTRA_DUMMY_CYCLELEN_V, 0,
SPI_MEM_EXTRA_DUMMY_CYCLELEN_S);
}
}
//-------------------------------------PSRAM timing tuning-------------------------------------//
void IRAM_ATTR spi_timing_config_set_psram_clock(uint8_t spi_num, uint32_t freqdiv)
{
if (freqdiv == 1) {
WRITE_PERI_REG(SPI_MEM_SRAM_CLK_REG(spi_num), SPI_MEM_SCLK_EQU_SYSCLK);
} else {
uint32_t freqbits = (((freqdiv-1)<<SPI_MEM_SCLKCNT_N_S)) | (((freqdiv/2-1)<<SPI_MEM_SCLKCNT_H_S)) | ((freqdiv-1)<<SPI_MEM_SCLKCNT_L_S);
WRITE_PERI_REG(SPI_MEM_SRAM_CLK_REG(spi_num), freqbits);
}
}
void IRAM_ATTR spi_timing_config_psram_set_din_mode_num(uint8_t spi_num, uint8_t din_mode, uint8_t din_num)
{
uint32_t reg_val = 0;
reg_val = (REG_READ(SPI_MEM_SPI_SMEM_DIN_MODE_REG(spi_num)) & (~(SPI_MEM_SPI_SMEM_DIN0_MODE_M | SPI_MEM_SPI_SMEM_DIN1_MODE_M | SPI_MEM_SPI_SMEM_DIN2_MODE_M | SPI_MEM_SPI_SMEM_DIN3_MODE_M | SPI_MEM_SPI_SMEM_DIN4_MODE_M | SPI_MEM_SPI_SMEM_DIN5_MODE_M | SPI_MEM_SPI_SMEM_DIN6_MODE_M | SPI_MEM_SPI_SMEM_DIN7_MODE_M | SPI_MEM_SPI_SMEM_DINS_MODE_M)))
| (din_mode << SPI_MEM_SPI_SMEM_DIN0_MODE_S) | (din_mode << SPI_MEM_SPI_SMEM_DIN1_MODE_S) | (din_mode << SPI_MEM_SPI_SMEM_DIN2_MODE_S) | (din_mode << SPI_MEM_SPI_SMEM_DIN3_MODE_S)
| (din_mode << SPI_MEM_SPI_SMEM_DIN4_MODE_S) | (din_mode << SPI_MEM_SPI_SMEM_DIN5_MODE_S) | (din_mode << SPI_MEM_SPI_SMEM_DIN6_MODE_S) | (din_mode << SPI_MEM_SPI_SMEM_DIN7_MODE_S) | (din_mode << SPI_MEM_SPI_SMEM_DINS_MODE_S);
REG_WRITE(SPI_MEM_SPI_SMEM_DIN_MODE_REG(spi_num), reg_val);
reg_val = (REG_READ(SPI_MEM_SPI_SMEM_DIN_NUM_REG(spi_num)) & (~(SPI_MEM_SPI_SMEM_DIN0_NUM_M | SPI_MEM_SPI_SMEM_DIN1_NUM_M | SPI_MEM_SPI_SMEM_DIN2_NUM_M | SPI_MEM_SPI_SMEM_DIN3_NUM_M | SPI_MEM_SPI_SMEM_DIN4_NUM_M | SPI_MEM_SPI_SMEM_DIN5_NUM_M | SPI_MEM_SPI_SMEM_DIN6_NUM_M | SPI_MEM_SPI_SMEM_DIN7_NUM_M | SPI_MEM_SPI_SMEM_DINS_NUM_M)))
| (din_num << SPI_MEM_SPI_SMEM_DIN0_NUM_S) | (din_num << SPI_MEM_SPI_SMEM_DIN1_NUM_S) | (din_num << SPI_MEM_SPI_SMEM_DIN2_NUM_S) | (din_num << SPI_MEM_SPI_SMEM_DIN3_NUM_S)
| (din_num << SPI_MEM_SPI_SMEM_DIN4_NUM_S) | (din_num << SPI_MEM_SPI_SMEM_DIN5_NUM_S) | (din_num << SPI_MEM_SPI_SMEM_DIN6_NUM_S) | (din_num << SPI_MEM_SPI_SMEM_DIN7_NUM_S) | (din_num << SPI_MEM_SPI_SMEM_DINS_NUM_S);
REG_WRITE(SPI_MEM_SPI_SMEM_DIN_NUM_REG(spi_num), reg_val);
}
void IRAM_ATTR spi_timing_config_psram_set_extra_dummy(uint8_t spi_num, uint8_t extra_dummy)
{
if (extra_dummy > 0) {
SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num), SPI_MEM_SPI_SMEM_TIMING_CALI_M);
SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num), SPI_MEM_SPI_SMEM_EXTRA_DUMMY_CYCLELEN_V, extra_dummy,
SPI_MEM_SPI_SMEM_EXTRA_DUMMY_CYCLELEN_S);
} else {
CLEAR_PERI_REG_MASK(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num), SPI_MEM_SPI_SMEM_TIMING_CALI_M);
SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num), SPI_MEM_SPI_SMEM_EXTRA_DUMMY_CYCLELEN_V, 0,
SPI_MEM_SPI_SMEM_EXTRA_DUMMY_CYCLELEN_S);
}
}
//-------------------------------------------FLASH/PSRAM Read/Write------------------------------------------//
void IRAM_ATTR spi_timing_config_flash_read_data(uint8_t spi_num, uint8_t *buf, uint32_t addr, uint32_t len)
{
#if CONFIG_ESPTOOLPY_OCT_FLASH
// note that in spi_flash_read API, there is a wait-idle stage, since flash can only be read in idle state.
// but after we change the timing settings, we might not read correct idle status via RDSR.
// so, here we should use a read API that won't check idle status.
for (int i = 0; i < 16; i++) {
REG_WRITE(SPI_MEM_W0_REG(1) + i*4, 0);
}
esp_rom_opiflash_read_raw(addr, buf, len);
#else
abort();
#endif
}
void IRAM_ATTR spi_timing_config_psram_write_data(uint8_t spi_num, uint8_t *buf, uint32_t addr, uint32_t len)
{
#if CONFIG_ESPTOOLPY_OCT_FLASH
uint32_t cmd = OPI_PSRAM_SYNC_WRITE;
int dummy = OCT_PSRAM_WR_DUMMY_NUM;
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_OPI_DTR_MODE,
cmd, 16,
addr, 32,
dummy,
buf, 8 * len,
NULL, 0,
BIT(1),
false);
#else
abort();
#endif
}
void IRAM_ATTR spi_timing_config_psram_read_data(uint8_t spi_num,uint8_t *buf, uint32_t addr, uint32_t len)
{
#if CONFIG_ESPTOOLPY_OCT_FLASH
uint32_t cmd = OPI_PSRAM_SYNC_READ;
int dummy = OCT_PSRAM_RD_DUMMY_NUM;
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_OPI_DTR_MODE,
cmd, 16,
addr, 32,
dummy,
NULL, 0,
buf, 8 * len,
BIT(1),
false);
#else
abort();
#endif
}
#endif //#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING

Wyświetl plik

@ -50,7 +50,7 @@ static const char *TAG = "spiram";
#define PSRAM_SPEED PSRAM_CACHE_S20M #define PSRAM_SPEED PSRAM_CACHE_S20M
#endif #endif
static bool spiram_inited = false; static bool s_spiram_inited = false;
/* /*
@ -245,8 +245,7 @@ esp_err_t esp_spiram_init(void)
#endif #endif
return r; return r;
} }
s_spiram_inited = true;
spiram_inited = true;
#if (CONFIG_SPIRAM_SIZE != -1) #if (CONFIG_SPIRAM_SIZE != -1)
if (esp_spiram_get_size() != CONFIG_SPIRAM_SIZE) { if (esp_spiram_get_size() != CONFIG_SPIRAM_SIZE) {
ESP_EARLY_LOGE(TAG, "Expected %dKiB chip but found %dKiB chip. Bailing out..", CONFIG_SPIRAM_SIZE / 1024, esp_spiram_get_size() / 1024); ESP_EARLY_LOGE(TAG, "Expected %dKiB chip but found %dKiB chip. Bailing out..", CONFIG_SPIRAM_SIZE / 1024, esp_spiram_get_size() / 1024);
@ -296,7 +295,7 @@ esp_err_t esp_spiram_reserve_dma_pool(size_t size)
size_t esp_spiram_get_size(void) size_t esp_spiram_get_size(void)
{ {
if (!spiram_inited) { if (!s_spiram_inited) {
ESP_EARLY_LOGE(TAG, "SPI RAM not initialized"); ESP_EARLY_LOGE(TAG, "SPI RAM not initialized");
abort(); abort();
} }
@ -311,6 +310,12 @@ size_t esp_spiram_get_size(void)
if (size == PSRAM_SIZE_64MBITS) { if (size == PSRAM_SIZE_64MBITS) {
return 8 * 1024 * 1024; return 8 * 1024 * 1024;
} }
if (size == PSRAM_SIZE_128MBITS) {
return 16 * 1024 * 1024;
}
if (size == PSRAM_SIZE_256MBITS) {
return 32 * 1024 * 1024;
}
return CONFIG_SPIRAM_SIZE; return CONFIG_SPIRAM_SIZE;
} }

Wyświetl plik

@ -45,7 +45,7 @@
#include "driver/periph_ctrl.h" #include "driver/periph_ctrl.h"
#include "bootloader_common.h" #include "bootloader_common.h"
#if CONFIG_SPIRAM #if CONFIG_SPIRAM_MODE_QUAD
#include "soc/rtc.h" #include "soc/rtc.h"
static const char* TAG = "psram"; static const char* TAG = "psram";

Wyświetl plik

@ -28,9 +28,11 @@ typedef enum {
} psram_cache_mode_t; } psram_cache_mode_t;
typedef enum { typedef enum {
PSRAM_SIZE_16MBITS = 0, PSRAM_SIZE_16MBITS = 0,
PSRAM_SIZE_32MBITS = 1, PSRAM_SIZE_32MBITS = 1,
PSRAM_SIZE_64MBITS = 2, PSRAM_SIZE_64MBITS = 2,
PSRAM_SIZE_128MBITS = 3,
PSRAM_SIZE_256MBITS = 4,
PSRAM_SIZE_MAX, PSRAM_SIZE_MAX,
} psram_size_t; } psram_size_t;

Wyświetl plik

@ -128,6 +128,7 @@ PROVIDE( esp_rom_opiflash_write = 0x40000930 );
PROVIDE( esp_rom_spi_set_dtr_swap_mode = 0x4000093c ); PROVIDE( esp_rom_spi_set_dtr_swap_mode = 0x4000093c );
PROVIDE( esp_rom_opiflash_exit_continuous_read_mode = 0x40000948 ); PROVIDE( esp_rom_opiflash_exit_continuous_read_mode = 0x40000948 );
PROVIDE( esp_rom_opiflash_legacy_driver_init = 0x40000954 ); PROVIDE( esp_rom_opiflash_legacy_driver_init = 0x40000954 );
PROVIDE( esp_rom_opiflash_read_raw = 0x4004d9d4);
/* Data (.data, .bss, .rodata) */ /* Data (.data, .bss, .rodata) */
PROVIDE( rom_opiflash_cmd_def = 0x3fcefff4 ); PROVIDE( rom_opiflash_cmd_def = 0x3fcefff4 );
PROVIDE( rom_spi_usr_cmd_legacy_funcs = 0x3fcefff0 ); PROVIDE( rom_spi_usr_cmd_legacy_funcs = 0x3fcefff0 );

Wyświetl plik

@ -8,12 +8,46 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include "spi_flash.h" #include "spi_flash.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #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 { typedef struct {
uint16_t cmd; /*!< Command value */ uint16_t cmd; /*!< Command value */
uint16_t cmdBitLen; /*!< Command byte length*/ uint16_t cmdBitLen; /*!< Command byte length*/
@ -40,7 +74,6 @@ typedef struct {
#define ESP_ROM_SPIFLASH_BP2 BIT4 #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_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2)
#define ESP_ROM_SPIFLASH_QE BIT9 #define ESP_ROM_SPIFLASH_QE BIT9
#define ESP_ROM_SPIFLASH_BP_MASK_ISSI (BIT7 | BIT5 | BIT4 | BIT3 | BIT2)
#define FLASH_OP_MODE_RDCMD_DOUT 0x3B #define FLASH_OP_MODE_RDCMD_DOUT 0x3B
#define ESP_ROM_FLASH_SECTOR_SIZE 0x1000 #define ESP_ROM_FLASH_SECTOR_SIZE 0x1000
@ -112,8 +145,14 @@ typedef struct {
#define ROM_FLASH_CMD_EN4B_GD 0xB7 #define ROM_FLASH_CMD_EN4B_GD 0xB7
#define ROM_FLASH_CMD_DIS4B_GD 0xE9 #define ROM_FLASH_CMD_DIS4B_GD 0xE9
// spi user mode command config 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);
// spi user mode command config
/** /**
* @brief Config the spi user command * @brief Config the spi user command
* @param spi_num spi port * @param spi_num spi port
@ -159,8 +198,6 @@ void esp_rom_spi_set_dtr_swap_mode(int spi, bool wr_swap, bool rd_swap);
*/ */
void esp_rom_opiflash_mode_reset(int spi_num); void esp_rom_opiflash_mode_reset(int spi_num);
#if 0
// MX25UM25645G opi flash interface
/** /**
* @brief To execute a flash operation command * @brief To execute a flash operation command
* @param spi_num spi port * @param spi_num spi port
@ -193,105 +230,91 @@ void esp_rom_opiflash_exec_cmd(int spi_num, esp_rom_spiflash_read_mode_t mode,
*/ */
void esp_rom_opiflash_soft_reset(int spi_num, esp_rom_spiflash_read_mode_t mode); void esp_rom_opiflash_soft_reset(int spi_num, esp_rom_spiflash_read_mode_t mode);
/**
* @brief to read opi flash ID(for MX25UM25645G)
* @param spi_num spi port
* @param mode Flash Operation Mode
* @return opi flash id
*/
uint32_t esp_rom_opiflash_read_id(int spi_num, esp_rom_spiflash_read_mode_t mode);
/** /**
* @brief to read opi flash status register(for MX25UM25645G) * @brief to read opi flash ID
* @param spi_num spi port * @note command format would be defined in initialization
* @param mode Flash Operation Mode * @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 * @return opi flash status value
*/ */
uint8_t esp_rom_opiflash_rdsr(int spi_num, esp_rom_spiflash_read_mode_t mode); uint8_t esp_rom_opiflash_rdsr(void);
/** /**
* @brief wait opi flash status register to be idle * @brief wait opi flash status register to be idle
* @param spi_num spi port * @note command format would be defined in initialization
* @param mode Flash Operation Mode
*/
void esp_rom_opiflash_wait_idle(int spi_num, esp_rom_spiflash_read_mode_t mode);
/**
* @brief to read the config register2(for MX25UM25645G)
* @param spi_num spi port
* @param mode Flash Operation Mode
* @param addr the address of configure register
* @return value of config register2
*/
uint8_t esp_rom_opiflash_rdcr2(int spi_num, esp_rom_spiflash_read_mode_t mode, uint32_t addr);
/**
* @brief to write the config register2(for MX25UM25645G)
* @param spi_num spi port
* @param mode Flash Operation Mode
* @param addr the address of config register
* @param val the value to write
*/
void esp_rom_opiflash_wrcr2(int spi_num, esp_rom_spiflash_read_mode_t mode, uint32_t addr, uint8_t val);
/**
* @brief to erase flash sector(for MX25UM25645G)
* @param spi_num spi port
* @param address the sector address to be erased
* @param mode Flash operation mode
* @return flash operation result * @return flash operation result
*/ */
esp_rom_spiflash_result_t esp_rom_opiflash_erase_sector(int spi_num, uint32_t address, esp_rom_spiflash_read_mode_t mode); esp_rom_spiflash_result_t esp_rom_opiflash_wait_idle(void);
/** /**
* @brief to erase flash block(for MX25UM25645G) * @brief to erase flash sector
* @param spi_num spi port * @note command format would be defined in initialization
* @param address the block address to be erased * @param sector_num the sector to be erased
* @param mode Flash operation mode
* @return flash operation result * @return flash operation result
*/ */
esp_rom_spiflash_result_t esp_rom_opiflash_erase_block_64k(int spi_num, uint32_t address, esp_rom_spiflash_read_mode_t mode); esp_rom_spiflash_result_t esp_rom_opiflash_erase_sector(uint32_t sector_num);
/** /**
* @brief to erase a flash area define by start address and length(for MX25UM25645G) * @brief to erase flash block
* @param spi_num spi port * @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 start_addr the start address to be erased
* @param area_len the erea length to be erased * @param area_len the erea length to be erased
* @param mode flash operation mode
* @return flash operation result * @return flash operation result
*/ */
esp_rom_spiflash_result_t esp_rom_opiflash_erase_area(int spi_num, uint32_t start_addr, uint32_t area_len, esp_rom_spiflash_read_mode_t mode); 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(for MX25UM25645G) * @brief to read data from opi flash
* @param spi_num spi port * @note command format would be defined in initialization
* @param mode flash operation mode
* @param flash_addr flash address to read data from * @param flash_addr flash address to read data from
* @param data_addr data buffer to accept the data * @param data_addr data buffer to accept the data
* @param len data length to be read * @param len data length to be read
* @return flash operation result * @return flash operation result
*/ */
esp_rom_spiflash_result_t esp_rom_opiflash_read(int spi_num, esp_rom_spiflash_read_mode_t mode, uint32_t flash_addr, uint8_t *data_addr, int len); 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(for MX25UM25645G) * @brief to write data to opi flash
* @param spi_num spi port * @note command format would be defined in initialization
* @param mode flash operation mode
* @param flash_addr flash address to write data to * @param flash_addr flash address to write data to
* @param data_addr data buffer to write to flash * @param data_addr data buffer to write to flash
* @param len data length to write * @param len data length to write
* @return flash operation result * @return flash operation result
*/ */
esp_rom_spiflash_result_t esp_rom_opiflash_write(int spi_num, esp_rom_spiflash_read_mode_t mode, uint32_t flash_addr, uint8_t *data_addr, uint32_t len); esp_rom_spiflash_result_t esp_rom_opiflash_write(uint32_t flash_addr, const uint32_t *data_addr, int len);
/** /**
* @brief to set opi flash operation mode(for MX25UM25645G) * @brief send WREN command
* @param spi_num spi port * @note command format would be defined in initialization
* @param cur_mode current operation mode * @param arg not used, set to NULL
* @param target the target operation mode to be set * @return flash operation result
*/ */
void esp_rom_opiflash_set_mode(int spi_num, esp_rom_spiflash_read_mode_t cur_mode, esp_rom_spiflash_read_mode_t target_mode); esp_rom_spiflash_result_t esp_rom_opiflash_wren(void* arg);
#endif
/**
* @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 #ifdef __cplusplus
} }

Wyświetl plik

@ -121,7 +121,12 @@ typedef enum {
ESP_ROM_SPIFLASH_DIO_MODE, ESP_ROM_SPIFLASH_DIO_MODE,
ESP_ROM_SPIFLASH_DOUT_MODE, ESP_ROM_SPIFLASH_DOUT_MODE,
ESP_ROM_SPIFLASH_FASTRD_MODE, ESP_ROM_SPIFLASH_FASTRD_MODE,
ESP_ROM_SPIFLASH_SLOWRD_MODE ESP_ROM_SPIFLASH_SLOWRD_MODE,
ESP_ROM_SPIFLASH_OPI_STR_MODE,
ESP_ROM_SPIFLASH_OPI_DTR_MODE,
ESP_ROM_SPIFLASH_OOUT_MODE,
ESP_ROM_SPIFLASH_OIO_STR_MODE,
ESP_ROM_SPIFLASH_OIO_DTR_MODE,
} esp_rom_spiflash_read_mode_t; } esp_rom_spiflash_read_mode_t;
typedef enum { typedef enum {
@ -148,6 +153,34 @@ typedef struct {
uint16_t data; uint16_t data;
} esp_rom_spiflash_common_cmd_t; } esp_rom_spiflash_common_cmd_t;
typedef void (*spi_flash_func_t)(void);
typedef esp_rom_spiflash_result_t (*spi_flash_op_t)(void);
typedef esp_rom_spiflash_result_t (*spi_flash_erase_t)(uint32_t);
typedef esp_rom_spiflash_result_t (*spi_flash_rd_t)(uint32_t, void*, int);
typedef esp_rom_spiflash_result_t (*spi_flash_wr_t)(uint32_t, const uint32_t*, int);
typedef esp_rom_spiflash_result_t (*spi_flash_ewr_t)(uint32_t, const void*, uint32_t);
typedef esp_rom_spiflash_result_t (*spi_flash_wren_t)(void*);
typedef esp_rom_spiflash_result_t (* spi_flash_erase_area_t)(uint32_t, uint32_t);
typedef struct {
uint8_t pp_addr_bit_len;
uint8_t se_addr_bit_len;
uint8_t be_addr_bit_len;
uint8_t rd_addr_bit_len;
uint32_t read_sub_len;
uint32_t write_sub_len;
spi_flash_op_t unlock;
spi_flash_erase_t erase_sector;
spi_flash_erase_t erase_block;
spi_flash_rd_t read;
spi_flash_wr_t write;
spi_flash_ewr_t encrypt_write;
spi_flash_func_t check_sus;
spi_flash_wren_t wren;
spi_flash_op_t wait_idle;
spi_flash_erase_area_t erase_area;
} spiflash_legacy_funcs_t;
/** /**
* @brief Fix the bug in SPI hardware communication with Flash/Ext-SRAM in High Speed. * @brief Fix the bug in SPI hardware communication with Flash/Ext-SRAM in High Speed.
@ -548,33 +581,6 @@ void esp_rom_spiflash_select_qio_pins(uint8_t wp_gpio_num, uint32_t spiconfig);
* @return always ESP_ROM_SPIFLASH_RESULT_OK * @return always ESP_ROM_SPIFLASH_RESULT_OK
*/ */
esp_rom_spiflash_result_t esp_rom_spiflash_write_disable(void); esp_rom_spiflash_result_t esp_rom_spiflash_write_disable(void);
typedef void (* spi_flash_func_t)(void);
typedef SpiFlashOpResult (* spi_flash_op_t)(void);
typedef SpiFlashOpResult (* spi_flash_erase_t)(uint32_t);
typedef SpiFlashOpResult (* spi_flash_rd_t)(uint32_t, uint32_t*, int);
typedef SpiFlashOpResult (* spi_flash_wr_t)(uint32_t, const uint32_t*, int);
typedef SpiFlashOpResult (* spi_flash_ewr_t)(uint32_t, const void*, uint32_t);
typedef SpiFlashOpResult (* spi_flash_wren_t)(void*);
typedef struct {
uint32_t read_sub_len;
uint32_t write_sub_len;
spi_flash_op_t unlock;
spi_flash_erase_t erase_sector;
spi_flash_erase_t erase_block;
spi_flash_rd_t read;
spi_flash_wr_t write;
spi_flash_ewr_t encrypt_write;
spi_flash_func_t check_sus;
spi_flash_wren_t wren;
spi_flash_op_t wait_idle;
} spiflash_legacy_funcs_t;
/* Defined in the interfaces file, default value is rom_default_spiflash_legacy_flash_func */
extern const spiflash_legacy_funcs_t *rom_spiflash_legacy_funcs;
typedef struct { typedef struct {
esp_rom_spiflash_chip_t chip; esp_rom_spiflash_chip_t chip;
uint8_t dummy_len_plus[3]; uint8_t dummy_len_plus[3];

Wyświetl plik

@ -54,6 +54,7 @@
#include "soc/assist_debug_reg.h" #include "soc/assist_debug_reg.h"
#include "soc/cache_memory.h" #include "soc/cache_memory.h"
#include "soc/system_reg.h" #include "soc/system_reg.h"
#include "esp32s3/rom/opi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rtc.h" #include "esp32c3/rtc.h"
#include "esp32c3/rom/cache.h" #include "esp32c3/rom/cache.h"
@ -62,6 +63,7 @@
#include "esp32c3/memprot.h" #include "esp32c3/memprot.h"
#endif #endif
#include "spi_flash_private.h"
#include "bootloader_flash_config.h" #include "bootloader_flash_config.h"
#include "esp_private/crosscore_int.h" #include "esp_private/crosscore_int.h"
#include "esp_flash_encrypt.h" #include "esp_flash_encrypt.h"
@ -353,6 +355,16 @@ void IRAM_ATTR call_start_cpu0(void)
Cache_Set_IDROM_MMU_Size(cache_mmu_irom_size, CACHE_DROM_MMU_MAX_END - cache_mmu_irom_size); Cache_Set_IDROM_MMU_Size(cache_mmu_irom_size, CACHE_DROM_MMU_MAX_END - cache_mmu_irom_size);
#endif // CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #endif // CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3
#if CONFIG_ESPTOOLPY_OCT_FLASH
bool efuse_opflash_en = REG_GET_FIELD(EFUSE_RD_REPEAT_DATA3_REG, EFUSE_FLASH_TYPE);
if (!efuse_opflash_en) {
ESP_EARLY_LOGE(TAG, "Octal Flash option selected, but EFUSE not configured!");
abort();
}
esp_opiflash_init();
spi_timing_flash_tuning();
#endif
bootloader_init_mem(); bootloader_init_mem();
#if CONFIG_SPIRAM_BOOT_INIT #if CONFIG_SPIRAM_BOOT_INIT
if (esp_spiram_init() != ESP_OK) { if (esp_spiram_init() != ESP_OK) {

Wyświetl plik

@ -61,6 +61,33 @@ menu "Serial flasher config"
The flasher tool sends a precompiled download stub first by default. That stub allows things The flasher tool sends a precompiled download stub first by default. That stub allows things
like compressed downloads and more. Usually you should not need to disable that feature like compressed downloads and more. Usually you should not need to disable that feature
config ESPTOOLPY_OCT_FLASH
depends on IDF_TARGET_ESP32S3
bool "Enable Octal Flash"
default n
choice ESPTOOLPY_FLASH_VENDOR
depends on ESPTOOLPY_OCT_FLASH
prompt "Select OPI Flash Vendor"
default ESPTOOLPY_FLASH_VENDOR_MXIC
config ESPTOOLPY_FLASH_VENDOR_MXIC
bool "MXIC OPI FLASH(MX25UM25645G)"
endchoice
choice ESPTOOLPY_FLASHMODE_OCT
depends on ESPTOOLPY_OCT_FLASH
prompt "Flash OPI mode"
default ESPTOOLPY_FLASHMODE_OPI_DTR
config ESPTOOLPY_FLASHMODE_OPI_STR
depends on ESPTOOLPY_FLASH_VENDOR_MXIC
bool "OPI_STR"
config ESPTOOLPY_FLASHMODE_OPI_DTR
depends on ESPTOOLPY_FLASH_VENDOR_MXIC
bool "OPI_DTR"
endchoice
choice ESPTOOLPY_FLASHMODE choice ESPTOOLPY_FLASHMODE
prompt "Flash SPI mode" prompt "Flash SPI mode"
default ESPTOOLPY_FLASHMODE_DIO default ESPTOOLPY_FLASHMODE_DIO
@ -101,6 +128,7 @@ menu "Serial flasher config"
bool "40 MHz" bool "40 MHz"
config ESPTOOLPY_FLASHFREQ_26M config ESPTOOLPY_FLASHFREQ_26M
bool "26 MHz" bool "26 MHz"
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3
config ESPTOOLPY_FLASHFREQ_20M config ESPTOOLPY_FLASHFREQ_20M
bool "20 MHz" bool "20 MHz"
endchoice endchoice

Wyświetl plik

@ -70,7 +70,7 @@
#define DR_REG_PCNT_BASE 0x60017000 #define DR_REG_PCNT_BASE 0x60017000
#define DR_REG_SLC_BASE 0x60018000 #define DR_REG_SLC_BASE 0x60018000
#define DR_REG_LEDC_BASE 0x60019000 #define DR_REG_LEDC_BASE 0x60019000
#define DR_REG_EFUSE_BASE 0x6001A000 #define DR_REG_EFUSE_BASE 0x60007000
#define DR_REG_NRX_BASE 0x6001CC00 #define DR_REG_NRX_BASE 0x6001CC00
#define DR_REG_BB_BASE 0x6001D000 #define DR_REG_BB_BASE 0x6001D000
#define DR_REG_PWM0_BASE 0x6001E000 #define DR_REG_PWM0_BASE 0x6001E000

Wyświetl plik

@ -77,6 +77,14 @@ else()
"${target}/spi_flash_rom_patch.c" "${target}/spi_flash_rom_patch.c"
) )
if(CONFIG_ESPTOOLPY_OCT_FLASH)
list(APPEND srcs "${target}/spi_flash_oct_flash_init.c")
endif()
if(CONFIG_IDF_TARGET_ESP32S3)
list(APPEND srcs "spi_flash_timing_tuning.c")
endif()
# New implementation after IDF v4.0 # New implementation after IDF v4.0
list(APPEND srcs list(APPEND srcs
"spi_flash_chip_drivers.c" "spi_flash_chip_drivers.c"

Wyświetl plik

@ -5,6 +5,8 @@ COMPONENT_PRIV_INCLUDEDIRS := include/spi_flash
COMPONENT_ADD_LDFRAGMENTS += linker.lf COMPONENT_ADD_LDFRAGMENTS += linker.lf
COMPONENT_OBJEXCLUDE := spi_flash_timing_tuning.o
ifdef IS_BOOTLOADER_BUILD ifdef IS_BOOTLOADER_BUILD
# Bootloader needs updated SPIUnlock from this file # Bootloader needs updated SPIUnlock from this file
COMPONENT_OBJS := esp32/spi_flash_rom_patch.o COMPONENT_OBJS := esp32/spi_flash_rom_patch.o

Wyświetl plik

@ -0,0 +1,184 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#if CONFIG_ESPTOOLPY_FLASH_VENDOR_MXIC
#if CONFIG_ESPTOOLPY_FLASHMODE_OPI_STR
#define OPI_CMD_FORMAT() { \
.rdid = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0x609f, \
.addr = 0, \
.addr_bit_len = 4*8, \
.dummy_bit_len = 4, \
.data_bit_len = 4 * 8, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.rdsr = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0xfa05, \
.addr = 0, \
.addr_bit_len = 4*8, \
.dummy_bit_len = 4, \
.data_bit_len = 1 * 8, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.wren = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0xf906, \
.addr = 0, \
.addr_bit_len = 0, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.se = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0xde21, \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 1, \
}, \
.be64k = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0x23dc, \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 1, \
}, \
.read = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0x13ec, \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 20, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.pp = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0xed12, \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 1, \
}, \
.cache_rd_cmd = { \
.addr_bit_len = 32, \
.dummy_bit_len = 20, \
.cmd = 0x13ec, \
.cmd_bit_len = 16, \
.var_dummy_en = 1, \
} \
}
#elif CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR
#define OPI_CMD_FORMAT() { \
.rdid = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0x609f, \
.addr = 0, \
.addr_bit_len = 4*8, \
.dummy_bit_len = 4*2, \
.data_bit_len = 4 * 8, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.rdsr = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0xfa05, \
.addr = 0, \
.addr_bit_len = 4*8, \
.dummy_bit_len = 4*2, \
.data_bit_len = 2 * 8, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.wren = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0xf906, \
.addr = 0, \
.addr_bit_len = 0, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.se = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0xde21, \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 1, \
}, \
.be64k = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0x23dc, \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 1, \
}, \
.read = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0x11ee, \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 20*2, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.pp = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = 0xed12, \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 1, \
}, \
.cache_rd_cmd = { \
.addr_bit_len = 32, \
.dummy_bit_len = 20*2, \
.cmd = 0x11ee, \
.cmd_bit_len = 16, \
.var_dummy_en = 1, \
} \
}
#endif
#endif

Wyświetl plik

@ -0,0 +1,194 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_rom_gpio.h"
#include "esp32s3/rom/gpio.h"
#include "esp32s3/rom/spi_flash.h"
#include "esp32s3/rom/opi_flash.h"
#include "spi_flash_private.h"
#include "soc/spi_mem_reg.h"
#if CONFIG_ESPTOOLPY_FLASH_VENDOR_MXIC
#include "opi_flash_cmd_format_mxic.h"
#endif
#define SPI_FLASH_SPI_CMD_WRCR2 0x72
#define SPI_FLASH_SPI_CMD_RDSR 0x05
#define SPI_FLASH_SPI_CMD_RDCR 0x15
#define SPI_FLASH_SPI_CMD_WRSRCR 0x01
#define SPI_FLASH_OCTCLK_IO 30
#define SPI_FLASH_OCTDQS_IO 37
#define SPI_FLASH_OCTD0_IO 32
#define SPI_FLASH_OCTD1_IO 31
#define SPI_FLASH_OCTD2_IO 28
#define SPI_FLASH_OCTD3_IO 27
#define SPI_FLASH_OCTD4_IO 33
#define SPI_FLASH_OCTD5_IO 34
#define SPI_FLASH_OCTD6_IO 35
#define SPI_FLASH_OCTD7_IO 36
#define SPI_FLASH_OCTCS_IO 29
#define SPI_FLASH_OCTCS1_IO 26
// default value is rom_default_spiflash_legacy_flash_func
extern const spiflash_legacy_funcs_t *rom_spiflash_legacy_funcs;
extern int SPI_write_enable(void *spi);
DRAM_ATTR const esp_rom_opiflash_def_t opiflash_cmd_def = OPI_CMD_FORMAT();
void s_set_flash_pin_drive_capability(uint8_t drv)
{
esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTCLK_IO, drv);
esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTDQS_IO, drv);
esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD0_IO, drv);
esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD1_IO, drv);
esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD2_IO, drv);
esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD3_IO, drv);
esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD4_IO, drv);
esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD5_IO, drv);
esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD6_IO, drv);
esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD7_IO, drv);
esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTCS_IO, drv);
esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTCS1_IO, drv);
}
static void s_register_rom_function(void)
{
static spiflash_legacy_funcs_t rom_func =
{
.read_sub_len = 32,
.write_sub_len = 32,
.unlock = esp_rom_opiflash_wait_idle,
.erase_block = esp_rom_opiflash_erase_block_64k,
.erase_sector = esp_rom_opiflash_erase_sector,
.read = esp_rom_opiflash_read,
.write = esp_rom_opiflash_write,
.wait_idle = esp_rom_opiflash_wait_idle,
.wren = esp_rom_opiflash_wren,
.erase_area = esp_rom_opiflash_erase_area,
};
rom_spiflash_legacy_funcs = &rom_func;
}
#if CONFIG_ESPTOOLPY_FLASH_VENDOR_MXIC
// 0x00: SPI; 0x01: STR OPI; 0x02: DTR OPI
static void s_set_flash_dtr_str_opi_mode(int spi_num, uint8_t val)
{
uint8_t cmd_len = 8;
int addr_bit_len = 32;
int dummy = 0;
int data_bit_len = 8;
SPI_write_enable(&g_rom_flashchip);
//SPI command, WRCR2
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE,
SPI_FLASH_SPI_CMD_WRCR2, cmd_len,
0, addr_bit_len,
dummy,
(uint8_t *)&val, data_bit_len,
NULL, 0,
ESP_ROM_OPIFLASH_SEL_CS0,
false);
}
//To set the output driver strength
static void s_set_flash_ouput_driver_strength(int spi_num, uint8_t strength)
{
uint16_t reg_val = 0;
uint8_t sr_reg_val = 0;
uint8_t cr_reg_val = 0;
uint8_t cmd_len = 8;
uint32_t addr = 0;
int addr_bit_len = 0;
int dummy = 0;
int data_bit_len = 8;
//Read
//SPI command, RDSR
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE,
SPI_FLASH_SPI_CMD_RDSR, cmd_len,
addr, addr_bit_len,
dummy,
NULL, 0,
(uint8_t*)&sr_reg_val, data_bit_len,
ESP_ROM_OPIFLASH_SEL_CS0,
false);
//SPI command, RDCR
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE,
SPI_FLASH_SPI_CMD_RDCR, cmd_len,
addr, addr_bit_len,
dummy,
NULL, 0,
(uint8_t*)&cr_reg_val, data_bit_len,
ESP_ROM_OPIFLASH_SEL_CS0,
false);
//Modify
reg_val = (((cr_reg_val & 0xf8) | strength) << 8) | sr_reg_val;
//Write
//SPI command, WRSR/WRCR
data_bit_len = 16;
SPI_write_enable(&g_rom_flashchip);
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE,
SPI_FLASH_SPI_CMD_WRSRCR, cmd_len,
addr, addr_bit_len,
dummy,
(uint8_t*)&reg_val, data_bit_len,
NULL, 0,
ESP_ROM_OPIFLASH_SEL_CS0,
false);
}
static void s_flash_init_mxic(esp_rom_spiflash_read_mode_t mode)
{
esp_rom_opiflash_legacy_driver_init(&opiflash_cmd_def);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
// increase flash output driver strength
s_set_flash_ouput_driver_strength(1, 7);
// STR/DTR specific setting
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
#if CONFIG_ESPTOOLPY_FLASHMODE_OPI_STR
s_set_flash_pin_drive_capability(1);
s_set_flash_dtr_str_opi_mode(1, 0x1);
esp_rom_opiflash_cache_mode_config(mode, &rom_opiflash_cmd_def->cache_rd_cmd);
esp_rom_spi_set_dtr_swap_mode(0, false, false);
esp_rom_spi_set_dtr_swap_mode(1, false, false);
#else //CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR
s_set_flash_pin_drive_capability(3);
s_set_flash_dtr_str_opi_mode(1, 0x2);
esp_rom_opiflash_cache_mode_config(mode, &rom_opiflash_cmd_def->cache_rd_cmd);
esp_rom_spi_set_dtr_swap_mode(0, true, true);
esp_rom_spi_set_dtr_swap_mode(1, true, true);
#endif
s_register_rom_function();
esp_rom_opiflash_wait_idle();
}
#endif // #if CONFIG_FLASH_VENDOR_XXX
esp_err_t esp_opiflash_init(void)
{
esp_rom_spiflash_read_mode_t mode;
#if CONFIG_ESPTOOLPY_FLASHMODE_OPI_STR
mode = ESP_ROM_SPIFLASH_OPI_STR_MODE;
#elif CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR
mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
#else
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
#endif
#if CONFIG_ESPTOOLPY_FLASH_VENDOR_MXIC
s_flash_init_mxic(mode);
#else
abort();
#endif
return ESP_OK;
}

Wyświetl plik

@ -1,28 +1,6 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
// Licensed under the Apache License, Version 2.0 (the "License"); *
// you may not use this file except in compliance with the License. * SPDX-License-Identifier: Apache-2.0
// You may obtain a copy of the License at */
// We keep this file here only for future use
// 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.
#include "sdkconfig.h"
#include "esp32s3/rom/spi_flash.h"
#include "soc/spi_periph.h"
#include "spi_flash_defs.h"
#define SPI_IDX 1
extern esp_rom_spiflash_chip_t g_rom_spiflash_chip;
esp_rom_spiflash_result_t esp_rom_spiflash_write_disable(void)
{
REG_WRITE(SPI_MEM_CMD_REG(SPI_IDX), SPI_MEM_FLASH_WRDI);
while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0);
return ESP_ROM_SPIFLASH_RESULT_OK;
}

Wyświetl plik

@ -37,6 +37,7 @@
#include "esp32s2/rom/spi_flash.h" #include "esp32s2/rom/spi_flash.h"
#include "esp32s2/clk.h" #include "esp32s2/clk.h"
#elif CONFIG_IDF_TARGET_ESP32S3 #elif CONFIG_IDF_TARGET_ESP32S3
#include "soc/spi_mem_reg.h"
#include "esp32s3/rom/spi_flash.h" #include "esp32s3/rom/spi_flash.h"
#include "esp32s3/rom/cache.h" #include "esp32s3/rom/cache.h"
#include "esp32s3/clk.h" #include "esp32s3/clk.h"
@ -50,6 +51,7 @@
#include "cache_utils.h" #include "cache_utils.h"
#include "esp_flash.h" #include "esp_flash.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "spi_flash_private.h"
esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_addr, const void *src, size_t size); esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_addr, const void *src, size_t size);
@ -876,3 +878,16 @@ void spi_flash_dump_counters(void)
// TODO esp32s2: Remove once ESP32-S2 & later chips has new SPI Flash API support // TODO esp32s2: Remove once ESP32-S2 & later chips has new SPI Flash API support
esp_flash_t *esp_flash_default_chip = NULL; esp_flash_t *esp_flash_default_chip = NULL;
#endif #endif
void IRAM_ATTR spi_flash_set_rom_required_regs(void)
{
#if CONFIG_ESPTOOLPY_OCT_FLASH
//Disable the variable dummy mode when doing timing tuning
CLEAR_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY);
/**
* STR /DTR mode setting is done every time when `esp_rom_opiflash_exec_cmd` is called
*
* Add any registers that are not set in ROM SPI flash functions here in the future
*/
#endif
}

Wyświetl plik

@ -0,0 +1,67 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* Currently the MSPI timing tuning related APIs are designed to be private.
* Because:
* 1. now we don't split SPI0 and SPI1, we don't have a component for SPI0, including PSRAM, Cache, etc..
* 2. SPI0 and SPI1 are strongly coupling.
*
* In the future, we may consider creating a component for SPI0, and spi_flash component will only work on SPI1 (and it
* can rely on SPI0). Therefore, we can put these APIs there.
*
*/
#pragma once
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/spi_flash.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Register ROM functions and init flash device registers to make use of octal flash
*/
esp_err_t esp_opiflash_init(void);
/**
* @brief Make MSPI work under 20Mhz
*/
void spi_timing_enter_mspi_low_speed_mode(void);
/**
* @brief Make MSPI work under the frequency as users set
*/
void spi_timing_enter_mspi_high_speed_mode(void);
/**
* @brief Tune MSPI flash timing to make it work under high frequency
*/
void spi_timing_flash_tuning(void);
/**
* @brief Tune MSPI psram timing to make it work under high frequency
*/
void spi_timing_psram_tuning(void);
/**
* @brief Set SPI1 registers to make ROM functions work
* @note This function is used for setting SPI1 registers to the state that ROM SPI functions work
*/
void spi_flash_set_rom_required_regs(void);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -10,4 +10,10 @@ entries:
memspi_host_driver (noflash) memspi_host_driver (noflash)
if IDF_TARGET_ESP32 = n: if IDF_TARGET_ESP32 = n:
spi_flash_chip_boya (noflash) spi_flash_chip_boya (noflash)
if IDF_TARGET_ESP32S3 = y:
spi_flash_timing_tuning (noflash)
if IDF_TARGET_ESP32S3 = y && ESPTOOLPY_OCT_FLASH = y:
spi_flash_oct_flash_init (noflash)

Wyświetl plik

@ -0,0 +1,348 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_types.h"
#include "esp_log.h"
#include "soc/spi_mem_reg.h"
#include "spi_flash_private.h"
#if CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/spi_timing_config.h"
#endif
static spi_timing_tuning_param_t s_flash_best_timing_tuning_config;
static spi_timing_tuning_param_t s_psram_best_timing_tuning_config;
static spi_timing_config_core_clock_t get_mspi_core_clock(void)
{
return spi_timing_config_get_core_clock();
}
static uint32_t get_flash_clock_divider(void)
{
#if CONFIG_ESPTOOLPY_FLASHFREQ_20M
return SPI_TIMING_CORE_CLOCK_MHZ / 20;
#elif CONFIG_ESPTOOLPY_FLASHFREQ_40M
return SPI_TIMING_CORE_CLOCK_MHZ / 40;
#elif CONFIG_ESPTOOLPY_FLASHFREQ_80M
return SPI_TIMING_CORE_CLOCK_MHZ / 80;
#elif CONFIG_ESPTOOLPY_FLASHFREQ_120M
return SPI_TIMING_CORE_CLOCK_MHZ / 120;
#else
abort();
#endif
}
static uint32_t get_psram_clock_divider(void)
{
#if CONFIG_SPIRAM_SPEED_40M
return SPI_TIMING_CORE_CLOCK_MHZ / 40;
#elif CONFIG_SPIRAM_SPEED_80M
return SPI_TIMING_CORE_CLOCK_MHZ / 80;
#else
//Will enter this branch only if PSRAM is not enable
return 0;
#endif
}
#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING
/**
* Set timing tuning regs, in order to get successful sample points
*/
static void init_spi1_for_tuning(bool is_flash)
{
//Get required core clock and module clock settings
spi_timing_config_core_clock_t core_clock = get_mspi_core_clock();
//Set SPI1 core clock. SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
spi_timing_config_set_core_clock(0, core_clock);
//Set SPI1 module clock as required
if (is_flash) {
uint32_t flash_div = get_flash_clock_divider();
spi_timing_config_set_flash_clock(1, flash_div);
//Power on HCLK
REG_SET_BIT(SPI_MEM_TIMING_CALI_REG(0), SPI_MEM_TIMING_CLK_ENA);
} else {
//We use SPI1 Flash to tune PSRAM, PSRAM timing related regs do nothing on SPI1
uint32_t psram_div = get_psram_clock_divider();
spi_timing_config_set_flash_clock(1, psram_div);
//Power on HCLK
REG_SET_BIT(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(0), SPI_MEM_SPI_SMEM_TIMING_CLK_ENA);
}
}
/**
* We use different SPI1 timing tuning config to read data to see if current MSPI sampling is successful.
* The sampling result will be stored in an array. In this array, successful item will be 1, failed item will be 0.
*/
static void sweep_for_success_sample_points(uint8_t *reference_data, const spi_timing_config_t *config, bool is_flash, uint8_t *out_array)
{
uint32_t config_idx = 0;
uint8_t read_data[SPI_TIMING_TEST_DATA_LEN] = {0};
for (config_idx = 0; config_idx < config->available_config_num; config_idx++) {
memset(read_data, 0, SPI_TIMING_TEST_DATA_LEN);
#if SPI_TIMING_FLASH_NEEDS_TUNING
if (is_flash) {
/**
* 1. SPI_MEM_DINx_MODE(1), SPI_MEM_DINx_NUM(1) are meaningless
* SPI0 and SPI1 share the SPI_MEM_DINx_MODE(0), SPI_MEM_DINx_NUM(0) for FLASH timing tuning
* 2. We use SPI1 to get the best Flash timing tuning (mode and num) config
*/
spi_timing_config_flash_set_din_mode_num(0, config->tuning_config_table[config_idx].spi_din_mode, config->tuning_config_table[config_idx].spi_din_num);
spi_timing_config_flash_set_extra_dummy(1, config->tuning_config_table[config_idx].extra_dummy_len);
spi_timing_config_flash_read_data(1, read_data, SPI_TIMING_FLASH_TEST_DATA_ADDR, sizeof(read_data));
}
#endif
#if SPI_TIMING_PSRAM_NEEDS_TUNING
if (!is_flash) {
/**
* 1. SPI_MEM_SPI_SMEM_DINx_MODE(1), SPI_MEM_SPI_SMEM_DINx_NUM(1) are meaningless
* SPI0 and SPI1 share the SPI_MEM_SPI_SMEM_DINx_MODE(0), SPI_MEM_SPI_SMEM_DINx_NUM(0) for PSRAM timing tuning
* 2. We use SPI1 to get the best PSRAM timing tuning (mode and num) config
*/
spi_timing_config_psram_set_din_mode_num(0, config->tuning_config_table[config_idx].spi_din_mode, config->tuning_config_table[config_idx].spi_din_num);
spi_timing_config_flash_set_extra_dummy(1, config->tuning_config_table[config_idx].extra_dummy_len);
spi_timing_config_psram_read_data(1, read_data, SPI_TIMING_PSRAM_TEST_DATA_ADDR, SPI_TIMING_TEST_DATA_LEN);
}
#endif
if (memcmp(reference_data, read_data, sizeof(read_data)) == 0) {
out_array[config_idx] = 1;
}
}
}
/**
* Find consecutive successful sampling points.
* e.g. array: {1, 1, 0, 0, 1, 1, 1, 0}
* out_length: 3
* outout_end_index: 6
*/
static void find_max_consecutive_success_points(uint8_t *array, uint32_t size, uint32_t *out_length, uint32_t *out_end_index)
{
uint32_t max = 0;
uint32_t match_num = 0;
uint32_t i = 0;
uint32_t end = 0;
while (i < size) {
if (array[i]) {
match_num++;
} else {
if (match_num > max) {
max = match_num;
end = i - 1;
}
match_num = 0;
}
i++;
}
*out_length = match_num > max ? match_num : max;
*out_end_index = match_num == size ? size : end;
}
static void select_best_tuning_config(spi_timing_config_t *config, uint32_t length, uint32_t end, bool is_flash)
{
uint32_t best_point;
if (length >= 3) {
best_point = end - length / 2;
} else {
best_point = config->default_config_id;
}
if (is_flash) {
s_flash_best_timing_tuning_config = config->tuning_config_table[best_point];
} else {
s_psram_best_timing_tuning_config = config->tuning_config_table[best_point];
}
}
static void do_tuning(uint8_t *reference_data, spi_timing_config_t *timing_config, bool is_flash)
{
/**
* We use SPI1 to tune the FLASH timing:
* 1. Get all SPI1 sampling results.
* 2. Find the longest consecutive successful sampling points from the result above.
* 3. The middle one will be the best sampling point.
*/
uint32_t consecutive_length = 0;
uint32_t last_success_point = 0;
uint8_t sample_result[SPI_TIMING_CONFIG_NUM_DEFAULT] = {0};
init_spi1_for_tuning(is_flash);
sweep_for_success_sample_points(reference_data, timing_config, is_flash, sample_result);
find_max_consecutive_success_points(sample_result, SPI_TIMING_CONFIG_NUM_DEFAULT, &consecutive_length, &last_success_point);
select_best_tuning_config(timing_config, consecutive_length, last_success_point, is_flash);
}
#endif //#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING
//------------------------------------------FLASH Timing Tuning----------------------------------------//
#if SPI_TIMING_FLASH_NEEDS_TUNING
static void get_flash_tuning_configs(spi_timing_config_t *config)
{
#if SPI_TIMING_FLASH_DTR_MODE
#define FLASH_MODE DTR_MODE
#else //SPI_TIMING_FLASH_STR_MODE
#define FLASH_MODE STR_MODE
#endif
#if CONFIG_ESPTOOLPY_FLASHFREQ_20M
*config = SPI_TIMING_FLASH_GET_TUNING_CONFIG(SPI_TIMING_CORE_CLOCK_MHZ, 20, FLASH_MODE);
#elif CONFIG_ESPTOOLPY_FLASHFREQ_40M
*config = SPI_TIMING_FLASH_GET_TUNING_CONFIG(SPI_TIMING_CORE_CLOCK_MHZ, 40, FLASH_MODE);
#elif CONFIG_ESPTOOLPY_FLASHFREQ_80M
*config = SPI_TIMING_FLASH_GET_TUNING_CONFIG(SPI_TIMING_CORE_CLOCK_MHZ, 80, FLASH_MODE);
#elif CONFIG_ESPTOOLPY_FLASHFREQ_120M
*config = SPI_TIMING_FLASH_GET_TUNING_CONFIG(SPI_TIMING_CORE_CLOCK_MHZ, 120, FLASH_MODE);
#endif
#undef FLASH_MODE
}
void spi_timing_flash_tuning(void)
{
/**
* set SPI01 related regs to 20mhz configuration, to get reference data from FLASH
* see detailed comments in this function (`spi_timing_enter_mspi_low_speed_mode)
*/
spi_timing_enter_mspi_low_speed_mode();
//Disable the variable dummy mode when doing timing tuning
CLEAR_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY); //GD flash will read error in variable mode with 20MHz
uint8_t reference_data[SPI_TIMING_TEST_DATA_LEN] = {0};
spi_timing_config_flash_read_data(1, reference_data, SPI_TIMING_FLASH_TEST_DATA_ADDR, sizeof(reference_data));
spi_timing_config_t timing_configs = {0};
get_flash_tuning_configs(&timing_configs);
do_tuning(reference_data, &timing_configs, true);
spi_timing_enter_mspi_high_speed_mode();
}
#else
void spi_timing_flash_tuning(void)
{
//Empty function for compatibility, therefore upper layer won't need to know that FLASH in which operation mode and frequency config needs to be tuned
}
#endif //SPI_TIMING_FLASH_NEEDS_TUNING
//------------------------------------------PSRAM Timing Tuning----------------------------------------//
#if SPI_TIMING_PSRAM_NEEDS_TUNING
static void get_psram_tuning_configs(spi_timing_config_t *config)
{
#if SPI_TIMING_PSRAM_DTR_MODE
#define PSRAM_MODE DTR_MODE
#else //SPI_TIMING_PSRAM_STR_MODE
#define PSRAM_MODE STR_MODE
#endif
#if CONFIG_SPIRAM_SPEED_40M
*config = SPI_TIMING_PSRAM_GET_TUNING_CONFIG(SPI_TIMING_CORE_CLOCK_MHZ, 40, PSRAM_MODE);
#elif CONFIG_SPIRAM_SPEED_80M
*config = SPI_TIMING_PSRAM_GET_TUNING_CONFIG(SPI_TIMING_CORE_CLOCK_MHZ, 80, PSRAM_MODE);
#endif
#undef PSRAM_MODE
}
void spi_timing_psram_tuning(void)
{
/**
* set SPI01 related regs to 20mhz configuration, to write reference data to PSRAM
* see detailed comments in this function (`spi_timing_enter_mspi_low_speed_mode)
*/
spi_timing_enter_mspi_low_speed_mode();
// write data into psram, used to do timing tuning test.
uint8_t reference_data[SPI_TIMING_TEST_DATA_LEN];
for (int i=0; i < SPI_TIMING_TEST_DATA_LEN/4; i++) {
((uint32_t *)reference_data)[i] = 0xa5ff005a;
}
spi_timing_config_psram_write_data(1, reference_data, SPI_TIMING_PSRAM_TEST_DATA_ADDR, SPI_TIMING_TEST_DATA_LEN);
spi_timing_config_t timing_configs = {0};
get_psram_tuning_configs(&timing_configs);
//Disable the variable dummy mode when doing timing tuning
CLEAR_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY);
//Get required config, and set them to PSRAM related registers
do_tuning(reference_data, &timing_configs, false);
spi_timing_enter_mspi_high_speed_mode();
}
#else
void spi_timing_psram_tuning(void)
{
//Empty function for compatibility, therefore upper layer won't need to know that FLASH in which operation mode and frequency config needs to be tuned
}
#endif //SPI_TIMING_PSRAM_NEEDS_TUNING
//---------------------------------------------APIs to make SPI0 and SPI1 FLASH work for high/low freq-------------------------------//
static void clear_timing_tuning_regs(void)
{
spi_timing_config_flash_set_din_mode_num(0, 0, 0); //SPI0 and SPI1 share the registers for flash din mode and num setting, so we only set SPI0's reg
spi_timing_config_flash_set_extra_dummy(0, 0);
spi_timing_config_flash_set_extra_dummy(1, 0);
}
void spi_timing_enter_mspi_low_speed_mode(void)
{
/**
* Here we are going to slow the SPI1 frequency to 20Mhz, so we need to set SPI1 din_num and din_mode regs.
*
* Because SPI0 and SPI1 share the din_num and din_mode regs, so if we clear SPI1 din_num and din_mode to
* 0, if the SPI0 flash module clock is still in high freq, it may not work correctly.
*
* Therefore, here we need to slow both the SPI0 and SPI1 and related timing tuning regs to 20Mhz configuration.
*/
//Switch SPI1 and SPI0 clock as 20MHz, set its SPIMEM core clock as 80M and set clock division as 4
spi_timing_config_set_core_clock(0, SPI_TIMING_CONFIG_CORE_CLOCK_80M); //SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
spi_timing_config_set_flash_clock(1, 4);
spi_timing_config_set_flash_clock(0, 4);
clear_timing_tuning_regs();
}
static void set_timing_tuning_regs_as_required(void)
{
//SPI0 and SPI1 share the registers for flash din mode and num setting, so we only set SPI0's reg
spi_timing_config_flash_set_din_mode_num(0, s_flash_best_timing_tuning_config.spi_din_mode, s_flash_best_timing_tuning_config.spi_din_num);
spi_timing_config_flash_set_extra_dummy(0, s_flash_best_timing_tuning_config.extra_dummy_len);
spi_timing_config_flash_set_extra_dummy(1, s_flash_best_timing_tuning_config.extra_dummy_len);
spi_timing_config_psram_set_din_mode_num(0, s_psram_best_timing_tuning_config.spi_din_mode, s_psram_best_timing_tuning_config.spi_din_num);
spi_timing_config_psram_set_extra_dummy(0, s_psram_best_timing_tuning_config.extra_dummy_len);
}
/**
* Set SPI0 and SPI1 flash module clock, din_num, din_mode and extra dummy,
* according to the configuration got from timing tuning function (`calculate_best_flash_tuning_config`).
*
* This function should always be called after `spi_timing_flash_tuning` or `calculate_best_flash_tuning_config`
*/
void spi_timing_enter_mspi_high_speed_mode(void)
{
spi_timing_config_core_clock_t core_clock = get_mspi_core_clock();
uint32_t flash_div = get_flash_clock_divider();
uint32_t psram_div = get_psram_clock_divider();
//Set SPI01 core clock
spi_timing_config_set_core_clock(0, core_clock); //SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
//Set FLASH module clock
spi_timing_config_set_flash_clock(0, flash_div);
spi_timing_config_set_flash_clock(1, flash_div);
//Set PSRAM module clock
spi_timing_config_set_psram_clock(0, psram_div);
set_timing_tuning_regs_as_required();
}

Wyświetl plik

@ -148,3 +148,4 @@ components/ulp/include/esp32s2/ulp_riscv.h
components/lwip/include/apps/sntp/sntp.h components/lwip/include/apps/sntp/sntp.h
components/mbedtls/esp_crt_bundle/include/esp_crt_bundle.h components/mbedtls/esp_crt_bundle/include/esp_crt_bundle.h
components/wifi_provisioning/include/wifi_provisioning/scheme_softap.h components/wifi_provisioning/include/wifi_provisioning/scheme_softap.h
components/spi_flash/include/spi_flash_private.h