Merge branch 'bugfix/fix_psram_eid_v3.0' into 'release/v3.0'

psram: fix psram eid (backport v3.0)

See merge request idf/esp-idf!3463
This commit is contained in:
Angus Gratton 2018-10-12 11:41:13 +08:00
commit 6313ea0088
5 changed files with 217 additions and 111 deletions

View File

@ -18,8 +18,23 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include "esp_err.h" #include "esp_err.h"
typedef enum {
ESP_SPIRAM_SIZE_32MBITS = 0, /*!< SPI RAM size is 32 MBits */
ESP_SPIRAM_SIZE_64MBITS = 1, /*!< SPI RAM size is 64 MBits */
ESP_SPIRAM_SIZE_INVALID, /*!< SPI RAM size is invalid */
} esp_spiram_size_t;
/**
* @brief get SPI RAM size
* @return
* - ESP_SPIRAM_SIZE_INVALID if SPI RAM not enabled or not valid
* - SPI RAM size
*/
esp_spiram_size_t esp_spiram_get_chip_size();
/** /**
* @brief Initialize spiram interface/hardware. Normally called from cpu_start.c. * @brief Initialize spiram interface/hardware. Normally called from cpu_start.c.
* *

View File

@ -117,6 +117,8 @@ extern "C" {
#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 FLASH_ID_GD25LQ32C 0xC86016
typedef enum { typedef enum {
ESP_ROM_SPIFLASH_QIO_MODE = 0, ESP_ROM_SPIFLASH_QIO_MODE = 0,
ESP_ROM_SPIFLASH_QOUT_MODE, ESP_ROM_SPIFLASH_QOUT_MODE,

View File

@ -23,6 +23,7 @@ we add more types of external RAM memory, this can be made into a more intellige
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_spiram.h"
#include "spiram_psram.h" #include "spiram_psram.h"
#include "esp_log.h" #include "esp_log.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
@ -102,6 +103,22 @@ void IRAM_ATTR esp_spiram_init_cache()
#endif #endif
} }
esp_spiram_size_t esp_spiram_get_chip_size()
{
if (!spiram_inited) {
ESP_LOGE(TAG, "SPI RAM not initialized");
return ESP_SPIRAM_SIZE_INVALID;
}
psram_size_t psram_size = psram_get_size();
switch (psram_size) {
case PSRAM_SIZE_32MBITS:
return ESP_SPIRAM_SIZE_32MBITS;
case PSRAM_SIZE_64MBITS:
return ESP_SPIRAM_SIZE_64MBITS;
default:
return ESP_SPIRAM_SIZE_INVALID;
}
}
esp_err_t esp_spiram_init() esp_err_t esp_spiram_init()
{ {

View File

@ -39,26 +39,39 @@
#if CONFIG_SPIRAM_SUPPORT #if CONFIG_SPIRAM_SUPPORT
//Commands for PSRAM chip //Commands for PSRAM chip
#define PSRAM_READ 0x03 #define PSRAM_READ 0x03
#define PSRAM_FAST_READ 0x0B #define PSRAM_FAST_READ 0x0B
#define PSRAM_FAST_READ_DUMMY 0x3 #define PSRAM_FAST_READ_DUMMY 0x3
#define PSRAM_FAST_READ_QUAD 0xEB #define PSRAM_FAST_READ_QUAD 0xEB
#define PSRAM_WRITE 0x02 #define PSRAM_FAST_READ_QUAD_DUMMY 0x5
#define PSRAM_QUAD_WRITE 0x38 #define PSRAM_WRITE 0x02
#define PSRAM_ENTER_QMODE 0x35 #define PSRAM_QUAD_WRITE 0x38
#define PSRAM_EXIT_QMODE 0xF5 #define PSRAM_ENTER_QMODE 0x35
#define PSRAM_RESET_EN 0x66 #define PSRAM_EXIT_QMODE 0xF5
#define PSRAM_RESET 0x99 #define PSRAM_RESET_EN 0x66
#define PSRAM_SET_BURST_LEN 0xC0 #define PSRAM_RESET 0x99
#define PSRAM_DEVICE_ID 0x9F #define PSRAM_SET_BURST_LEN 0xC0
#define PSRAM_DEVICE_ID 0x9F
#if CONFIG_SPIRAM_TYPE_ESPPSRAM32 typedef enum {
PSRAM_CLK_MODE_NORM = 0, /*!< Normal SPI mode */
PSRAM_CLK_MODE_DCLK = 1, /*!< Two extra clock cycles after CS is set high level */
} psram_clk_mode_t;
#define PSRAM_MFG_ID_M 0xff #define PSRAM_ID_KGD_M 0xff
#define PSRAM_MFG_ID_S 8 #define PSRAM_ID_KGD_S 8
#define PSRAM_MFG_ID_V 0x5d #define PSRAM_ID_KGD 0x5d
#define PSRAM_ID_EID_M 0xff
#define PSRAM_ID_EID_S 16
#endif #define PSRAM_KGD(id) (((id) >> PSRAM_ID_KGD_S) & PSRAM_ID_KGD_M)
#define PSRAM_EID(id) (((id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M)
#define PSRAM_IS_VALID(id) (PSRAM_KGD(id) == PSRAM_ID_KGD)
// PSRAM_EID = 0x26 or 0x4x ----> 64MBit psram
// PSRAM_EID = 0x20 ------------> 32MBit psram
#define PSRAM_IS_64MBIT(id) ((PSRAM_EID(id) == 0x26) || ((PSRAM_EID(id) & 0xf0) == 0x40))
#define PSRAM_IS_32MBIT_VER0(id) (PSRAM_EID(id) == 0x20)
// IO-pins for PSRAM. These need to be in the VDD_SIO power domain because all chips we // IO-pins for PSRAM. These need to be in the VDD_SIO power domain because all chips we
// currently support are 1.8V parts. // currently support are 1.8V parts.
@ -98,6 +111,8 @@ typedef enum {
} psram_spi_num_t; } psram_spi_num_t;
static psram_cache_mode_t s_psram_mode = PSRAM_CACHE_MAX; static psram_cache_mode_t s_psram_mode = PSRAM_CACHE_MAX;
static psram_clk_mode_t s_clk_mode = PSRAM_CLK_MODE_DCLK;
static uint32_t s_psram_id = 0;
/* dummy_len_plus values defined in ROM for SPI flash configuration */ /* dummy_len_plus values defined in ROM for SPI flash configuration */
extern uint8_t g_rom_spiflash_dummy_len_plus[]; extern uint8_t g_rom_spiflash_dummy_len_plus[];
@ -286,7 +301,7 @@ static int psram_cmd_config(psram_spi_num_t spi_num, psram_cmd_t* pInData)
return 0; return 0;
} }
void psram_cmd_end(int spi_num) { static void psram_cmd_end(int spi_num) {
while (READ_PERI_REG(SPI_CMD_REG(spi_num)) & SPI_USR); while (READ_PERI_REG(SPI_CMD_REG(spi_num)) & SPI_USR);
WRITE_PERI_REG(SPI_USER_REG(spi_num), backup_usr[spi_num]); WRITE_PERI_REG(SPI_USER_REG(spi_num), backup_usr[spi_num]);
WRITE_PERI_REG(SPI_USER1_REG(spi_num), backup_usr1[spi_num]); WRITE_PERI_REG(SPI_USER1_REG(spi_num), backup_usr1[spi_num]);
@ -298,17 +313,19 @@ static void psram_disable_qio_mode(psram_spi_num_t spi_num)
{ {
psram_cmd_t ps_cmd; psram_cmd_t ps_cmd;
uint32_t cmd_exit_qpi; uint32_t cmd_exit_qpi;
switch (s_psram_mode) { cmd_exit_qpi = PSRAM_EXIT_QMODE;
case PSRAM_CACHE_F80M_S80M: ps_cmd.txDataBitLen = 8;
cmd_exit_qpi = PSRAM_EXIT_QMODE; if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
ps_cmd.txDataBitLen = 8; switch (s_psram_mode) {
break; case PSRAM_CACHE_F80M_S80M:
case PSRAM_CACHE_F80M_S40M: break;
case PSRAM_CACHE_F40M_S40M: case PSRAM_CACHE_F80M_S40M:
default: case PSRAM_CACHE_F40M_S40M:
cmd_exit_qpi = PSRAM_EXIT_QMODE << 8; default:
ps_cmd.txDataBitLen = 16; cmd_exit_qpi = PSRAM_EXIT_QMODE << 8;
break; ps_cmd.txDataBitLen = 16;
break;
}
} }
ps_cmd.txData = &cmd_exit_qpi; ps_cmd.txData = &cmd_exit_qpi;
ps_cmd.cmd = 0; ps_cmd.cmd = 0;
@ -328,29 +345,34 @@ static void psram_read_id(uint32_t* dev_id)
{ {
psram_spi_num_t spi_num = PSRAM_SPI_1; psram_spi_num_t spi_num = PSRAM_SPI_1;
psram_disable_qio_mode(spi_num); psram_disable_qio_mode(spi_num);
uint32_t addr = (PSRAM_DEVICE_ID << 24) | 0; uint32_t dummy_bits = 0 + extra_dummy;
uint32_t dummy_bits = 0;
psram_cmd_t ps_cmd; psram_cmd_t ps_cmd;
switch (s_psram_mode) {
case PSRAM_CACHE_F80M_S80M: uint32_t addr = 0;
dummy_bits = 0 + extra_dummy; ps_cmd.addrBitLen = 3 * 8;
ps_cmd.cmdBitLen = 0; ps_cmd.cmd = PSRAM_DEVICE_ID;
break; ps_cmd.cmdBitLen = 8;
case PSRAM_CACHE_F80M_S40M: if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
case PSRAM_CACHE_F40M_S40M: switch (s_psram_mode) {
default: case PSRAM_CACHE_F80M_S80M:
dummy_bits = 0 + extra_dummy; break;
ps_cmd.cmdBitLen = 2; //this two bits is used to delay 2 clock cycle case PSRAM_CACHE_F80M_S40M:
break; case PSRAM_CACHE_F40M_S40M:
default:
ps_cmd.cmdBitLen = 2; //this two bits is used to delay 2 clock cycle
ps_cmd.cmd = 0;
addr = (PSRAM_DEVICE_ID << 24) | 0;
ps_cmd.addrBitLen = 4 * 8;
break;
}
} }
ps_cmd.cmd = 0;
ps_cmd.addr = &addr; ps_cmd.addr = &addr;
ps_cmd.addrBitLen = 4 * 8;
ps_cmd.txDataBitLen = 0; ps_cmd.txDataBitLen = 0;
ps_cmd.txData = NULL; ps_cmd.txData = NULL;
ps_cmd.rxDataBitLen = 4 * 8; ps_cmd.rxDataBitLen = 4 * 8;
ps_cmd.rxData = dev_id; ps_cmd.rxData = dev_id;
ps_cmd.dummyBitLen = dummy_bits; ps_cmd.dummyBitLen = dummy_bits;
psram_cmd_config(spi_num, &ps_cmd); psram_cmd_config(spi_num, &ps_cmd);
psram_clear_spi_fifo(spi_num); psram_clear_spi_fifo(spi_num);
psram_cmd_recv_start(spi_num, ps_cmd.rxData, ps_cmd.rxDataBitLen / 8, PSRAM_CMD_SPI); psram_cmd_recv_start(spi_num, ps_cmd.rxData, ps_cmd.rxDataBitLen / 8, PSRAM_CMD_SPI);
@ -362,15 +384,18 @@ static esp_err_t IRAM_ATTR psram_enable_qio_mode(psram_spi_num_t spi_num)
{ {
psram_cmd_t ps_cmd; psram_cmd_t ps_cmd;
uint32_t addr = (PSRAM_ENTER_QMODE << 24) | 0; uint32_t addr = (PSRAM_ENTER_QMODE << 24) | 0;
switch (s_psram_mode) {
case PSRAM_CACHE_F80M_S80M: ps_cmd.cmdBitLen = 0;
ps_cmd.cmdBitLen = 0; if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
break; switch (s_psram_mode) {
case PSRAM_CACHE_F80M_S40M: case PSRAM_CACHE_F80M_S80M:
case PSRAM_CACHE_F40M_S40M: break;
default: case PSRAM_CACHE_F80M_S40M:
ps_cmd.cmdBitLen = 2; case PSRAM_CACHE_F40M_S40M:
break; default:
ps_cmd.cmdBitLen = 2;
break;
}
} }
ps_cmd.cmd = 0; ps_cmd.cmd = 0;
ps_cmd.addr = &addr; ps_cmd.addr = &addr;
@ -473,6 +498,17 @@ static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
} }
psram_size_t psram_get_size()
{
if (PSRAM_IS_32MBIT_VER0(s_psram_id)) {
return PSRAM_SIZE_32MBITS;
} else if (PSRAM_IS_64MBIT(s_psram_id)) {
return PSRAM_SIZE_64MBITS;
} else {
return PSRAM_SIZE_MAX;
}
}
//psram gpio init , different working frequency we have different solutions //psram gpio init , different working frequency we have different solutions
esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode) //psram init esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode) //psram init
{ {
@ -489,17 +525,6 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
return ESP_FAIL; return ESP_FAIL;
} }
/* note: If the third mode(80Mhz+80Mhz) is enabled, VSPI port will be occupied by the system,
Application code should never touch VSPI hardware in this case. We try to stop applications
from doing this using the drivers by claiming the port for ourselves*/
if (mode == PSRAM_CACHE_F80M_S80M) {
periph_module_enable(PERIPH_VSPI_MODULE);
bool r=spicommon_periph_claim(VSPI_HOST);
if (!r) {
return ESP_ERR_INVALID_STATE;
}
}
WRITE_PERI_REG(GPIO_ENABLE_W1TC_REG, BIT(PSRAM_CLK_IO) | BIT(PSRAM_CS_IO)); //DISABLE OUPUT FOR IO16/17 WRITE_PERI_REG(GPIO_ENABLE_W1TC_REG, BIT(PSRAM_CLK_IO) | BIT(PSRAM_CS_IO)); //DISABLE OUPUT FOR IO16/17
assert(mode < PSRAM_CACHE_MAX && "we don't support any other mode for now."); assert(mode < PSRAM_CACHE_MAX && "we don't support any other mode for now.");
s_psram_mode = mode; s_psram_mode = mode;
@ -514,21 +539,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
psram_spi_init(PSRAM_SPI_1, mode); psram_spi_init(PSRAM_SPI_1, mode);
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_HOLD); CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_HOLD);
gpio_matrix_out(PSRAM_CS_IO, SPICS1_OUT_IDX, 0, 0); gpio_matrix_out(PSRAM_CS_IO, SPICS1_OUT_IDX, 0, 0);
gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 0, 0); gpio_matrix_out(PSRAM_CLK_IO, SPICLK_OUT_IDX, 0, 0);
//use spi3 clock,but use spi1 data/cs wires
//We get a solid 80MHz clock from SPI3 by setting it up, starting a transaction, waiting until it
//is in progress, then cutting the clock (but not the reset!) to that peripheral.
WRITE_PERI_REG(SPI_ADDR_REG(PSRAM_SPI_3), 32 << 24);
WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_3), SPI_CLK_EQU_SYSCLK_M); //SET 80M AND CLEAR OTHERS
SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_3), SPI_FLASH_READ_M);
uint32_t spi_status;
while (1) {
spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
if (spi_status != 0 && spi_status != 1) {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
break;
}
}
break; break;
case PSRAM_CACHE_F80M_S40M: case PSRAM_CACHE_F80M_S40M:
case PSRAM_CACHE_F40M_S40M: case PSRAM_CACHE_F40M_S40M:
@ -554,13 +565,59 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG, BIT(PSRAM_CS_IO)| BIT(PSRAM_CLK_IO)); WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG, BIT(PSRAM_CS_IO)| BIT(PSRAM_CLK_IO));
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CS_IO], PIN_FUNC_GPIO); PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CS_IO], PIN_FUNC_GPIO);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], PIN_FUNC_GPIO); PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], PIN_FUNC_GPIO);
uint32_t id;
psram_read_id(&id); psram_read_id(&s_psram_id);
if (((id >> PSRAM_MFG_ID_S) & PSRAM_MFG_ID_M) != PSRAM_MFG_ID_V) { if (!PSRAM_IS_VALID(s_psram_id)) {
return ESP_FAIL; return ESP_FAIL;
} }
uint32_t flash_id = g_rom_flashchip.device_id;
if (flash_id == FLASH_ID_GD25LQ32C) {
// Set drive ability for 1.8v flash in 80Mhz.
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CS_IO], FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], FUN_DRV_V, 3, FUN_DRV_S);
}
if (PSRAM_IS_64MBIT(s_psram_id)) {
// For this psram, we don't need any extra clock cycles after cs get back to high level
s_clk_mode = PSRAM_CLK_MODE_NORM;
gpio_matrix_out(PSRAM_INTERNAL_IO_28, SIG_GPIO_OUT_IDX, 0, 0);
gpio_matrix_out(PSRAM_INTERNAL_IO_29, SIG_GPIO_OUT_IDX, 0, 0);
gpio_matrix_out(PSRAM_CLK_IO, SPICLK_OUT_IDX, 0, 0);
} else if (PSRAM_IS_32MBIT_VER0(s_psram_id)) {
s_clk_mode = PSRAM_CLK_MODE_DCLK;
if (mode == PSRAM_CACHE_F80M_S80M) {
/* note: If the third mode(80Mhz+80Mhz) is enabled for 32MBit 1V8 psram, VSPI port will be
occupied by the system.
Application code should never touch VSPI hardware in this case. We try to stop applications
from doing this using the drivers by claiming the port for ourselves */
periph_module_enable(PERIPH_VSPI_MODULE);
bool r=spicommon_periph_claim(VSPI_HOST);
if (!r) {
return ESP_ERR_INVALID_STATE;
}
gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 0, 0);
//use spi3 clock,but use spi1 data/cs wires
//We get a solid 80MHz clock from SPI3 by setting it up, starting a transaction, waiting until it
//is in progress, then cutting the clock (but not the reset!) to that peripheral.
WRITE_PERI_REG(SPI_ADDR_REG(PSRAM_SPI_3), 32 << 24);
WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_3), SPI_CLK_EQU_SYSCLK_M); //SET 80M AND CLEAR OTHERS
SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_3), SPI_FLASH_READ_M);
uint32_t spi_status;
while (1) {
spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
if (spi_status != 0 && spi_status != 1) {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
break;
}
}
}
}
psram_enable_qio_mode(PSRAM_SPI_1); psram_enable_qio_mode(PSRAM_SPI_1);
psram_cache_init(mode, vaddrmode); psram_cache_init(mode, vaddrmode);
return ESP_OK; return ESP_OK;
} }
@ -579,27 +636,15 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk,80+40; CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk,80+40;
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0. FLASH DIV 2+SRAM DIV4 CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0. FLASH DIV 2+SRAM DIV4
WRITE_PERI_REG(SPI_CLOCK_REG(0), SPI_CLK_EQU_SYSCLK_M); //SET 1DIV CLOCK AND RESET OTHER PARAMS WRITE_PERI_REG(SPI_CLOCK_REG(0), SPI_CLK_EQU_SYSCLK_M); //SET 1DIV CLOCK AND RESET OTHER PARAMS
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
break; break;
case PSRAM_CACHE_F80M_S40M: case PSRAM_CACHE_F80M_S40M:
SET_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk SET_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0. CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0.
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
break; break;
case PSRAM_CACHE_F40M_S40M: case PSRAM_CACHE_F40M_S40M:
default: default:
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
break; break;
} }
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_WCMD_M); // cache write command enable SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_WCMD_M); // cache write command enable
@ -607,30 +652,38 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_QIO_M); //enable qio mode for cache command SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_QIO_M); //enable qio mode for cache command
CLEAR_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_DIO_M); //disable dio mode for cache command CLEAR_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_DIO_M); //disable dio mode for cache command
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 7,
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S);
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, PSRAM_QUAD_WRITE,
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 7,
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S);
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, PSRAM_FAST_READ_QUAD,
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy,
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
//config sram cache r/w command //config sram cache r/w command
switch (psram_cache_mode) { switch (psram_cache_mode) {
case PSRAM_CACHE_F80M_S80M: //in this mode , no delay is needed case PSRAM_CACHE_F80M_S80M: //in this mode , no delay is needed
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 7,
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S);
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, PSRAM_QUAD_WRITE,
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 7,
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S);
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, PSRAM_FAST_READ,
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b
break; break;
case PSRAM_CACHE_F80M_S40M: //is sram is @40M, need 2 cycles of delay case PSRAM_CACHE_F80M_S40M: //is sram is @40M, need 2 cycles of delay
case PSRAM_CACHE_F40M_S40M: case PSRAM_CACHE_F40M_S40M:
default: default:
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 15, if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S); //read command length, 2 bytes(1byte for delay),sending in qio mode in cache SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 15,
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, ((PSRAM_FAST_READ) << 8), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S); //read command length, 2 bytes(1byte for delay),sending in qio mode in cache
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b, read command value,(0x00 for delay,0x0b for cmd) SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, ((PSRAM_FAST_READ_QUAD) << 8),
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 15, SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b, read command value,(0x00 for delay,0x0b for cmd)
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S); //write command length,2 bytes(1byte for delay,send in qio mode in cache) SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 15,
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, ((PSRAM_QUAD_WRITE) << 8), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S); //write command length,2 bytes(1byte for delay,send in qio mode in cache)
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38, write command value,(0x00 for delay) SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, ((PSRAM_QUAD_WRITE) << 8),
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38, write command value,(0x00 for delay)
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy,
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
}
break; break;
} }
@ -653,6 +706,11 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
CLEAR_PERI_REG_MASK(SPI_PIN_REG(0), SPI_CS1_DIS_M); //ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM) CLEAR_PERI_REG_MASK(SPI_PIN_REG(0), SPI_CS1_DIS_M); //ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM)
if (s_clk_mode == PSRAM_CLK_MODE_NORM) { //different
SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD);
// Set cs time.
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
}
} }
#endif // CONFIG_SPIRAM_SUPPORT #endif // CONFIG_SPIRAM_SUPPORT

View File

@ -26,6 +26,11 @@ typedef enum {
PSRAM_CACHE_MAX, PSRAM_CACHE_MAX,
} psram_cache_mode_t; } psram_cache_mode_t;
typedef enum {
PSRAM_SIZE_32MBITS = 0,
PSRAM_SIZE_64MBITS = 1,
PSRAM_SIZE_MAX,
} psram_size_t;
/* /*
See the TRM, chapter PID/MPU/MMU, header 'External RAM' for the definitions of these modes. See the TRM, chapter PID/MPU/MMU, header 'External RAM' for the definitions of these modes.
@ -34,12 +39,21 @@ Important is that NORMAL works with the app CPU cache disabled, but gives huge c
issues when both app and pro CPU are enabled. LOWHIGH and EVENODD do not have these coherency issues when both app and pro CPU are enabled. LOWHIGH and EVENODD do not have these coherency
issues but cannot be used when the app CPU cache is disabled. issues but cannot be used when the app CPU cache is disabled.
*/ */
typedef enum { typedef enum {
PSRAM_VADDR_MODE_NORMAL=0, ///< App and pro CPU use their own flash cache for external RAM access PSRAM_VADDR_MODE_NORMAL=0, ///< App and pro CPU use their own flash cache for external RAM access
PSRAM_VADDR_MODE_LOWHIGH, ///< App and pro CPU share external RAM caches: pro CPU has low 2M, app CPU has high 2M PSRAM_VADDR_MODE_LOWHIGH, ///< App and pro CPU share external RAM caches: pro CPU has low 2M, app CPU has high 2M
PSRAM_VADDR_MODE_EVENODD, ///< App and pro CPU share external RAM caches: pro CPU does even 32yte ranges, app does odd ones. PSRAM_VADDR_MODE_EVENODD, ///< App and pro CPU share external RAM caches: pro CPU does even 32yte ranges, app does odd ones.
} psram_vaddr_mode_t; } psram_vaddr_mode_t;
/**
* @brief get psram size
* @return
* - PSRAM_SIZE_MAX if psram not enabled or not valid
* - PSRAM size
*/
psram_size_t psram_get_size();
/** /**
* @brief psram cache enable function * @brief psram cache enable function
* *