From: Vikas Manocha Date: Sun, 12 Feb 2017 18:25:45 +0000 (-0800) Subject: clk: stm32f7: add clock driver for stm32f7 family X-Git-Tag: v2017.05-rc1~64 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=712f99a5ddc404f8c6eac481cfe19f82ca2ecb4f;p=oweals%2Fu-boot.git clk: stm32f7: add clock driver for stm32f7 family add basic clock driver support for stm32f7 to enable clocks required by the peripherals. Signed-off-by: Vikas Manocha Reviewed-by: Simon Glass --- diff --git a/arch/arm/mach-stm32/stm32f7/Makefile b/arch/arm/mach-stm32/stm32f7/Makefile index 643d4d919c..03269bd461 100644 --- a/arch/arm/mach-stm32/stm32f7/Makefile +++ b/arch/arm/mach-stm32/stm32f7/Makefile @@ -5,4 +5,4 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y += timer.o clock.o soc.o +obj-y += timer.o soc.o diff --git a/arch/arm/mach-stm32/stm32f7/clock.c b/arch/arm/mach-stm32/stm32f7/clock.c deleted file mode 100644 index e1ee1731f7..0000000000 --- a/arch/arm/mach-stm32/stm32f7/clock.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * (C) Copyright 2016 - * Vikas Manocha, - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include - -#define RCC_CR_HSION BIT(0) -#define RCC_CR_HSEON BIT(16) -#define RCC_CR_HSERDY BIT(17) -#define RCC_CR_HSEBYP BIT(18) -#define RCC_CR_CSSON BIT(19) -#define RCC_CR_PLLON BIT(24) -#define RCC_CR_PLLRDY BIT(25) - -#define RCC_PLLCFGR_PLLM_MASK GENMASK(5, 0) -#define RCC_PLLCFGR_PLLN_MASK GENMASK(14, 6) -#define RCC_PLLCFGR_PLLP_MASK GENMASK(17, 16) -#define RCC_PLLCFGR_PLLQ_MASK GENMASK(27, 24) -#define RCC_PLLCFGR_PLLSRC BIT(22) -#define RCC_PLLCFGR_PLLM_SHIFT 0 -#define RCC_PLLCFGR_PLLN_SHIFT 6 -#define RCC_PLLCFGR_PLLP_SHIFT 16 -#define RCC_PLLCFGR_PLLQ_SHIFT 24 - -#define RCC_CFGR_AHB_PSC_MASK GENMASK(7, 4) -#define RCC_CFGR_APB1_PSC_MASK GENMASK(12, 10) -#define RCC_CFGR_APB2_PSC_MASK GENMASK(15, 13) -#define RCC_CFGR_SW0 BIT(0) -#define RCC_CFGR_SW1 BIT(1) -#define RCC_CFGR_SW_MASK GENMASK(1, 0) -#define RCC_CFGR_SW_HSI 0 -#define RCC_CFGR_SW_HSE RCC_CFGR_SW0 -#define RCC_CFGR_SW_PLL RCC_CFGR_SW1 -#define RCC_CFGR_SWS0 BIT(2) -#define RCC_CFGR_SWS1 BIT(3) -#define RCC_CFGR_SWS_MASK GENMASK(3, 2) -#define RCC_CFGR_SWS_HSI 0 -#define RCC_CFGR_SWS_HSE RCC_CFGR_SWS0 -#define RCC_CFGR_SWS_PLL RCC_CFGR_SWS1 -#define RCC_CFGR_HPRE_SHIFT 4 -#define RCC_CFGR_PPRE1_SHIFT 10 -#define RCC_CFGR_PPRE2_SHIFT 13 - -/* - * Offsets of some PWR registers - */ -#define PWR_CR1_ODEN BIT(16) -#define PWR_CR1_ODSWEN BIT(17) -#define PWR_CSR1_ODRDY BIT(16) -#define PWR_CSR1_ODSWRDY BIT(17) - -struct pll_psc { - u8 pll_m; - u16 pll_n; - u8 pll_p; - u8 pll_q; - u8 ahb_psc; - u8 apb1_psc; - u8 apb2_psc; -}; - -#define AHB_PSC_1 0 -#define AHB_PSC_2 0x8 -#define AHB_PSC_4 0x9 -#define AHB_PSC_8 0xA -#define AHB_PSC_16 0xB -#define AHB_PSC_64 0xC -#define AHB_PSC_128 0xD -#define AHB_PSC_256 0xE -#define AHB_PSC_512 0xF - -#define APB_PSC_1 0 -#define APB_PSC_2 0x4 -#define APB_PSC_4 0x5 -#define APB_PSC_8 0x6 -#define APB_PSC_16 0x7 - -#if !defined(CONFIG_STM32_HSE_HZ) -#error "CONFIG_STM32_HSE_HZ not defined!" -#else -#if (CONFIG_STM32_HSE_HZ == 25000000) -#if (CONFIG_SYS_CLK_FREQ == 200000000) -/* 200 MHz */ -struct pll_psc sys_pll_psc = { - .pll_m = 25, - .pll_n = 400, - .pll_p = 2, - .pll_q = 8, - .ahb_psc = AHB_PSC_1, - .apb1_psc = APB_PSC_4, - .apb2_psc = APB_PSC_2 -}; -#endif -#else -#error "No PLL/Prescaler configuration for given CONFIG_STM32_HSE_HZ exists" -#endif -#endif - -int configure_clocks(void) -{ - /* Reset RCC configuration */ - setbits_le32(&STM32_RCC->cr, RCC_CR_HSION); - writel(0, &STM32_RCC->cfgr); /* Reset CFGR */ - clrbits_le32(&STM32_RCC->cr, (RCC_CR_HSEON | RCC_CR_CSSON - | RCC_CR_PLLON)); - writel(0x24003010, &STM32_RCC->pllcfgr); /* Reset value from RM */ - clrbits_le32(&STM32_RCC->cr, RCC_CR_HSEBYP); - writel(0, &STM32_RCC->cir); /* Disable all interrupts */ - - /* Configure for HSE+PLL operation */ - setbits_le32(&STM32_RCC->cr, RCC_CR_HSEON); - while (!(readl(&STM32_RCC->cr) & RCC_CR_HSERDY)) - ; - - setbits_le32(&STM32_RCC->cfgr, (( - sys_pll_psc.ahb_psc << RCC_CFGR_HPRE_SHIFT) - | (sys_pll_psc.apb1_psc << RCC_CFGR_PPRE1_SHIFT) - | (sys_pll_psc.apb2_psc << RCC_CFGR_PPRE2_SHIFT))); - - /* Configure the main PLL */ - uint32_t pllcfgr = 0; - pllcfgr = RCC_PLLCFGR_PLLSRC; /* pll source HSE */ - pllcfgr |= sys_pll_psc.pll_m << RCC_PLLCFGR_PLLM_SHIFT; - pllcfgr |= sys_pll_psc.pll_n << RCC_PLLCFGR_PLLN_SHIFT; - pllcfgr |= ((sys_pll_psc.pll_p >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT; - pllcfgr |= sys_pll_psc.pll_q << RCC_PLLCFGR_PLLQ_SHIFT; - writel(pllcfgr, &STM32_RCC->pllcfgr); - - /* Enable the main PLL */ - setbits_le32(&STM32_RCC->cr, RCC_CR_PLLON); - while (!(readl(&STM32_RCC->cr) & RCC_CR_PLLRDY)) - ; - - /* Enable high performance mode, System frequency up to 200 MHz */ - setbits_le32(&STM32_RCC->apb1enr, RCC_APB1ENR_PWREN); - setbits_le32(&STM32_PWR->cr1, PWR_CR1_ODEN); - /* Infinite wait! */ - while (!(readl(&STM32_PWR->csr1) & PWR_CSR1_ODRDY)) - ; - /* Enable the Over-drive switch */ - setbits_le32(&STM32_PWR->cr1, PWR_CR1_ODSWEN); - /* Infinite wait! */ - while (!(readl(&STM32_PWR->csr1) & PWR_CSR1_ODSWRDY)) - ; - - stm32_flash_latency_cfg(5); - clrbits_le32(&STM32_RCC->cfgr, (RCC_CFGR_SW0 | RCC_CFGR_SW1)); - setbits_le32(&STM32_RCC->cfgr, RCC_CFGR_SW_PLL); - - while ((readl(&STM32_RCC->cfgr) & RCC_CFGR_SWS_MASK) != - RCC_CFGR_SWS_PLL) - ; - - return 0; -} - -unsigned long clock_get(enum clock clck) -{ - u32 sysclk = 0; - u32 shift = 0; - /* Prescaler table lookups for clock computation */ - u8 ahb_psc_table[16] = { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9 - }; - u8 apb_psc_table[8] = { - 0, 0, 0, 0, 1, 2, 3, 4 - }; - - if ((readl(&STM32_RCC->cfgr) & RCC_CFGR_SWS_MASK) == - RCC_CFGR_SWS_PLL) { - u16 pllm, plln, pllp; - pllm = (readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLM_MASK); - plln = ((readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLN_MASK) - >> RCC_PLLCFGR_PLLN_SHIFT); - pllp = ((((readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLP_MASK) - >> RCC_PLLCFGR_PLLP_SHIFT) + 1) << 1); - sysclk = ((CONFIG_STM32_HSE_HZ / pllm) * plln) / pllp; - } - - switch (clck) { - case CLOCK_CORE: - return sysclk; - break; - case CLOCK_AHB: - shift = ahb_psc_table[( - (readl(&STM32_RCC->cfgr) & RCC_CFGR_AHB_PSC_MASK) - >> RCC_CFGR_HPRE_SHIFT)]; - return sysclk >>= shift; - break; - case CLOCK_APB1: - shift = apb_psc_table[( - (readl(&STM32_RCC->cfgr) & RCC_CFGR_APB1_PSC_MASK) - >> RCC_CFGR_PPRE1_SHIFT)]; - return sysclk >>= shift; - break; - case CLOCK_APB2: - shift = apb_psc_table[( - (readl(&STM32_RCC->cfgr) & RCC_CFGR_APB2_PSC_MASK) - >> RCC_CFGR_PPRE2_SHIFT)]; - return sysclk >>= shift; - break; - default: - return 0; - break; - } -} - - -void clock_setup(int peripheral) -{ - switch (peripheral) { - case USART1_CLOCK_CFG: - setbits_le32(&STM32_RCC->apb2enr, RCC_APB2ENR_USART1EN); - break; - case GPIO_A_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_A_EN); - break; - case GPIO_B_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_B_EN); - break; - case GPIO_C_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_C_EN); - break; - case GPIO_D_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_D_EN); - break; - case GPIO_E_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_E_EN); - break; - case GPIO_F_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_F_EN); - break; - case GPIO_G_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_G_EN); - break; - case GPIO_H_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_H_EN); - break; - case GPIO_I_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_I_EN); - break; - case GPIO_J_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_J_EN); - break; - case GPIO_K_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_K_EN); - break; - case SYSCFG_CLOCK_CFG: - setbits_le32(&STM32_RCC->apb2enr, RCC_APB2ENR_SYSCFGEN); - break; - case TIMER2_CLOCK_CFG: - setbits_le32(&STM32_RCC->apb1enr, RCC_APB1ENR_TIM2EN); - break; - case FMC_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb3enr, RCC_AHB3ENR_FMC_EN); - break; - case STMMAC_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_ETHMAC_EN); - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_ETHMAC_RX_EN); - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_ETHMAC_TX_EN); - break; - case QSPI_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb3enr, RCC_AHB3ENR_QSPI_EN); - break; - default: - break; - } -} diff --git a/arch/arm/mach-stm32/stm32f7/soc.c b/arch/arm/mach-stm32/stm32f7/soc.c index 8baee99a4f..06af631cc1 100644 --- a/arch/arm/mach-stm32/stm32f7/soc.c +++ b/arch/arm/mach-stm32/stm32f7/soc.c @@ -17,8 +17,6 @@ u32 get_cpu_rev(void) int arch_cpu_init(void) { - configure_clocks(); - /* * Configure the memory protection unit (MPU) * 0x00000000 - 0xffffffff: Strong-order, Shareable diff --git a/configs/stm32f746-disco_defconfig b/configs/stm32f746-disco_defconfig index f638ca0924..8fcab9db75 100644 --- a/configs/stm32f746-disco_defconfig +++ b/configs/stm32f746-disco_defconfig @@ -39,3 +39,4 @@ CONFIG_DM_SPI=y CONFIG_STM32_QSPI=y CONFIG_OF_LIBFDT_OVERLAY=y # CONFIG_EFI_LOADER is not set +CONFIG_CLK=y diff --git a/doc/device-tree-bindings/clock/st,stm32-rcc.txt b/doc/device-tree-bindings/clock/st,stm32-rcc.txt new file mode 100644 index 0000000000..0532d815da --- /dev/null +++ b/doc/device-tree-bindings/clock/st,stm32-rcc.txt @@ -0,0 +1,95 @@ +STMicroelectronics STM32 Reset and Clock Controller +=================================================== + +The RCC IP is both a reset and a clock controller. + +Please refer to clock-bindings.txt for common clock controller binding usage. +Please also refer to reset.txt for common reset controller binding usage. + +Required properties: +- compatible: Should be: + "st,stm32f42xx-rcc" + "st,stm32f469-rcc" +- reg: should be register base and length as documented in the + datasheet +- #reset-cells: 1, see below +- #clock-cells: 2, device nodes should specify the clock in their "clocks" + property, containing a phandle to the clock device node, an index selecting + between gated clocks and other clocks and an index specifying the clock to + use. + +Example: + + rcc: rcc@40023800 { + #reset-cells = <1>; + #clock-cells = <2> + compatible = "st,stm32f42xx-rcc", "st,stm32-rcc"; + reg = <0x40023800 0x400>; + }; + +Specifying gated clocks +======================= + +The primary index must be set to 0. + +The secondary index is the bit number within the RCC register bank, starting +from the first RCC clock enable register (RCC_AHB1ENR, address offset 0x30). + +It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register (LSB is 0, MSB is 31). + +To simplify the usage and to share bit definition with the reset and clock +drivers of the RCC IP, macros are available to generate the index in +human-readble format. + +For STM32F4 series, the macro are available here: + - include/dt-bindings/mfd/stm32f4-rcc.h + +Example: + + /* Gated clock, AHB1 bit 0 (GPIOA) */ + ... { + clocks = <&rcc 0 STM32F4_AHB1_CLOCK(GPIOA)> + }; + + /* Gated clock, AHB2 bit 4 (CRYP) */ + ... { + clocks = <&rcc 0 STM32F4_AHB2_CLOCK(CRYP)> + }; + +Specifying other clocks +======================= + +The primary index must be set to 1. + +The secondary index is bound with the following magic numbers: + + 0 SYSTICK + 1 FCLK + +Example: + + /* Misc clock, FCLK */ + ... { + clocks = <&rcc 1 STM32F4_APB1_CLOCK(TIM2)> + }; + + +Specifying softreset control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the reset device node and an index specifying +which channel to use. +The index is the bit number within the RCC registers bank, starting from RCC +base address. +It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register. +For example, for CRC reset: + crc = AHB1RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x10 / 4 * 32 + 12 = 140 + +example: + + timer2 { + resets = <&rcc STM32F4_APB1_RESET(TIM2)>; + }; diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 40df3cd8ba..01a8cd641e 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -18,5 +18,5 @@ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_CLK_AT91) += at91/ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o - obj-$(CONFIG_ARCH_ASPEED) += aspeed/ +obj-$(CONFIG_STM32F7) += clk_stm32f7.o diff --git a/drivers/clk/clk_stm32f7.c b/drivers/clk/clk_stm32f7.c new file mode 100644 index 0000000000..4c5388adab --- /dev/null +++ b/drivers/clk/clk_stm32f7.c @@ -0,0 +1,332 @@ +/* + * (C) Copyright 2017 + * Vikas Manocha, + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include +#include +#include +#include +#include +#include +#include + +#define RCC_CR_HSION BIT(0) +#define RCC_CR_HSEON BIT(16) +#define RCC_CR_HSERDY BIT(17) +#define RCC_CR_HSEBYP BIT(18) +#define RCC_CR_CSSON BIT(19) +#define RCC_CR_PLLON BIT(24) +#define RCC_CR_PLLRDY BIT(25) + +#define RCC_PLLCFGR_PLLM_MASK GENMASK(5, 0) +#define RCC_PLLCFGR_PLLN_MASK GENMASK(14, 6) +#define RCC_PLLCFGR_PLLP_MASK GENMASK(17, 16) +#define RCC_PLLCFGR_PLLQ_MASK GENMASK(27, 24) +#define RCC_PLLCFGR_PLLSRC BIT(22) +#define RCC_PLLCFGR_PLLM_SHIFT 0 +#define RCC_PLLCFGR_PLLN_SHIFT 6 +#define RCC_PLLCFGR_PLLP_SHIFT 16 +#define RCC_PLLCFGR_PLLQ_SHIFT 24 + +#define RCC_CFGR_AHB_PSC_MASK GENMASK(7, 4) +#define RCC_CFGR_APB1_PSC_MASK GENMASK(12, 10) +#define RCC_CFGR_APB2_PSC_MASK GENMASK(15, 13) +#define RCC_CFGR_SW0 BIT(0) +#define RCC_CFGR_SW1 BIT(1) +#define RCC_CFGR_SW_MASK GENMASK(1, 0) +#define RCC_CFGR_SW_HSI 0 +#define RCC_CFGR_SW_HSE RCC_CFGR_SW0 +#define RCC_CFGR_SW_PLL RCC_CFGR_SW1 +#define RCC_CFGR_SWS0 BIT(2) +#define RCC_CFGR_SWS1 BIT(3) +#define RCC_CFGR_SWS_MASK GENMASK(3, 2) +#define RCC_CFGR_SWS_HSI 0 +#define RCC_CFGR_SWS_HSE RCC_CFGR_SWS0 +#define RCC_CFGR_SWS_PLL RCC_CFGR_SWS1 +#define RCC_CFGR_HPRE_SHIFT 4 +#define RCC_CFGR_PPRE1_SHIFT 10 +#define RCC_CFGR_PPRE2_SHIFT 13 + +/* + * Offsets of some PWR registers + */ +#define PWR_CR1_ODEN BIT(16) +#define PWR_CR1_ODSWEN BIT(17) +#define PWR_CSR1_ODRDY BIT(16) +#define PWR_CSR1_ODSWRDY BIT(17) + +struct pll_psc { + u8 pll_m; + u16 pll_n; + u8 pll_p; + u8 pll_q; + u8 ahb_psc; + u8 apb1_psc; + u8 apb2_psc; +}; + +#define AHB_PSC_1 0 +#define AHB_PSC_2 0x8 +#define AHB_PSC_4 0x9 +#define AHB_PSC_8 0xA +#define AHB_PSC_16 0xB +#define AHB_PSC_64 0xC +#define AHB_PSC_128 0xD +#define AHB_PSC_256 0xE +#define AHB_PSC_512 0xF + +#define APB_PSC_1 0 +#define APB_PSC_2 0x4 +#define APB_PSC_4 0x5 +#define APB_PSC_8 0x6 +#define APB_PSC_16 0x7 + +#if !defined(CONFIG_STM32_HSE_HZ) +#error "CONFIG_STM32_HSE_HZ not defined!" +#else +#if (CONFIG_STM32_HSE_HZ == 25000000) +#if (CONFIG_SYS_CLK_FREQ == 200000000) +/* 200 MHz */ +struct pll_psc sys_pll_psc = { + .pll_m = 25, + .pll_n = 400, + .pll_p = 2, + .pll_q = 8, + .ahb_psc = AHB_PSC_1, + .apb1_psc = APB_PSC_4, + .apb2_psc = APB_PSC_2 +}; +#endif +#else +#error "No PLL/Prescaler configuration for given CONFIG_STM32_HSE_HZ exists" +#endif +#endif + +int configure_clocks(void) +{ + /* Reset RCC configuration */ + setbits_le32(&STM32_RCC->cr, RCC_CR_HSION); + writel(0, &STM32_RCC->cfgr); /* Reset CFGR */ + clrbits_le32(&STM32_RCC->cr, (RCC_CR_HSEON | RCC_CR_CSSON + | RCC_CR_PLLON)); + writel(0x24003010, &STM32_RCC->pllcfgr); /* Reset value from RM */ + clrbits_le32(&STM32_RCC->cr, RCC_CR_HSEBYP); + writel(0, &STM32_RCC->cir); /* Disable all interrupts */ + + /* Configure for HSE+PLL operation */ + setbits_le32(&STM32_RCC->cr, RCC_CR_HSEON); + while (!(readl(&STM32_RCC->cr) & RCC_CR_HSERDY)) + ; + + setbits_le32(&STM32_RCC->cfgr, (( + sys_pll_psc.ahb_psc << RCC_CFGR_HPRE_SHIFT) + | (sys_pll_psc.apb1_psc << RCC_CFGR_PPRE1_SHIFT) + | (sys_pll_psc.apb2_psc << RCC_CFGR_PPRE2_SHIFT))); + + /* Configure the main PLL */ + uint32_t pllcfgr = 0; + pllcfgr = RCC_PLLCFGR_PLLSRC; /* pll source HSE */ + pllcfgr |= sys_pll_psc.pll_m << RCC_PLLCFGR_PLLM_SHIFT; + pllcfgr |= sys_pll_psc.pll_n << RCC_PLLCFGR_PLLN_SHIFT; + pllcfgr |= ((sys_pll_psc.pll_p >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT; + pllcfgr |= sys_pll_psc.pll_q << RCC_PLLCFGR_PLLQ_SHIFT; + writel(pllcfgr, &STM32_RCC->pllcfgr); + + /* Enable the main PLL */ + setbits_le32(&STM32_RCC->cr, RCC_CR_PLLON); + while (!(readl(&STM32_RCC->cr) & RCC_CR_PLLRDY)) + ; + + /* Enable high performance mode, System frequency up to 200 MHz */ + setbits_le32(&STM32_RCC->apb1enr, RCC_APB1ENR_PWREN); + setbits_le32(&STM32_PWR->cr1, PWR_CR1_ODEN); + /* Infinite wait! */ + while (!(readl(&STM32_PWR->csr1) & PWR_CSR1_ODRDY)) + ; + /* Enable the Over-drive switch */ + setbits_le32(&STM32_PWR->cr1, PWR_CR1_ODSWEN); + /* Infinite wait! */ + while (!(readl(&STM32_PWR->csr1) & PWR_CSR1_ODSWRDY)) + ; + + stm32_flash_latency_cfg(5); + clrbits_le32(&STM32_RCC->cfgr, (RCC_CFGR_SW0 | RCC_CFGR_SW1)); + setbits_le32(&STM32_RCC->cfgr, RCC_CFGR_SW_PLL); + + while ((readl(&STM32_RCC->cfgr) & RCC_CFGR_SWS_MASK) != + RCC_CFGR_SWS_PLL) + ; + + return 0; +} + +unsigned long clock_get(enum clock clck) +{ + u32 sysclk = 0; + u32 shift = 0; + /* Prescaler table lookups for clock computation */ + u8 ahb_psc_table[16] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9 + }; + u8 apb_psc_table[8] = { + 0, 0, 0, 0, 1, 2, 3, 4 + }; + + if ((readl(&STM32_RCC->cfgr) & RCC_CFGR_SWS_MASK) == + RCC_CFGR_SWS_PLL) { + u16 pllm, plln, pllp; + pllm = (readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLM_MASK); + plln = ((readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLN_MASK) + >> RCC_PLLCFGR_PLLN_SHIFT); + pllp = ((((readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLP_MASK) + >> RCC_PLLCFGR_PLLP_SHIFT) + 1) << 1); + sysclk = ((CONFIG_STM32_HSE_HZ / pllm) * plln) / pllp; + } + + switch (clck) { + case CLOCK_CORE: + return sysclk; + break; + case CLOCK_AHB: + shift = ahb_psc_table[( + (readl(&STM32_RCC->cfgr) & RCC_CFGR_AHB_PSC_MASK) + >> RCC_CFGR_HPRE_SHIFT)]; + return sysclk >>= shift; + break; + case CLOCK_APB1: + shift = apb_psc_table[( + (readl(&STM32_RCC->cfgr) & RCC_CFGR_APB1_PSC_MASK) + >> RCC_CFGR_PPRE1_SHIFT)]; + return sysclk >>= shift; + break; + case CLOCK_APB2: + shift = apb_psc_table[( + (readl(&STM32_RCC->cfgr) & RCC_CFGR_APB2_PSC_MASK) + >> RCC_CFGR_PPRE2_SHIFT)]; + return sysclk >>= shift; + break; + default: + return 0; + break; + } +} + +static int stm32_clk_enable(struct clk *clk) +{ + u32 offset = clk->id / 32; + u32 bit_index = clk->id % 32; + + debug("%s: clkid = %ld, offset from AHB1ENR is %d, bit_index = %d\n", + __func__, clk->id, offset, bit_index); + setbits_le32(&STM32_RCC->ahb1enr + offset, BIT(bit_index)); + + return 0; +} + +void clock_setup(int peripheral) +{ + switch (peripheral) { + case USART1_CLOCK_CFG: + setbits_le32(&STM32_RCC->apb2enr, RCC_APB2ENR_USART1EN); + break; + case GPIO_A_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_A_EN); + break; + case GPIO_B_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_B_EN); + break; + case GPIO_C_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_C_EN); + break; + case GPIO_D_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_D_EN); + break; + case GPIO_E_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_E_EN); + break; + case GPIO_F_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_F_EN); + break; + case GPIO_G_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_G_EN); + break; + case GPIO_H_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_H_EN); + break; + case GPIO_I_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_I_EN); + break; + case GPIO_J_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_J_EN); + break; + case GPIO_K_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_K_EN); + break; + case SYSCFG_CLOCK_CFG: + setbits_le32(&STM32_RCC->apb2enr, RCC_APB2ENR_SYSCFGEN); + break; + case TIMER2_CLOCK_CFG: + setbits_le32(&STM32_RCC->apb1enr, RCC_APB1ENR_TIM2EN); + break; + case FMC_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb3enr, RCC_AHB3ENR_FMC_EN); + break; + case STMMAC_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_ETHMAC_EN); + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_ETHMAC_RX_EN); + setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_ETHMAC_TX_EN); + break; + case QSPI_CLOCK_CFG: + setbits_le32(&STM32_RCC->ahb3enr, RCC_AHB3ENR_QSPI_EN); + break; + default: + break; + } +} + +static int stm32_clk_probe(struct udevice *dev) +{ + debug("%s: stm32_clk_probe\n", __func__); + configure_clocks(); + + return 0; +} + +static int stm32_clk_of_xlate(struct clk *clk, + struct fdtdec_phandle_args *args) +{ + debug("%s(clk=%p)\n", __func__, clk); + + if (args->args_count != 2) { + debug("Invaild args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args_count) + clk->id = args->args[1]; + else + clk->id = 0; + + return 0; +} + +static struct clk_ops stm32_clk_ops = { + .of_xlate = stm32_clk_of_xlate, + .enable = stm32_clk_enable, +}; + +static const struct udevice_id stm32_clk_ids[] = { + { .compatible = "st,stm32f42xx-rcc"}, + {} +}; + +U_BOOT_DRIVER(stm32f7_clk) = { + .name = "stm32f7_clk", + .id = UCLASS_CLK, + .of_match = stm32_clk_ids, + .ops = &stm32_clk_ops, + .probe = stm32_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +};