mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
mspi: mspi timing tuning ll
This commit is contained in:
parent
9c1897028a
commit
99882ac2d1
@ -16,13 +16,12 @@
|
||||
#include "esp_private/mspi_timing_tuning.h"
|
||||
#include "soc/soc.h"
|
||||
#include "hal/spi_flash_hal.h"
|
||||
#include "hal/mspi_timing_tuning_ll.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "port/esp32s3/mspi_timing_config.h"
|
||||
#include "esp32s3/rom/cache.h"
|
||||
#endif
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(*(arr)))
|
||||
|
||||
#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
const static char *TAG = "MSPI Timing";
|
||||
static spi_timing_tuning_param_t s_flash_best_timing_tuning_config;
|
||||
@ -36,18 +35,7 @@ void mspi_timing_set_pin_drive_strength(void)
|
||||
{
|
||||
//For now, set them all to 3. Need to check after QVL test results are out. TODO: IDF-3663
|
||||
//Set default clk
|
||||
SET_PERI_REG_MASK(SPI_MEM_DATE_REG(0), SPI_MEM_SPICLK_PAD_DRV_CTL_EN);
|
||||
REG_SET_FIELD(SPI_MEM_DATE_REG(0), SPI_MEM_SPI_SMEM_SPICLK_FUN_DRV, 3);
|
||||
REG_SET_FIELD(SPI_MEM_DATE_REG(0), SPI_MEM_SPI_FMEM_SPICLK_FUN_DRV, 3);
|
||||
//Set default mspi d0 ~ d7, dqs pin drive strength
|
||||
uint32_t regs[] = {IO_MUX_GPIO27_REG, IO_MUX_GPIO28_REG,
|
||||
IO_MUX_GPIO31_REG, IO_MUX_GPIO32_REG,
|
||||
IO_MUX_GPIO33_REG, IO_MUX_GPIO34_REG,
|
||||
IO_MUX_GPIO35_REG, IO_MUX_GPIO36_REG,
|
||||
IO_MUX_GPIO37_REG};
|
||||
for (int i = 0; i < ARRAY_SIZE(regs); i++) {
|
||||
PIN_SET_DRV(regs[i], 3);
|
||||
}
|
||||
mspi_timing_ll_set_all_pin_drive(0, 3);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
@ -105,13 +93,13 @@ static void init_spi1_for_tuning(bool 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);
|
||||
mspi_timinng_ll_enable_flash_hclk(0);
|
||||
} 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);
|
||||
mspi_timinng_ll_enable_psram_hclk(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,7 +295,7 @@ void mspi_timing_flash_tuning(void)
|
||||
mspi_timing_enter_low_speed_mode(true);
|
||||
|
||||
//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
|
||||
mspi_timing_ll_enable_flash_variable_dummy(1, false); //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));
|
||||
@ -366,7 +354,7 @@ void mspi_timing_psram_tuning(void)
|
||||
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);
|
||||
mspi_timing_ll_enable_flash_variable_dummy(1, false);
|
||||
//Get required config, and set them to PSRAM related registers
|
||||
do_tuning(reference_data, &timing_configs, false);
|
||||
mspi_timing_enter_high_speed_mode(true);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/spi_mem_reg.h"
|
||||
#include "hal/mspi_timing_tuning_ll.h"
|
||||
#include "mspi_timing_config.h"
|
||||
#include "bootloader_flash.h"
|
||||
|
||||
@ -24,15 +25,6 @@
|
||||
#define QPI_PSRAM_WRITE 0X38
|
||||
#define QPI_PSRAM_FAST_READ_DUMMY 6
|
||||
|
||||
#define MULTI_LINE_MASK_OCT_FLASH (SPI_MEM_FCMD_OCT | SPI_MEM_FADDR_OCT | SPI_MEM_FDIN_OCT | SPI_MEM_FDOUT_OCT)
|
||||
#define MULTI_LINE_MASK_QUAD_FLASH (SPI_MEM_FASTRD_MODE | SPI_MEM_FREAD_DUAL | SPI_MEM_FREAD_DIO | SPI_MEM_FREAD_QUAD | SPI_MEM_FREAD_QIO)
|
||||
#define SPI_FLASH_QIO_MODE (SPI_MEM_FREAD_QIO | SPI_MEM_FASTRD_MODE)
|
||||
#define SPI_FLASH_QUAD_MODE (SPI_MEM_FREAD_QUAD | SPI_MEM_FASTRD_MODE)
|
||||
#define SPI_FLASH_DIO_MODE (SPI_MEM_FREAD_DIO | SPI_MEM_FASTRD_MODE)
|
||||
#define SPI_FLASH_DUAL_MODE (SPI_MEM_FREAD_DUAL | SPI_MEM_FASTRD_MODE)
|
||||
#define SPI_FLASH_FAST_MODE (SPI_MEM_FASTRD_MODE)
|
||||
#define SPI_FLASH_SLOW_MODE 0
|
||||
|
||||
#define NOT_INIT_INT 127
|
||||
|
||||
//-------------------------------------MSPI Clock Setting-------------------------------------//
|
||||
@ -73,28 +65,18 @@ void spi_timing_config_set_core_clock(uint8_t spi_num, spi_timing_config_core_cl
|
||||
abort();
|
||||
}
|
||||
|
||||
REG_SET_FIELD(SPI_MEM_CORE_CLK_SEL_REG(spi_num), SPI_MEM_CORE_CLK_SEL, reg_val);
|
||||
mspi_timing_ll_set_core_clock_divider(spi_num, reg_val);
|
||||
}
|
||||
|
||||
void 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);
|
||||
}
|
||||
mspi_timing_ll_set_flash_clock(spi_num, freqdiv);
|
||||
}
|
||||
|
||||
void 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);
|
||||
}
|
||||
mspi_timing_ll_set_psram_clock(spi_num, freqdiv);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////TIMING TUNING IS NEEDED//////////////////////////////////////////////
|
||||
@ -123,40 +105,32 @@ extern void psram_exec_cmd(int spi_num, psram_cmd_mode_t mode,
|
||||
//-------------------------------------FLASH timing tuning register config-------------------------------------//
|
||||
void 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);
|
||||
mspi_timing_ll_set_flash_din_mode(spi_num, din_mode);
|
||||
mspi_timing_ll_set_flash_din_num(spi_num, din_num);
|
||||
}
|
||||
|
||||
static uint32_t spi_timing_config_get_dummy(void)
|
||||
{
|
||||
uint32_t ctrl_reg = READ_PERI_REG(SPI_MEM_CTRL_REG(0));
|
||||
if (ctrl_reg & MULTI_LINE_MASK_OCT_FLASH) {
|
||||
mspi_timing_ll_flash_mode_t mode = mspi_timing_ll_get_flash_mode(0);
|
||||
if (mode == MSPI_TIMING_LL_FLASH_OPI_MODE) {
|
||||
abort();
|
||||
}
|
||||
|
||||
#if CONFIG_SPI_FLASH_HPM_ENABLE
|
||||
if (spi_flash_hpm_dummy_adjust()) { // HPM is enabled
|
||||
const spi_flash_hpm_dummy_conf_t *hpm_dummy = spi_flash_hpm_get_dummy();
|
||||
switch (ctrl_reg & MULTI_LINE_MASK_QUAD_FLASH) {
|
||||
case SPI_FLASH_QIO_MODE:
|
||||
switch (mode) {
|
||||
case MSPI_TIMING_LL_FLASH_QIO_MODE:
|
||||
return hpm_dummy->qio_dummy - 1;
|
||||
case SPI_FLASH_QUAD_MODE:
|
||||
case MSPI_TIMING_LL_FLASH_QUAD_MODE:
|
||||
return hpm_dummy->qout_dummy - 1;
|
||||
case SPI_FLASH_DIO_MODE:
|
||||
case MSPI_TIMING_LL_FLASH_DIO_MODE:
|
||||
return hpm_dummy->dio_dummy - 1;
|
||||
case SPI_FLASH_DUAL_MODE:
|
||||
case MSPI_TIMING_LL_FLASH_DUAL_MODE:
|
||||
return hpm_dummy->dout_dummy - 1;
|
||||
case SPI_FLASH_FAST_MODE:
|
||||
case MSPI_TIMING_LL_FLASH_FAST_MODE:
|
||||
return hpm_dummy->fastrd_dummy - 1;
|
||||
case SPI_FLASH_SLOW_MODE:
|
||||
case MSPI_TIMING_LL_FLASH_SLOW_MODE:
|
||||
return 0;
|
||||
default:
|
||||
abort();
|
||||
@ -164,18 +138,18 @@ static uint32_t spi_timing_config_get_dummy(void)
|
||||
} else
|
||||
#endif
|
||||
{ // HPM is not enabled
|
||||
switch (ctrl_reg & MULTI_LINE_MASK_QUAD_FLASH) {
|
||||
case SPI_FLASH_QIO_MODE:
|
||||
switch (mode) {
|
||||
case MSPI_TIMING_LL_FLASH_QIO_MODE:
|
||||
return SPI1_R_QIO_DUMMY_CYCLELEN;
|
||||
case SPI_FLASH_QUAD_MODE:
|
||||
case MSPI_TIMING_LL_FLASH_QUAD_MODE:
|
||||
return SPI1_R_FAST_DUMMY_CYCLELEN;
|
||||
case SPI_FLASH_DIO_MODE:
|
||||
case MSPI_TIMING_LL_FLASH_DIO_MODE:
|
||||
return SPI1_R_DIO_DUMMY_CYCLELEN;
|
||||
case SPI_FLASH_DUAL_MODE:
|
||||
case MSPI_TIMING_LL_FLASH_DUAL_MODE:
|
||||
return SPI1_R_FAST_DUMMY_CYCLELEN;
|
||||
case SPI_FLASH_FAST_MODE:
|
||||
case MSPI_TIMING_LL_FLASH_FAST_MODE:
|
||||
return SPI1_R_FAST_DUMMY_CYCLELEN;
|
||||
case SPI_FLASH_SLOW_MODE:
|
||||
case MSPI_TIMING_LL_FLASH_SLOW_MODE:
|
||||
return 0;
|
||||
default:
|
||||
abort();
|
||||
@ -186,18 +160,11 @@ static uint32_t spi_timing_config_get_dummy(void)
|
||||
void spi_timing_config_flash_set_extra_dummy(uint8_t spi_num, uint8_t extra_dummy)
|
||||
{
|
||||
if (bootloader_flash_is_octal_mode_enabled()) {
|
||||
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);
|
||||
}
|
||||
mspi_timing_ll_set_octal_flash_extra_dummy(spi_num, extra_dummy);
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* HW workaround:
|
||||
* The `SPI_MEM_TIMING_CALI_REG` register is only used for OPI on 728
|
||||
* Here we only need to update this global variable for extra dummy. Since we use the ROM Flash API, which will set the dummy based on this.
|
||||
* We only initialise the SPI0. And leave the SPI1 for flash driver to configure.
|
||||
@ -215,31 +182,16 @@ void spi_timing_config_flash_set_extra_dummy(uint8_t spi_num, uint8_t extra_dumm
|
||||
//-------------------------------------PSRAM timing tuning register config-------------------------------------//
|
||||
void 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);
|
||||
mspi_timing_ll_set_psram_din_mode(spi_num, din_mode);
|
||||
mspi_timing_ll_set_psram_din_num(spi_num, din_num);
|
||||
}
|
||||
|
||||
void spi_timing_config_psram_set_extra_dummy(uint8_t spi_num, uint8_t extra_dummy)
|
||||
{
|
||||
#if CONFIG_SPIRAM_MODE_OCT
|
||||
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);
|
||||
}
|
||||
mspi_timing_ll_set_octal_psram_extra_dummy(spi_num, extra_dummy);
|
||||
#elif CONFIG_SPIRAM_MODE_QUAD
|
||||
//HW workaround: Use normal dummy register to set extra dummy, the calibration dedicated extra dummy register doesn't work for quad mode
|
||||
SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(spi_num), SPI_MEM_USR_RD_SRAM_DUMMY_M);
|
||||
SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(spi_num), SPI_MEM_SRAM_RDUMMY_CYCLELEN_V, (QPI_PSRAM_FAST_READ_DUMMY + extra_dummy - 1), SPI_MEM_SRAM_RDUMMY_CYCLELEN_S);
|
||||
#endif
|
||||
|
317
components/hal/esp32s3/include/hal/mspi_timing_tuning_ll.h
Normal file
317
components/hal/esp32s3/include/hal/mspi_timing_tuning_ll.h
Normal file
@ -0,0 +1,317 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* NOTICE
|
||||
* The ll is not public api, don't use in application code.
|
||||
* See readme.md in hal/include/hal/readme.md
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_bit_defs.h"
|
||||
#include "hal/assert.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/spi_mem_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof((arr))/sizeof(*(arr)))
|
||||
#define MSPI_TIMING_LL_FLASH_OCT_MASK (SPI_MEM_FCMD_OCT | SPI_MEM_FADDR_OCT | SPI_MEM_FDIN_OCT | SPI_MEM_FDOUT_OCT)
|
||||
#define MSPI_TIMING_LL_FLASH_QUAD_MASK (SPI_MEM_FASTRD_MODE | SPI_MEM_FREAD_DUAL | SPI_MEM_FREAD_DIO | SPI_MEM_FREAD_QUAD | SPI_MEM_FREAD_QIO)
|
||||
#define MSPI_TIMING_LL_FLASH_QIO_MODE_MASK (SPI_MEM_FREAD_QIO | SPI_MEM_FASTRD_MODE)
|
||||
#define MSPI_TIMING_LL_FLASH_QUAD_MODE_MASK (SPI_MEM_FREAD_QUAD | SPI_MEM_FASTRD_MODE)
|
||||
#define MSPI_TIMING_LL_FLASH_DIO_MODE_MASK (SPI_MEM_FREAD_DIO | SPI_MEM_FASTRD_MODE)
|
||||
#define MSPI_TIMING_LL_FLASH_DUAL_MODE_MASK (SPI_MEM_FREAD_DUAL | SPI_MEM_FASTRD_MODE)
|
||||
#define MSPI_TIMING_LL_FLASH_FAST_MODE_MASK (SPI_MEM_FASTRD_MODE)
|
||||
#define MSPI_TIMING_LL_FLASH_SLOW_MODE_MASK 0
|
||||
|
||||
typedef enum {
|
||||
MSPI_TIMING_LL_FLASH_OPI_MODE = BIT(0),
|
||||
MSPI_TIMING_LL_FLASH_QIO_MODE = BIT(1),
|
||||
MSPI_TIMING_LL_FLASH_QUAD_MODE = BIT(2),
|
||||
MSPI_TIMING_LL_FLASH_DIO_MODE = BIT(3),
|
||||
MSPI_TIMING_LL_FLASH_DUAL_MODE = BIT(4),
|
||||
MSPI_TIMING_LL_FLASH_FAST_MODE = BIT(5),
|
||||
MSPI_TIMING_LL_FLASH_SLOW_MODE = BIT(6),
|
||||
} mspi_timing_ll_flash_mode_t;
|
||||
|
||||
/**
|
||||
* Set all MSPI pin drive strength
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
* @param val Pin drive strength
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timing_ll_set_all_pin_drive(uint8_t spi_num, uint32_t val)
|
||||
{
|
||||
SET_PERI_REG_MASK(SPI_MEM_DATE_REG(spi_num), SPI_MEM_SPICLK_PAD_DRV_CTL_EN);
|
||||
REG_SET_FIELD(SPI_MEM_DATE_REG(spi_num), SPI_MEM_SPI_SMEM_SPICLK_FUN_DRV, val);
|
||||
REG_SET_FIELD(SPI_MEM_DATE_REG(spi_num), SPI_MEM_SPI_FMEM_SPICLK_FUN_DRV, val);
|
||||
|
||||
uint32_t regs[] = {IO_MUX_GPIO27_REG, IO_MUX_GPIO28_REG,
|
||||
IO_MUX_GPIO31_REG, IO_MUX_GPIO32_REG,
|
||||
IO_MUX_GPIO33_REG, IO_MUX_GPIO34_REG,
|
||||
IO_MUX_GPIO35_REG, IO_MUX_GPIO36_REG,
|
||||
IO_MUX_GPIO37_REG};
|
||||
for (int i = 0; i < ARRAY_SIZE(regs); i++) {
|
||||
PIN_SET_DRV(regs[i], val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all MSPI Flash clock pin drive strength
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
* @param val Pin drive strength
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timing_ll_set_flash_clock_pin_drive(uint8_t spi_num, uint32_t val)
|
||||
{
|
||||
bool clk_pin_drive_control = GET_PERI_REG_MASK(SPI_MEM_DATE_REG(spi_num), SPI_MEM_SPICLK_PAD_DRV_CTL_EN);
|
||||
//You should never call this function, while `mspi_timing_ll_set_all_pin_drive()` isn't called
|
||||
HAL_ASSERT(clk_pin_drive_control);
|
||||
REG_SET_FIELD(SPI_MEM_DATE_REG(spi_num), SPI_MEM_SPI_FMEM_SPICLK_FUN_DRV, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all MSPI PSRAM clock pin drive strength
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
* @param val Pin drive strength
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timing_ll_set_psram_clock_pin_drive(uint8_t spi_num, uint32_t val)
|
||||
{
|
||||
bool clk_pin_drive_control = GET_PERI_REG_MASK(SPI_MEM_DATE_REG(spi_num), SPI_MEM_SPICLK_PAD_DRV_CTL_EN);
|
||||
//You should never call this function, while `mspi_timing_ll_set_all_pin_drive()` isn't called
|
||||
HAL_ASSERT(clk_pin_drive_control);
|
||||
REG_SET_FIELD(SPI_MEM_DATE_REG(spi_num), SPI_MEM_SPI_SMEM_SPICLK_FUN_DRV, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Flash HCLK
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timinng_ll_enable_flash_hclk(uint8_t spi_num)
|
||||
{
|
||||
REG_SET_BIT(SPI_MEM_TIMING_CALI_REG(spi_num), SPI_MEM_TIMING_CLK_ENA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable PSRAM HCLK
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timinng_ll_enable_psram_hclk(uint8_t spi_num)
|
||||
{
|
||||
REG_SET_BIT(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num), SPI_MEM_SPI_SMEM_TIMING_CLK_ENA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable Flash variable dummy
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
* @param enable Enable / Disable
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timing_ll_enable_flash_variable_dummy(uint8_t spi_num, bool enable)
|
||||
{
|
||||
REG_SET_FIELD(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY, enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MSPI core clock divider
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
* @param val Divider value
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timing_ll_set_core_clock_divider(uint8_t spi_num, uint32_t val)
|
||||
{
|
||||
REG_SET_FIELD(SPI_MEM_CORE_CLK_SEL_REG(spi_num), SPI_MEM_CORE_CLK_SEL, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MSPI Flash clock
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
* @param freqdiv Divider value
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timing_ll_set_flash_clock(uint8_t spi_num, uint32_t freqdiv)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MSPI PSRAM clock
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
* @param freqdiv Divider value
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timing_ll_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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MSPI Flash din mode
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
* @param din_mode Din mode value
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timing_ll_set_flash_din_mode(uint8_t spi_num, uint8_t din_mode)
|
||||
{
|
||||
uint32_t 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MSPI Flash din num
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
* @param din_num Din num value
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timing_ll_set_flash_din_num(uint8_t spi_num, uint8_t din_num)
|
||||
{
|
||||
uint32_t 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MSPI Flash mode
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
*
|
||||
* @return Flash mode
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline mspi_timing_ll_flash_mode_t mspi_timing_ll_get_flash_mode(uint8_t spi_num)
|
||||
{
|
||||
uint32_t ctrl_reg = READ_PERI_REG(SPI_MEM_CTRL_REG(0));
|
||||
if (ctrl_reg & MSPI_TIMING_LL_FLASH_OCT_MASK) {
|
||||
return MSPI_TIMING_LL_FLASH_OPI_MODE;
|
||||
}
|
||||
|
||||
switch (ctrl_reg & MSPI_TIMING_LL_FLASH_QUAD_MASK) {
|
||||
case MSPI_TIMING_LL_FLASH_QIO_MODE_MASK:
|
||||
return MSPI_TIMING_LL_FLASH_QIO_MODE;
|
||||
case MSPI_TIMING_LL_FLASH_QUAD_MODE_MASK:
|
||||
return MSPI_TIMING_LL_FLASH_QUAD_MODE;
|
||||
case MSPI_TIMING_LL_FLASH_DIO_MODE_MASK:
|
||||
return MSPI_TIMING_LL_FLASH_DIO_MODE;
|
||||
case MSPI_TIMING_LL_FLASH_DUAL_MODE_MASK:
|
||||
return MSPI_TIMING_LL_FLASH_DUAL_MODE;
|
||||
case MSPI_TIMING_LL_FLASH_FAST_MODE_MASK:
|
||||
return MSPI_TIMING_LL_FLASH_FAST_MODE;
|
||||
case MSPI_TIMING_LL_FLASH_SLOW_MODE_MASK:
|
||||
return MSPI_TIMING_LL_FLASH_SLOW_MODE;
|
||||
default:
|
||||
HAL_ASSERT(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MSPI Octal Flash extra dummy
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
* @param extra_dummy Extra dummy
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timing_ll_set_octal_flash_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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MSPI PSRAM din mode
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
* @param din_mode Din mode value
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timing_ll_set_psram_din_mode(uint8_t spi_num, uint8_t din_mode)
|
||||
{
|
||||
uint32_t 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MSPI PSRAM din num
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
* @param din_num Din num value
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timing_ll_set_psram_din_num(uint8_t spi_num, uint8_t din_num)
|
||||
{
|
||||
uint32_t 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MSPI Octal PSRAM extra dummy
|
||||
*
|
||||
* @param spi_num SPI0 / SPI1
|
||||
* @param extra_dummy Extra dummy
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mspi_timing_ll_set_octal_psram_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);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user