mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-25 01:41:43 +00:00
refactor(spi_flash): Refactor gpspi flash for making it's clock accurate
This commit is contained in:
@@ -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) {
|
||||
|
Reference in New Issue
Block a user