mspi: support 120M DDR flash and psram on S3 (experimental)

This commit is contained in:
Armando 2023-03-28 17:03:47 +08:00
parent 0026f73dcb
commit 6d4c0bb3aa
11 changed files with 234 additions and 56 deletions

View File

@ -139,43 +139,45 @@ void mspi_timing_config_psram_read_data(uint8_t *buf, uint32_t addr, uint32_t le
/*-------------------------------------------------------------------------------------------------
* SPI1 Timing Tuning APIs
* These APIs are only used in `spi_flash_timing_tuning.c/sweep_for_success_sample_points()` for
* configuring SPI1 timing tuning related registers to find best tuning parameter
*
* These APIs are only used in `mspi_timing_tuning.c` for configuring SPI1 timing
* tuning related registers to find best tuning parameter for Flash and PSRAM
*-------------------------------------------------------------------------------------------------*/
/**
* @brief Tune Flash Din Mode and Num of SPI1
* @param din_mode Din mode
* @param din_num Din num
* @brief Tune Flash timing registers for SPI1 accessing Flash
*
* @param[in] params Timing parameters
*/
void mspi_timing_config_flash_tune_din_num_mode(uint8_t din_mode, uint8_t din_num);
void mspi_timing_config_flash_set_tuning_regs(const mspi_timing_tuning_param_t *params);
/**
* @brief Tune Flash extra dummy of SPI1
* @param extra_dummy extra dummy bits
* @brief Tune PSRAM timing registers for SPI1 accessing PSRAM
*
* @param[in] params Timing parameters
*/
void mspi_timing_config_psram_set_tuning_regs(const mspi_timing_tuning_param_t *params);
/*-------------------------------------------------------------------------------------------------
* APIs for coordination with ESP Flash driver
*-------------------------------------------------------------------------------------------------*/
/**
* SPI1 register info get APIs. These APIs inform `mspi_timing_tuning.c` (driver layer) of the SPI1 flash settings.
* In this way, other components (e.g.: esp_flash driver) can get the info from it (`mspi_timing_tuning.c`).
*/
void mspi_timing_config_flash_tune_dummy(uint8_t extra_dummy);
/**
* @brief Tune PSRAM Din Mode and Num of SPI1
* @param din_mode Din mode
* @param din_num Din num
*/
void mspi_timing_config_psram_tune_din_num_mode(uint8_t din_mode, uint8_t din_num);
/**
* @brief Tune PSRAM extra dummy of SPI1
* @param extra_dummy extra dummy bits
*/
void mspi_timing_config_psram_tune_dummy(uint8_t extra_dummy);
/**
* SPI1 register info get APIs. These APIs inform `spi_flash_timing_tuning.c` (driver layer) of the SPI1 flash settings.
* In this way, other components (e.g.: esp_flash driver) can get the info from it (`spi_flash_timing_tuning.c`).
* @brief Get CS timing
*
* @param[out] setup_time Setup time
* @param[out] hold_time Hold time
*/
void mspi_timing_config_get_cs_timing(uint8_t *setup_time, uint32_t *hold_time);
/**
* @brief Get Flash clock reg val
*
* @return Flash clock reg val
*/
uint32_t mspi_timing_config_get_flash_clock_reg(void);

View File

@ -15,8 +15,11 @@
#include "soc/io_mux_reg.h"
#include "esp_private/mspi_timing_tuning.h"
#include "soc/soc.h"
#include "soc/rtc.h"
#include "hal/spi_flash_hal.h"
#include "hal/mspi_timing_tuning_ll.h"
#include "hal/clk_tree_ll.h"
#include "hal/regi2c_ctrl_ll.h"
#include "mspi_timing_config.h"
#if CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/cache.h"
@ -107,7 +110,7 @@ static void init_spi1_for_tuning(bool is_flash)
* We use different SPI1 timing tuning config to read data to see if current MSPI sampling is successful.
* The sampling result will be stored in an array. In this array, successful item will be 1, failed item will be 0.
*/
static void sweep_for_success_sample_points(uint8_t *reference_data, const mspi_timing_config_t *config, bool is_flash, uint8_t *out_array)
static void sweep_for_success_sample_points(const uint8_t *reference_data, const mspi_timing_config_t *config, bool is_flash, uint8_t *out_array)
{
uint32_t config_idx = 0;
uint8_t read_data[MSPI_TIMING_TEST_DATA_LEN] = {0};
@ -116,20 +119,21 @@ static void sweep_for_success_sample_points(uint8_t *reference_data, const mspi_
memset(read_data, 0, MSPI_TIMING_TEST_DATA_LEN);
#if MSPI_TIMING_FLASH_NEEDS_TUNING
if (is_flash) {
mspi_timing_config_flash_tune_din_num_mode(config->tuning_config_table[config_idx].spi_din_mode, config->tuning_config_table[config_idx].spi_din_num);
mspi_timing_config_flash_tune_dummy(config->tuning_config_table[config_idx].extra_dummy_len);
mspi_timing_config_flash_set_tuning_regs(&(config->tuning_config_table[config_idx]));
mspi_timing_config_flash_read_data(read_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR, sizeof(read_data));
}
#endif
#if MSPI_TIMING_PSRAM_NEEDS_TUNING
if (!is_flash) {
mspi_timing_config_psram_tune_din_num_mode(config->tuning_config_table[config_idx].spi_din_mode, config->tuning_config_table[config_idx].spi_din_num);
mspi_timing_config_psram_tune_dummy(config->tuning_config_table[config_idx].extra_dummy_len);
mspi_timing_config_psram_set_tuning_regs(&(config->tuning_config_table[config_idx]));
mspi_timing_config_psram_read_data(read_data, MSPI_TIMING_PSRAM_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN);
}
#endif
if (memcmp(reference_data, read_data, sizeof(read_data)) == 0) {
out_array[config_idx] = 1;
ESP_EARLY_LOGD(TAG, "%d, good", config_idx);
} else {
ESP_EARLY_LOGD(TAG, "%d, bad", config_idx);
}
}
}
@ -164,14 +168,77 @@ static void find_max_consecutive_success_points(uint8_t *array, uint32_t size, u
*out_end_index = match_num == size ? size : end;
}
#if (MSPI_TIMING_FLASH_DTR_MODE || MSPI_TIMING_PSRAM_DTR_MODE) && (MSPI_TIMING_CORE_CLOCK_MHZ == 240)
static bool get_working_pll_freq(const uint8_t *reference_data, bool is_flash, uint32_t *out_max_freq, uint32_t *out_min_freq)
{
uint8_t read_data[MSPI_TIMING_TEST_DATA_LEN] = {0};
rtc_cpu_freq_config_t previous_config;
rtc_clk_cpu_freq_get_config(&previous_config);
uint32_t big_num = MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX * 2; //This number should be larger than MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX, for error handling
uint32_t max_freq = 0;
uint32_t min_freq = big_num;
rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
//BBPLL CALIBRATION START
regi2c_ctrl_ll_bbpll_calibration_start();
for (int pll_mhz_tuning = MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MIN; pll_mhz_tuning <= MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX; pll_mhz_tuning += 8) {
/**
* pll_mhz = xtal_mhz * (oc_div + 4) / (oc_ref_div + 1)
*/
clk_ll_bbpll_set_frequency_for_mspi_tuning(xtal_freq, pll_mhz_tuning, ((pll_mhz_tuning / 4) - 4), 9);
memset(read_data, 0, MSPI_TIMING_TEST_DATA_LEN);
if (is_flash) {
mspi_timing_config_flash_read_data(read_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN);
} else {
mspi_timing_config_psram_read_data(read_data, MSPI_TIMING_PSRAM_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN);
}
if (memcmp(read_data, reference_data, MSPI_TIMING_TEST_DATA_LEN) == 0) {
max_freq = MAX(pll_mhz_tuning, max_freq);
min_freq = MIN(pll_mhz_tuning, min_freq);
//Continue to find successful cases
continue;
}
if (max_freq != 0) {
//The first fail case after successful case(s) is the end
break;
}
//If no break, no successful case found, continue to find successful cases
}
//restore PLL config
clk_ll_bbpll_set_freq_mhz(previous_config.source_freq_mhz);
clk_ll_bbpll_set_config(previous_config.source_freq_mhz, xtal_freq);
//WAIT CALIBRATION DONE
while(!regi2c_ctrl_ll_bbpll_calibration_is_done());
//BBPLL CALIBRATION STOP
regi2c_ctrl_ll_bbpll_calibration_stop();
*out_max_freq = max_freq;
*out_min_freq = min_freq;
return (max_freq != 0);
}
#endif //Frequency Scanning
#if MSPI_TIMING_FLASH_DTR_MODE || MSPI_TIMING_PSRAM_DTR_MODE
static uint32_t select_best_tuning_config_dtr(mspi_timing_config_t *config, uint32_t consecutive_length, uint32_t end)
static uint32_t select_best_tuning_config_dtr(mspi_timing_config_t *config, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_flash)
{
#if (MSPI_TIMING_CORE_CLOCK_MHZ == 160)
//Core clock 160M DTR best point scheme
uint32_t best_point;
(void) reference_data;
(void) is_flash;
uint32_t best_point = 0;
//Define these magic number in macros in `spi_timing_config.h`. TODO: IDF-3663
//These numbers will probably be same on other chips, if this version of algorithm is utilised
if (consecutive_length <= 2 || consecutive_length >= 6) {
//tuning is FAIL, select default point, and generate a warning
best_point = config->default_config_id;
@ -187,6 +254,41 @@ static uint32_t select_best_tuning_config_dtr(mspi_timing_config_t *config, uint
}
return best_point;
#elif (MSPI_TIMING_CORE_CLOCK_MHZ == 240)
uint32_t best_point = 0;
uint32_t current_point = end + 1 - consecutive_length;
bool ret = false;
//This `max_freq` is the max pll frequency that per MSPI timing tuning config can work
uint32_t max_freq = 0;
uint32_t temp_max_freq = 0;
uint32_t temp_min_freq = 0;
for (; current_point <= end; current_point++) {
if (is_flash) {
mspi_timing_config_flash_set_tuning_regs(&(config->tuning_config_table[current_point]));
} else {
mspi_timing_config_psram_set_tuning_regs(&(config->tuning_config_table[current_point]));
}
ret = get_working_pll_freq(reference_data, is_flash, &temp_max_freq, &temp_min_freq);
if (ret && temp_min_freq <= MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_LOW && temp_max_freq >= MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_HIGH && temp_max_freq > max_freq) {
max_freq = temp_max_freq;
best_point = current_point;
}
ESP_EARLY_LOGD(TAG, "sample point %d, max pll is %d mhz, min pll is %d\n", current_point, temp_max_freq, temp_min_freq);
}
if (max_freq == 0) {
ESP_EARLY_LOGW(TAG, "freq scan tuning fail, best point is fallen back to index %d", end + 1 - consecutive_length);
best_point = end + 1 - consecutive_length;
} else {
ESP_EARLY_LOGD(TAG, "freq scan success, max pll is %dmhz, best point is index %d", max_freq, best_point);
}
return best_point;
#else
//won't reach here
abort();
@ -221,19 +323,19 @@ static uint32_t select_best_tuning_config_str(mspi_timing_config_t *config, uint
}
#endif
static void select_best_tuning_config(mspi_timing_config_t *config, uint32_t consecutive_length, uint32_t end, bool is_flash)
static void select_best_tuning_config(mspi_timing_config_t *config, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_flash)
{
uint32_t best_point = 0;
if (is_flash) {
#if MSPI_TIMING_FLASH_DTR_MODE
best_point = select_best_tuning_config_dtr(config, consecutive_length, end);
best_point = select_best_tuning_config_dtr(config, consecutive_length, end, reference_data, is_flash);
#elif MSPI_TIMING_FLASH_STR_MODE
best_point = select_best_tuning_config_str(config, consecutive_length, end);
#endif
s_flash_best_timing_tuning_config = config->tuning_config_table[best_point];
} else {
#if MSPI_TIMING_PSRAM_DTR_MODE
best_point = select_best_tuning_config_dtr(config, consecutive_length, end);
best_point = select_best_tuning_config_dtr(config, consecutive_length, end, reference_data, is_flash);
#elif MSPI_TIMING_PSRAM_STR_MODE
best_point = select_best_tuning_config_str(config, consecutive_length, end);
#endif
@ -241,7 +343,7 @@ static void select_best_tuning_config(mspi_timing_config_t *config, uint32_t con
}
}
static void do_tuning(uint8_t *reference_data, mspi_timing_config_t *timing_config, bool is_flash)
static void do_tuning(const uint8_t *reference_data, mspi_timing_config_t *timing_config, bool is_flash)
{
/**
* We use SPI1 to tune the timing:
@ -256,7 +358,7 @@ static void do_tuning(uint8_t *reference_data, mspi_timing_config_t *timing_conf
init_spi1_for_tuning(is_flash);
sweep_for_success_sample_points(reference_data, timing_config, is_flash, sample_result);
find_max_consecutive_success_points(sample_result, MSPI_TIMING_CONFIG_NUM_DEFAULT, &consecutive_length, &last_success_point);
select_best_tuning_config(timing_config, consecutive_length, last_success_point, is_flash);
select_best_tuning_config(timing_config, consecutive_length, last_success_point, reference_data, is_flash);
}
#endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING

View File

@ -290,40 +290,33 @@ void mspi_timing_config_psram_read_data(uint8_t *buf, uint32_t addr, uint32_t le
* These APIs are only used in `spi_flash_timing_tuning.c/sweep_for_success_sample_points()` for
* configuring SPI1 timing tuning related registers to find best tuning parameter
*-------------------------------------------------------------------------------------------------*/
void mspi_timing_config_flash_tune_din_num_mode(uint8_t din_mode, uint8_t din_num)
void mspi_timing_config_flash_set_tuning_regs(const mspi_timing_tuning_param_t *params)
{
/**
* 1. SPI_MEM_DINx_MODE(1), SPI_MEM_DINx_NUM(1) are meaningless
* SPI0 and SPI1 share the SPI_MEM_DINx_MODE(0), SPI_MEM_DINx_NUM(0) for FLASH timing tuning
* 2. We use SPI1 to get the best Flash timing tuning (mode and num) config
*/
mspi_timing_config_flash_set_din_mode_num(0, din_mode, din_num);
mspi_timing_config_flash_set_din_mode_num(0, params->spi_din_mode, params->spi_din_num);
mspi_timing_config_flash_set_extra_dummy(1, params->extra_dummy_len);
}
void mspi_timing_config_flash_tune_dummy(uint8_t extra_dummy)
{
mspi_timing_config_flash_set_extra_dummy(1, extra_dummy);
}
void mspi_timing_config_psram_tune_din_num_mode(uint8_t din_mode, uint8_t din_num)
void mspi_timing_config_psram_set_tuning_regs(const mspi_timing_tuning_param_t *params)
{
/**
* 1. SPI_MEM_SPI_SMEM_DINx_MODE(1), SPI_MEM_SPI_SMEM_DINx_NUM(1) are meaningless
* SPI0 and SPI1 share the SPI_MEM_SPI_SMEM_DINx_MODE(0), SPI_MEM_SPI_SMEM_DINx_NUM(0) for PSRAM timing tuning
* 2. We use SPI1 to get the best PSRAM timing tuning (mode and num) config
*/
mspi_timing_config_psram_set_din_mode_num(0, din_mode, din_num);
}
mspi_timing_config_psram_set_din_mode_num(0, params->spi_din_mode, params->spi_din_num);
void mspi_timing_config_psram_tune_dummy(uint8_t extra_dummy)
{
#if CONFIG_SPIRAM_MODE_OCT
//On 728, for SPI1, flash and psram share the extra dummy register
mspi_timing_config_flash_set_extra_dummy(1, extra_dummy);
mspi_timing_config_flash_set_extra_dummy(1, params->extra_dummy_len);
#elif CONFIG_SPIRAM_MODE_QUAD
//Update this `s_psram_extra_dummy`, the `s_psram_read_data` will set dummy according to this `s_psram_extra_dummy`
s_psram_extra_dummy = extra_dummy;
mspi_timing_ll_set_quad_flash_dummy(1, extra_dummy - 1);
s_psram_extra_dummy = params->extra_dummy_len;
mspi_timing_ll_set_quad_flash_dummy(1, s_psram_extra_dummy - 1);
#endif
}

View File

@ -128,6 +128,11 @@
#endif
#endif //PSRAM 120M STR
//PSRAM 120M STR
#if MSPI_TIMING_PSRAM_DTR_MODE && CONFIG_SPIRAM_SPEED_120M
#define MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 240
#endif //PSRAM 120M DTR
//------------------------------------------Determine the Core Clock-----------------------------------------------//
/**
@ -233,3 +238,20 @@ ESP_STATIC_ASSERT(CHECK_POWER_OF_2(MSPI_TIMING_CORE_CLOCK_MHZ / MSPI_TIMING_PSRA
#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE {{2, 0, 1}, {0, 0, 0}, {2, 2, 2}, {1, 0, 1}, {2, 0, 2}, {0, 0, 1}, {2, 2, 3}, {1, 0, 2}, {2, 0, 3}, {0, 0, 2}, {2, 2, 4}, {1, 0, 3}}
#define MSPI_TIMING_PSRAM_CONFIG_NUM_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 12
#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 2
//PSRAM: core clock 240M, module clock 120M, DTR mode
#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE {{0, 0, 0}, {4, 1, 2}, {1, 0, 1}, {4, 0, 2}, {0, 0, 1}, {4, 1, 3}, {1, 0, 2}, {4, 0, 3}, {0, 0, 2}, {4, 1, 4}, {1, 0, 3}, {4, 0, 4}, {0, 0, 3}, {4, 1, 5}}
#define MSPI_TIMING_PSRAM_CONFIG_NUM_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE 14
#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE 1
//------------------------------------------Frequency Scanning Related-----------------------------------------------//
/**
* On ESP32S3, only module clock 120M, DDR mode needs frequency scan. Frequency scanning is to get the max workable PLL
* frequency under each successfull timing tuning configuration. PLL frequency may fluctuate under high temperature,
* this method is to get the tuning configuration that can work under higher PLL frequency.
*/
#define MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MIN 440
#define MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX 600
#define MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_LOW 448
#define MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_HIGH 520
#define MSPI_TIMING_PLL_FREQ_SCAN_STEP_MHZ_MODULE_CLK_120M 8

View File

@ -0,0 +1,6 @@
# F8R8, Flash 120M DDR, PSRAM disable
CONFIG_ESPTOOLPY_OCT_FLASH=y
CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR=y
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y

View File

@ -0,0 +1,10 @@
# F8R8, Flash 120M DDR, PSRAM 120M DDR
CONFIG_ESPTOOLPY_OCT_FLASH=y
CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR=y
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_120M=y

View File

@ -1,5 +1,6 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_SPIRAM_RODATA=y
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"

View File

@ -82,7 +82,6 @@ menu "SPI RAM config"
Select the speed for the SPI RAM chip.
config SPIRAM_SPEED_120M
depends on SPIRAM_MODE_QUAD
bool "120MHz clock speed"
config SPIRAM_SPEED_80M
bool "80MHz clock speed"

View File

@ -95,7 +95,7 @@ menu "Serial flasher config"
config ESPTOOLPY_FLASHFREQ_120M
bool "120 MHz"
select SPI_FLASH_HPM_ENABLE
depends on SOC_MEMSPI_SRC_FREQ_120M && ESPTOOLPY_FLASH_SAMPLE_MODE_STR
depends on SOC_MEMSPI_SRC_FREQ_120M
config ESPTOOLPY_FLASHFREQ_80M
bool "80 MHz"
depends on SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED

View File

@ -12,6 +12,7 @@
#include "soc/rtc.h"
#include "soc/system_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/regi2c_defs.h"
#include "hal/regi2c_ctrl.h"
#include "soc/regi2c_bbpll.h"
#include "hal/assert.h"
@ -682,6 +683,45 @@ static inline __attribute__((always_inline)) uint32_t clk_ll_rtc_slow_load_cal(v
return REG_READ(RTC_SLOW_CLK_CAL_REG);
}
/**
* @brief Configure PLL frequency for MSPI timing tuning
* @note Only used by the MSPI Timing tuning driver
*
* @param xtal_freq Xtal frequency
* @param pll_freq PLL frequency
* @param oc_div OC divider
* @param oc_ref_div OC ref divider
*/
static inline __attribute__((always_inline))
void clk_ll_bbpll_set_frequency_for_mspi_tuning(rtc_xtal_freq_t xtal_freq, int pll_freq, uint8_t oc_div, uint8_t oc_ref_div)
{
HAL_ASSERT(xtal_freq == RTC_XTAL_FREQ_40M);
uint32_t pll_reg = GET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
HAL_ASSERT(pll_reg == 0);
/* Set this register to let the digital part know 480M PLL is used */
SET_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
uint8_t dr1 = 0;
uint8_t dr3 = 0;
uint8_t dchgp = 5;
uint8_t dcur = 3;
uint8_t dbias = 2;
uint8_t i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | (oc_ref_div);
uint8_t i2c_bbpll_div_7_0 = oc_div;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B);
uint8_t i2c_bbpll_dcur = (1 << I2C_BBPLL_OC_DLREF_SEL_LSB ) | (3 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, i2c_bbpll_lref);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR1, dr1);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR3, dr3);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_VCO_DBIAS, dbias);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DHREF_SEL, 3);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DLREF_SEL, 1);
}
#ifdef __cplusplus
}
#endif

View File

@ -575,6 +575,9 @@ static inline uint8_t spimem_flash_ll_get_source_freq_mhz(void)
case 2:
clock_val = 160;
break;
case 3:
clock_val = 240;
break;
default:
abort();
}