1
6
7
8
9
10
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
38
39
42
53
54
55
56
57
62
63
64
65
66
67
68
69
70
71
72
73
74
75
78
79
80
81
82
83
101
102
103
104
107
108
109
110
111
112
113
114
115
116
117
118
122
127
128
129
134
135
136
144
145
146
147
148
154
155
156
/* ... */
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "soc/soc_caps.h"
#include "hal/gpio_ll.h"
#include "hal/spi_flash_hal.h"
#include "hal/assert.h"
#include "hal/log.h"
#include "hal/spi_flash_types.h"9 includes
#define APB_CYCLE_NS (1000*1000*1000LL/APB_CLK_FREQ)
static const char *TAG = "flash_hal";
static uint32_t get_flash_clock_divider(const spi_flash_hal_config_t *cfg)
{
const int clk_source = cfg->clock_src_freq;
const int clk_freq_mhz = cfg->freq_mhz;
int best_div = 0;
if (clk_source < clk_freq_mhz) {
HAL_LOGE(TAG, "Target frequency %dMHz higher than supported.", clk_freq_mhz);
abort();
}{...}
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
if (clk_freq_mhz == 26 || clk_freq_mhz == 27) {
best_div = 3;
}{...} else
#endif
{
/* ... */
best_div = (clk_source + clk_freq_mhz - 1) / clk_freq_mhz;
const div_t res = div(clk_source, clk_freq_mhz);
if (res.rem != 0) {
HAL_LOGW(TAG, "Flash clock frequency round down to %d", res.quot);
}{...}
}{...}
return best_div;
}{ ... }
static uint32_t spi_flash_cal_clock(const spi_flash_hal_config_t *cfg)
{
uint32_t div_parameter = spi_flash_ll_calculate_clock_reg(cfg->host_id, get_flash_clock_divider(cfg));
return div_parameter;
}{ ... }
static inline int get_dummy_n(bool gpio_is_used, int input_delay_ns, int eff_clk)
{
const int apbclk_kHz = APB_CLK_FREQ / 1000;
const int apbclk_n = APB_CLK_FREQ / eff_clk;
int gpio_delay_ns = 0;
#if GPIO_LL_MATRIX_DELAY_NS
gpio_delay_ns = gpio_is_used ? GPIO_LL_MATRIX_DELAY_NS : 0;
#endif
int apb_period_n = (1 + input_delay_ns + gpio_delay_ns) * apbclk_kHz / 1000 / 1000;
if (apb_period_n < 0) {
apb_period_n = 0;
}{...}
return apb_period_n / apbclk_n;
}{ ... }
#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
static inline int extra_dummy_under_timing_tuning(const spi_flash_hal_config_t *cfg)
{
bool main_flash = (cfg->host_id == SPI1_HOST && cfg->cs_num == 0);
int extra_dummy = 0;
if (main_flash) {
/* ... */
extra_dummy = cfg->extra_dummy;
}{...} else {
abort();
}{...}
return extra_dummy;
}{...}
/* ... */#endif
esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_hal_config_t *cfg)
{
if (cfg->cs_num >= SOC_SPI_PERIPH_CS_NUM(cfg->host_id)) {
return ESP_ERR_INVALID_ARG;
}{...}
*data_out = (spi_flash_hal_context_t) {
.inst = data_out->inst,
.spi = spi_flash_ll_get_hw(cfg->host_id),
.cs_num = cfg->cs_num,
.cs_hold = cfg->cs_hold,
.cs_setup = cfg->cs_setup,
.base_io_mode = cfg->default_io_mode,
.freq_mhz = cfg->freq_mhz,
}{...};
#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
if (cfg->using_timing_tuning) {
data_out->extra_dummy = extra_dummy_under_timing_tuning(cfg);
data_out->clock_conf = cfg->clock_config;
}{...} else
#endif
{
data_out->extra_dummy = get_dummy_n(!cfg->iomux, cfg->input_delay_ns, APB_CLK_FREQ/get_flash_clock_divider(cfg));
data_out->clock_conf = (spi_flash_ll_clock_reg_t)spi_flash_cal_clock(cfg);
}{...}
if (cfg->auto_sus_en) {
data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_SUSPEND;
data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_RESUME;
data_out->tsus_val = cfg->tsus_val;
}{...}
#if SOC_SPI_MEM_SUPPORT_OPI_MODE
if (cfg->octal_mode_en) {
data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_OCTAL_MODE;
}{...}
if (cfg->default_io_mode == SPI_FLASH_OPI_DTR) {
data_out->slicer_flags |= SPI_FLASH_HOST_CONTEXT_SLICER_FLAG_DTR;
}{...}
#endif/* ... */
return ESP_OK;
}{ ... }
bool spi_flash_hal_supports_direct_write(spi_flash_host_inst_t *host, const void *p)
{
(void)p;
bool direct_write = (((spi_flash_hal_context_t *)host)->spi != spi_flash_ll_get_hw(SPI1_HOST));
return direct_write;
}{ ... }
bool spi_flash_hal_supports_direct_read(spi_flash_host_inst_t *host, const void *p)
{
(void)p;
bool direct_read = ( ((spi_flash_hal_context_t *)host)->spi != spi_flash_ll_get_hw(SPI1_HOST));
return direct_read;
}{ ... }