clk: stm32f7: add clock driver for stm32f7 family
authorVikas Manocha <vikas.manocha@st.com>
Sun, 12 Feb 2017 18:25:45 +0000 (10:25 -0800)
committerTom Rini <trini@konsulko.com>
Fri, 17 Mar 2017 18:15:12 +0000 (14:15 -0400)
add basic clock driver support for stm32f7 to enable clocks required by
the peripherals.

Signed-off-by: Vikas Manocha <vikas.manocha@st.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
arch/arm/mach-stm32/stm32f7/Makefile
arch/arm/mach-stm32/stm32f7/clock.c [deleted file]
arch/arm/mach-stm32/stm32f7/soc.c
configs/stm32f746-disco_defconfig
doc/device-tree-bindings/clock/st,stm32-rcc.txt [new file with mode: 0644]
drivers/clk/Makefile
drivers/clk/clk_stm32f7.c [new file with mode: 0644]

index 643d4d919c2cdf5c0f156f362a09540de2202cc3..03269bd461c9058f91ea100c8e5296d3f2283ba1 100644 (file)
@@ -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 (file)
index e1ee173..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * (C) Copyright 2016
- * Vikas Manocha, <vikas.manocha@st.com>
- *
- * SPDX-License-Identifier:    GPL-2.0+
- */
-
-#include <common.h>
-#include <asm/io.h>
-#include <asm/arch/rcc.h>
-#include <asm/arch/stm32.h>
-#include <asm/arch/stm32_periph.h>
-
-#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;
-       }
-}
index 8baee99a4f782229ae90252b9e08c8f8267ebbd5..06af631cc107096840c41d089895551093f2d801 100644 (file)
@@ -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
index f638ca092432ac7473188b5f51dc72efa6782650..8fcab9db7567d368a566f73a0022437681e0bded 100644 (file)
@@ -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 (file)
index 0000000..0532d81
--- /dev/null
@@ -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)>;
+       };
index 40df3cd8bae41cb52d469273172fccc69b0d19b8..01a8cd641e7f5b129917f7ca6cacf23be3b24da7 100644 (file)
@@ -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 (file)
index 0000000..4c5388a
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * (C) Copyright 2017
+ * Vikas Manocha, <vikas.manocha@st.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <asm/arch/rcc.h>
+#include <asm/arch/stm32.h>
+#include <asm/arch/stm32_periph.h>
+
+#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,
+};