mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
198 lines
9.3 KiB
C
198 lines
9.3 KiB
C
/*
|
|
* 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
|