feat(psram): support psram device driver

This commit is contained in:
armando
2026-03-31 13:56:43 +08:00
parent 582451a451
commit ebbd9cdb59
35 changed files with 2871 additions and 907 deletions
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -29,12 +29,16 @@
#include "esp_bit_defs.h"
#include "hal/assert.h"
#include "soc/soc.h"
#include "soc/hp_sys_clkrst_struct.h"
#include "soc/spi_mem_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/iomux_mspi_pin_reg.h"
#include "soc/iomux_mspi_pin_struct.h"
#include "soc/spi_mem_struct.h"
#include "soc/spi_mem_s_struct.h"
#include "soc/spi_mem_c_reg.h"
#include "soc/spi1_mem_c_reg.h"
#include "soc/clk_tree_defs.h"
#ifdef __cplusplus
extern "C" {
@@ -50,8 +54,171 @@ extern "C" {
#define MSPI_LL_AXI_DISABLE_SUPPORTED 1
#define MSPI_LL_INTR_EVENT_SUPPORTED 1
// TODO: ["ESP32S31"] IDF-14653
/**
* MSPI DQS ID
*/
typedef enum {
MSPI_LL_DQS_ID_0,
} mspi_ll_dqs_id_t;
/**
* MSPI DQS Phase
*/
typedef enum {
MSPI_LL_DQS_PHASE_67_5,
MSPI_LL_DQS_PHASE_78_75,
MSPI_LL_DQS_PHASE_90,
MSPI_LL_DQS_PHASE_101_25,
MSPI_LL_DQS_PHASE_MAX,
} mspi_ll_dqs_phase_t;
/**
* MSPI Delayline
*
* @note The Sequence of these enums should not be changed
*/
typedef enum {
MSPI_LL_PIN_D = 0,
MSPI_LL_PIN_Q,
MSPI_LL_PIN_WP,
MSPI_LL_PIN_HD,
MSPI_LL_PIN_D4,
MSPI_LL_PIN_D5,
MSPI_LL_PIN_D6,
MSPI_LL_PIN_D7,
MSPI_LL_PIN_DQS0,
MSPI_LL_PIN_CLK,
MSPI_LL_PIN_CS,
MSPI_LL_PIN_MAX,
} mspi_ll_pin_t;
/*---------------------------------------------------------------
PSRAM tuning
---------------------------------------------------------------*/
/**
* Set all MSPI DQS phase
*
* @param dqs_id DQS ID
* @param phase Phase
*/
__attribute__((always_inline))
static inline void mspi_timing_ll_set_dqs_phase(mspi_ll_dqs_id_t dqs_id, mspi_ll_dqs_phase_t phase)
{
HAL_ASSERT(dqs_id < 1);
REG_SET_FIELD(IOMUX_MSPI_PIN_PSRAM_DQS_0_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_DQS_0_PHASE, phase);
}
/**
* Set all MSPI delayline
*
* @param pin Pin
* @param delayline Delayline
*/
__attribute__((always_inline))
static inline void mspi_timing_ll_set_delayline(mspi_ll_pin_t pin, uint8_t delayline)
{
HAL_ASSERT(pin < MSPI_LL_PIN_MAX);
switch (pin) {
case MSPI_LL_PIN_DQS0:
MSPI_IOMUX.psram_pin_group.dqs0.reg_psram_dqs_delay_90 = delayline;
MSPI_IOMUX.psram_pin_group.dqs0.reg_psram_dqs_delay_270 = delayline;
break;
case MSPI_LL_PIN_D:
case MSPI_LL_PIN_Q:
case MSPI_LL_PIN_WP:
case MSPI_LL_PIN_HD:
case MSPI_LL_PIN_D4:
case MSPI_LL_PIN_D5:
case MSPI_LL_PIN_D6:
case MSPI_LL_PIN_D7:
MSPI_IOMUX.psram_pin_group.pin_group0[pin].reg_psram_pin_dlc = delayline;
break;
case MSPI_LL_PIN_CLK:
MSPI_IOMUX.psram_pin_group.pin_clk.reg_psram_pin_dlc = delayline;
break;
case MSPI_LL_PIN_CS:
MSPI_IOMUX.psram_pin_group.pin_cs.reg_psram_pin_dlc = delayline;
break;
default:
HAL_ASSERT(false);
break;
}
}
/**
* Enable DQS
*
* @param en Enable/disable
*/
__attribute__((always_inline))
static inline void mspi_timing_ll_enable_dqs(bool en)
{
if (en) {
REG_SET_BIT(IOMUX_MSPI_PIN_PSRAM_DQS_0_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_DQS_0_XPD);
} else {
REG_CLR_BIT(IOMUX_MSPI_PIN_PSRAM_DQS_0_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_DQS_0_XPD);
}
}
/**
* Set all MSPI pin drive
*
* @param drv Pin drive
*/
__attribute__((always_inline))
static inline void mspi_timing_ll_pin_drv_set(uint8_t drv)
{
REG_SET_FIELD(IOMUX_MSPI_PIN_PSRAM_D_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_D_DRV, drv);
REG_SET_FIELD(IOMUX_MSPI_PIN_PSRAM_Q_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_Q_DRV, drv);
REG_SET_FIELD(IOMUX_MSPI_PIN_PSRAM_WP_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_WP_DRV, drv);
REG_SET_FIELD(IOMUX_MSPI_PIN_PSRAM_HOLD_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_HOLD_DRV, drv);
REG_SET_FIELD(IOMUX_MSPI_PIN_PSRAM_DQ4_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_DQ4_DRV, drv);
REG_SET_FIELD(IOMUX_MSPI_PIN_PSRAM_DQ5_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_DQ5_DRV, drv);
REG_SET_FIELD(IOMUX_MSPI_PIN_PSRAM_DQ6_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_DQ6_DRV, drv);
REG_SET_FIELD(IOMUX_MSPI_PIN_PSRAM_DQ7_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_DQ7_DRV, drv);
REG_SET_FIELD(IOMUX_MSPI_PIN_PSRAM_DQS_0_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_DQS_0_DRV, drv);
REG_SET_FIELD(IOMUX_MSPI_PIN_PSRAM_CK_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_CK_DRV, drv);
REG_SET_FIELD(IOMUX_MSPI_PIN_PSRAM_CS_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_CS_DRV, drv);
}
/*---------------------------------------------------------------
Flash tuning
---------------------------------------------------------------*/
/*
* @brief Select FLASH clock source
*
* @param mspi_id mspi_id
* @param clk_src clock source, see valid sources in type `soc_periph_flash_clk_src_t`
*/
__attribute__((always_inline))
static inline void _mspi_timing_ll_set_flash_clk_src(uint32_t mspi_id, soc_periph_flash_clk_src_t clk_src)
{
HAL_ASSERT(mspi_id == MSPI_TIMING_LL_MSPI_ID_0);
uint32_t clk_val = 0;
switch (clk_src) {
case FLASH_CLK_SRC_XTAL:
clk_val = 0;
break;
case FLASH_CLK_SRC_SPLL:
clk_val = 1;
break;
case FLASH_CLK_SRC_CPLL:
clk_val = 2;
break;
default:
HAL_ASSERT(false);
break;
}
HP_SYS_CLKRST.flash_ctrl0.reg_flash_sys_clk_en = 1;
HP_SYS_CLKRST.flash_ctrl0.reg_flash_pll_clk_en = 1;
HP_SYS_CLKRST.flash_ctrl0.reg_flash_clk_src_sel = clk_val;
}
/*---------------------------------------------------------------
Misc
---------------------------------------------------------------*/
/**
* @brief Enable/Disable MSPI controller interrupt
*
@@ -0,0 +1,946 @@
/*
* SPDX-FileCopyrightText: 2026 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 "hal/assert.h"
#include "hal/misc.h"
#include "hal/config.h"
#include "soc/spi_mem_s_struct.h"
#include "soc/spi_mem_s_reg.h"
#include "soc/spi1_mem_s_reg.h"
#include "soc/spi1_mem_s_struct.h"
#include "soc/hp_sys_clkrst_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/hp_system_struct.h"
#include "rom/opi_flash.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PSRAM_CTRLR_LL_MSPI_ID_2 2
#define PSRAM_CTRLR_LL_MSPI_ID_3 3
#define PSRAM_CTRLR_LL_MSPI_ID_SYSTEM PSRAM_CTRLR_LL_MSPI_ID_2
#define PSRAM_CTRLR_LL_MSPI_ID_PERI PSRAM_CTRLR_LL_MSPI_ID_3
#define PSRAM_CTRLR_LL_PMS_REGION_NUMS 4
#define PSRAM_CTRLR_LL_PMS_ATTR_WRITABLE (1<<0)
#define PSRAM_CTRLR_LL_PMS_ATTR_READABLE (1<<1)
#define PSRAM_CTRLR_LL_FIFO_MAX_BYTES 64
#define PSRAM_CTRLR_LL_THRESH_INT_SUPPORTED 1
#define PSRAM_CTRLR_LL_PMS_INT_SUPPORTED 1
#define PSRAM_CTRLR_LL_ADDR_INT_SUPPORTED 1
#define PSRAM_CTRLR_LL_EVENT_SLV_ST_END (1<<3)
#define PSRAM_CTRLR_LL_EVENT_MST_ST_END (1<<4)
#define PSRAM_CTRLR_LL_EVENT_ECC_ERR (1<<5)
#define PSRAM_CTRLR_LL_EVENT_PMS_REJECT (1<<6)
#define PSRAM_CTRLR_LL_EVENT_AXI_RADDR_ERR (1<<7)
#define PSRAM_CTRLR_LL_EVENT_AXI_WR_FLASH_ERR (1<<8)
#define PSRAM_CTRLR_LL_EVENT_AXI_WADDR_ERR (1<<9)
#define PSRAM_CTRLR_LL_EVENT_RX_TRANS_OVF (1<<26)
#define PSRAM_CTRLR_LL_EVENT_TX_TRANS_UDF (1<<27)
#define PSRAM_CTRLR_LL_EVENT_MASK (PSRAM_CTRLR_LL_EVENT_ECC_ERR | PSRAM_CTRLR_LL_EVENT_PMS_REJECT | PSRAM_CTRLR_LL_EVENT_AXI_RADDR_ERR | \
PSRAM_CTRLR_LL_EVENT_AXI_WR_FLASH_ERR | PSRAM_CTRLR_LL_EVENT_AXI_WADDR_ERR | PSRAM_CTRLR_LL_EVENT_RX_TRANS_OVF | \
PSRAM_CTRLR_LL_EVENT_TX_TRANS_UDF)
#define PSRAM_CTRLR_LL_INTR_EVENT_SUPPORTED 1
/**
* @brief Set PSRAM write cmd
*
* @param mspi_id mspi_id
* @param cmd_bitlen command bitlen
* @param cmd_val command value
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_wr_cmd(uint32_t mspi_id, uint32_t cmd_bitlen, uint32_t cmd_val)
{
(void)mspi_id;
HAL_ASSERT(cmd_bitlen > 0);
SPIMEM2.mem_cache_sctrl.mem_cache_sram_usr_wcmd = 1;
SPIMEM2.mem_sram_dwr_cmd.mem_cache_sram_usr_wr_cmd_bitlen = cmd_bitlen - 1;
HAL_FORCE_MODIFY_U32_REG_FIELD(SPIMEM2.mem_sram_dwr_cmd, mem_cache_sram_usr_wr_cmd_value, cmd_val);
}
/**
* @brief Set PSRAM read cmd
*
* @param mspi_id mspi_id
* @param cmd_bitlen command bitlen
* @param cmd_val command value
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_rd_cmd(uint32_t mspi_id, uint32_t cmd_bitlen, uint32_t cmd_val)
{
(void)mspi_id;
HAL_ASSERT(cmd_bitlen > 0);
SPIMEM2.mem_cache_sctrl.mem_cache_sram_usr_rcmd = 1;
SPIMEM2.mem_sram_drd_cmd.mem_cache_sram_usr_rd_cmd_bitlen = cmd_bitlen - 1;
HAL_FORCE_MODIFY_U32_REG_FIELD(SPIMEM2.mem_sram_drd_cmd, mem_cache_sram_usr_rd_cmd_value, cmd_val);
}
/**
* @brief Set PSRAM addr bitlen
*
* @param mspi_id mspi_id
* @param addr_bitlen address bitlen
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_addr_bitlen(uint32_t mspi_id, uint32_t addr_bitlen)
{
(void)mspi_id;
HAL_ASSERT(addr_bitlen > 0);
SPIMEM2.mem_cache_sctrl.mem_sram_addr_bitlen = addr_bitlen - 1;
}
/**
* @brief Enable PSRAM 4B addr
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_4byte_addr(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.mem_cache_sctrl.mem_cache_usr_saddr_4byte = en;
}
/**
* @brief Set PSRAM write dummy
*
* @param mspi_id mspi_id
* @param dummy_n dummy number
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_wr_dummy(uint32_t mspi_id, uint32_t dummy_n)
{
(void)mspi_id;
HAL_ASSERT(dummy_n > 0);
SPIMEM2.mem_cache_sctrl.mem_usr_wr_sram_dummy = 1;
SPIMEM2.mem_cache_sctrl.mem_sram_wdummy_cyclelen = dummy_n - 1;
}
/**
* @brief Set PSRAM read dummy
*
* @param mspi_id mspi_id
* @param dummy_n dummy number
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_rd_dummy(uint32_t mspi_id, uint32_t dummy_n)
{
(void)mspi_id;
HAL_ASSERT(dummy_n > 0);
SPIMEM2.mem_cache_sctrl.mem_usr_rd_sram_dummy = 1;
SPIMEM2.mem_cache_sctrl.mem_sram_rdummy_cyclelen = dummy_n - 1;
}
/**
* @brief Enable PSRAM variable dummy
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_variable_dummy(uint32_t mspi_id, bool en)
{
if (mspi_id == PSRAM_CTRLR_LL_MSPI_ID_2) {
SPIMEM2.smem_ddr.smem_var_dummy = en;
} else if (mspi_id == PSRAM_CTRLR_LL_MSPI_ID_3) {
SPIMEM3.ddr.fmem_var_dummy = en;
}
}
/**
* @brief Enable PSRAM write dummy level control
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_wr_dummy_level_control(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.mem_sram_cmd.mem_sdummy_wout = en;
}
/**
* @brief Enable PSRAM read dummy level control
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_rd_dummy_level_control(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.mem_sram_cmd.mem_sdummy_rin = en;
}
/**
* @brief Enable PSRAM ddr mode
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_ddr_mode(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.smem_ddr.smem_ddr_en = en;
}
/**
* @brief Enable PSRAM ddr write data swap
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_ddr_wr_data_swap(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.smem_ddr.smem_ddr_wdat_swp = en;
}
/**
* @brief Enable PSRAM ddr read data swap
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_ddr_rd_data_swap(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.smem_ddr.smem_ddr_rdat_swp = en;
}
/**
* @brief Enable PSRAM octal mode
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_oct_line_mode(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.mem_cache_sctrl.mem_sram_oct = en;
SPIMEM2.mem_sram_cmd.mem_scmd_oct = en;
SPIMEM2.mem_sram_cmd.mem_saddr_oct = en;
SPIMEM2.mem_sram_cmd.mem_sdout_oct = en;
SPIMEM2.mem_sram_cmd.mem_sdin_oct = en;
}
/**
* @brief Enable PSRAM hex data line mode
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_hex_data_line_mode(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.mem_sram_cmd.mem_sdin_hex = en;
SPIMEM2.mem_sram_cmd.mem_sdout_hex = en;
}
/**
* @brief Get PSRAM hex data line mode enable status
*
* @param mspi_id mspi_id
*
* @return true if hex data line mode is enabled, false otherwise
*/
__attribute__((always_inline))
static inline bool psram_ctrlr_ll_is_hex_data_line_mode(uint32_t mspi_id)
{
(void)mspi_id;
return (SPIMEM2.mem_sram_cmd.mem_sdin_hex & SPIMEM2.mem_sram_cmd.mem_sdout_hex);
}
/**
* @brief Enable PSRAM AXI master access
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_axi_access(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.mem_cache_fctrl.mem_axi_req_en = en;
SPIMEM2.mem_cache_fctrl.close_axi_inf_en = !en;
}
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
/**
* @brief Enable PSRAM AXI weight arbiter for TX / RX AXI requests
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_axi_req_weight_arbiter(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.mem_cache_fctrl.mem_arb_wei_en = en;
}
/**
* @brief Set PSRAM AXI request weight
*
* @param mspi_id mspi_id
* @param rd_weight read weight
* @param wr_weight write weight
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_axi_req_weight(uint32_t mspi_id, uint32_t rd_weight, uint32_t wr_weight)
{
//1~15
HAL_ASSERT(rd_weight && rd_weight < 16);
HAL_ASSERT(wr_weight && wr_weight < 16);
SPIMEM2.mem_cache_fctrl.mem_arb_req0_wei = rd_weight;
SPIMEM2.mem_cache_fctrl.mem_arb_req1_wei = wr_weight;
}
/**
* @brief Set PSRAM AXI request priority
*
* @param mspi_id mspi_id
* @param rd_prio read priority
* @param wr_prio write priority
*/
static inline void psram_ctrlr_ll_set_axi_req_priority(uint32_t mspi_id, uint32_t rd_prio, uint32_t wr_prio)
{
SPIMEM2.mem_cache_fctrl.mem_arb_req0_pri = rd_prio;
SPIMEM2.mem_cache_fctrl.mem_arb_req1_pri = wr_prio;
}
#endif
/**
* @brief Enable PSRAM write splice transfer
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_wr_splice(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.mem_ctrl1.mem_aw_splice_en = en;
}
/**
* @brief Enable PSRAM read splice transfer
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_rd_splice(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.mem_ctrl1.mem_ar_splice_en = en;
}
/**
* @brief Enable PSRAM module clock
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void _psram_ctrlr_ll_enable_module_clock(uint32_t mspi_id, bool en)
{
(void)mspi_id;
HP_SYS_CLKRST.psram_ctrl0.reg_psram_sys_clk_en = en;
HP_SYS_CLKRST.psram_ctrl0.reg_psram_pll_clk_en = en;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define psram_ctrlr_ll_enable_module_clock(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_psram_ctrlr_ll_enable_module_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset PSRAM module clock
*
* @param mspi_id mspi_id
*/
__attribute__((always_inline))
static inline void _psram_ctrlr_ll_reset_module_clock(uint32_t mspi_id)
{
HP_SYS_CLKRST.psram_ctrl0.reg_psram_axi_rst_en = 1;
HP_SYS_CLKRST.psram_ctrl0.reg_psram_apb_rst_en = 1;
HP_SYS_CLKRST.psram_ctrl0.reg_psram_apb_rst_en = 0;
HP_SYS_CLKRST.psram_ctrl0.reg_psram_axi_rst_en = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define psram_ctrlr_ll_reset_module_clock(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_psram_ctrlr_ll_reset_module_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Select PSRAM clock source
*
* @param mspi_id mspi_id
* @param clk_src clock source, see valid sources in type `soc_periph_psram_clk_src_t`
*/
__attribute__((always_inline))
static inline void _psram_ctrlr_ll_select_clk_source(uint32_t mspi_id, soc_periph_psram_clk_src_t clk_src)
{
(void)mspi_id;
uint32_t clk_val = 0;
switch (clk_src) {
case PSRAM_CLK_SRC_XTAL:
clk_val = 0;
break;
case PSRAM_CLK_SRC_MPLL:
clk_val = 1;
break;
case PSRAM_CLK_SRC_CPLL:
clk_val = 2;
break;
default:
HAL_ASSERT(false);
break;
}
HP_SYS_CLKRST.psram_ctrl0.reg_psram_clk_src_sel = clk_val;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define psram_ctrlr_ll_select_clk_source(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_psram_ctrlr_ll_select_clk_source(__VA_ARGS__); \
} while(0)
/**
* @brief Set PSRAM core clock
*
* @param mspi_id mspi_id
* @param freqdiv Divider value
*/
__attribute__((always_inline))
static inline void _psram_ctrlr_ll_set_core_clock_div(uint8_t spi_num, uint32_t freqdiv)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.psram_ctrl0, reg_psram_core_clk_div_num, freqdiv - 1);
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define psram_ctrlr_ll_set_core_clock_div(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_psram_ctrlr_ll_set_core_clock_div(__VA_ARGS__); \
} while(0)
/**
* @brief Enable or disable the PSRAM core clock
*
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void _psram_ctrlr_ll_enable_core_clock(uint8_t spi_num, bool en)
{
HP_SYS_CLKRST.psram_ctrl0.reg_psram_core_clk_en = en;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define psram_ctrlr_ll_enable_core_clock(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_psram_ctrlr_ll_enable_core_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Set PSRAM bus clock
*
* @param mspi_id mspi_id
* @param freqdiv Divider value
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_bus_clock(uint32_t mspi_id, uint32_t freqdiv)
{
if (mspi_id == PSRAM_CTRLR_LL_MSPI_ID_2) {
if (freqdiv == 1) {
WRITE_PERI_REG(SPI_MEM_S_SRAM_CLK_REG, SPI_MEM_S_SCLK_EQU_SYSCLK);
} else {
uint32_t freqbits = (((freqdiv - 1) << SPI_MEM_S_SCLKCNT_N_S)) | (((freqdiv / 2 - 1) << SPI_MEM_S_SCLKCNT_H_S)) | ((freqdiv - 1) << SPI_MEM_S_SCLKCNT_L_S);
WRITE_PERI_REG(SPI_MEM_S_SRAM_CLK_REG, freqbits);
}
} else if (mspi_id == PSRAM_CTRLR_LL_MSPI_ID_3) {
if (freqdiv == 1) {
WRITE_PERI_REG(SPI1_MEM_S_CLOCK_REG, SPI1_MEM_S_CLK_EQU_SYSCLK);
} else {
uint32_t freqbits = (((freqdiv - 1) << SPI1_MEM_S_CLKCNT_N_S)) | (((freqdiv / 2 - 1) << SPI1_MEM_S_CLKCNT_H_S)) | ((freqdiv - 1) << SPI1_MEM_S_CLKCNT_L_S);
WRITE_PERI_REG(SPI1_MEM_S_CLOCK_REG, freqbits);
}
}
}
/**
* @brief Enable PSRAM DLL
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_dll(uint32_t mspi_id, bool en)
{
if (mspi_id == PSRAM_CTRLR_LL_MSPI_ID_2) {
SPIMEM2.smem_timing_cali.smem_dll_timing_cali = en;
} else if (mspi_id == PSRAM_CTRLR_LL_MSPI_ID_3) {
SPIMEM2.mem_timing_cali.mem_dll_timing_cali = en;
} else {
HAL_ASSERT(false);
}
}
/**
* @brief Set CS setup
*
* @param mspi_id mspi_id
* @param setup_n cs setup time
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_cs_setup(uint32_t mspi_id, uint32_t setup_n)
{
(void)mspi_id;
HAL_ASSERT(setup_n > 0);
SPIMEM2.smem_ac.smem_cs_setup = 1;
SPIMEM2.smem_ac.smem_cs_setup_time = setup_n - 1;
}
/**
* @brief Set CS hold
*
* @param mspi_id mspi_id
* @param hold_n cs hold time
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_cs_hold(uint32_t mspi_id, uint32_t hold_n)
{
(void)mspi_id;
HAL_ASSERT(hold_n > 0);
SPIMEM2.smem_ac.smem_cs_hold = 1;
SPIMEM2.smem_ac.smem_cs_hold_time = hold_n - 1;
}
/**
* @brief Set CS hold delay
*
* @param mspi_id mspi_id
* @param hold_n cs hold time
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_cs_hold_delay(uint32_t mspi_id, uint32_t hold_delay_n)
{
(void)mspi_id;
HAL_ASSERT(hold_delay_n > 0);
SPIMEM2.smem_ac.smem_cs_hold_delay = hold_delay_n - 1;
}
/**
* @brief Set ECC CS hold
*
* @param mspi_id mspi_id
* @param hold_n cs hold time
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_cs_hold_ecc(uint32_t mspi_id, uint32_t hold_n)
{
(void)mspi_id;
HAL_ASSERT(hold_n > 0);
SPIMEM2.smem_ac.smem_ecc_cs_hold_time = hold_n - 1;
}
/**
* @brief Enable 16to18 ECC
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_16to18_ecc(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.smem_ac.smem_ecc_16to18_byte_en = en;
}
/**
* @brief Enable ECC skip page corner
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_skip_page_corner(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.smem_ac.smem_ecc_skip_page_corner = en;
}
/**
* @brief Enable splitting transactions
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_split_trans(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.smem_ac.smem_split_trans_en = en;
}
/**
* @brief Enable ECC address conversion
*
* @param mspi_id mspi_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_ecc_addr_conversion(uint32_t mspi_id, bool en)
{
(void)mspi_id;
SPIMEM2.smem_ecc_ctrl.smem_ecc_addr_en = en;
}
/**
* @brief Set page size
*
* @param mspi_id mspi_id
* @param page_size page size
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_page_size(uint32_t mspi_id, uint32_t page_size)
{
(void)mspi_id;
switch (page_size) {
case 256:
SPIMEM2.smem_ecc_ctrl.smem_page_size = 0;
break;
case 512:
SPIMEM2.smem_ecc_ctrl.smem_page_size = 1;
break;
case 1024:
SPIMEM2.smem_ecc_ctrl.smem_page_size = 2;
break;
case 2048:
SPIMEM2.smem_ecc_ctrl.smem_page_size = 3;
break;
default:
HAL_ASSERT(false);
}
}
/**
* @brief Get page size
*
* @param mspi_id mspi_id
*
* @return page size
*/
__attribute__((always_inline))
static inline uint32_t psram_ctrlr_ll_get_page_size(uint32_t mspi_id)
{
(void)mspi_id;
uint32_t page_size = 0;
uint32_t reg_val = SPIMEM2.smem_ecc_ctrl.smem_page_size;
switch (reg_val) {
case 0:
page_size = 256;
break;
case 1:
page_size = 512;
break;
case 2:
page_size = 1024;
break;
case 3:
page_size = 2048;
break;
default:
HAL_ASSERT(false);
}
return page_size;
}
/**
* @brief Enable PMS ECC
*
* @param mspi_id mspi_id
* @param region_id region_id
* @param en enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_pms_region_ecc(uint32_t mspi_id, uint32_t region_id, bool en)
{
(void)mspi_id;
HAL_ASSERT(region_id < PSRAM_CTRLR_LL_PMS_REGION_NUMS);
SPIMEM2.smem_pmsn_attr[region_id].smem_pmsn_ecc = en;
}
/**
* @brief Set PMS attr
*
* @param mspi_id mspi_id
* @param region_id region_id
* @param attr_mask attribute mask
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_pms_region_attr(uint32_t mspi_id, uint32_t region_id, uint32_t attr_mask)
{
(void)mspi_id;
HAL_ASSERT(region_id < PSRAM_CTRLR_LL_PMS_REGION_NUMS);
SPIMEM2.smem_pmsn_attr[region_id].smem_pmsn_wr_attr = 0;
SPIMEM2.smem_pmsn_attr[region_id].smem_pmsn_rd_attr = 0;
if (attr_mask & PSRAM_CTRLR_LL_PMS_ATTR_WRITABLE) {
SPIMEM2.smem_pmsn_attr[region_id].smem_pmsn_wr_attr = 1;
}
if (attr_mask & PSRAM_CTRLR_LL_PMS_ATTR_READABLE) {
SPIMEM2.smem_pmsn_attr[region_id].smem_pmsn_rd_attr = 1;
}
}
/**
* @brief Set PMS address
*
* @param mspi_id mspi_id
* @param region_id region_id
* @param addr start addr
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_pms_region_start_addr(uint32_t mspi_id, uint32_t region_id, uint32_t addr)
{
(void)mspi_id;
HAL_ASSERT(region_id < PSRAM_CTRLR_LL_PMS_REGION_NUMS);
SPIMEM2.smem_pmsn_addr[region_id].smem_pmsn_addr_s = addr;
}
/**
* @brief Set PMS size
*
* @param mspi_id mspi_id
* @param region_id region_id
* @param size size
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_set_pms_region_size(uint32_t mspi_id, uint32_t region_id, uint32_t size)
{
(void)mspi_id;
HAL_ASSERT(region_id < PSRAM_CTRLR_LL_PMS_REGION_NUMS);
SPIMEM2.smem_pmsn_size[region_id].smem_pmsn_size = size;
}
/**
* @brief Get PMS address
*
* @param mspi_id mspi_id
* @param region_id region_id
*/
__attribute__((always_inline))
static inline uint32_t psram_ctrlr_ll_get_pms_region_start_addr(uint32_t mspi_id, uint32_t region_id)
{
(void)mspi_id;
HAL_ASSERT(region_id < PSRAM_CTRLR_LL_PMS_REGION_NUMS);
return SPIMEM2.smem_pmsn_addr[region_id].smem_pmsn_addr_s;
}
/**
* @brief Get PMS size
*
* @param mspi_id mspi_id
* @param region_id region_id
*/
__attribute__((always_inline))
static inline uint32_t psram_ctrlr_ll_get_pms_region_size(uint32_t mspi_id, uint32_t region_id)
{
(void)mspi_id;
HAL_ASSERT(region_id < PSRAM_CTRLR_LL_PMS_REGION_NUMS);
return SPIMEM2.smem_pmsn_size[region_id].smem_pmsn_size;
}
/**
* @brief PSRAM common transaction
*
* See `opi_flash.h` for parameters
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_common_transaction_base(uint32_t mspi_id, esp_rom_spiflash_read_mode_t mode,
uint32_t cmd, uint32_t cmd_bitlen,
uint32_t addr, uint32_t addr_bitlen,
uint32_t dummy_bits,
uint8_t* mosi_data, uint32_t mosi_bitlen,
uint8_t* miso_data, uint32_t miso_bitlen,
uint32_t cs_mask,
bool is_write_erase_operation)
{
esp_rom_spi_set_op_mode(mspi_id, mode);
esp_rom_spi_cmd_t conf = {
.cmd = cmd,
.cmdBitLen = cmd_bitlen,
.addr = &addr,
.addrBitLen = addr_bitlen,
.txData = (uint32_t *)mosi_data,
.txDataBitLen = mosi_bitlen,
.rxData = (uint32_t *)miso_data,
.rxDataBitLen = miso_bitlen,
.dummyBitLen = dummy_bits,
};
esp_rom_spi_cmd_config(mspi_id, &conf);
esp_rom_spi_cmd_start(mspi_id, miso_data, miso_bitlen / 8, cs_mask, is_write_erase_operation);
}
/**
* @brief PSRAM common transaction
*
* See `opi_flash.h` for parameters
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_common_transaction(uint32_t mspi_id,
uint32_t cmd, uint32_t cmd_bitlen,
uint32_t addr, uint32_t addr_bitlen,
uint32_t dummy_bits,
uint8_t* mosi_data, uint32_t mosi_bitlen,
uint8_t* miso_data, uint32_t miso_bitlen,
bool is_write_erase_operation)
{
esp_rom_spiflash_read_mode_t mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
uint32_t cs_mask = 1 << 1;
psram_ctrlr_ll_common_transaction_base(mspi_id, mode, cmd, cmd_bitlen, addr, addr_bitlen, dummy_bits,
mosi_data, mosi_bitlen, miso_data, miso_bitlen, cs_mask,
is_write_erase_operation);
}
/**
* @brief Wait MSPI PSRAM controller transaction done
*
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_wait_all_transaction_done(void)
{
#define ALL_TRANSACTION_DONE ( SPI_MEM_S_ALL_FIFO_EMPTY | \
SPI_RDATA_AFIFO_REMPTY | \
SPI_RADDR_AFIFO_REMPTY | \
SPI_WDATA_AFIFO_REMPTY | \
SPI_WBLEN_AFIFO_REMPTY | \
SPI_ALL_AXI_TRANS_AFIFO_EMPTY)
while (SPIMEM2.smem_axi_addr_ctrl.val != ALL_TRANSACTION_DONE) {
;
}
}
/**
* @brief Enable/Disable PSRAM controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
* @param enable enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_intr(uint32_t mspi_id, uint32_t intr_mask, bool enable)
{
if (enable) {
SPIMEM2.mem_int_ena.val |= intr_mask;
} else {
SPIMEM2.mem_int_ena.val &= ~intr_mask;
}
}
/**
* @brief Clear PSRAM controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_clear_intr(uint32_t mspi_id, uint32_t intr_mask)
{
SPIMEM2.mem_int_clr.val = intr_mask;
}
/**
* @brief Get PSRAM controller interrupt raw
*
* @param mspi_id mspi_id
*/
__attribute__((always_inline))
static inline uint32_t psram_ctrlr_ll_get_intr_raw(uint32_t mspi_id)
{
return SPIMEM2.mem_int_raw.val;
}
/**
* @brief Backup PSRAM controller registers
*
* @param mspi_id mspi_id
* @param reg registers
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_backup_registers(uint32_t mspi_id, spi_mem_s_dev_t *reg)
{
memcpy(reg, &SPIMEM2, sizeof(spi_mem_s_dev_t));
}
/**
* @brief Restore PSRAM controller registers
*
* @param mspi_id mspi_id
* @param reg registers
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_restore_registers(uint32_t mspi_id, spi_mem_s_dev_t *reg)
{
memcpy(&SPIMEM2, reg, sizeof(spi_mem_s_dev_t));
}
/**
* @brief Disable core error response
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_disable_core_err_resp(void)
{
HP_SYSTEM.core_err_resp_dis.val = 0x7;
}
/**
* @brief Enable core error response
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_core_err_resp(void)
{
HP_SYSTEM.core_err_resp_dis.val = 0x0;
}
#ifdef __cplusplus
}
#endif
@@ -682,7 +682,7 @@ static inline uint8_t spimem_flash_ll_get_source_freq_mhz(void)
switch (HP_SYS_CLKRST.flash_ctrl0.reg_flash_clk_src_sel) {
case 0:
source_clk_mhz = clk_ll_xtal_load_freq_mhz();
source_clk_mhz = clk_ll_xtal_get_freq_mhz();
break;
case 1:
source_clk_mhz = CLK_LL_PLL_480M_FREQ_MHZ; // SPLL