Merge branch 'fix/fix_gpspi_flash_frequency' into 'master'

refactor(spi_flash): Refactor gpspi flash for making it's clock accurate

Closes IDF-13566

See merge request espressif/esp-idf!40651
This commit is contained in:
C.S.M
2025-07-23 16:46:30 +08:00
25 changed files with 552 additions and 15 deletions

View File

@ -425,6 +425,35 @@ static inline uint32_t gpspi_flash_ll_calculate_clock_reg(uint8_t clkdiv)
return div_parameter;
}
/**
* Set the clock source
*
* @param hw Beginning address of the peripheral registers.
* @param clk_source Clock source to use
*/
static inline void gpspi_flash_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source)
{
switch (clk_source) {
case SPI_CLK_SRC_XTAL:
hw->clk_gate.mst_clk_sel = 0;
break;
default:
hw->clk_gate.mst_clk_sel = 1;
break;
}
}
/**
* Enable/disable SPI flash module clock
*
* @param hw Beginning address of the peripheral registers.
* @param enable true to enable, false to disable
*/
static inline void gpspi_flash_ll_enable_clock(spi_dev_t *hw, bool enable)
{
hw->clk_gate.clk_en = enable;
}
#ifdef __cplusplus
}
#endif

View File

@ -24,7 +24,7 @@ extern "C" {
#define spi_flash_ll_calculate_clock_reg(host_id, clock_div) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_calculate_clock_reg(clock_div) \
: gpspi_flash_ll_calculate_clock_reg(clock_div))
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ)
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : -1)
#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \
: gpspi_flash_ll_get_hw(host_id)))

View File

@ -426,6 +426,35 @@ static inline uint32_t gpspi_flash_ll_calculate_clock_reg(uint8_t clkdiv)
return div_parameter;
}
/**
* Set the clock source
*
* @param hw Beginning address of the peripheral registers.
* @param clk_source Clock source to use
*/
static inline void gpspi_flash_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source)
{
switch (clk_source) {
case SPI_CLK_SRC_XTAL:
hw->clk_gate.mst_clk_sel = 0;
break;
default:
hw->clk_gate.mst_clk_sel = 1;
break;
}
}
/**
* Enable/disable SPI flash module clock
*
* @param hw Beginning address of the peripheral registers.
* @param enable true to enable, false to disable
*/
static inline void gpspi_flash_ll_enable_clock(spi_dev_t *hw, bool enable)
{
hw->clk_gate.clk_en = enable;
}
#ifdef __cplusplus
}
#endif

View File

@ -24,7 +24,7 @@ extern "C" {
#define spi_flash_ll_calculate_clock_reg(host_id, clock_div) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_calculate_clock_reg(clock_div) \
: gpspi_flash_ll_calculate_clock_reg(clock_div))
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ)
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : -1)
#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \
: gpspi_flash_ll_get_hw(host_id)))

View File

@ -15,6 +15,8 @@
#include <stdlib.h>
#include "soc/spi_periph.h"
#include "soc/spi_struct.h"
#include "soc/pcr_struct.h"
#include "hal/assert.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h"
#include <sys/param.h> // For MIN/MAX
@ -31,6 +33,8 @@ extern "C" {
typedef typeof(GPSPI2.clock.val) gpspi_flash_ll_clock_reg_t;
#define GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ (80)
#define GPSPI_FLASH_LL_SUPPORT_CLK_SRC_PRE_DIV (1)
#define GPSPI_FLASH_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
/*------------------------------------------------------------------------------
* Control
@ -426,6 +430,56 @@ static inline uint32_t gpspi_flash_ll_calculate_clock_reg(uint8_t clkdiv)
return div_parameter;
}
/**
* Set the clock source
*
* @param hw Beginning address of the peripheral registers.
* @param clk_source Clock source to use
*/
static inline void gpspi_flash_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source)
{
uint32_t clk_id = 0;
switch (clk_source) {
case SOC_MOD_CLK_PLL_F160M:
clk_id = 1;
break;
case SOC_MOD_CLK_RC_FAST:
clk_id = 2;
break;
case SOC_MOD_CLK_XTAL:
clk_id = 0;
break;
default:
HAL_ASSERT(false);
}
PCR.spi2_clkm_conf.spi2_clkm_sel = clk_id;
}
/**
* Enable/disable SPI flash module clock
*
* @param host_id SPI host ID
* @param enable true to enable, false to disable
*/
static inline void gpspi_flash_ll_enable_clock(spi_dev_t *hw, bool enable)
{
PCR.spi2_clkm_conf.spi2_clkm_en = enable;
}
/**
* Enable/disable SPI flash module clock
*
* @param hw Beginning address of the peripheral registers.
* @param enable true to enable, false to disable
*/
static inline void gpspi_flash_ll_clk_source_pre_div(spi_dev_t *hw, uint8_t hs_div, uint8_t mst_div)
{
// In IDF master driver 'mst_div' will be const 2 and 'hs_div' is actually pre_div temporally
(void) hs_div;
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.spi2_clkm_conf, spi2_clkm_div_num, mst_div - 1);
}
#ifdef __cplusplus
}
#endif

View File

@ -26,7 +26,7 @@ extern "C" {
#define spi_flash_ll_calculate_clock_reg(host_id, clock_div) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_calculate_clock_reg(clock_div) \
: gpspi_flash_ll_calculate_clock_reg(clock_div))
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ)
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : -1)
#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \
: gpspi_flash_ll_get_hw(host_id)))

View File

@ -15,6 +15,7 @@
#include <stdlib.h>
#include "soc/spi_periph.h"
#include "soc/spi_struct.h"
#include "soc/pcr_struct.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h"
#include <sys/param.h> // For MIN/MAX
@ -426,6 +427,39 @@ static inline uint32_t gpspi_flash_ll_calculate_clock_reg(uint8_t clkdiv)
return div_parameter;
}
/**
* Set the clock source
*
* @param hw Beginning address of the peripheral registers.
* @param clk_source Clock source to use
*/
static inline void gpspi_flash_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source)
{
switch (clk_source) {
case SPI_CLK_SRC_RC_FAST:
PCR.spi2_clkm_conf.spi2_clkm_sel = 2;
break;
case SPI_CLK_SRC_XTAL:
PCR.spi2_clkm_conf.spi2_clkm_sel = 0;
break;
default:
PCR.spi2_clkm_conf.spi2_clkm_sel = 1;
break;
}
}
/**
* Enable/disable SPI flash module clock
*
* @param hw Beginning address of the peripheral registers.
* @param enable true to enable, false to disable
*/
static inline void gpspi_flash_ll_enable_clock(spi_dev_t *hw, bool enable)
{
(void) hw;
PCR.spi2_clkm_conf.spi2_clkm_en = enable;
}
#ifdef __cplusplus
}
#endif

View File

@ -24,7 +24,7 @@ extern "C" {
#define spi_flash_ll_calculate_clock_reg(host_id, clock_div) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_calculate_clock_reg(clock_div) \
: gpspi_flash_ll_calculate_clock_reg(clock_div))
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ)
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : -1)
#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \
: gpspi_flash_ll_get_hw(host_id)))

View File

@ -15,6 +15,7 @@
#include <stdlib.h>
#include "soc/spi_periph.h"
#include "soc/spi_struct.h"
#include "soc/pcr_struct.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h"
#include <sys/param.h> // For MIN/MAX
@ -426,6 +427,39 @@ static inline uint32_t gpspi_flash_ll_calculate_clock_reg(uint8_t clkdiv)
return div_parameter;
}
/**
* Set the clock source
*
* @param hw Beginning address of the peripheral registers.
* @param clk_source Clock source to use
*/
static inline void gpspi_flash_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source)
{
switch (clk_source) {
case SPI_CLK_SRC_RC_FAST:
PCR.spi2_clkm_conf.spi2_clkm_sel = 2;
break;
case SPI_CLK_SRC_XTAL:
PCR.spi2_clkm_conf.spi2_clkm_sel = 0;
break;
default:
PCR.spi2_clkm_conf.spi2_clkm_sel = 1;
break;
}
}
/**
* Enable/disable SPI flash module clock
*
* @param hw Beginning address of the peripheral registers.
* @param enable true to enable, false to disable
*/
static inline void gpspi_flash_ll_enable_clock(spi_dev_t *hw, bool enable)
{
(void) hw;
PCR.spi2_clkm_conf.spi2_clkm_en = enable;
}
#ifdef __cplusplus
}
#endif

View File

@ -26,7 +26,7 @@ extern "C" {
#define spi_flash_ll_calculate_clock_reg(host_id, clock_div) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_calculate_clock_reg(clock_div) \
: gpspi_flash_ll_calculate_clock_reg(clock_div))
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ)
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : -1)
#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \
: gpspi_flash_ll_get_hw(host_id)))

View File

@ -15,6 +15,7 @@
#include <stdlib.h>
#include "soc/spi_periph.h"
#include "soc/spi_struct.h"
#include "soc/pcr_struct.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h"
#include <sys/param.h> // For MIN/MAX
@ -426,6 +427,39 @@ static inline uint32_t gpspi_flash_ll_calculate_clock_reg(uint8_t clkdiv)
return div_parameter;
}
/**
* Set the clock source
*
* @param hw Beginning address of the peripheral registers.
* @param clk_source Clock source to use
*/
static inline void gpspi_flash_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source)
{
switch (clk_source) {
case SPI_CLK_SRC_RC_FAST:
PCR.spi2_clkm_conf.spi2_clkm_sel = 2;
break;
case SPI_CLK_SRC_XTAL:
PCR.spi2_clkm_conf.spi2_clkm_sel = 0;
break;
default:
PCR.spi2_clkm_conf.spi2_clkm_sel = 1;
break;
}
}
/**
* Enable/disable SPI flash module clock
*
* @param hw Beginning address of the peripheral registers.
* @param enable true to enable, false to disable
*/
static inline void gpspi_flash_ll_enable_clock(spi_dev_t *hw, bool enable)
{
(void) hw;
PCR.spi2_clkm_conf.spi2_clkm_en = enable;
}
#ifdef __cplusplus
}
#endif

View File

@ -24,7 +24,7 @@ extern "C" {
#define spi_flash_ll_calculate_clock_reg(host_id, clock_div) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_calculate_clock_reg(clock_div) \
: gpspi_flash_ll_calculate_clock_reg(clock_div))
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ)
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : -1)
#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \
: gpspi_flash_ll_get_hw(host_id)))

View File

@ -15,6 +15,7 @@
#include <stdlib.h>
#include "soc/spi_periph.h"
#include "soc/spi_struct.h"
#include "soc/pcr_struct.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h"
#include <sys/param.h> // For MIN/MAX
@ -426,6 +427,38 @@ static inline uint32_t gpspi_flash_ll_calculate_clock_reg(uint8_t clkdiv)
return div_parameter;
}
/**
* Set the clock source
*
* @param hw Beginning address of the peripheral registers.
* @param clk_source Clock source to use
*/
static inline void gpspi_flash_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source)
{
switch (clk_source) {
case SPI_CLK_SRC_RC_FAST:
PCR.spi2_clkm_conf.spi2_clkm_sel = 2;
break;
case SPI_CLK_SRC_XTAL:
PCR.spi2_clkm_conf.spi2_clkm_sel = 0;
break;
default:
PCR.spi2_clkm_conf.spi2_clkm_sel = 1;
break;
}
}
/**
* Enable/disable SPI flash module clock
*
* @param hw Beginning address of the peripheral registers.
* @param enable true to enable, false to disable
*/
static inline void gpspi_flash_ll_enable_clock(spi_dev_t *hw, bool enable)
{
PCR.spi2_clkm_conf.spi2_clkm_en = enable;
}
#ifdef __cplusplus
}
#endif

View File

@ -21,7 +21,7 @@ extern "C" {
#define spi_flash_ll_calculate_clock_reg(host_id, clock_div) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_calculate_clock_reg(clock_div) \
: gpspi_flash_ll_calculate_clock_reg(clock_div))
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ)
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : -1)
#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \
: gpspi_flash_ll_get_hw(host_id)))

View File

@ -15,6 +15,7 @@
#include <stdlib.h>
#include "soc/spi_periph.h"
#include "soc/spi_struct.h"
#include "soc/pcr_struct.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h"
#include <sys/param.h> // For MIN/MAX
@ -425,6 +426,34 @@ static inline uint32_t gpspi_flash_ll_calculate_clock_reg(uint8_t clkdiv)
abort();
}
__attribute__((always_inline))
static inline void gpspi_flash_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source)
{
switch (clk_source) {
case SPI_CLK_SRC_RC_FAST:
PCR.spi2_clkm_conf.spi2_clkm_sel = 2;
break;
case SPI_CLK_SRC_XTAL:
PCR.spi2_clkm_conf.spi2_clkm_sel = 0;
break;
default:
PCR.spi2_clkm_conf.spi2_clkm_sel = 1;
break;
}
}
/**
* Enable/disable SPI flash module clock
*
* @param hw Beginning address of the peripheral registers.
* @param enable true to enable, false to disable
*/
static inline void gpspi_flash_ll_enable_clock(spi_dev_t *hw, bool enable)
{
(void) hw;
PCR.spi2_clkm_conf.spi2_clkm_en = enable;
}
#ifdef __cplusplus
}
#endif

View File

@ -26,7 +26,7 @@ extern "C" {
#define spi_flash_ll_calculate_clock_reg(host_id, clock_div) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_calculate_clock_reg(clock_div) \
: gpspi_flash_ll_calculate_clock_reg(clock_div))
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ)
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : -1)
#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \
: gpspi_flash_ll_get_hw(host_id)))

View File

@ -15,6 +15,8 @@
#include <stdlib.h>
#include "soc/spi_periph.h"
#include "soc/spi_struct.h"
#include "soc/hp_sys_clkrst_struct.h"
#include "hal/assert.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h"
#include <sys/param.h> // For MIN/MAX
@ -37,6 +39,8 @@ extern "C" {
typedef typeof(GPSPI2.clock.val) gpspi_flash_ll_clock_reg_t;
#define GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ (80)
#define GPSPI_FLASH_LL_SUPPORT_CLK_SRC_PRE_DIV (1)
#define GPSPI_FLASH_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
/*------------------------------------------------------------------------------
* Control
@ -432,6 +436,84 @@ static inline uint32_t gpspi_flash_ll_calculate_clock_reg(uint8_t clkdiv)
return div_parameter;
}
/**
* Set the clock source
*
* @param hw Beginning address of the peripheral registers.
* @param clk_source Clock source to use
*/
static inline void _gpspi_flash_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source)
{
uint32_t clk_id = 0;
switch (clk_source) {
case SPI_CLK_SRC_SPLL:
clk_id = 4;
break;
case SPI_CLK_SRC_RC_FAST:
clk_id = 1;
break;
case SPI_CLK_SRC_XTAL:
clk_id = 0;
break;
default:
HAL_ASSERT(false);
}
if (hw == &GPSPI2) {
HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi2_clk_src_sel = clk_id;
} else if (hw == &GPSPI3) {
HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi3_clk_src_sel = clk_id;
}
}
/// 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 gpspi_flash_ll_set_clk_source(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_gpspi_flash_ll_set_clk_source(__VA_ARGS__); \
} while(0)
/**
* Enable/disable SPI flash module clock
*
* @param host_id SPI host ID
* @param enable true to enable, false to disable
*/
static inline void _gpspi_flash_ll_enable_clock(spi_dev_t *hw, bool enable)
{
if (hw == &GPSPI2) {
HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi2_hs_clk_en = enable;
HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi2_mst_clk_en = enable;
} else if (hw == &GPSPI3) {
HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi3_hs_clk_en = enable;
HP_SYS_CLKRST.peri_clk_ctrl117.reg_gpspi3_mst_clk_en = enable;
}
}
/// 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 gpspi_flash_ll_enable_clock(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_gpspi_flash_ll_enable_clock(__VA_ARGS__); \
} while(0)
/**
* Enable/disable SPI flash module clock
*
* @param hw Beginning address of the peripheral registers.
* @param enable true to enable, false to disable
*/
static inline void gpspi_flash_ll_clk_source_pre_div(spi_dev_t *hw, uint8_t hs_div, uint8_t mst_div)
{
if (hw == &GPSPI2) {
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl116, reg_gpspi2_hs_clk_div_num, hs_div - 1);
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl116, reg_gpspi2_mst_clk_div_num, mst_div - 1);
} else if (hw == &GPSPI3) {
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl117, reg_gpspi3_hs_clk_div_num, hs_div - 1);
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl117, reg_gpspi3_mst_clk_div_num, mst_div - 1);
}
}
#ifdef __cplusplus
}
#endif

View File

@ -24,7 +24,7 @@ extern "C" {
#define spi_flash_ll_calculate_clock_reg(host_id, clock_div) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_calculate_clock_reg(clock_div) \
: gpspi_flash_ll_calculate_clock_reg(clock_div))
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ)
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : -1)
#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \
: gpspi_flash_ll_get_hw(host_id)))

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -421,6 +421,28 @@ static inline uint32_t gpspi_flash_ll_calculate_clock_reg(uint8_t clkdiv)
return div_parameter;
}
/**
* Set the clock source
*
* @param hw Beginning address of the peripheral registers.
* @param clk_source Clock source to use
*/
static inline void gpspi_flash_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source)
{
//empty, keep this for compatibility
}
/**
* Enable/disable SPI flash module clock
*
* @param hw Beginning address of the peripheral registers.
* @param enable true to enable, false to disable
*/
static inline void gpspi_flash_ll_enable_clock(spi_dev_t *hw, bool enable)
{
//empty, keep this for compatibility
}
#ifdef __cplusplus
}
#endif

View File

@ -25,7 +25,7 @@ extern "C" {
#define spi_flash_ll_calculate_clock_reg(host_id, clock_div) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_calculate_clock_reg(clock_div) \
: gpspi_flash_ll_calculate_clock_reg(clock_div))
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ)
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : -1)
#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \
: gpspi_flash_ll_get_hw(host_id)))

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -433,6 +433,35 @@ static inline uint32_t gpspi_flash_ll_calculate_clock_reg(uint8_t clkdiv)
return div_parameter;
}
/**
* Set the clock source
*
* @param hw Beginning address of the peripheral registers.
* @param clk_source Clock source to use
*/
static inline void gpspi_flash_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source)
{
switch (clk_source) {
case SPI_CLK_SRC_XTAL:
hw->clk_gate.mst_clk_sel = 0;
break;
default:
hw->clk_gate.mst_clk_sel = 1;
break;
}
}
/**
* Enable/disable SPI flash module clock
*
* @param hw Beginning address of the peripheral registers.
* @param enable true to enable, false to disable
*/
static inline void gpspi_flash_ll_enable_clock(spi_dev_t *hw, bool enable)
{
hw->clk_gate.clk_en = enable;
}
#ifdef __cplusplus
}
#endif

View File

@ -24,7 +24,7 @@ extern "C" {
#define spi_flash_ll_calculate_clock_reg(host_id, clock_div) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_calculate_clock_reg(clock_div) \
: gpspi_flash_ll_calculate_clock_reg(clock_div))
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ)
#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : -1)
#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \
: gpspi_flash_ll_get_hw(host_id)))

View File

@ -26,6 +26,9 @@
#include "esp_rom_spiflash.h"
#include "bootloader_flash.h"
#include "esp_check.h"
#include "esp_private/esp_clk_tree_common.h"
#include "clk_ctrl_os.h"
#include "soc/soc_caps.h"
__attribute__((unused)) static const char TAG[] = "spi_flash";
@ -37,6 +40,12 @@ __attribute__((unused)) static const char TAG[] = "spi_flash";
#error "Flash chip size equal or over 32MB memory cannot use driver in ROM"
#endif
#if SOC_PERIPH_CLK_CTRL_SHARED
#define GPSPI_FLASH_RCC_CLOCK_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define GPSPI_FLASH_RCC_CLOCK_ATOMIC()
#endif
/* This pointer is defined in ROM and extern-ed on targets where CONFIG_SPI_FLASH_ROM_IMPL = y*/
#if !CONFIG_SPI_FLASH_ROM_IMPL
esp_flash_t *esp_flash_default_chip = NULL;
@ -230,6 +239,120 @@ static esp_err_t acquire_spi_device(const esp_flash_spi_device_config_t *config,
return ret;
}
#if GPSPI_FLASH_LL_SUPPORT_CLK_SRC_PRE_DIV
static uint32_t s_spi_find_clock_src_pre_div(uint32_t src_freq, uint32_t target_freq)
{
// pre division must be even and at least 2
uint32_t min_div = ((src_freq / GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ) + 1) & (~0x01UL);
min_div = min_div < 2 ? 2 : min_div;
uint32_t total_div = src_freq / target_freq;
// Loop the `div` to find a divisible value of `total_div`
for (uint32_t pre_div = min_div; pre_div <= total_div; pre_div += 2) {
if ((total_div % pre_div) || (total_div / pre_div) > GPSPI_FLASH_LL_PERIPH_CLK_DIV_MAX) {
continue;
}
return pre_div;
}
return min_div;
}
#endif //GPSPI_FLASH_LL_SUPPORT_CLK_SRC_PRE_DIV
/**
* Configure GPSPI clock source and frequency for flash device
*
* @param config Flash device configuration
* @return Clock source frequency in MHz
*/
static uint32_t init_gpspi_clock(esp_flash_t *chip, const esp_flash_spi_device_config_t *config)
{
#if !CONFIG_IDF_TARGET_ESP32
// Get clock source frequency
uint32_t clk_src_freq = 0;
spi_clock_source_t clk_src = config->clock_source ? config->clock_source : SPI_CLK_SRC_DEFAULT;
#if SOC_SPI_SUPPORT_CLK_RC_FAST
if (config->clock_source == SPI_CLK_SRC_RC_FAST) {
periph_rtc_dig_clk8m_enable();
}
#endif
esp_clk_tree_enable_src(clk_src, true);
esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq);
// Enable GPSPI clock
GPSPI_FLASH_RCC_CLOCK_ATOMIC() {
gpspi_flash_ll_enable_clock(spi_flash_ll_get_hw(config->host_id), true);
gpspi_flash_ll_set_clk_source(spi_flash_ll_get_hw(config->host_id), clk_src);
}
// Store clock source in chip for later cleanup
chip->clock_source = clk_src;
// Calculate final clock source frequency
uint32_t final_freq_mhz;
#if GPSPI_FLASH_LL_SUPPORT_CLK_SRC_PRE_DIV
uint32_t pre_div = s_spi_find_clock_src_pre_div(clk_src_freq, GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ * 1000 * 1000);
gpspi_flash_ll_clk_source_pre_div(spi_flash_ll_get_hw(config->host_id), pre_div / 2, 2);
final_freq_mhz = clk_src_freq / (1 * 1000 * 1000) / (pre_div);
#else
final_freq_mhz = clk_src_freq / (1 * 1000 * 1000);
#endif
return final_freq_mhz;
#else
// Do nothing for ESP32
return SPI_FLASH_LL_CLOCK_FREQUENCY_MHZ;
#endif // !CONFIG_IDF_TARGET_ESP32
}
#if !CONFIG_IDF_TARGET_ESP32
/**
* Get host_id from esp_flash_t chip pointer
*
* @param chip Flash chip pointer
* @return host_id or -1 if invalid
*/
static int get_host_id_from_chip(esp_flash_t *chip)
{
if (!chip || !chip->host) {
return -1;
}
spi_flash_hal_context_t* ctx = (spi_flash_hal_context_t*)chip->host;
return spi_flash_ll_hw_get_id(ctx->spi);
}
#endif // !CONFIG_IDF_TARGET_ESP32
static void deinit_gpspi_clock(esp_flash_t *chip)
{
#if !CONFIG_IDF_TARGET_ESP32
if (!chip) {
return;
}
int host_id = get_host_id_from_chip(chip);
if (host_id < 0) {
return;
}
// Disable GPSPI clock
GPSPI_FLASH_RCC_CLOCK_ATOMIC() {
gpspi_flash_ll_enable_clock(spi_flash_ll_get_hw(host_id), false);
}
// Disable the clock source
esp_clk_tree_enable_src(chip->clock_source, false);
#if SOC_SPI_SUPPORT_CLK_RC_FAST
// Disable RC_FAST clock if it was used
if (chip->clock_source == SPI_CLK_SRC_RC_FAST) {
periph_rtc_dig_clk8m_disable();
}
#endif
#endif // !CONFIG_IDF_TARGET_ESP32
}
esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_device_config_t *config)
{
if (out_chip == NULL) {
@ -286,7 +409,8 @@ esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_d
.freq_mhz = config->freq_mhz,
};
host_cfg.clock_src_freq = spi_flash_ll_get_source_clock_freq_mhz(host_cfg.host_id);
// Init the gpspi clock
host_cfg.clock_src_freq = init_gpspi_clock(chip, config);
err = memspi_host_init_pointers(host, &host_cfg);
if (err != ESP_OK) {
@ -310,6 +434,9 @@ esp_err_t spi_bus_remove_flash_device(esp_flash_t *chip)
return ESP_ERR_INVALID_ARG;
}
// Disable GPSPI clocks before cleanup
deinit_gpspi_clock(chip);
spi_bus_lock_dev_handle_t dev_handle = NULL;
esp_flash_deinit_os_functions(chip, &dev_handle);
if (dev_handle) {

View File

@ -8,7 +8,6 @@
#include "esp_err.h"
#include <stdint.h>
#include <stdbool.h>
#include "hal/spi_flash_types.h"
#ifdef __cplusplus
@ -104,6 +103,7 @@ struct esp_flash_t {
uint32_t busy :1; ///< This flag is used to verify chip's status.
uint32_t hpm_dummy_ena :1; ///< This flag is used to verify whether flash works under HPM status.
uint32_t reserved_flags :30; ///< reserved.
int clock_source; ///< Clock source for GPSPI.
};

View File

@ -27,6 +27,7 @@ typedef struct {
*/
int cs_id;
int freq_mhz; ///< The frequency of flash chip(MHZ)
spi_clock_source_t clock_source;///< Select SPI clock source, `SPI_CLK_SRC_DEFAULT` by default.
} esp_flash_spi_device_config_t;
/**