diff --git a/arch/arm/soc/st_stm32/stm32f4/flash_registers.h b/arch/arm/soc/st_stm32/stm32f4/flash_registers.h new file mode 100644 index 00000000000..7075e4d2242 --- /dev/null +++ b/arch/arm/soc/st_stm32/stm32f4/flash_registers.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016 Linaro Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _STM32F4X_FLASH_REGISTERS_H_ +#define _STM32F4X_FLASH_REGISTERS_H_ + +/** + * @brief + * + * Based on reference manual: + * + * Chapter 3.4: Embedded Flash Memory + */ + +enum { + STM32F4X_FLASH_LATENCY_0 = 0x0, + STM32F4X_FLASH_LATENCY_1 = 0x1, + STM32F4X_FLASH_LATENCY_2 = 0x2, + STM32F4X_FLASH_LATENCY_3 = 0x3, + STM32F4X_FLASH_LATENCY_4 = 0x4, + STM32F4X_FLASH_LATENCY_5 = 0x5, +}; + +union __flash_acr { + uint32_t val; + struct { + uint32_t latency :4 __packed; + uint32_t rsvd__4_7 :4 __packed; + uint32_t prften :1 __packed; + uint32_t icen :1 __packed; + uint32_t dcen :1 __packed; + uint32_t icrst :1 __packed; + uint32_t dcrst :1 __packed; + uint32_t rsvd__13_31 :19 __packed; + } bit; +}; + +/* 3.8.7 Embedded flash registers */ +struct stm32f4x_flash { + union __flash_acr acr; + uint32_t key; + uint32_t optkey; + volatile uint32_t status; + volatile uint32_t ctrl; + uint32_t optctrl; +}; + +/** + * @brief setup embedded flash controller + * + * Configure flash access time latency depending on SYSCLK. + */ +static inline void __setup_flash(void) +{ + volatile struct stm32f4x_flash *regs; + uint32_t tmpreg = 0; + + regs = (struct stm32f4x_flash *) FLASH_R_BASE; + + if (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC <= 30000000) { + regs->acr.bit.latency = STM32F4X_FLASH_LATENCY_0; + } else if (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC <= 60000000) { + regs->acr.bit.latency = STM32F4X_FLASH_LATENCY_1; + } else if (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC <= 84000000) { + regs->acr.bit.latency = STM32F4X_FLASH_LATENCY_2; + } + + /* Make sure latency was set */ + tmpreg = regs->acr.bit.latency; +} + +#endif /* _STM32F4X_FLASHREGISTERS_H_ */ diff --git a/arch/arm/soc/st_stm32/stm32f4/rcc_registers.h b/arch/arm/soc/st_stm32/stm32f4/rcc_registers.h new file mode 100644 index 00000000000..bdaaa8fb77f --- /dev/null +++ b/arch/arm/soc/st_stm32/stm32f4/rcc_registers.h @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2016 Linaro Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions andSTM + * limitations under the License. + */ + +#ifndef _STM32F4X_CLOCK_H_ +#define _STM32F4X_CLOCK_H_ + +/** + * @brief Driver for Reset & Clock Control of STM32F4X family processor. + * + * Based on reference manual: + * RM0368 Reference manual STM32F401xB/C and STM32F401xD/E + * advanced ARM ® -based 32-bit MCUs + * + * Chapter 6. Reset and Clock control (RCC) for STM43F401xB/C and STM32F401xD/E + */ + +/* 6.3.1 Clock control register (RCC_CR) */ +enum { + STM32F4X_RCC_CFG_PLL_SRC_HSI = 0x0, + STM32F4X_RCC_CFG_PLL_SRC_HSE = 0x1, +}; + +enum { + STM32F4X_RCC_CFG_SYSCLK_SRC_HSI = 0x0, + STM32F4X_RCC_CFG_SYSCLK_SRC_HSE = 0x1, + STM32F4X_RCC_CFG_SYSCLK_SRC_PLL = 0x2, +}; + +enum { + STM32F4X_RCC_CFG_PLLP_DIV_2 = 0x0, + STM32F4X_RCC_CFG_PLLP_DIV_4 = 0x1, + STM32F4X_RCC_CFG_PLLP_DIV_6 = 0x2, + STM32F4X_RCC_CFG_PLLP_DIV_8 = 0x3, +}; + +enum { + STM32F4X_RCC_CFG_HCLK_DIV_0 = 0x0, + STM32F4X_RCC_CFG_HCLK_DIV_2 = 0x4, + STM32F4X_RCC_CFG_HCLK_DIV_4 = 0x5, + STM32F4X_RCC_CFG_HCLK_DIV_8 = 0x6, + STM32F4X_RCC_CFG_HCLK_DIV_16 = 0x7, +}; + +enum { + STM32F4X_RCC_CFG_SYSCLK_DIV_0 = 0x0, + STM32F4X_RCC_CFG_SYSCLK_DIV_2 = 0x8, + STM32F4X_RCC_CFG_SYSCLK_DIV_4 = 0x9, + STM32F4X_RCC_CFG_SYSCLK_DIV_8 = 0xa, + STM32F4X_RCC_CFG_SYSCLK_DIV_16 = 0xb, + STM32F4X_RCC_CFG_SYSCLK_DIV_64 = 0xc, + STM32F4X_RCC_CFG_SYSCLK_DIV_128 = 0xd, + STM32F4X_RCC_CFG_SYSCLK_DIV_256 = 0xe, + STM32F4X_RCC_CFG_SYSCLK_DIV_512 = 0xf, +}; + +/** + * @brief Reset and Clock Control + */ + +/* Helpers */ +enum { + STM32F4X_RCC_APB1ENR_PWREN = 0x10000000U, +}; + +union __rcc_cr { + uint32_t val; + struct { + uint32_t hsion :1 __packed; + uint32_t hsirdy :1 __packed; + uint32_t rsvd__2 :1 __packed; + uint32_t hsitrim :5 __packed; + uint32_t hsical :8 __packed; + uint32_t hseon :1 __packed; + uint32_t hserdy :1 __packed; + uint32_t hsebyp :1 __packed; + uint32_t csson :1 __packed; + uint32_t rsvd__20_23 :4 __packed; + uint32_t pllon :1 __packed; + uint32_t pllrdy :1 __packed; + uint32_t plli2son :1 __packed; + uint32_t plli2srdy :1 __packed; + uint32_t pllsaion :1 __packed; + uint32_t pllsairdy :1 __packed; + uint32_t rsvd__30_31 :2 __packed; + } bit; +}; + +union __rcc_pllcfgr { + uint32_t val; + struct { + uint32_t pllm :6 __packed; + uint32_t plln :9 __packed; + uint32_t rsvd__15 :1 __packed; + uint32_t pllp :2 __packed; + uint32_t rsvd__18_21 :4 __packed; + uint32_t pllsrc :1 __packed; + uint32_t rsvd__23 :1 __packed; + uint32_t pllq :4 __packed; + uint32_t rsvd__28_31 :4 __packed; + } bit; +}; + +union __rcc_cfgr { + uint32_t val; + struct { + uint32_t sw :2 __packed; + uint32_t sws :2 __packed; + uint32_t hpre :4 __packed; + uint32_t rsvd__8_9 :2 __packed; + uint32_t ppre1 :3 __packed; + uint32_t ppre2 :3 __packed; + uint32_t rtcpre :5 __packed; + uint32_t mco1 :2 __packed; + uint32_t i2sscr :1 __packed; + uint32_t mco1pre :3 __packed; + uint32_t mco2pre :3 __packed; + uint32_t mco2 :2 __packed; + } bit; +}; + +struct stm32f4x_rcc { + union __rcc_cr cr; + union __rcc_pllcfgr pllcfgr; + union __rcc_cfgr cfgr; + uint32_t cir; + uint32_t ahb1rstr; + uint32_t ahb2rstr; + uint32_t ahb3rstr; + uint32_t rsvd0; + uint32_t apb1rstr; + uint32_t apb2rstr; + uint32_t rsvd1[2]; + uint32_t ahb1enr; + uint32_t ahb2enr; + uint32_t ahb3enr; + uint32_t rsvd2; + uint32_t apb1enr; + uint32_t apb2enr; + uint32_t rsvd3[2]; + uint32_t ahb1lpenr; + uint32_t ahb2lpenr; + uint32_t ahb3lpenr; + uint32_t rsvd4; + uint32_t apb1lpenr; + uint32_t apb2lpenr; + uint32_t rsvd5[2]; + uint32_t bdcr; + uint32_t csr; + uint32_t rsvd6[2]; + uint32_t sscgr; + uint32_t plli2scfgr; + uint32_t rsvd7; + uint32_t dckcfgr; +}; + +#endif /* _STM32F4X_CLOCK_H_ */ diff --git a/arch/arm/soc/st_stm32/stm32f4/soc_registers.h b/arch/arm/soc/st_stm32/stm32f4/soc_registers.h new file mode 100644 index 00000000000..0453574deae --- /dev/null +++ b/arch/arm/soc/st_stm32/stm32f4/soc_registers.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016 Linaro Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _STM32F4_SOC_REGISTERS_H_ +#define _STM32F4_SOC_REGISTERS_H_ + +/* include register mapping headers */ +#include "rcc_registers.h" +#include "flash_registers.h" + +#endif /* _STM32F4_SOC_REGISTERS_H_ */ diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index fecc2207c6c..4c2adf93520 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -55,6 +55,8 @@ source "drivers/clock_control/Kconfig.quark_se" source "drivers/clock_control/Kconfig.stm32f10x" +source "drivers/clock_control/Kconfig.stm32f4x" + source "drivers/clock_control/Kconfig.nrf5" endif # CLOCK_CONTROL diff --git a/drivers/clock_control/Kconfig.stm32f4x b/drivers/clock_control/Kconfig.stm32f4x new file mode 100644 index 00000000000..a1309436705 --- /dev/null +++ b/drivers/clock_control/Kconfig.stm32f4x @@ -0,0 +1,151 @@ +# Kconfig - STM32F4 MCU clock control driver config +# +# Copyright (c) 2016 Open-RnD Sp. z o.o. +# Copyright (c) Linaro Limited. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +if SOC_SERIES_STM32F4X + +menuconfig CLOCK_CONTROL_STM32F4X + bool + prompt "STM32F4X Reset & Clock Control" + depends on CLOCK_CONTROL && SOC_SERIES_STM32F4X + default y if SOC_SERIES_STM32F4X + help + Enable driver for Reset & Clock Control subsystem found + in STM32F4 family of MCUs + +config CLOCK_CONTROL_STM32F4X_DEVICE_INIT_PRIORITY + int "Clock Control Device Priority" + default 1 + depends on CLOCK_CONTROL_STM32F4X + help + This option controls the priority of clock control + device initialization. Higher priority ensures that the device + is initialized earlier in the startup cycle. If unsure, leave + at default value 1 + +choice +prompt "STM32F4X System Clock Source" +depends on CLOCK_CONTROL_STM32F4X + +config CLOCK_STM32F4X_SYSCLK_SRC_HSI + bool "HSI" + help + Use HSI as source of SYSCLK + +config CLOCK_STM32F4X_SYSCLK_SRC_HSE + bool "HSE" + help + Use HSE as source of SYSCLK + +config CLOCK_STM32F4X_SYSCLK_SRC_PLL + bool "PLL" + help + Use PLL as source of SYSCLK + +endchoice + +choice +prompt "STM32F4X PLL Clock Source" +depends on CLOCK_CONTROL_STM32F4X && CLOCK_STM32F4X_SYSCLK_SRC_PLL + +config CLOCK_STM32F4X_PLL_SRC_HSI + bool "HSI" + help + Use HSI as source of PLL + +config CLOCK_STM32F4X_PLL_SRC_HSE + bool "HSE" + help + Use HSE as source of PLL + +endchoice + +config CLOCK_STM32F4X_HSE_BYPASS + bool "HSE bypass" + depends on CLOCK_CONTROL_STM32F4X && (CLOCK_STM32F4X_PLL_SRC_HSE || CLOCK_STM32F4X_SYSCLK_SRC_HSE) + help + Enable this option to bypass external high-speed clock (HSE). + +config CLOCK_STM32F4X_PLLM_DIV_FACTOR + int "Division factor for PLL VCO input clock" + depends on CLOCK_CONTROL_STM32F4X && CLOCK_STM32F4X_SYSCLK_SRC_PLL + default 8 + range 2 63 + help + PLLM division factor needs to be set correctly to ensure that the VCO + input frequency ranges from 1 to 2 MHz. It is recommended to select a + frequency of 2 MHz to limit PLL jitter. + Allowed values: 2-63 + +config CLOCK_STM32F4X_PLLN_MULTIPLIER + int "Multiplier factor for PLL VCO output clock" + depends on CLOCK_CONTROL_STM32F4X && CLOCK_STM32F4X_SYSCLK_SRC_PLL + default 336 + range 192 432 + help + PLLN multiplier factor needs to be set correctly to ensure that the + VCO output frequency is between 192 and 432 MHz. + Allowed values: 192-432 + +config CLOCK_STM32F4X_PLLP_DIV_FACTOR + int "PLL division factor for main system clock" + depends on CLOCK_CONTROL_STM32F4X && CLOCK_STM32F4X_SYSCLK_SRC_PLL + default 4 + range 2 8 + help + PLLP division factor needs to be set correctly to not exceed 84MHz. + Allowed values: 2, 4, 6, 8 + +config CLOCK_STM32F4X_PLLQ_DIV_FACTOR + int "Division factor for OTG FS, SDIO and RNG clocks" + depends on CLOCK_CONTROL_STM32F4X && CLOCK_STM32F4X_SYSCLK_SRC_PLL + default 7 + range 2 15 + help + The USB OTG FS requires a 48MHz clock to work correctly. SDIO and RNG + need a frequency lower than or equal to 48 MHz to work correctly. + Allowed values: 2-15 + +config CLOCK_STM32F4X_AHB_PRESCALER + int "AHB prescaler" + depends on CLOCK_CONTROL_STM32F4X + default 0 + range 0 512 + help + AHB prescaler, allowed values: 0, 2, 4, 8, 16, 64, 128, + 256, 512. + +config CLOCK_STM32F4X_APB1_PRESCALER + int "APB1 low speed clock prescaler" + depends on CLOCK_CONTROL_STM32F4X + default 2 + range 0 16 + help + APB1 Low speed clock (PCLK1) prescaler, allowed values: + 0, 2, 4, 8, 16. The APB1 clock must not exceed 42MHz. + +config CLOCK_STM32F4X_APB2_PRESCALER + int "APB2 high speed clock prescaler" + depends on CLOCK_CONTROL_STM32F4X + default 0 + range 0 16 + help + APB2 High speed clock (PCLK2) prescaler, allowed values: + 0, 2, 4, 8, 16. The APB2 clock must not exceed 84MHz. + +endif + diff --git a/drivers/clock_control/Makefile b/drivers/clock_control/Makefile index aaaf03d15ef..b23147eb936 100644 --- a/drivers/clock_control/Makefile +++ b/drivers/clock_control/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_CLOCK_CONTROL_QUARK_SE) += quark_se_clock_control.o obj-$(CONFIG_CLOCK_CONTROL_STM32F10X) += stm32f10x_clock.o +obj-$(CONFIG_CLOCK_CONTROL_STM32F4X) += stm32f4x_clock.o obj-$(CONFIG_CLOCK_CONTROL_NRF5) += nrf5_power_clock.o diff --git a/drivers/clock_control/stm32f4x_clock.c b/drivers/clock_control/stm32f4x_clock.c new file mode 100644 index 00000000000..458a7b300b8 --- /dev/null +++ b/drivers/clock_control/stm32f4x_clock.c @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2016 Open-RnD Sp. z o.o. + * Copyright (c) 2016 Linaro Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * @brief Driver for Reset & Clock Control of STM32F4X family processor. + * + * Based on reference manual: + * RM0368 Reference manual STM32F401xB/C and STM32F401xD/E + * advanced ARM ® -based 32-bit MCUs + * + * Chapter 6. Reset and Clock control (RCC) for STM43F401xB/C and STM32F401xD/E + */ + +#include +#include +#include +#include +#include + +struct stm32f4x_rcc_data { + uint8_t *base; +}; + +static inline int stm32f4x_clock_control_on(struct device *dev, + clock_control_subsys_t sub_system) +{ + struct stm32f4x_rcc_data *data = dev->driver_data; + volatile struct stm32f4x_rcc *rcc = (struct stm32f4x_rcc *)(data->base); + struct stm32f4x_pclken *pclken = (struct stm32f4x_pclken *)(sub_system); + uint32_t tmpreg = 0; /* Register delay helper */ + + switch (pclken->bus) { + case STM32F4X_CLOCK_BUS_AHB1: + rcc->ahb1enr |= pclken->enr; + tmpreg = rcc->ahb1enr; + break; + case STM32F4X_CLOCK_BUS_AHB2: + rcc->ahb2enr |= pclken->enr; + tmpreg = rcc->ahb2enr; + break; + case STM32F4X_CLOCK_BUS_APB1: + rcc->apb1enr |= pclken->enr; + tmpreg = rcc->apb1enr; + break; + case STM32F4X_CLOCK_BUS_APB2: + rcc->apb2enr |= pclken->enr; + tmpreg = rcc->apb2enr; + break; + } + + return 0; +} + +static inline int stm32f4x_clock_control_off(struct device *dev, + clock_control_subsys_t sub_system) +{ + struct stm32f4x_rcc_data *data = dev->driver_data; + volatile struct stm32f4x_rcc *rcc = (struct stm32f4x_rcc *)(data->base); + struct stm32f4x_pclken *pclken = (struct stm32f4x_pclken *)(sub_system); + uint32_t tmpreg = 0; /* Register delay helper */ + + switch (pclken->bus) { + case STM32F4X_CLOCK_BUS_AHB1: + rcc->ahb1enr &= ~pclken->enr; + tmpreg = rcc->ahb1enr; + break; + case STM32F4X_CLOCK_BUS_AHB2: + rcc->ahb2enr &= ~pclken->enr; + tmpreg = rcc->ahb2enr; + break; + case STM32F4X_CLOCK_BUS_APB1: + rcc->apb1enr &= ~pclken->enr; + tmpreg = rcc->apb1enr; + break; + case STM32F4X_CLOCK_BUS_APB2: + rcc->apb2enr &= ~pclken->enr; + tmpreg = rcc->apb2enr; + break; + } + + return 0; +} + +/** + * @brief helper for mapping a setting to register value + */ +struct regval_map { + int val; + int reg; +}; + +int map_reg_val(const struct regval_map *map, size_t cnt, int val) +{ + for (int i = 0; i < cnt; i++) { + if (map[i].val == val) { + return map[i].reg; + } + } + + return 0; +} + +/** + * @brief map APB prescaler setting to register value + */ +static int __apb_prescaler(int prescaler) +{ + if (prescaler == 0) { + return STM32F4X_RCC_CFG_HCLK_DIV_0; + } + + const struct regval_map map[] = { + {0, STM32F4X_RCC_CFG_HCLK_DIV_0}, + {2, STM32F4X_RCC_CFG_HCLK_DIV_2}, + {4, STM32F4X_RCC_CFG_HCLK_DIV_4}, + {8, STM32F4X_RCC_CFG_HCLK_DIV_8}, + {16, STM32F4X_RCC_CFG_HCLK_DIV_16}, + }; + + return map_reg_val(map, ARRAY_SIZE(map), prescaler); +} + +/** + * @brief map AHB prescaler setting to register value + */ +static int __ahb_prescaler(int prescaler) +{ + if (prescaler == 0) { + return STM32F4X_RCC_CFG_SYSCLK_DIV_0; + } + + const struct regval_map map[] = { + {0, STM32F4X_RCC_CFG_SYSCLK_DIV_0}, + {2, STM32F4X_RCC_CFG_SYSCLK_DIV_2}, + {4, STM32F4X_RCC_CFG_SYSCLK_DIV_4}, + {8, STM32F4X_RCC_CFG_SYSCLK_DIV_8}, + {16, STM32F4X_RCC_CFG_SYSCLK_DIV_16}, + {64, STM32F4X_RCC_CFG_SYSCLK_DIV_64}, + {128, STM32F4X_RCC_CFG_SYSCLK_DIV_128}, + {256, STM32F4X_RCC_CFG_SYSCLK_DIV_256}, + {512, STM32F4X_RCC_CFG_SYSCLK_DIV_512}, + }; + + return map_reg_val(map, ARRAY_SIZE(map), prescaler); +} + +#ifdef CONFIG_CLOCK_STM32F4X_SYSCLK_SRC_PLL +/** + * @brief map PPLP division factor to register value + */ +static int __pllp_div(int div) +{ + if (div == 0) { + return STM32F4X_RCC_CFG_PLLP_DIV_2; + } + + const struct regval_map map[] = { + {2, STM32F4X_RCC_CFG_PLLP_DIV_2}, + {4, STM32F4X_RCC_CFG_PLLP_DIV_4}, + {6, STM32F4X_RCC_CFG_PLLP_DIV_6}, + {8, STM32F4X_RCC_CFG_PLLP_DIV_8}, + }; + + return map_reg_val(map, ARRAY_SIZE(map), div); +} +#endif /* CONFIG_CLOCK_STM32F4X_SYSCLK_SRC_PLL */ + +uint32_t __get_ahb_clock(uint32_t sysclk) +{ + /* AHB clock is generated based on SYSCLK */ + uint32_t sysclk_div = CONFIG_CLOCK_STM32F4X_AHB_PRESCALER; + + if (sysclk_div == 0) { + sysclk_div = 1; + } + + return sysclk / sysclk_div; +} + +uint32_t __get_apb_clock(uint32_t ahb_clock, uint32_t prescaler) +{ + if (prescaler == 0) { + prescaler = 1; + } + + return ahb_clock / prescaler; +} + +static int stm32f4x_clock_control_get_subsys_rate(struct device *clock, + clock_control_subsys_t sub_system, + uint32_t *rate) +{ + struct stm32f4x_pclken *pclken = (struct stm32f4x_pclken *)(sub_system); + /* assumes SYSCLK is SYS_CLOCK_HW_CYCLES_PER_SEC */ + uint32_t ahb_clock = + __get_ahb_clock(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); + uint32_t apb1_clock = __get_apb_clock(ahb_clock, + CONFIG_CLOCK_STM32F4X_APB1_PRESCALER); + uint32_t apb2_clock = __get_apb_clock(ahb_clock, + CONFIG_CLOCK_STM32F4X_APB2_PRESCALER); + ARG_UNUSED(clock); + + switch (pclken->bus) { + case STM32F4X_CLOCK_BUS_AHB1: + case STM32F4X_CLOCK_BUS_AHB2: + *rate = ahb_clock; + break; + case STM32F4X_CLOCK_BUS_APB1: + *rate = apb1_clock; + break; + case STM32F4X_CLOCK_BUS_APB2: + *rate = apb2_clock; + break; + } + + return 0; +} + +static struct clock_control_driver_api stm32f4x_clock_control_api = { + .on = stm32f4x_clock_control_on, + .off = stm32f4x_clock_control_off, + .get_rate = stm32f4x_clock_control_get_subsys_rate, +}; + +int stm32f4x_clock_control_init(struct device *dev) +{ + struct stm32f4x_rcc_data *data = dev->driver_data; + volatile struct stm32f4x_rcc *rcc = + (struct stm32f4x_rcc *)(data->base); + /* SYSCLK source defaults to HSI */ + int sysclk_src = STM32F4X_RCC_CFG_SYSCLK_SRC_HSI; + uint32_t hpre = __ahb_prescaler(CONFIG_CLOCK_STM32F4X_AHB_PRESCALER); + uint32_t ppre1 = __apb_prescaler(CONFIG_CLOCK_STM32F4X_APB1_PRESCALER); + uint32_t ppre2 = __apb_prescaler(CONFIG_CLOCK_STM32F4X_APB2_PRESCALER); +#ifdef CONFIG_CLOCK_STM32F4X_SYSCLK_SRC_PLL + uint32_t pllmdiv = CONFIG_CLOCK_STM32F4X_PLLM_DIV_FACTOR; + uint32_t pllnmul = CONFIG_CLOCK_STM32F4X_PLLN_MULTIPLIER; + uint32_t pllpdiv = __pllp_div(CONFIG_CLOCK_STM32F4X_PLLP_DIV_FACTOR); + uint32_t pllqdiv = CONFIG_CLOCK_STM32F4X_PLLQ_DIV_FACTOR; +#endif /* CONFIG_CLOCK_STM32F4X_SYSCLK_SRC_PLL */ + /* Register delay helper */ + uint32_t tmpreg = 0; + + /* Enable power control clock */ + rcc->apb1enr |= STM32F4X_RCC_APB1ENR_PWREN; + tmpreg = rcc->apb1enr; + + /* disable PLL */ + rcc->cr.bit.pllon = 0; + /* disable HSE */ + rcc->cr.bit.hseon = 0; + +#ifdef CONFIG_CLOCK_STM32F4X_HSE_BYPASS + /* HSE is disabled, HSE bypass can be enabled */ + rcc->cr.bit.hsebyp = 1; +#endif + +#ifdef CONFIG_CLOCK_STM32F4X_PLL_SRC_HSI + /* enable HSI clock */ + rcc->cr.bit.hsion = 1; + + /* this should end after one test */ + while (rcc->cr.bit.hsirdy != 1) { + } + + /* TODO: should we care about HSI calibration adjustment? */ + + /* PLL input from HSI */ + rcc->pllcfgr.bit.pllsrc = STM32F4X_RCC_CFG_PLL_SRC_HSI; +#endif /* CONFIG_CLOCK_STM32F4X_PLL_SRC_HSI */ + +#ifdef CONFIG_CLOCK_STM32F4X_PLL_SRC_HSE + /* wait for to become ready */ + rcc->cr.bit.hseon = 1; + + while (rcc->cr.bit.hserdy != 1) { + } + + /* TODO: should we disable HSI if HSE gets used? */ + + rcc->pllcfgr.bit.pllsrc = STM32F4X_RCC_CFG_PLL_SRC_HSE; +#endif /* CONFIG_CLOCK_STM32F4X_PLL_SRC_HSE */ + + /* setup AHB prescaler */ + rcc->cfgr.bit.hpre = hpre; + + /* setup APB1, must not exceed 42MHz */ + rcc->cfgr.bit.ppre1 = ppre1; + + /* setup APB2 */ + rcc->cfgr.bit.ppre2 = ppre2; + +#ifdef CONFIG_CLOCK_STM32F4X_SYSCLK_SRC_PLL + /* default set of dividers and multipliers (PLL must be disabled) */ + rcc->pllcfgr.bit.pllm = pllmdiv; + rcc->pllcfgr.bit.plln = pllnmul; + rcc->pllcfgr.bit.pllp = pllpdiv; + rcc->pllcfgr.bit.pllq = pllqdiv; + + /* enable PLL */ + rcc->cr.bit.pllon = 1; + + /* wait for PLL to become ready */ + while (rcc->cr.bit.pllrdy != 1) { + } + + sysclk_src = STM32F4X_RCC_CFG_SYSCLK_SRC_PLL; +#elif defined(CONFIG_CLOCK_STM32F4X_SYSCLK_SRC_HSE) + /* wait for to become ready */ + rcc->cr.bit.hseon = 1; + while (rcc->cr.bit.hserdy != 1) { + } + + sysclk_src = STM32F4X_RCC_CFG_SYSCLK_SRC_HSE; +#endif + + /* configure flash access latency before SYSCLK source switch */ + __setup_flash(); + + /* set SYSCLK clock value */ + rcc->cfgr.bit.sw = sysclk_src; + + /* wait for SYSCLK to switch the source */ + while (rcc->cfgr.bit.sws != sysclk_src) { + } + + return 0; +} + +static struct stm32f4x_rcc_data stm32f4x_rcc_data = { + .base = (uint8_t *)RCC_BASE, +}; + +/* FIXME: move prescaler/multiplier defines into device config */ + +/** + * @brief RCC device, note that priority is intentionally set to 1 so + * that the device init runs just after SOC init + */ +DEVICE_AND_API_INIT(rcc_stm32f4x, STM32_CLOCK_CONTROL_NAME, + &stm32f4x_clock_control_init, + &stm32f4x_rcc_data, NULL, + PRIMARY, + CONFIG_CLOCK_CONTROL_STM32F4X_DEVICE_INIT_PRIORITY, + &stm32f4x_clock_control_api); diff --git a/include/drivers/clock_control/stm32_clock_control.h b/include/drivers/clock_control/stm32_clock_control.h index 7041558bb2b..2d6084c1596 100644 --- a/include/drivers/clock_control/stm32_clock_control.h +++ b/include/drivers/clock_control/stm32_clock_control.h @@ -23,6 +23,8 @@ #ifdef CONFIG_SOC_SERIES_STM32F1X #include "stm32f1_clock_control.h" +#elif CONFIG_SOC_SERIES_STM32F4X +#include "stm32f4_clock_control.h" #endif #endif /* _STM32_CLOCK_CONTROL_H_ */ diff --git a/include/drivers/clock_control/stm32f4_clock_control.h b/include/drivers/clock_control/stm32f4_clock_control.h new file mode 100644 index 00000000000..af48e92e7df --- /dev/null +++ b/include/drivers/clock_control/stm32f4_clock_control.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016 Open-RnD Sp. z o.o. + * (c) 2016 Linaro Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _STM32F4_CLOCK_CONTROL_H_ +#define _STM32F4_CLOCK_CONTROL_H_ + +/** + * @file + * + * @brief Clock subsystem IDs for STM32F4 family + */ + +/* Bus */ +enum { + STM32F4X_CLOCK_BUS_AHB1, + STM32F4X_CLOCK_BUS_AHB2, + STM32F4X_CLOCK_BUS_APB1, + STM32F4X_CLOCK_BUS_APB2, +}; + +/* AHB1 pins */ +enum { + /* AHB1 */ + STM32F4X_CLOCK_ENABLE_GPIOA = 1 << 0, + STM32F4X_CLOCK_ENABLE_GPIOB = 1 << 1, + STM32F4X_CLOCK_ENABLE_GPIOC = 1 << 2, + STM32F4X_CLOCK_ENABLE_GPIOD = 1 << 3, + STM32F4X_CLOCK_ENABLE_GPIOE = 1 << 4, + STM32F4X_CLOCK_ENABLE_GPIOF = 1 << 5, + STM32F4X_CLOCK_ENABLE_GPIOG = 1 << 6, + STM32F4X_CLOCK_ENABLE_GPIOH = 1 << 7, + STM32F4X_CLOCK_ENABLE_GPIOI = 1 << 8, + STM32F4X_CLOCK_ENABLE_GPIOJ = 1 << 9, + STM32F4X_CLOCK_ENABLE_GPIOK = 1 << 10, + STM32F4X_CLOCK_ENABLE_CRC = 1 << 12, + STM32F4X_CLOCK_ENABLE_BKPSRAM = 1 << 14, + STM32F4X_CLOCK_ENABLE_CCMDATARAM = 1 << 16, + STM32F4X_CLOCK_ENABLE_DMA1 = 1 << 21, + STM32F4X_CLOCK_ENABLE_DMA2 = 1 << 22, + STM32F4X_CLOCK_ENABLE_ETHMAC = 1 << 25, + STM32F4X_CLOCK_ENABLE_ETHMACTX = 1 << 26, + STM32F4X_CLOCK_ENABLE_ETHMACRX = 1 << 27, + STM32F4X_CLOCK_ENABLE_ETHMACPTP = 1 << 28, + STM32F4X_CLOCK_ENABLE_OTGHS = 1 << 29, + STM32F4X_CLOCK_ENABLE_OTGHSULPI = 1 << 30, +}; + +/* AHB2 pins */ +enum { + STM32F4X_CLOCK_ENABLE_DCMI = 1 << 0, + STM32F4X_CLOCK_ENABLE_CRYP = 1 << 4, + STM32F4X_CLOCK_ENABLE_HASH = 1 << 5, + STM32F4X_CLOCK_ENABLE_RNG = 1 << 6, + STM32F4X_CLOCK_ENABLE_OTGFS = 1 << 7, +}; + +/* APB1 pins */ +enum { + STM32F4X_CLOCK_ENABLE_TIM2 = 1 << 0, + STM32F4X_CLOCK_ENABLE_TIM3 = 1 << 1, + STM32F4X_CLOCK_ENABLE_TIM4 = 1 << 2, + STM32F4X_CLOCK_ENABLE_TIM5 = 1 << 3, + STM32F4X_CLOCK_ENABLE_TIM6 = 1 << 4, + STM32F4X_CLOCK_ENABLE_TIM7 = 1 << 5, + STM32F4X_CLOCK_ENABLE_TIM12 = 1 << 6, + STM32F4X_CLOCK_ENABLE_TIM13 = 1 << 7, + STM32F4X_CLOCK_ENABLE_TIM14 = 1 << 8, + STM32F4X_CLOCK_ENABLE_WWDG = 1 << 11, + STM32F4X_CLOCK_ENABLE_SPI2 = 1 << 14, + STM32F4X_CLOCK_ENABLE_SPI3 = 1 << 15, + STM32F4X_CLOCK_ENABLE_USART2 = 1 << 17, + STM32F4X_CLOCK_ENABLE_USART3 = 1 << 18, + STM32F4X_CLOCK_ENABLE_UART4 = 1 << 19, + STM32F4X_CLOCK_ENABLE_UART5 = 1 << 20, + STM32F4X_CLOCK_ENABLE_I2C1 = 1 << 21, + STM32F4X_CLOCK_ENABLE_I2C2 = 1 << 22, + STM32F4X_CLOCK_ENABLE_I2C3 = 1 << 23, + STM32F4X_CLOCK_ENABLE_CAN1 = 1 << 25, + STM32F4X_CLOCK_ENABLE_CAN2 = 1 << 26, + STM32F4X_CLOCK_ENABLE_PWR = 1 << 28, + STM32F4X_CLOCK_ENABLE_DAC = 1 << 29, + STM32F4X_CLOCK_ENABLE_UART7 = 1 << 30, + STM32F4X_CLOCK_ENABLE_UART8 = 1 << 31, +}; + +/* APB2 pins */ +enum { + STM32F4X_CLOCK_ENABLE_TIM1 = 1 << 0, + STM32F4X_CLOCK_ENABLE_TIM8 = 1 << 1, + STM32F4X_CLOCK_ENABLE_USART1 = 1 << 4, + STM32F4X_CLOCK_ENABLE_USART6 = 1 << 5, + STM32F4X_CLOCK_ENABLE_ADC = 1 << 8, + STM32F4X_CLOCK_ENABLE_SDIO = 1 << 11, + STM32F4X_CLOCK_ENABLE_SPI1 = 1 << 12, + STM32F4X_CLOCK_ENABLE_SPI4 = 1 << 13, + STM32F4X_CLOCK_ENABLE_SYSCFG = 1 << 14, + STM32F4X_CLOCK_ENABLE_TIM9 = 1 << 16, + STM32F4X_CLOCK_ENABLE_TIM10 = 1 << 17, + STM32F4X_CLOCK_ENABLE_TIM11 = 1 << 18, + STM32F4X_CLOCK_ENABLE_SPI5 = 1 << 20, + STM32F4X_CLOCK_ENABLE_SPI6 = 1 << 21, + STM32F4X_CLOCK_ENABLE_SAI1 = 1 << 22, + STM32F4X_CLOCK_ENABLE_LTDC = 1 << 26, + STM32F4X_CLOCK_ENABLE_DSI = 1 << 27, +}; + +struct stm32f4x_pclken { + uint32_t bus; + uint32_t enr; +}; + +#endif /* _STM32F4_CLOCK_CONTROL_H_ */