kopia lustrzana https://github.com/espressif/esp-idf
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!12946pull/7307/head
commit
afc2bc94b3
|
@ -21,6 +21,9 @@
|
|||
#define FLASH_IO_MATRIX_DUMMY_40M 0
|
||||
#define FLASH_IO_MATRIX_DUMMY_80M 0
|
||||
#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()
|
||||
{
|
||||
|
@ -30,12 +33,18 @@ void bootloader_flash_update_id()
|
|||
|
||||
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_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_SETUP_TIME_V, 0, 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_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_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, FLASH_CS_SETUP_TIME, SPI_MEM_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);
|
||||
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)
|
||||
|
|
|
@ -16,7 +16,7 @@ else()
|
|||
"esp_crypto_lock.c"
|
||||
"memprot.c"
|
||||
"spiram.c"
|
||||
"spiram_psram.c")
|
||||
"spi_timing_config.c")
|
||||
set(include_dirs "include")
|
||||
|
||||
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
|
||||
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}"
|
||||
INCLUDE_DIRS "${include_dirs}"
|
||||
REQUIRES "${requires}"
|
||||
|
|
|
@ -169,8 +169,19 @@ menu "ESP32S3-Specific"
|
|||
menu "SPI RAM config"
|
||||
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
|
||||
prompt "Type of SPI RAM chip in use"
|
||||
prompt "Type of SPIRAM chip in use"
|
||||
default SPIRAM_TYPE_AUTO
|
||||
|
||||
config SPIRAM_TYPE_AUTO
|
||||
|
@ -178,12 +189,14 @@ menu "ESP32S3-Specific"
|
|||
|
||||
config SPIRAM_TYPE_ESPPSRAM16
|
||||
bool "ESP-PSRAM16 or APS1604"
|
||||
depends on SPIRAM_MODE_QUAD
|
||||
|
||||
config SPIRAM_TYPE_ESPPSRAM32
|
||||
bool "ESP-PSRAM32 or IS25WP032"
|
||||
depends on SPIRAM_MODE_QUAD
|
||||
|
||||
config SPIRAM_TYPE_ESPPSRAM64
|
||||
bool "ESP-PSRAM64 or LY68L6400"
|
||||
bool "ESP-PSRAM64 , LY68L6400 or APS6408"
|
||||
endchoice
|
||||
|
||||
config SPIRAM_SIZE
|
||||
|
@ -192,6 +205,8 @@ menu "ESP32S3-Specific"
|
|||
default 2097152 if SPIRAM_TYPE_ESPPSRAM16
|
||||
default 4194304 if SPIRAM_TYPE_ESPPSRAM32
|
||||
default 8388608 if SPIRAM_TYPE_ESPPSRAM64
|
||||
default 16777216 if SPIRAM_TYPE_ESPPSRAM128
|
||||
default 33554432 if SPIRAM_TYPE_ESPPSRAM256
|
||||
default 0
|
||||
|
||||
menu "PSRAM Clock and CS IO for ESP32S3"
|
||||
|
@ -235,10 +250,6 @@ menu "ESP32S3-Specific"
|
|||
bool "80MHz clock speed"
|
||||
config SPIRAM_SPEED_40M
|
||||
bool "40Mhz clock speed"
|
||||
config SPIRAM_SPEED_26M
|
||||
bool "26Mhz clock speed"
|
||||
config SPIRAM_SPEED_20M
|
||||
bool "20Mhz clock speed"
|
||||
endchoice
|
||||
|
||||
# insert non-chip-specific items here
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -50,7 +50,7 @@ static const char *TAG = "spiram";
|
|||
#define PSRAM_SPEED PSRAM_CACHE_S20M
|
||||
#endif
|
||||
|
||||
static bool spiram_inited = false;
|
||||
static bool s_spiram_inited = false;
|
||||
|
||||
|
||||
/*
|
||||
|
@ -245,8 +245,7 @@ esp_err_t esp_spiram_init(void)
|
|||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
spiram_inited = true;
|
||||
s_spiram_inited = true;
|
||||
#if (CONFIG_SPIRAM_SIZE != -1)
|
||||
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);
|
||||
|
@ -296,7 +295,7 @@ esp_err_t esp_spiram_reserve_dma_pool(size_t size)
|
|||
|
||||
size_t esp_spiram_get_size(void)
|
||||
{
|
||||
if (!spiram_inited) {
|
||||
if (!s_spiram_inited) {
|
||||
ESP_EARLY_LOGE(TAG, "SPI RAM not initialized");
|
||||
abort();
|
||||
}
|
||||
|
@ -311,6 +310,12 @@ size_t esp_spiram_get_size(void)
|
|||
if (size == PSRAM_SIZE_64MBITS) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
#include "driver/periph_ctrl.h"
|
||||
#include "bootloader_common.h"
|
||||
|
||||
#if CONFIG_SPIRAM
|
||||
#if CONFIG_SPIRAM_MODE_QUAD
|
||||
#include "soc/rtc.h"
|
||||
|
||||
static const char* TAG = "psram";
|
||||
|
|
|
@ -28,9 +28,11 @@ typedef enum {
|
|||
} psram_cache_mode_t;
|
||||
|
||||
typedef enum {
|
||||
PSRAM_SIZE_16MBITS = 0,
|
||||
PSRAM_SIZE_32MBITS = 1,
|
||||
PSRAM_SIZE_64MBITS = 2,
|
||||
PSRAM_SIZE_16MBITS = 0,
|
||||
PSRAM_SIZE_32MBITS = 1,
|
||||
PSRAM_SIZE_64MBITS = 2,
|
||||
PSRAM_SIZE_128MBITS = 3,
|
||||
PSRAM_SIZE_256MBITS = 4,
|
||||
PSRAM_SIZE_MAX,
|
||||
} psram_size_t;
|
||||
|
||||
|
|
|
@ -128,6 +128,7 @@ PROVIDE( esp_rom_opiflash_write = 0x40000930 );
|
|||
PROVIDE( esp_rom_spi_set_dtr_swap_mode = 0x4000093c );
|
||||
PROVIDE( esp_rom_opiflash_exit_continuous_read_mode = 0x40000948 );
|
||||
PROVIDE( esp_rom_opiflash_legacy_driver_init = 0x40000954 );
|
||||
PROVIDE( esp_rom_opiflash_read_raw = 0x4004d9d4);
|
||||
/* Data (.data, .bss, .rodata) */
|
||||
PROVIDE( rom_opiflash_cmd_def = 0x3fcefff4 );
|
||||
PROVIDE( rom_spi_usr_cmd_legacy_funcs = 0x3fcefff0 );
|
||||
|
|
|
@ -8,12 +8,46 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "spi_flash.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 cmdBitLen; /*!< Command byte length*/
|
||||
|
@ -40,7 +74,6 @@ typedef struct {
|
|||
#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 ESP_ROM_SPIFLASH_BP_MASK_ISSI (BIT7 | BIT5 | BIT4 | BIT3 | BIT2)
|
||||
|
||||
#define FLASH_OP_MODE_RDCMD_DOUT 0x3B
|
||||
#define ESP_ROM_FLASH_SECTOR_SIZE 0x1000
|
||||
|
@ -112,8 +145,14 @@ typedef struct {
|
|||
#define ROM_FLASH_CMD_EN4B_GD 0xB7
|
||||
#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
|
||||
* @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);
|
||||
|
||||
#if 0
|
||||
// MX25UM25645G opi flash interface
|
||||
/**
|
||||
* @brief To execute a flash operation command
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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)
|
||||
* @param spi_num spi port
|
||||
* @param mode Flash Operation 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(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
|
||||
* @param spi_num spi port
|
||||
* @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
|
||||
* @note command format would be defined in initialization
|
||||
* @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)
|
||||
* @param spi_num spi port
|
||||
* @param address the block address to be erased
|
||||
* @param mode Flash operation mode
|
||||
* @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_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)
|
||||
* @param spi_num spi port
|
||||
* @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
|
||||
* @param mode flash operation mode
|
||||
* @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)
|
||||
* @param spi_num spi port
|
||||
* @param mode flash operation mode
|
||||
* @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(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)
|
||||
* @param spi_num spi port
|
||||
* @param mode flash operation mode
|
||||
* @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(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)
|
||||
* @param spi_num spi port
|
||||
* @param cur_mode current operation mode
|
||||
* @param target the target operation mode to be set
|
||||
* @brief send WREN command
|
||||
* @note command format would be defined in initialization
|
||||
* @param arg not used, set to NULL
|
||||
* @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);
|
||||
#endif
|
||||
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
|
||||
}
|
||||
|
|
|
@ -121,7 +121,12 @@ typedef enum {
|
|||
ESP_ROM_SPIFLASH_DIO_MODE,
|
||||
ESP_ROM_SPIFLASH_DOUT_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;
|
||||
|
||||
typedef enum {
|
||||
|
@ -148,6 +153,34 @@ typedef struct {
|
|||
uint16_t data;
|
||||
} 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.
|
||||
|
@ -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
|
||||
*/
|
||||
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 {
|
||||
esp_rom_spiflash_chip_t chip;
|
||||
uint8_t dummy_len_plus[3];
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include "soc/assist_debug_reg.h"
|
||||
#include "soc/cache_memory.h"
|
||||
#include "soc/system_reg.h"
|
||||
#include "esp32s3/rom/opi_flash.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rtc.h"
|
||||
#include "esp32c3/rom/cache.h"
|
||||
|
@ -62,6 +63,7 @@
|
|||
#include "esp32c3/memprot.h"
|
||||
#endif
|
||||
|
||||
#include "spi_flash_private.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "esp_private/crosscore_int.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);
|
||||
#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();
|
||||
#if CONFIG_SPIRAM_BOOT_INIT
|
||||
if (esp_spiram_init() != ESP_OK) {
|
||||
|
|
|
@ -61,6 +61,33 @@ menu "Serial flasher config"
|
|||
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
|
||||
|
||||
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
|
||||
prompt "Flash SPI mode"
|
||||
default ESPTOOLPY_FLASHMODE_DIO
|
||||
|
@ -101,6 +128,7 @@ menu "Serial flasher config"
|
|||
bool "40 MHz"
|
||||
config ESPTOOLPY_FLASHFREQ_26M
|
||||
bool "26 MHz"
|
||||
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3
|
||||
config ESPTOOLPY_FLASHFREQ_20M
|
||||
bool "20 MHz"
|
||||
endchoice
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
#define DR_REG_PCNT_BASE 0x60017000
|
||||
#define DR_REG_SLC_BASE 0x60018000
|
||||
#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_BB_BASE 0x6001D000
|
||||
#define DR_REG_PWM0_BASE 0x6001E000
|
||||
|
|
|
@ -77,6 +77,14 @@ else()
|
|||
"${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
|
||||
list(APPEND srcs
|
||||
"spi_flash_chip_drivers.c"
|
||||
|
|
|
@ -5,6 +5,8 @@ COMPONENT_PRIV_INCLUDEDIRS := include/spi_flash
|
|||
|
||||
COMPONENT_ADD_LDFRAGMENTS += linker.lf
|
||||
|
||||
COMPONENT_OBJEXCLUDE := spi_flash_timing_tuning.o
|
||||
|
||||
ifdef IS_BOOTLOADER_BUILD
|
||||
# Bootloader needs updated SPIUnlock from this file
|
||||
COMPONENT_OBJS := esp32/spi_flash_rom_patch.o
|
||||
|
|
|
@ -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
|
|
@ -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*)®_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;
|
||||
}
|
|
@ -1,28 +1,6 @@
|
|||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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.
|
||||
#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;
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
// We keep this file here only for future use
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "esp32s2/rom/spi_flash.h"
|
||||
#include "esp32s2/clk.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "soc/spi_mem_reg.h"
|
||||
#include "esp32s3/rom/spi_flash.h"
|
||||
#include "esp32s3/rom/cache.h"
|
||||
#include "esp32s3/clk.h"
|
||||
|
@ -50,6 +51,7 @@
|
|||
#include "cache_utils.h"
|
||||
#include "esp_flash.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);
|
||||
|
||||
|
@ -876,3 +878,16 @@ void spi_flash_dump_counters(void)
|
|||
// TODO esp32s2: Remove once ESP32-S2 & later chips has new SPI Flash API support
|
||||
esp_flash_t *esp_flash_default_chip = NULL;
|
||||
#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
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -10,4 +10,10 @@ entries:
|
|||
memspi_host_driver (noflash)
|
||||
|
||||
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)
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -148,3 +148,4 @@ components/ulp/include/esp32s2/ulp_riscv.h
|
|||
components/lwip/include/apps/sntp/sntp.h
|
||||
components/mbedtls/esp_crt_bundle/include/esp_crt_bundle.h
|
||||
components/wifi_provisioning/include/wifi_provisioning/scheme_softap.h
|
||||
components/spi_flash/include/spi_flash_private.h
|
||||
|
|
Ładowanie…
Reference in New Issue