diff --git a/include/libopencm3/stm32/h7/rcc.h b/include/libopencm3/stm32/h7/rcc.h index 1a2c1ce3..404da035 100644 --- a/include/libopencm3/stm32/h7/rcc.h +++ b/include/libopencm3/stm32/h7/rcc.h @@ -415,9 +415,8 @@ LGPL License Terms @ref lgpl_license #define RCC_HSI_BASE_FREQUENCY 64000000UL -/** Enumerations for clocks in the clock tree to allow user to get the current configuration of the - * clocks from the RCC module. These clock sources will each be tracked through the settings. - */ +/** Enumerations for core system/bus clocks for user/driver/system access to base bus clocks + * not directly associated with a peripheral. */ enum rcc_clock_source { RCC_CPUCLK, RCC_SYSCLK, @@ -439,22 +438,11 @@ enum rcc_osc { RCC_LSI }; -enum rcc_sysclk_mux { - RCC_SYSCLK_PLL, - RCC_SYSCLK_HSE, - RCC_SYSCLK_HSI, -}; - -enum rcc_pll_mux { - RCC_PLL_HSI = RCC_PLLCKSELR_PLLSRC_HSI, - RCC_PLL_HSE = RCC_PLLCKSELR_PLLSRC_HSE -}; - /** PLL Configuration structure. */ struct rcc_pll_config { - uint32_t hse_frequency; /**< User configured external crystal frequency. */ - enum rcc_sysclk_mux sysclk_mux; /**< SYSCLK source input selection. */ - enum rcc_pll_mux pll_mux; /**< PLL source input selection. */ + enum rcc_osc sysclock_source; /**< SYSCLK source input selection. */ + uint8_t pll_source; /**< RCC_PLLCKSELR_PLLSRC_xxx value. */ + uint32_t hse_frequency; /**< User specified HSE frequency, 0 if none. */ struct pll_config { uint8_t divm; /**< Pre-divider value for each PLL. 0-64 integers. */ uint16_t divn; /**< Multiplier, 0-512 integer. */ @@ -462,12 +450,14 @@ struct rcc_pll_config { uint8_t divq; /**< Post divider for PLLQ clock. */ uint8_t divr; /**< Post divider for PLLR clock. */ } pll1, pll2, pll3; /**< PLL1-PLL3 configurations. */ - uint32_t d1cfg_core_prescale; /**< Core prescaler for domain 1. */ - uint32_t d1cfg_hclk3_prescale; /**< HCLK3 prescaler for domain 1. */ - uint32_t d1cfg_pclk3_prescale; /**< APB3 Peripheral prescaler for domain 1. */ - uint32_t d2cfg_pclk1_prescale; /**< APB1 Peripheral prescaler for domain 2. */ - uint32_t d2cfg_pclk2_prescale; /**< APB2 Peripheral prescaler for domain 2. */ - uint32_t d3cfg_pclk4_prescale; /**< APB4 Peripheral prescaler for domain 3. */ + uint8_t core_pre; /**< Core prescaler note: domain 1. */ + uint8_t hpre; /**< HCLK3 prescaler note: domain 1. */ + uint8_t ppre1; /**< APB1 Peripheral prescaler note: domain 2. */ + uint8_t ppre2; /**< APB2 Peripheral prescaler note: domain 2. */ + uint8_t ppre3; /**< APB3 Peripheral prescaler note: domain 1. */ + uint8_t ppre4; /**< APB4 Peripheral prescaler note: domain 3. */ + uint8_t flash_waitstates; /**< Latency Value to set for flahs. */ + enum pwr_vos_scale voltage_scale; /**< LDO Voltage scale used for this frequency. */ }; #define _REG_BIT(base, bit) (((base) << 5) + (bit)) diff --git a/lib/stm32/h7/rcc.c b/lib/stm32/h7/rcc.c index bc57c353..4a24f7ec 100644 --- a/lib/stm32/h7/rcc.c +++ b/lib/stm32/h7/rcc.c @@ -110,10 +110,10 @@ static void rcc_set_and_enable_plls(const struct rcc_pll_config *config) { RCC_PLLCKSELR = RCC_PLLCKSELR_DIVM1(config->pll1.divm) | RCC_PLLCKSELR_DIVM2(config->pll2.divm) | RCC_PLLCKSELR_DIVM3(config->pll3.divm) | - config->pll_mux; + config->pll_source; - uint32_t clkin = (config->pll_mux == RCC_PLL_HSI) ? RCC_HSI_BASE_FREQUENCY - : config->hse_frequency; + uint32_t clkin = (config->pll_source == RCC_PLLCKSELR_PLLSRC_HSI) + ? RCC_HSI_BASE_FREQUENCY : config->hse_frequency; RCC_PLLCFGR = 0; rcc_configure_pll(clkin, &config->pll1, 1); @@ -145,38 +145,37 @@ static uint16_t rcc_prediv_3bit_log_div(uint16_t clk_mhz, uint32_t div_val) { static void rcc_clock_setup_domain1(const struct rcc_pll_config *config) { RCC_D1CFGR = 0; - RCC_D1CFGR |= config->d1cfg_core_prescale | config->d1cfg_hclk3_prescale | - config->d1cfg_pclk3_prescale; + RCC_D1CFGR |= RCC_D1CFGR_D1CPRE(config->core_pre) | + RCC_D1CFGR_D1HPRE(config->hpre) | RCC_D1CFGR_D1PPRE(config->ppre3); /* Update our clock values in our tree based on the config values. */ - rcc_clock_tree.cpu_mhz = rcc_prediv_log_skip32_div(rcc_clock_tree.sysclk_mhz, - config->d1cfg_core_prescale >> RCC_D1CFGR_D1CPRE_SHIFT); - - rcc_clock_tree.hclk_mhz = rcc_prediv_log_skip32_div(rcc_clock_tree.cpu_mhz, - config->d1cfg_hclk3_prescale); - - rcc_clock_tree.per.pclk3_mhz = rcc_prediv_3bit_log_div(rcc_clock_tree.hclk_mhz, - config->d1cfg_pclk3_prescale >> RCC_D1CFGR_D1PPRE_SHIFT); + rcc_clock_tree.cpu_mhz = + rcc_prediv_log_skip32_div(rcc_clock_tree.sysclk_mhz, config->core_pre); + rcc_clock_tree.hclk_mhz = + rcc_prediv_log_skip32_div(rcc_clock_tree.cpu_mhz, config->hpre); + rcc_clock_tree.per.pclk3_mhz = + rcc_prediv_3bit_log_div(rcc_clock_tree.hclk_mhz, config->ppre3); } static void rcc_clock_setup_domain2(const struct rcc_pll_config *config) { RCC_D2CFGR = 0; - RCC_D2CFGR |= config->d2cfg_pclk1_prescale | config->d2cfg_pclk2_prescale; + RCC_D2CFGR |= RCC_D2CFGR_D2PPRE1(config->ppre1) | + RCC_D2CFGR_D2PPRE2(config->ppre2); /* Update our clock values in our tree based on the config values. */ - rcc_clock_tree.per.pclk2_mhz = rcc_prediv_3bit_log_div(rcc_clock_tree.hclk_mhz, - config->d2cfg_pclk2_prescale >> RCC_D2CFGR_D2PPRE2_SHIFT); - rcc_clock_tree.per.pclk1_mhz = rcc_prediv_3bit_log_div(rcc_clock_tree.hclk_mhz, - config->d2cfg_pclk1_prescale >> RCC_D2CFGR_D2PPRE1_SHIFT); + rcc_clock_tree.per.pclk2_mhz = + rcc_prediv_3bit_log_div(rcc_clock_tree.hclk_mhz, config->ppre2); + rcc_clock_tree.per.pclk1_mhz = + rcc_prediv_3bit_log_div(rcc_clock_tree.hclk_mhz, config->ppre1); } static void rcc_clock_setup_domain3(const struct rcc_pll_config *config) { RCC_D3CFGR &= 0; - RCC_D3CFGR |= config->d3cfg_pclk4_prescale; + RCC_D3CFGR |= RCC_D3CFGR_D3PPRE(config->ppre4); /* Update our clock values in our tree based on the config values. */ - rcc_clock_tree.per.pclk4_mhz = rcc_prediv_3bit_log_div(rcc_clock_tree.hclk_mhz, - config->d3cfg_pclk4_prescale >> RCC_D3CFGR_D3PPRE_SHIFT); + rcc_clock_tree.per.pclk4_mhz = + rcc_prediv_3bit_log_div(rcc_clock_tree.hclk_mhz, config->ppre4); } void rcc_clock_setup_pll(const struct rcc_pll_config *config) { @@ -186,6 +185,18 @@ void rcc_clock_setup_pll(const struct rcc_pll_config *config) { while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_HSI); RCC_CR = RCC_CR_HSION; + /* Now that we're safely running on HSI, let's setup the LDO. */ + pwr_set_mode_ldo(); + pwr_set_vos_scale(config->voltage_scale); + + /* Set flash waitstates. Enable flash prefetch if we have at least 1WS */ + flash_set_ws(config->flash_waitstates); + if (config->flash_waitstates > FLASH_ACR_LATENCY_0WS) { + flash_prefetch_enable(); + } else { + flash_prefetch_disable(); + } + /* User has specified an external oscillator, make sure we turn it on. */ if (config->hse_frequency > 0) { RCC_CR |= RCC_CR_HSEON; @@ -197,9 +208,9 @@ void rcc_clock_setup_pll(const struct rcc_pll_config *config) { rcc_set_and_enable_plls(config); /* Populate our base sysclk settings for use with domain clocks. */ - if (config->sysclk_mux == RCC_SYSCLK_PLL) { + if (config->sysclock_source == RCC_PLL) { rcc_clock_tree.sysclk_mhz = rcc_clock_tree.pll1.p_mhz; - } else if (config->sysclk_mux == RCC_SYSCLK_HSE) { + } else if (config->sysclock_source == RCC_HSE) { rcc_clock_tree.sysclk_mhz = config->hse_frequency / HZ_PER_MHZ; } else { rcc_clock_tree.sysclk_mhz = RCC_HSI_BASE_FREQUENCY / HZ_PER_MHZ;