Files
esp-idf/components/esp_hal_mspi/esp32s31/include/hal/mspi_ll.h
T
2026-04-02 20:39:59 +08:00

289 lines
8.0 KiB
C

/*
* SPDX-FileCopyrightText: 2025-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
******************************************************************************/
/**
* Background
*
* This file is for the MSPI related, but not Flash driver related registers, these registers:
* - may influence both Flash and PSRAM
* - not related or directly related to Flash controller driver
*
* Some hints for naming convention:
* - For MSPI timing tuning related registers, the LL should start with `mspi_timing_ll_`
* - For others, the LL should start with `mspi_ll_`
*/
#pragma once
#include <sys/param.h>
#include <stdbool.h>
#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" {
#endif
#define MSPI_LL_PERIPH_NUM 4
#define MSPI_TIMING_LL_MSPI_ID_0 0
#define MSPI_TIMING_LL_MSPI_ID_1 1
// PSRAM frequency should be constrained by AXI frequency to avoid FIFO underflow.
#define MSPI_TIMING_LL_PSRAM_FREQ_AXI_CONSTRAINED 1
#define MSPI_LL_AXI_DISABLE_SUPPORTED 1
#define MSPI_LL_INTR_EVENT_SUPPORTED 1
/**
* 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_BBPLL:
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
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
* @param enable enable / disable
*/
__attribute__((always_inline))
static inline void mspi_ll_enable_intr(uint8_t spi_num, uint32_t intr_mask, bool enable)
{
if (enable) {
SPIMEM0.mem_int_ena.val |= intr_mask;
} else {
SPIMEM0.mem_int_ena.val &= ~intr_mask;
}
}
/**
* @brief Clear MSPI controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
*/
__attribute__((always_inline))
static inline void mspi_ll_clear_intr(uint8_t spi_num, uint32_t intr_mask)
{
SPIMEM0.mem_int_clr.val = intr_mask;
}
/**
* @brief Get MSPI controller interrupt raw
*
* @param mspi_id mspi_id
*/
__attribute__((always_inline))
static inline uint32_t mspi_ll_get_intr_raw(uint8_t spi_num)
{
return SPIMEM0.mem_int_raw.val;
}
/**
* Enable AXI access to flash
*
* @param spi_num SPI0 / SPI1
* @param enable Enable / Disable
*/
__attribute__((always_inline))
static inline void mspi_ll_flash_enable_axi_access(uint8_t spi_num, bool enable)
{
SPIMEM0.mem_cache_fctrl.close_axi_inf_en = !enable;
}
/**
* Enable AXI access to PSRAM
*
* @param spi_num SPI0 / SPI1
* @param enable Enable / Disable
*/
__attribute__((always_inline))
static inline void mspi_ll_psram_enable_axi_access(uint8_t spi_num, bool enable)
{
SPIMEM2.mem_cache_fctrl.close_axi_inf_en = !enable;
}
#ifdef __cplusplus
}
#endif