From 57c2b00a69f97205313e1c7ab8116ee1893b231e Mon Sep 17 00:00:00 2001 From: Chuck McManis Date: Thu, 28 Jul 2016 20:37:58 -0700 Subject: [PATCH] stm32f4: rcc: support new plls for new f4 parts Revise the PLL inits to support new and old PLL configurations, particularly to support F4x9 devices. Signed-off-by: Karl Palsson --- include/libopencm3/stm32/f4/rcc.h | 29 ++++---- lib/stm32/f4/rcc.c | 106 ++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 30 deletions(-) diff --git a/include/libopencm3/stm32/f4/rcc.h b/include/libopencm3/stm32/f4/rcc.h index 749042de..4f22f226 100644 --- a/include/libopencm3/stm32/f4/rcc.h +++ b/include/libopencm3/stm32/f4/rcc.h @@ -563,6 +563,14 @@ /* RCC_PLLSAICFGR[18:16]: PLLSAIP */ #define RCC_PLLSAICFGR_PLLSAIP_SHIFT 16 #define RCC_PLLSAICFGR_PLLSAIP_MASK 0x3 +/** @defgroup rcc_pllsaicfgr_pllsaip PLLSAICFGR PLLSAIP values +@ingroup rcc_defines +@{*/ +#define RCC_PLLSAICFGR_PLLSAIP_DIV2 0x0 +#define RCC_PLLSAICFGR_PLLSAIP_DIV4 0x1 +#define RCC_PLLSAICFGR_PLLSAIP_DIV6 0x2 +#define RCC_PLLSAICFGR_PLLSAIP_DIV8 0x3 +/**@}*/ /* RCC_PLLSAICFGR[14:6]: PLLSAIN */ #define RCC_PLLSAICFGR_PLLSAIN_SHIFT 6 @@ -611,22 +619,6 @@ static inline bool rcc_pllsai_ready(void) return (RCC_CR & RCC_CR_PLLSAIRDY) != 0; } -/* pllsain=49..432, pllsaiq=2..15, pllsair=2..7 */ -static inline void rcc_pllsai_config(uint16_t pllsain, - uint16_t pllsaiq, - uint16_t pllsair) -{ - RCC_PLLSAICFGR = (((pllsain & 0x1ff) << 6) | - ((pllsaiq & 0xF) << 24) | - ((pllsair & 0x7) << 28)); -} - -static inline void rcc_ltdc_set_clock_divr(uint8_t pllsaidivr) -{ - RCC_DCKCFGR = (((RCC_DCKCFGR & - ~RCC_DCKCFGR_PLLSAIDIVR_MASK) | - ((pllsaidivr & 0x3) << 16))); -} /* --- Variable definitions ------------------------------------------------ */ extern uint32_t rcc_ahb_frequency; @@ -648,6 +640,7 @@ struct rcc_clock_scale { uint16_t plln; uint8_t pllp; uint8_t pllq; + uint8_t pllr; uint32_t flash_config; uint8_t hpre; uint8_t ppre1; @@ -959,9 +952,9 @@ void rcc_set_ppre1(uint32_t ppre1); void rcc_set_hpre(uint32_t hpre); void rcc_set_rtcpre(uint32_t rtcpre); void rcc_set_main_pll_hsi(uint32_t pllm, uint32_t plln, uint32_t pllp, - uint32_t pllq); + uint32_t pllq, uint32_t pllr); void rcc_set_main_pll_hse(uint32_t pllm, uint32_t plln, uint32_t pllp, - uint32_t pllq); + uint32_t pllq, uint32_t pllr); uint32_t rcc_system_clock_source(void); void rcc_clock_setup_hse_3v3(const struct rcc_clock_scale *clock); diff --git a/lib/stm32/f4/rcc.c b/lib/stm32/f4/rcc.c index 6748e01f..0b741a94 100644 --- a/lib/stm32/f4/rcc.c +++ b/lib/stm32/f4/rcc.c @@ -55,6 +55,7 @@ const struct rcc_clock_scale rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 96, .pllp = 2, .pllq = 2, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, @@ -70,6 +71,7 @@ const struct rcc_clock_scale rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 336, .pllp = 4, .pllq = 7, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_2, .ppre2 = RCC_CFGR_PPRE_DIV_NONE, @@ -84,6 +86,7 @@ const struct rcc_clock_scale rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 240, .pllp = 2, .pllq = 5, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, @@ -99,6 +102,7 @@ const struct rcc_clock_scale rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 336, .pllp = 2, .pllq = 7, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, @@ -116,6 +120,7 @@ const struct rcc_clock_scale rcc_hse_12mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 96, .pllp = 2, .pllq = 2, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, @@ -131,6 +136,7 @@ const struct rcc_clock_scale rcc_hse_12mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 336, .pllp = 4, .pllq = 7, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_2, .ppre2 = RCC_CFGR_PPRE_DIV_NONE, @@ -145,6 +151,7 @@ const struct rcc_clock_scale rcc_hse_12mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 240, .pllp = 2, .pllq = 5, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, @@ -160,6 +167,7 @@ const struct rcc_clock_scale rcc_hse_12mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 336, .pllp = 2, .pllq = 7, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, @@ -177,6 +185,7 @@ const struct rcc_clock_scale rcc_hse_16mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 96, .pllp = 2, .pllq = 2, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, @@ -192,6 +201,7 @@ const struct rcc_clock_scale rcc_hse_16mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 336, .pllp = 4, .pllq = 7, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_2, .ppre2 = RCC_CFGR_PPRE_DIV_NONE, @@ -206,6 +216,7 @@ const struct rcc_clock_scale rcc_hse_16mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 240, .pllp = 2, .pllq = 5, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, @@ -221,6 +232,7 @@ const struct rcc_clock_scale rcc_hse_16mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 336, .pllp = 2, .pllq = 7, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, @@ -238,6 +250,7 @@ const struct rcc_clock_scale rcc_hse_25mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 96, .pllp = 2, .pllq = 2, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, @@ -253,6 +266,7 @@ const struct rcc_clock_scale rcc_hse_25mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 336, .pllp = 4, .pllq = 7, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_2, .ppre2 = RCC_CFGR_PPRE_DIV_NONE, @@ -267,6 +281,7 @@ const struct rcc_clock_scale rcc_hse_25mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 240, .pllp = 2, .pllq = 5, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, @@ -282,6 +297,7 @@ const struct rcc_clock_scale rcc_hse_25mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 336, .pllp = 2, .pllq = 7, + .pllr = 0, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, @@ -546,6 +562,43 @@ void rcc_osc_bypass_disable(enum rcc_osc osc) } } + +/** + * Set the dividers for the PLLSAI clock outputs + * divider p is only available on F4x9 parts, pass 0 for other parts. + * @param n valid range is 49..432 + * @param p 0 if unused, @ref rcc_pllsaicfgr_pllsaip + * @param q valid range is 2..15 + * @param r valid range is 2..7 + * @sa rcc_pllsai_postscalers + */ +void rcc_pllsai_config(uint16_t n, uint16_t p, uint16_t q, uint16_t r) +{ + RCC_PLLSAICFGR = ( + ((n & RCC_PLLSAICFGR_PLLSAIN_MASK) << RCC_PLLSAICFGR_PLLSAIN_SHIFT) | + ((p & RCC_PLLSAICFGR_PLLSAIP_MASK) << RCC_PLLSAICFGR_PLLSAIP_SHIFT) | + ((q & RCC_PLLSAICFGR_PLLSAIQ_MASK) << RCC_PLLSAICFGR_PLLSAIQ_SHIFT) | + ((r & RCC_PLLSAICFGR_PLLSAIR_MASK) << RCC_PLLSAICFGR_PLLSAIR_SHIFT)); +} + + +/** + * Set the dedicated dividers after the PLLSAI configuration. + * + * @param q dedicated PLLSAI divider, for either A or B + * @param r dedicated LCD-TFT divider, see LTDC + * @sa rcc_pllsai_config + */ +void rcc_pllsai_postscalers(uint8_t q, uint8_t r) +{ + uint32 reg32 = RCC_DCKCFGR; + reg32 &= ((RCC_DCKCFGR_PLLSAIDIVR_MASK << RCC_DCKCFGR_PLLSAIDIVR_SHIFT) + | (RCC_DCKCFGR_PLLSAIDIVQ_MASK << RCC_DCKCFGR_PLLSAIDIVQ_SHIFT)); + RCC_DCKCFGR = reg32 | ((q << RCC_DCKCFGR_PLLSAIDIVQ_SHIFT) | + (r << RCC_DCKCFGR_PLLSAIDIVR_SHIFT)); +} + + void rcc_set_sysclk_source(uint32_t clk) { uint32_t reg32; @@ -600,23 +653,52 @@ void rcc_set_rtcpre(uint32_t rtcpre) RCC_CFGR = (reg32 | (rtcpre << 16)); } +/** + * Reconfigures the main PLL for a HSI source. + * Any reserved bits are kept at their reset values. + * @param pllm Divider for the main PLL input clock + * @param plln Main PLL multiplication factor for VCO + * @param pllp Main PLL divider for main system clock + * @param pllq Main PLL divider for USB OTG FS, SDMMC & RNG + * @param pllr Main PLL divider for DSI (for parts without DSI, provide 0 here) + */ void rcc_set_main_pll_hsi(uint32_t pllm, uint32_t plln, uint32_t pllp, - uint32_t pllq) + uint32_t pllq, uint32_t pllr) { - RCC_PLLCFGR = (pllm << RCC_PLLCFGR_PLLM_SHIFT) | - (plln << RCC_PLLCFGR_PLLN_SHIFT) | - (((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) | - (pllq << RCC_PLLCFGR_PLLQ_SHIFT); + /* Use reset value if not legal, for parts without pllr */ + if (pllr < 2) { + pllr = 2; + } + RCC_PLLCFGR = 0 | /* HSI */ + ((pllm & RCC_PLLCFGR_PLLM_MASK) << RCC_PLLCFGR_PLLM_SHIFT) | + ((plln & RCC_PLLCFGR_PLLN_MASK) << RCC_PLLCFGR_PLLN_SHIFT) | + ((((pllp & RCC_PLLCFGR_PLLP_MASK) >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) | + ((pllq & RCC_PLLCFGR_PLLQ_MASK) << RCC_PLLCFGR_PLLQ_SHIFT) | + ((pllr & RCC_PLLCFGR_PLLR_MASK) << RCC_PLLCFGR_PLLR_SHIFT); } +/** + * Reconfigures the main PLL for a HSE source. + * Any reserved bits are kept at their reset values. + * @param pllm Divider for the main PLL input clock + * @param plln Main PLL multiplication factor for VCO + * @param pllp Main PLL divider for main system clock + * @param pllq Main PLL divider for USB OTG FS, SDMMC & RNG + * @param pllr Main PLL divider for DSI (for parts without DSI, provide 0 here) + */ void rcc_set_main_pll_hse(uint32_t pllm, uint32_t plln, uint32_t pllp, - uint32_t pllq) + uint32_t pllq, uint32_t pllr) { - RCC_PLLCFGR = (pllm << RCC_PLLCFGR_PLLM_SHIFT) | - (plln << RCC_PLLCFGR_PLLN_SHIFT) | - (((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) | - RCC_PLLCFGR_PLLSRC | - (pllq << RCC_PLLCFGR_PLLQ_SHIFT); + /* Use reset value if not legal, for parts without pllr */ + if (pllr < 2) { + pllr = 2; + } + RCC_PLLCFGR = RCC_PLLCFGR_PLLSRC | /* HSE */ + ((pllm & RCC_PLLCFGR_PLLM_MASK) << RCC_PLLCFGR_PLLM_SHIFT) | + ((plln & RCC_PLLCFGR_PLLN_MASK) << RCC_PLLCFGR_PLLN_SHIFT) | + ((((pllp & RCC_PLLCFGR_PLLP_MASK) >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) | + ((pllq & RCC_PLLCFGR_PLLQ_MASK) << RCC_PLLCFGR_PLLQ_SHIFT) | + ((pllr & RCC_PLLCFGR_PLLR_MASK) << RCC_PLLCFGR_PLLR_SHIFT); } uint32_t rcc_system_clock_source(void) @@ -654,7 +736,7 @@ void rcc_clock_setup_hse_3v3(const struct rcc_clock_scale *clock) rcc_set_ppre2(clock->ppre2); rcc_set_main_pll_hse(clock->pllm, clock->plln, - clock->pllp, clock->pllq); + clock->pllp, clock->pllq, clock->pllr); /* Enable PLL oscillator and wait for it to stabilize. */ rcc_osc_on(RCC_PLL);