stm32mp1: Add clock and reset support
authorYann Gautier <[email protected]>
Tue, 24 Jul 2018 15:13:36 +0000 (17:13 +0200)
committerYann Gautier <[email protected]>
Tue, 24 Jul 2018 15:13:36 +0000 (17:13 +0200)
The clock driver is under dual license, BSD and GPLv2.
The clock driver uses device tree, so a minimal support for this is added.
The required files for driver and DTS files are in include/dt-bindings/.

Signed-off-by: Yann Gautier <[email protected]>
Signed-off-by: Patrick Delaunay <[email protected]>
Signed-off-by: Nicolas Le Bayon <[email protected]>
Signed-off-by: Lionel Debieve <[email protected]>
12 files changed:
drivers/st/clk/stm32mp1_clk.c [new file with mode: 0644]
drivers/st/clk/stm32mp1_clkfunc.c [new file with mode: 0644]
drivers/st/reset/stm32mp1_reset.c [new file with mode: 0644]
include/drivers/st/stm32mp1_clk.h [new file with mode: 0644]
include/drivers/st/stm32mp1_clkfunc.h [new file with mode: 0644]
include/drivers/st/stm32mp1_reset.h [new file with mode: 0644]
include/dt-bindings/clock/stm32mp1-clks.h [new file with mode: 0644]
include/dt-bindings/clock/stm32mp1-clksrc.h [new file with mode: 0644]
plat/st/stm32mp1/bl2_plat_setup.c
plat/st/stm32mp1/include/stm32mp1_dt.h [new file with mode: 0644]
plat/st/stm32mp1/platform.mk
plat/st/stm32mp1/stm32mp1_dt.c [new file with mode: 0644]

diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c
new file mode 100644 (file)
index 0000000..7dff98b
--- /dev/null
@@ -0,0 +1,1611 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include <errno.h>
+#include <generic_delay_timer.h>
+#include <libfdt.h>
+#include <mmio.h>
+#include <platform.h>
+#include <stdint.h>
+#include <stm32mp1_clk.h>
+#include <stm32mp1_clkfunc.h>
+#include <stm32mp1_dt.h>
+#include <stm32mp1_private.h>
+#include <stm32mp1_rcc.h>
+#include <utils_def.h>
+
+#define MAX_HSI_HZ     64000000
+
+#define TIMEOUT_200MS  (plat_get_syscnt_freq2() / 5U)
+#define TIMEOUT_1S     plat_get_syscnt_freq2()
+
+#define PLLRDY_TIMEOUT TIMEOUT_200MS
+#define CLKSRC_TIMEOUT TIMEOUT_200MS
+#define CLKDIV_TIMEOUT TIMEOUT_200MS
+#define HSIDIV_TIMEOUT TIMEOUT_200MS
+#define OSCRDY_TIMEOUT TIMEOUT_1S
+
+enum stm32mp1_parent_id {
+/* Oscillators are defined in enum stm32mp_osc_id */
+
+/* Other parent source */
+       _HSI_KER = NB_OSC,
+       _HSE_KER,
+       _HSE_KER_DIV2,
+       _CSI_KER,
+       _PLL1_P,
+       _PLL1_Q,
+       _PLL1_R,
+       _PLL2_P,
+       _PLL2_Q,
+       _PLL2_R,
+       _PLL3_P,
+       _PLL3_Q,
+       _PLL3_R,
+       _PLL4_P,
+       _PLL4_Q,
+       _PLL4_R,
+       _ACLK,
+       _PCLK1,
+       _PCLK2,
+       _PCLK3,
+       _PCLK4,
+       _PCLK5,
+       _HCLK6,
+       _HCLK2,
+       _CK_PER,
+       _CK_MPU,
+       _PARENT_NB,
+       _UNKNOWN_ID = 0xff,
+};
+
+enum stm32mp1_parent_sel {
+       _I2C46_SEL,
+       _UART6_SEL,
+       _UART24_SEL,
+       _UART35_SEL,
+       _UART78_SEL,
+       _SDMMC12_SEL,
+       _SDMMC3_SEL,
+       _QSPI_SEL,
+       _FMC_SEL,
+       _USBPHY_SEL,
+       _USBO_SEL,
+       _STGEN_SEL,
+       _PARENT_SEL_NB,
+       _UNKNOWN_SEL = 0xff,
+};
+
+enum stm32mp1_pll_id {
+       _PLL1,
+       _PLL2,
+       _PLL3,
+       _PLL4,
+       _PLL_NB
+};
+
+enum stm32mp1_div_id {
+       _DIV_P,
+       _DIV_Q,
+       _DIV_R,
+       _DIV_NB,
+};
+
+enum stm32mp1_clksrc_id {
+       CLKSRC_MPU,
+       CLKSRC_AXI,
+       CLKSRC_PLL12,
+       CLKSRC_PLL3,
+       CLKSRC_PLL4,
+       CLKSRC_RTC,
+       CLKSRC_MCO1,
+       CLKSRC_MCO2,
+       CLKSRC_NB
+};
+
+enum stm32mp1_clkdiv_id {
+       CLKDIV_MPU,
+       CLKDIV_AXI,
+       CLKDIV_APB1,
+       CLKDIV_APB2,
+       CLKDIV_APB3,
+       CLKDIV_APB4,
+       CLKDIV_APB5,
+       CLKDIV_RTC,
+       CLKDIV_MCO1,
+       CLKDIV_MCO2,
+       CLKDIV_NB
+};
+
+enum stm32mp1_pllcfg {
+       PLLCFG_M,
+       PLLCFG_N,
+       PLLCFG_P,
+       PLLCFG_Q,
+       PLLCFG_R,
+       PLLCFG_O,
+       PLLCFG_NB
+};
+
+enum stm32mp1_pllcsg {
+       PLLCSG_MOD_PER,
+       PLLCSG_INC_STEP,
+       PLLCSG_SSCG_MODE,
+       PLLCSG_NB
+};
+
+enum stm32mp1_plltype {
+       PLL_800,
+       PLL_1600,
+       PLL_TYPE_NB
+};
+
+struct stm32mp1_pll {
+       uint8_t refclk_min;
+       uint8_t refclk_max;
+       uint8_t divn_max;
+};
+
+struct stm32mp1_clk_gate {
+       uint16_t offset;
+       uint8_t bit;
+       uint8_t index;
+       uint8_t set_clr;
+       enum stm32mp1_parent_sel sel;
+       enum stm32mp1_parent_id fixed;
+       bool secure;
+};
+
+struct stm32mp1_clk_sel {
+       uint16_t offset;
+       uint8_t src;
+       uint8_t msk;
+       uint8_t nb_parent;
+       const uint8_t *parent;
+};
+
+#define REFCLK_SIZE 4
+struct stm32mp1_clk_pll {
+       enum stm32mp1_plltype plltype;
+       uint16_t rckxselr;
+       uint16_t pllxcfgr1;
+       uint16_t pllxcfgr2;
+       uint16_t pllxfracr;
+       uint16_t pllxcr;
+       uint16_t pllxcsgr;
+       enum stm32mp_osc_id refclk[REFCLK_SIZE];
+};
+
+struct stm32mp1_clk_data {
+       const struct stm32mp1_clk_gate *gate;
+       const struct stm32mp1_clk_sel *sel;
+       const struct stm32mp1_clk_pll *pll;
+       const int nb_gate;
+};
+
+struct stm32mp1_clk_priv {
+       uint32_t base;
+       const struct stm32mp1_clk_data *data;
+       unsigned long osc[NB_OSC];
+       uint32_t pkcs_usb_value;
+};
+
+#define STM32MP1_CLK(off, b, idx, s)                   \
+       {                                               \
+               .offset = (off),                        \
+               .bit = (b),                             \
+               .index = (idx),                         \
+               .set_clr = 0,                           \
+               .sel = (s),                             \
+               .fixed = _UNKNOWN_ID,                   \
+               .secure = 0,                            \
+       }
+
+#define STM32MP1_CLK_F(off, b, idx, f)                 \
+       {                                               \
+               .offset = (off),                        \
+               .bit = (b),                             \
+               .index = (idx),                         \
+               .set_clr = 0,                           \
+               .sel = _UNKNOWN_SEL,                    \
+               .fixed = (f),                           \
+               .secure = 0,                            \
+       }
+
+#define STM32MP1_CLK_SET_CLR(off, b, idx, s)           \
+       {                                               \
+               .offset = (off),                        \
+               .bit = (b),                             \
+               .index = (idx),                         \
+               .set_clr = 1,                           \
+               .sel = (s),                             \
+               .fixed = _UNKNOWN_ID,                   \
+               .secure = 0,                            \
+       }
+
+#define STM32MP1_CLK_SET_CLR_F(off, b, idx, f)         \
+       {                                               \
+               .offset = (off),                        \
+               .bit = (b),                             \
+               .index = (idx),                         \
+               .set_clr = 1,                           \
+               .sel = _UNKNOWN_SEL,                    \
+               .fixed = (f),                           \
+               .secure = 0,                            \
+       }
+
+#define STM32MP1_CLK_SEC_SET_CLR(off, b, idx, s)       \
+       {                                               \
+               .offset = (off),                        \
+               .bit = (b),                             \
+               .index = (idx),                         \
+               .set_clr = 1,                           \
+               .sel = (s),                             \
+               .fixed = _UNKNOWN_ID,                   \
+               .secure = 1,                            \
+       }
+
+#define STM32MP1_CLK_PARENT(idx, off, s, m, p)         \
+       [(idx)] = {                                     \
+               .offset = (off),                        \
+               .src = (s),                             \
+               .msk = (m),                             \
+               .parent = (p),                          \
+               .nb_parent = ARRAY_SIZE((p))            \
+       }
+
+#define STM32MP1_CLK_PLL(idx, type, off1, off2, off3,  \
+                        off4, off5, off6,              \
+                        p1, p2, p3, p4)                \
+       [(idx)] = {                                     \
+               .plltype = (type),                      \
+               .rckxselr = (off1),                     \
+               .pllxcfgr1 = (off2),                    \
+               .pllxcfgr2 = (off3),                    \
+               .pllxfracr = (off4),                    \
+               .pllxcr = (off5),                       \
+               .pllxcsgr = (off6),                     \
+               .refclk[0] = (p1),                      \
+               .refclk[1] = (p2),                      \
+               .refclk[2] = (p3),                      \
+               .refclk[3] = (p4),                      \
+       }
+
+static const uint8_t stm32mp1_clks[][2] = {
+       {CK_PER, _CK_PER},
+       {CK_MPU, _CK_MPU},
+       {CK_AXI, _ACLK},
+       {CK_HSE, _HSE},
+       {CK_CSI, _CSI},
+       {CK_LSI, _LSI},
+       {CK_LSE, _LSE},
+       {CK_HSI, _HSI},
+       {CK_HSE_DIV2, _HSE_KER_DIV2},
+};
+
+static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
+       STM32MP1_CLK(RCC_DDRITFCR, 0, DDRC1, _UNKNOWN_SEL),
+       STM32MP1_CLK(RCC_DDRITFCR, 1, DDRC1LP, _UNKNOWN_SEL),
+       STM32MP1_CLK(RCC_DDRITFCR, 2, DDRC2, _UNKNOWN_SEL),
+       STM32MP1_CLK(RCC_DDRITFCR, 3, DDRC2LP, _UNKNOWN_SEL),
+       STM32MP1_CLK_F(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
+       STM32MP1_CLK(RCC_DDRITFCR, 5, DDRPHYCLP, _UNKNOWN_SEL),
+       STM32MP1_CLK(RCC_DDRITFCR, 6, DDRCAPB, _UNKNOWN_SEL),
+       STM32MP1_CLK(RCC_DDRITFCR, 7, DDRCAPBLP, _UNKNOWN_SEL),
+       STM32MP1_CLK(RCC_DDRITFCR, 8, AXIDCG, _UNKNOWN_SEL),
+       STM32MP1_CLK(RCC_DDRITFCR, 9, DDRPHYCAPB, _UNKNOWN_SEL),
+       STM32MP1_CLK(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _UNKNOWN_SEL),
+
+       STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
+
+       STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
+
+       STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
+
+       STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
+       STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
+       STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 11, TZC1, _UNKNOWN_SEL),
+       STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 12, TZC2, _UNKNOWN_SEL),
+       STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
+
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
+
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
+
+       STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 0, GPIOZ, _UNKNOWN_SEL),
+       STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 5, HASH1, _UNKNOWN_SEL),
+       STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 6, RNG1_K, _CSI_KER),
+       STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 8, BKPSRAM, _UNKNOWN_SEL),
+
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
+       STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
+
+       STM32MP1_CLK(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
+};
+
+static const uint8_t i2c46_parents[] = {_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER};
+static const uint8_t uart6_parents[] = {_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER,
+                                       _HSE_KER};
+static const uint8_t uart24_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER,
+                                        _HSE_KER};
+static const uint8_t uart35_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER,
+                                        _HSE_KER};
+static const uint8_t uart78_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER,
+                                        _HSE_KER};
+static const uint8_t sdmmc12_parents[] = {_HCLK6, _PLL3_R, _PLL4_P, _HSI_KER};
+static const uint8_t sdmmc3_parents[] = {_HCLK2, _PLL3_R, _PLL4_P, _HSI_KER};
+static const uint8_t qspi_parents[] = {_ACLK, _PLL3_R, _PLL4_P, _CK_PER};
+static const uint8_t fmc_parents[] = {_ACLK, _PLL3_R, _PLL4_P, _CK_PER};
+static const uint8_t usbphy_parents[] = {_HSE_KER, _PLL4_R, _HSE_KER_DIV2};
+static const uint8_t usbo_parents[] = {_PLL4_R, _USB_PHY_48};
+static const uint8_t stgen_parents[] = {_HSI_KER, _HSE_KER};
+
+static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
+       STM32MP1_CLK_PARENT(_I2C46_SEL, RCC_I2C46CKSELR, 0, 0x7, i2c46_parents),
+       STM32MP1_CLK_PARENT(_UART6_SEL, RCC_UART6CKSELR, 0, 0x7, uart6_parents),
+       STM32MP1_CLK_PARENT(_UART24_SEL, RCC_UART24CKSELR, 0, 0x7,
+                           uart24_parents),
+       STM32MP1_CLK_PARENT(_UART35_SEL, RCC_UART35CKSELR, 0, 0x7,
+                           uart35_parents),
+       STM32MP1_CLK_PARENT(_UART78_SEL, RCC_UART78CKSELR, 0, 0x7,
+                           uart78_parents),
+       STM32MP1_CLK_PARENT(_SDMMC12_SEL, RCC_SDMMC12CKSELR, 0, 0x7,
+                           sdmmc12_parents),
+       STM32MP1_CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7,
+                           sdmmc3_parents),
+       STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents),
+       STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_parents),
+       STM32MP1_CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents),
+       STM32MP1_CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents),
+       STM32MP1_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents),
+};
+
+/* Define characteristic of PLL according type */
+#define DIVN_MIN       24
+static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
+       [PLL_800] = {
+               .refclk_min = 4,
+               .refclk_max = 16,
+               .divn_max = 99,
+       },
+       [PLL_1600] = {
+               .refclk_min = 8,
+               .refclk_max = 16,
+               .divn_max = 199,
+       },
+};
+
+/* PLLNCFGR2 register divider by output */
+static const uint8_t pllncfgr2[_DIV_NB] = {
+       [_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT,
+       [_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT,
+       [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT
+};
+
+static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = {
+       STM32MP1_CLK_PLL(_PLL1, PLL_1600,
+                        RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2,
+                        RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR,
+                        _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
+       STM32MP1_CLK_PLL(_PLL2, PLL_1600,
+                        RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2,
+                        RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR,
+                        _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
+       STM32MP1_CLK_PLL(_PLL3, PLL_800,
+                        RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2,
+                        RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR,
+                        _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID),
+       STM32MP1_CLK_PLL(_PLL4, PLL_800,
+                        RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2,
+                        RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR,
+                        _HSI, _HSE, _CSI, _I2S_CKIN),
+};
+
+/* Prescaler table lookups for clock computation */
+
+/* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */
+#define stm32mp1_mpu_div stm32mp1_mpu_apbx_div
+#define stm32mp1_apbx_div stm32mp1_mpu_apbx_div
+static const uint8_t stm32mp1_mpu_apbx_div[8] = {
+       0, 1, 2, 3, 4, 4, 4, 4
+};
+
+/* div = /1 /2 /3 /4 */
+static const uint8_t stm32mp1_axi_div[8] = {
+       1, 2, 3, 4, 4, 4, 4, 4
+};
+
+static const struct stm32mp1_clk_data stm32mp1_data = {
+       .gate = stm32mp1_clk_gate,
+       .sel = stm32mp1_clk_sel,
+       .pll = stm32mp1_clk_pll,
+       .nb_gate = ARRAY_SIZE(stm32mp1_clk_gate),
+};
+
+static struct stm32mp1_clk_priv stm32mp1_clk_priv_data;
+
+static unsigned long stm32mp1_clk_get_fixed(struct stm32mp1_clk_priv *priv,
+                                           enum stm32mp_osc_id idx)
+{
+       if (idx >= NB_OSC) {
+               return 0;
+       }
+
+       return priv->osc[idx];
+}
+
+static int stm32mp1_clk_get_id(struct stm32mp1_clk_priv *priv, unsigned long id)
+{
+       const struct stm32mp1_clk_gate *gate = priv->data->gate;
+       int i;
+       int nb_clks = priv->data->nb_gate;
+
+       for (i = 0; i < nb_clks; i++) {
+               if (gate[i].index == id) {
+                       return i;
+               }
+       }
+
+       ERROR("%s: clk id %d not found\n", __func__, (uint32_t)id);
+
+       return -EINVAL;
+}
+
+static enum stm32mp1_parent_sel
+stm32mp1_clk_get_sel(struct stm32mp1_clk_priv *priv, int i)
+{
+       const struct stm32mp1_clk_gate *gate = priv->data->gate;
+
+       return gate[i].sel;
+}
+
+static enum stm32mp1_parent_id
+stm32mp1_clk_get_fixed_parent(struct stm32mp1_clk_priv *priv, int i)
+{
+       const struct stm32mp1_clk_gate *gate = priv->data->gate;
+
+       return gate[i].fixed;
+}
+
+static int stm32mp1_clk_get_parent(struct stm32mp1_clk_priv *priv,
+                                  unsigned long id)
+{
+       const struct stm32mp1_clk_sel *sel = priv->data->sel;
+       uint32_t j, p_sel;
+       int i;
+       enum stm32mp1_parent_id p;
+       enum stm32mp1_parent_sel s;
+
+       for (j = 0; j < ARRAY_SIZE(stm32mp1_clks); j++) {
+               if (stm32mp1_clks[j][0] == id) {
+                       return (int)stm32mp1_clks[j][1];
+               }
+       }
+
+       i = stm32mp1_clk_get_id(priv, id);
+       if (i < 0) {
+               return i;
+       }
+
+       p = stm32mp1_clk_get_fixed_parent(priv, i);
+       if (p < _PARENT_NB) {
+               return (int)p;
+       }
+
+       s = stm32mp1_clk_get_sel(priv, i);
+       if (s >= _PARENT_SEL_NB) {
+               return -EINVAL;
+       }
+
+       p_sel = (mmio_read_32(priv->base + sel[s].offset) >> sel[s].src) &
+               sel[s].msk;
+
+       if (p_sel < sel[s].nb_parent) {
+               return (int)sel[s].parent[p_sel];
+       }
+
+       ERROR("%s: no parents defined for clk id %ld\n", __func__, id);
+
+       return -EINVAL;
+}
+
+static unsigned long stm32mp1_pll_get_fref_ck(struct stm32mp1_clk_priv *priv,
+                                             enum stm32mp1_pll_id pll_id)
+{
+       const struct stm32mp1_clk_pll *pll = priv->data->pll;
+       uint32_t selr, src;
+       unsigned long refclk;
+
+       selr = mmio_read_32(priv->base + pll[pll_id].rckxselr);
+       src = selr & RCC_SELR_REFCLK_SRC_MASK;
+
+       refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]);
+
+       return refclk;
+}
+
+/*
+ * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL
+ * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1)
+ * - PLL3 & PLL4 => return VCO     with Fpll_y_ck = FVCO / (DIVy + 1)
+ * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1)
+ */
+static unsigned long stm32mp1_pll_get_fvco(struct stm32mp1_clk_priv *priv,
+                                          enum stm32mp1_pll_id pll_id)
+{
+       const struct stm32mp1_clk_pll *pll = priv->data->pll;
+       unsigned long refclk, fvco;
+       uint32_t cfgr1, fracr, divm, divn;
+
+       cfgr1 = mmio_read_32(priv->base + pll[pll_id].pllxcfgr1);
+       fracr = mmio_read_32(priv->base + pll[pll_id].pllxfracr);
+
+       divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT;
+       divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK;
+
+       refclk = stm32mp1_pll_get_fref_ck(priv, pll_id);
+
+       /*
+        * With FRACV :
+        *   Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1)
+        * Without FRACV
+        *   Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1)
+        */
+       if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) {
+               uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK)
+                           >> RCC_PLLNFRACR_FRACV_SHIFT;
+               unsigned long long numerator, denominator;
+
+               numerator = ((unsigned long long)divn + 1U) << 13;
+               numerator = (refclk * numerator) + fracv;
+               denominator = ((unsigned long long)divm + 1U)  << 13;
+               fvco = (unsigned long)(numerator / denominator);
+       } else {
+               fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U));
+       }
+
+       return fvco;
+}
+
+static unsigned long stm32mp1_read_pll_freq(struct stm32mp1_clk_priv *priv,
+                                           enum stm32mp1_pll_id pll_id,
+                                           enum stm32mp1_div_id div_id)
+{
+       const struct stm32mp1_clk_pll *pll = priv->data->pll;
+       unsigned long dfout;
+       uint32_t cfgr2, divy;
+
+       if (div_id >= _DIV_NB) {
+               return 0;
+       }
+
+       cfgr2 = mmio_read_32(priv->base + pll[pll_id].pllxcfgr2);
+       divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK;
+
+       dfout = stm32mp1_pll_get_fvco(priv, pll_id) / (divy + 1U);
+
+       return dfout;
+}
+
+static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p)
+{
+       uint32_t reg, clkdiv;
+       unsigned long clock = 0;
+
+       switch (p) {
+       case _CK_MPU:
+       /* MPU sub system */
+               reg = mmio_read_32(priv->base + RCC_MPCKSELR);
+               switch (reg & RCC_SELR_SRC_MASK) {
+               case RCC_MPCKSELR_HSI:
+                       clock = stm32mp1_clk_get_fixed(priv, _HSI);
+                       break;
+               case RCC_MPCKSELR_HSE:
+                       clock = stm32mp1_clk_get_fixed(priv, _HSE);
+                       break;
+               case RCC_MPCKSELR_PLL:
+                       clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P);
+                       break;
+               case RCC_MPCKSELR_PLL_MPUDIV:
+                       clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P);
+
+                       reg = mmio_read_32(priv->base + RCC_MPCKDIVR);
+                       clkdiv = reg & RCC_MPUDIV_MASK;
+                       if (clkdiv != 0U) {
+                               clock /= stm32mp1_mpu_div[clkdiv];
+                       }
+
+                       break;
+               default:
+                       break;
+               }
+               break;
+       /* AXI sub system */
+       case _ACLK:
+       case _HCLK2:
+       case _HCLK6:
+       case _PCLK4:
+       case _PCLK5:
+               reg = mmio_read_32(priv->base + RCC_ASSCKSELR);
+               switch (reg & RCC_SELR_SRC_MASK) {
+               case RCC_ASSCKSELR_HSI:
+                       clock = stm32mp1_clk_get_fixed(priv, _HSI);
+                       break;
+               case RCC_ASSCKSELR_HSE:
+                       clock = stm32mp1_clk_get_fixed(priv, _HSE);
+                       break;
+               case RCC_ASSCKSELR_PLL:
+                       clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_P);
+                       break;
+               default:
+                       break;
+               }
+
+               /* System clock divider */
+               reg = mmio_read_32(priv->base + RCC_AXIDIVR);
+               clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK];
+
+               switch (p) {
+               case _PCLK4:
+                       reg = mmio_read_32(priv->base + RCC_APB4DIVR);
+                       clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+                       break;
+               case _PCLK5:
+                       reg = mmio_read_32(priv->base + RCC_APB5DIVR);
+                       clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case _CK_PER:
+               reg = mmio_read_32(priv->base + RCC_CPERCKSELR);
+               switch (reg & RCC_SELR_SRC_MASK) {
+               case RCC_CPERCKSELR_HSI:
+                       clock = stm32mp1_clk_get_fixed(priv, _HSI);
+                       break;
+               case RCC_CPERCKSELR_HSE:
+                       clock = stm32mp1_clk_get_fixed(priv, _HSE);
+                       break;
+               case RCC_CPERCKSELR_CSI:
+                       clock = stm32mp1_clk_get_fixed(priv, _CSI);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case _HSI:
+       case _HSI_KER:
+               clock = stm32mp1_clk_get_fixed(priv, _HSI);
+               break;
+       case _CSI:
+       case _CSI_KER:
+               clock = stm32mp1_clk_get_fixed(priv, _CSI);
+               break;
+       case _HSE:
+       case _HSE_KER:
+               clock = stm32mp1_clk_get_fixed(priv, _HSE);
+               break;
+       case _HSE_KER_DIV2:
+               clock = stm32mp1_clk_get_fixed(priv, _HSE) >> 1;
+               break;
+       case _LSI:
+               clock = stm32mp1_clk_get_fixed(priv, _LSI);
+               break;
+       case _LSE:
+               clock = stm32mp1_clk_get_fixed(priv, _LSE);
+               break;
+       /* PLL */
+       case _PLL1_P:
+               clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P);
+               break;
+       case _PLL1_Q:
+               clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_Q);
+               break;
+       case _PLL1_R:
+               clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_R);
+               break;
+       case _PLL2_P:
+               clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_P);
+               break;
+       case _PLL2_Q:
+               clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_Q);
+               break;
+       case _PLL2_R:
+               clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_R);
+               break;
+       case _PLL3_P:
+               clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_P);
+               break;
+       case _PLL3_Q:
+               clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_Q);
+               break;
+       case _PLL3_R:
+               clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_R);
+               break;
+       case _PLL4_P:
+               clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_P);
+               break;
+       case _PLL4_Q:
+               clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_Q);
+               break;
+       case _PLL4_R:
+               clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_R);
+               break;
+       /* Other */
+       case _USB_PHY_48:
+               clock = stm32mp1_clk_get_fixed(priv, _USB_PHY_48);
+               break;
+       default:
+               break;
+       }
+
+       return clock;
+}
+
+bool stm32mp1_clk_is_enabled(unsigned long id)
+{
+       struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
+       const struct stm32mp1_clk_gate *gate = priv->data->gate;
+       int i = stm32mp1_clk_get_id(priv, id);
+
+       if (i < 0) {
+               return false;
+       }
+
+       return ((mmio_read_32(priv->base + gate[i].offset) &
+                BIT(gate[i].bit)) != 0U);
+}
+
+int stm32mp1_clk_enable(unsigned long id)
+{
+       struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
+       const struct stm32mp1_clk_gate *gate = priv->data->gate;
+       int i = stm32mp1_clk_get_id(priv, id);
+
+       if (i < 0) {
+               return i;
+       }
+
+       if (gate[i].set_clr != 0U) {
+               mmio_write_32(priv->base + gate[i].offset, BIT(gate[i].bit));
+       } else {
+               mmio_setbits_32(priv->base + gate[i].offset, BIT(gate[i].bit));
+       }
+
+       return 0;
+}
+
+int stm32mp1_clk_disable(unsigned long id)
+{
+       struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
+       const struct stm32mp1_clk_gate *gate = priv->data->gate;
+       int i = stm32mp1_clk_get_id(priv, id);
+
+       if (i < 0) {
+               return i;
+       }
+
+       if (gate[i].set_clr != 0U) {
+               mmio_write_32(priv->base + gate[i].offset
+                             + RCC_MP_ENCLRR_OFFSET,
+                             BIT(gate[i].bit));
+       } else {
+               mmio_clrbits_32(priv->base + gate[i].offset, BIT(gate[i].bit));
+       }
+
+       return 0;
+}
+
+unsigned long stm32mp1_clk_get_rate(unsigned long id)
+{
+       struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
+       int p = stm32mp1_clk_get_parent(priv, id);
+       unsigned long rate;
+
+       if (p < 0) {
+               return 0;
+       }
+
+       rate = stm32mp1_clk_get(priv, p);
+
+       return rate;
+}
+
+static void stm32mp1_ls_osc_set(int enable, uint32_t rcc, uint32_t offset,
+                               uint32_t mask_on)
+{
+       uint32_t address = rcc + offset;
+
+       if (enable != 0) {
+               mmio_setbits_32(address, mask_on);
+       } else {
+               mmio_clrbits_32(address, mask_on);
+       }
+}
+
+static void stm32mp1_hs_ocs_set(int enable, uint32_t rcc, uint32_t mask_on)
+{
+       if (enable != 0) {
+               mmio_setbits_32(rcc + RCC_OCENSETR, mask_on);
+       } else {
+               mmio_setbits_32(rcc + RCC_OCENCLRR, mask_on);
+       }
+}
+
+static int stm32mp1_osc_wait(int enable, uint32_t rcc, uint32_t offset,
+                            uint32_t mask_rdy)
+{
+       unsigned long start;
+       uint32_t mask_test;
+       uint32_t address = rcc + offset;
+
+       if (enable != 0) {
+               mask_test = mask_rdy;
+       } else {
+               mask_test = 0;
+       }
+
+       start = get_timer(0);
+       while ((mmio_read_32(address) & mask_rdy) != mask_test) {
+               if (get_timer(start) > OSCRDY_TIMEOUT) {
+                       ERROR("OSC %x @ %x timeout for enable=%d : 0x%x\n",
+                             mask_rdy, address, enable, mmio_read_32(address));
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+static void stm32mp1_lse_enable(uint32_t rcc, bool bypass, uint32_t lsedrv)
+{
+       uint32_t value;
+
+       if (bypass) {
+               mmio_setbits_32(rcc + RCC_BDCR, RCC_BDCR_LSEBYP);
+       }
+
+       /*
+        * Warning: not recommended to switch directly from "high drive"
+        * to "medium low drive", and vice-versa.
+        */
+       value = (mmio_read_32(rcc + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >>
+               RCC_BDCR_LSEDRV_SHIFT;
+
+       while (value != lsedrv) {
+               if (value > lsedrv) {
+                       value--;
+               } else {
+                       value++;
+               }
+
+               mmio_clrsetbits_32(rcc + RCC_BDCR,
+                                  RCC_BDCR_LSEDRV_MASK,
+                                  value << RCC_BDCR_LSEDRV_SHIFT);
+       }
+
+       stm32mp1_ls_osc_set(1, rcc, RCC_BDCR, RCC_BDCR_LSEON);
+}
+
+static void stm32mp1_lse_wait(uint32_t rcc)
+{
+       if (stm32mp1_osc_wait(1, rcc, RCC_BDCR, RCC_BDCR_LSERDY) != 0) {
+               VERBOSE("%s: failed\n", __func__);
+       }
+}
+
+static void stm32mp1_lsi_set(uint32_t rcc, int enable)
+{
+       stm32mp1_ls_osc_set(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSION);
+       if (stm32mp1_osc_wait(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) !=
+           0) {
+               VERBOSE("%s: failed\n", __func__);
+       }
+}
+
+static void stm32mp1_hse_enable(uint32_t rcc, bool bypass, bool css)
+{
+       if (bypass) {
+               mmio_setbits_32(rcc + RCC_OCENSETR, RCC_OCENR_HSEBYP);
+       }
+
+       stm32mp1_hs_ocs_set(1, rcc, RCC_OCENR_HSEON);
+       if (stm32mp1_osc_wait(1, rcc, RCC_OCRDYR, RCC_OCRDYR_HSERDY) !=
+           0) {
+               VERBOSE("%s: failed\n", __func__);
+       }
+
+       if (css) {
+               mmio_setbits_32(rcc + RCC_OCENSETR, RCC_OCENR_HSECSSON);
+       }
+}
+
+static void stm32mp1_csi_set(uint32_t rcc, int enable)
+{
+       stm32mp1_ls_osc_set(enable, rcc, RCC_OCENSETR, RCC_OCENR_CSION);
+       if (stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) !=
+           0) {
+               VERBOSE("%s: failed\n", __func__);
+       }
+}
+
+static void stm32mp1_hsi_set(uint32_t rcc, int enable)
+{
+       stm32mp1_hs_ocs_set(enable, rcc, RCC_OCENR_HSION);
+       if (stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) !=
+           0) {
+               VERBOSE("%s: failed\n", __func__);
+       }
+}
+
+static int stm32mp1_set_hsidiv(uint32_t rcc, uint8_t hsidiv)
+{
+       unsigned long start;
+       uint32_t address = rcc + RCC_OCRDYR;
+
+       mmio_clrsetbits_32(rcc + RCC_HSICFGR,
+                          RCC_HSICFGR_HSIDIV_MASK,
+                          RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv);
+
+       start = get_timer(0);
+       while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) {
+               if (get_timer(start) > HSIDIV_TIMEOUT) {
+                       ERROR("HSIDIV failed @ 0x%x: 0x%x\n",
+                             address, mmio_read_32(address));
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+static int stm32mp1_hsidiv(uint32_t rcc, unsigned long hsifreq)
+{
+       uint8_t hsidiv;
+       uint32_t hsidivfreq = MAX_HSI_HZ;
+
+       for (hsidiv = 0; hsidiv < 4U; hsidiv++) {
+               if (hsidivfreq == hsifreq) {
+                       break;
+               }
+
+               hsidivfreq /= 2U;
+       }
+
+       if (hsidiv == 4U) {
+               ERROR("Invalid clk-hsi frequency\n");
+               return -1;
+       }
+
+       if (hsidiv != 0U) {
+               return stm32mp1_set_hsidiv(rcc, hsidiv);
+       }
+
+       return 0;
+}
+
+static void stm32mp1_pll_start(struct stm32mp1_clk_priv *priv,
+                              enum stm32mp1_pll_id pll_id)
+{
+       const struct stm32mp1_clk_pll *pll = priv->data->pll;
+
+       mmio_write_32(priv->base + pll[pll_id].pllxcr, RCC_PLLNCR_PLLON);
+}
+
+static int stm32mp1_pll_output(struct stm32mp1_clk_priv *priv,
+                              enum stm32mp1_pll_id pll_id, uint32_t output)
+{
+       const struct stm32mp1_clk_pll *pll = priv->data->pll;
+       uint32_t pllxcr = priv->base + pll[pll_id].pllxcr;
+       unsigned long start;
+
+       start = get_timer(0);
+       /* Wait PLL lock */
+       while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) {
+               if (get_timer(start) > PLLRDY_TIMEOUT) {
+                       ERROR("PLL%d start failed @ 0x%x: 0x%x\n",
+                             pll_id, pllxcr, mmio_read_32(pllxcr));
+                       return -ETIMEDOUT;
+               }
+       }
+
+       /* Start the requested output */
+       mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT);
+
+       return 0;
+}
+
+static int stm32mp1_pll_stop(struct stm32mp1_clk_priv *priv,
+                            enum stm32mp1_pll_id pll_id)
+{
+       const struct stm32mp1_clk_pll *pll = priv->data->pll;
+       uint32_t pllxcr = priv->base + pll[pll_id].pllxcr;
+       unsigned long start;
+
+       /* Stop all output */
+       mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
+                       RCC_PLLNCR_DIVREN);
+
+       /* Stop PLL */
+       mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON);
+
+       start = get_timer(0);
+       /* Wait PLL stopped */
+       while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) {
+               if (get_timer(start) > PLLRDY_TIMEOUT) {
+                       ERROR("PLL%d stop failed @ 0x%x: 0x%x\n",
+                             pll_id, pllxcr, mmio_read_32(pllxcr));
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+static void stm32mp1_pll_config_output(struct stm32mp1_clk_priv *priv,
+                                      enum stm32mp1_pll_id pll_id,
+                                      uint32_t *pllcfg)
+{
+       const struct stm32mp1_clk_pll *pll = priv->data->pll;
+       uint32_t rcc = priv->base;
+       uint32_t value;
+
+       value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
+               RCC_PLLNCFGR2_DIVP_MASK;
+       value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
+                RCC_PLLNCFGR2_DIVQ_MASK;
+       value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
+                RCC_PLLNCFGR2_DIVR_MASK;
+       mmio_write_32(rcc + pll[pll_id].pllxcfgr2, value);
+}
+
+static int stm32mp1_pll_config(struct stm32mp1_clk_priv *priv,
+                              enum stm32mp1_pll_id pll_id,
+                              uint32_t *pllcfg, uint32_t fracv)
+{
+       const struct stm32mp1_clk_pll *pll = priv->data->pll;
+       uint32_t rcc = priv->base;
+       enum stm32mp1_plltype type = pll[pll_id].plltype;
+       unsigned long refclk;
+       uint32_t ifrge = 0;
+       uint32_t src, value;
+
+       src = mmio_read_32(priv->base + pll[pll_id].rckxselr) &
+               RCC_SELR_REFCLK_SRC_MASK;
+
+       refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]) /
+                (pllcfg[PLLCFG_M] + 1U);
+
+       if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
+           (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
+               return -EINVAL;
+       }
+
+       if ((type == PLL_800) && (refclk >= 8000000U)) {
+               ifrge = 1U;
+       }
+
+       value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
+               RCC_PLLNCFGR1_DIVN_MASK;
+       value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
+                RCC_PLLNCFGR1_DIVM_MASK;
+       value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
+                RCC_PLLNCFGR1_IFRGE_MASK;
+       mmio_write_32(rcc + pll[pll_id].pllxcfgr1, value);
+
+       /* Fractional configuration */
+       value = 0;
+       mmio_write_32(rcc + pll[pll_id].pllxfracr, value);
+
+       value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
+       mmio_write_32(rcc + pll[pll_id].pllxfracr, value);
+
+       value |= RCC_PLLNFRACR_FRACLE;
+       mmio_write_32(rcc + pll[pll_id].pllxfracr, value);
+
+       stm32mp1_pll_config_output(priv, pll_id, pllcfg);
+
+       return 0;
+}
+
+static void stm32mp1_pll_csg(struct stm32mp1_clk_priv *priv,
+                            enum stm32mp1_pll_id pll_id,
+                            uint32_t *csg)
+{
+       const struct stm32mp1_clk_pll *pll = priv->data->pll;
+       uint32_t pllxcsg = 0;
+
+       pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) &
+                   RCC_PLLNCSGR_MOD_PER_MASK;
+
+       pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) &
+                   RCC_PLLNCSGR_INC_STEP_MASK;
+
+       pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) &
+                   RCC_PLLNCSGR_SSCG_MODE_MASK;
+
+       mmio_write_32(priv->base + pll[pll_id].pllxcsgr, pllxcsg);
+}
+
+static int stm32mp1_set_clksrc(struct stm32mp1_clk_priv *priv,
+                              unsigned int clksrc)
+{
+       uint32_t address = priv->base + (clksrc >> 4);
+       unsigned long start;
+
+       mmio_clrsetbits_32(address, RCC_SELR_SRC_MASK,
+                          clksrc & RCC_SELR_SRC_MASK);
+
+       start = get_timer(0);
+       while ((mmio_read_32(address) & RCC_SELR_SRCRDY) == 0U) {
+               if (get_timer(start) > CLKSRC_TIMEOUT) {
+                       ERROR("CLKSRC %x start failed @ 0x%x: 0x%x\n",
+                             clksrc, address, mmio_read_32(address));
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+static int stm32mp1_set_clkdiv(unsigned int clkdiv, uint32_t address)
+{
+       unsigned long start;
+
+       mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK,
+                          clkdiv & RCC_DIVR_DIV_MASK);
+
+       start = get_timer(0);
+       while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) {
+               if (get_timer(start) > CLKDIV_TIMEOUT) {
+                       ERROR("CLKDIV %x start failed @ 0x%x: 0x%x\n",
+                             clkdiv, address, mmio_read_32(address));
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+static void stm32mp1_mco_csg(struct stm32mp1_clk_priv *priv,
+                            uint32_t clksrc, uint32_t clkdiv)
+{
+       uint32_t address = priv->base + (clksrc >> 4);
+
+       /*
+        * Binding clksrc :
+        *      bit15-4 offset
+        *      bit3:   disable
+        *      bit2-0: MCOSEL[2:0]
+        */
+       if ((clksrc & 0x8U) != 0U) {
+               mmio_clrbits_32(address, RCC_MCOCFG_MCOON);
+       } else {
+               mmio_clrsetbits_32(address,
+                                  RCC_MCOCFG_MCOSRC_MASK,
+                                  clksrc & RCC_MCOCFG_MCOSRC_MASK);
+               mmio_clrsetbits_32(address,
+                                  RCC_MCOCFG_MCODIV_MASK,
+                                  clkdiv << RCC_MCOCFG_MCODIV_SHIFT);
+               mmio_setbits_32(address, RCC_MCOCFG_MCOON);
+       }
+}
+
+static void stm32mp1_set_rtcsrc(struct stm32mp1_clk_priv *priv,
+                               unsigned int clksrc, bool lse_css)
+{
+       uint32_t address = priv->base + RCC_BDCR;
+
+       if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) ||
+           (clksrc != (uint32_t)CLK_RTC_DISABLED)) {
+               mmio_clrsetbits_32(address,
+                                  RCC_BDCR_RTCSRC_MASK,
+                                  clksrc << RCC_BDCR_RTCSRC_SHIFT);
+
+               mmio_setbits_32(address, RCC_BDCR_RTCCKEN);
+       }
+
+       if (lse_css) {
+               mmio_setbits_32(address, RCC_BDCR_LSECSSON);
+       }
+}
+
+#define CNTCVL_OFF     0x008
+#define CNTCVU_OFF     0x00C
+
+static void stm32mp1_stgen_config(struct stm32mp1_clk_priv *priv)
+{
+       uintptr_t stgen;
+       int p;
+       uint32_t cntfid0;
+       unsigned long rate;
+
+       stgen = fdt_get_stgen_base();
+
+       cntfid0 = mmio_read_32(stgen + CNTFID_OFF);
+       p = stm32mp1_clk_get_parent(priv, STGEN_K);
+       rate = stm32mp1_clk_get(priv, p);
+
+       if (cntfid0 != rate) {
+               unsigned long long counter;
+
+               mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN);
+               counter = (unsigned long long)
+                       mmio_read_32(stgen + CNTCVL_OFF);
+               counter |= ((unsigned long long)
+                           (mmio_read_32(stgen + CNTCVU_OFF))) << 32;
+               counter = (counter * rate / cntfid0);
+               mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)counter);
+               mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(counter >> 32));
+               mmio_write_32(stgen + CNTFID_OFF, rate);
+               mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN);
+
+               write_cntfrq((u_register_t)rate);
+
+               /* Need to update timer with new frequency */
+               generic_delay_timer_init();
+       }
+}
+
+void stm32mp1_stgen_increment(unsigned long long offset_in_ms)
+{
+       uintptr_t stgen;
+       unsigned long long cnt;
+
+       stgen = fdt_get_stgen_base();
+
+       cnt = ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF) << 32) |
+               mmio_read_32(stgen + CNTCVL_OFF);
+
+       cnt += (offset_in_ms * mmio_read_32(stgen + CNTFID_OFF)) / 1000U;
+
+       mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN);
+       mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)cnt);
+       mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(cnt >> 32));
+       mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN);
+}
+
+static void stm32mp1_pkcs_config(struct stm32mp1_clk_priv *priv, uint32_t pkcs)
+{
+       uint32_t address = priv->base + ((pkcs >> 4) & 0xFFFU);
+       uint32_t value = pkcs & 0xFU;
+       uint32_t mask = 0xFU;
+
+       if ((pkcs & BIT(31)) != 0U) {
+               mask <<= 4;
+               value <<= 4;
+       }
+
+       mmio_clrsetbits_32(address, mask, value);
+}
+
+int stm32mp1_clk_init(void)
+{
+       struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
+       uint32_t rcc = priv->base;
+       unsigned int clksrc[CLKSRC_NB];
+       unsigned int clkdiv[CLKDIV_NB];
+       unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
+       int plloff[_PLL_NB];
+       int ret, len;
+       enum stm32mp1_pll_id i;
+       bool lse_css = false;
+       const uint32_t *pkcs_cell;
+
+       /* Check status field to disable security */
+       if (!fdt_get_rcc_secure_status()) {
+               mmio_write_32(rcc + RCC_TZCR, 0);
+       }
+
+       ret = fdt_rcc_read_uint32_array("st,clksrc", clksrc,
+                                       (uint32_t)CLKSRC_NB);
+       if (ret < 0) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       ret = fdt_rcc_read_uint32_array("st,clkdiv", clkdiv,
+                                       (uint32_t)CLKDIV_NB);
+       if (ret < 0) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
+               char name[12];
+
+               sprintf(name, "st,pll@%d", i);
+               plloff[i] = fdt_rcc_subnode_offset(name);
+
+               if (!fdt_check_node(plloff[i])) {
+                       continue;
+               }
+
+               ret = fdt_read_uint32_array(plloff[i], "cfg",
+                                           pllcfg[i], (int)PLLCFG_NB);
+               if (ret < 0) {
+                       return -FDT_ERR_NOTFOUND;
+               }
+       }
+
+       stm32mp1_mco_csg(priv, clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]);
+       stm32mp1_mco_csg(priv, clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]);
+
+       /*
+        * Switch ON oscillator found in device-tree.
+        * Note: HSI already ON after BootROM stage.
+        */
+       if (priv->osc[_LSI] != 0U) {
+               stm32mp1_lsi_set(rcc, 1);
+       }
+       if (priv->osc[_LSE] != 0U) {
+               bool bypass;
+               uint32_t lsedrv;
+
+               bypass = fdt_osc_read_bool(_LSE, "st,bypass");
+               lse_css = fdt_osc_read_bool(_LSE, "st,css");
+               lsedrv = fdt_osc_read_uint32_default(_LSE, "st,drive",
+                                                    LSEDRV_MEDIUM_HIGH);
+               stm32mp1_lse_enable(rcc, bypass, lsedrv);
+       }
+       if (priv->osc[_HSE] != 0U) {
+               bool bypass, css;
+
+               bypass = fdt_osc_read_bool(_LSE, "st,bypass");
+               css = fdt_osc_read_bool(_LSE, "st,css");
+               stm32mp1_hse_enable(rcc, bypass, css);
+       }
+       /*
+        * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR)
+        * => switch on CSI even if node is not present in device tree
+        */
+       stm32mp1_csi_set(rcc, 1);
+
+       /* Come back to HSI */
+       ret = stm32mp1_set_clksrc(priv, CLK_MPU_HSI);
+       if (ret != 0) {
+               return ret;
+       }
+       ret = stm32mp1_set_clksrc(priv, CLK_AXI_HSI);
+       if (ret != 0) {
+               return ret;
+       }
+
+       for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
+               if (i == _PLL4)
+                       continue;
+               ret = stm32mp1_pll_stop(priv, i);
+               if (ret != 0) {
+                       return ret;
+               }
+       }
+
+       /* Configure HSIDIV */
+       if (priv->osc[_HSI] != 0U) {
+               ret = stm32mp1_hsidiv(rcc, priv->osc[_HSI]);
+               if (ret != 0) {
+                       return ret;
+               }
+               stm32mp1_stgen_config(priv);
+       }
+
+       /* Select DIV */
+       /* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */
+       mmio_write_32(rcc + RCC_MPCKDIVR,
+                     clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK);
+       ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc + RCC_AXIDIVR);
+       if (ret != 0) {
+               return ret;
+       }
+       ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc + RCC_APB4DIVR);
+       if (ret != 0) {
+               return ret;
+       }
+       ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc + RCC_APB5DIVR);
+       if (ret != 0) {
+               return ret;
+       }
+       ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc + RCC_APB1DIVR);
+       if (ret != 0) {
+               return ret;
+       }
+       ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc + RCC_APB2DIVR);
+       if (ret != 0) {
+               return ret;
+       }
+       ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc + RCC_APB3DIVR);
+       if (ret != 0) {
+               return ret;
+       }
+
+       /* No ready bit for RTC */
+       mmio_write_32(rcc + RCC_RTCDIVR,
+                     clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK);
+
+       /* Configure PLLs source */
+       ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL12]);
+       if (ret != 0) {
+               return ret;
+       }
+       ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL3]);
+       if (ret != 0) {
+               return ret;
+       }
+
+       ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL4]);
+       if (ret != 0) {
+               return ret;
+       }
+
+       /* Configure and start PLLs */
+       for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
+               uint32_t fracv;
+               uint32_t csg[PLLCSG_NB];
+
+               if (!fdt_check_node(plloff[i])) {
+                       continue;
+               }
+
+               fracv = fdt_read_uint32_default(plloff[i], "frac", 0);
+
+               ret = stm32mp1_pll_config(priv, i, pllcfg[i], fracv);
+               if (ret != 0) {
+                       return ret;
+               }
+               ret = fdt_read_uint32_array(plloff[i], "csg", csg,
+                                           (uint32_t)PLLCSG_NB);
+               if (ret == 0) {
+                       stm32mp1_pll_csg(priv, i, csg);
+               } else if (ret != -FDT_ERR_NOTFOUND) {
+                       return ret;
+               }
+
+               stm32mp1_pll_start(priv, i);
+       }
+       /* Wait and start PLLs ouptut when ready */
+       for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
+               if (!fdt_check_node(plloff[i])) {
+                       continue;
+               }
+
+               ret = stm32mp1_pll_output(priv, i, pllcfg[i][PLLCFG_O]);
+               if (ret != 0) {
+                       return ret;
+               }
+       }
+       /* Wait LSE ready before to use it */
+       if (priv->osc[_LSE] != 0U) {
+               stm32mp1_lse_wait(rcc);
+       }
+
+       /* Configure with expected clock source */
+       ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_MPU]);
+       if (ret != 0) {
+               return ret;
+       }
+       ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_AXI]);
+       if (ret != 0) {
+               return ret;
+       }
+       stm32mp1_set_rtcsrc(priv, clksrc[CLKSRC_RTC], lse_css);
+
+       /* Configure PKCK */
+       pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len);
+       if (pkcs_cell != NULL) {
+               bool ckper_disabled = false;
+               uint32_t j;
+
+               priv->pkcs_usb_value = 0;
+
+               for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) {
+                       uint32_t pkcs = (uint32_t)fdt32_to_cpu(pkcs_cell[j]);
+
+                       if (pkcs == (uint32_t)CLK_CKPER_DISABLED) {
+                               ckper_disabled = true;
+                               continue;
+                       }
+                       stm32mp1_pkcs_config(priv, pkcs);
+               }
+
+               /*
+                * CKPER is source for some peripheral clocks
+                * (FMC-NAND / QPSI-NOR) and switching source is allowed
+                * only if previous clock is still ON
+                * => deactivated CKPER only after switching clock
+                */
+               if (ckper_disabled) {
+                       stm32mp1_pkcs_config(priv, CLK_CKPER_DISABLED);
+               }
+       }
+
+       /* Switch OFF HSI if not found in device-tree */
+       if (priv->osc[_HSI] == 0U) {
+               stm32mp1_hsi_set(rcc, 0);
+       }
+       stm32mp1_stgen_config(priv);
+
+       /* Software Self-Refresh mode (SSR) during DDR initilialization */
+       mmio_clrsetbits_32(priv->base + RCC_DDRITFCR,
+                          RCC_DDRITFCR_DDRCKMOD_MASK,
+                          RCC_DDRITFCR_DDRCKMOD_SSR <<
+                          RCC_DDRITFCR_DDRCKMOD_SHIFT);
+
+       return 0;
+}
+
+static void stm32mp1_osc_clk_init(const char *name,
+                                 struct stm32mp1_clk_priv *priv,
+                                 enum stm32mp_osc_id index)
+{
+       uint32_t frequency;
+
+       priv->osc[index] = 0;
+
+       if (fdt_osc_read_freq(name, &frequency) != 0) {
+               ERROR("%s frequency request failed\n", name);
+               panic();
+       } else {
+               priv->osc[index] = frequency;
+       }
+}
+
+static void stm32mp1_osc_init(void)
+{
+       struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
+       enum stm32mp_osc_id i;
+
+       for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) {
+               stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], priv, i);
+       }
+}
+
+int stm32mp1_clk_probe(void)
+{
+       struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
+
+       priv->base = fdt_rcc_read_addr();
+       if (priv->base == 0U) {
+               return -EINVAL;
+       }
+
+       priv->data = &stm32mp1_data;
+
+       if ((priv->data->gate == NULL) || (priv->data->sel == NULL) ||
+           (priv->data->pll == NULL)) {
+               return -EINVAL;
+       }
+
+       stm32mp1_osc_init();
+
+       return 0;
+}
diff --git a/drivers/st/clk/stm32mp1_clkfunc.c b/drivers/st/clk/stm32mp1_clkfunc.c
new file mode 100644 (file)
index 0000000..d4c69cb
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include <errno.h>
+#include <libfdt.h>
+#include <stm32mp1_clk.h>
+#include <stm32mp1_clkfunc.h>
+#include <stm32mp1_dt.h>
+
+#define DT_RCC_NODE_NAME       "rcc@50000000"
+#define DT_RCC_CLK_COMPAT      "st,stm32mp1-rcc"
+#define DT_RCC_COMPAT          "syscon"
+#define DT_STGEN_COMPAT                "st,stm32-stgen"
+#define DT_UART_COMPAT         "st,stm32h7-uart"
+#define DT_USART_COMPAT                "st,stm32h7-usart"
+
+const char *stm32mp_osc_node_label[NB_OSC] = {
+       [_LSI] = "clk-lsi",
+       [_LSE] = "clk-lse",
+       [_HSI] = "clk-hsi",
+       [_HSE] = "clk-hse",
+       [_CSI] = "clk-csi",
+       [_I2S_CKIN] = "i2s_ckin",
+       [_USB_PHY_48] = "ck_usbo_48m"
+};
+
+/*******************************************************************************
+ * This function reads the frequency of an oscillator from its name.
+ * It reads the value indicated inside the device tree.
+ * Returns 0 if success, and a negative value else.
+ * If success, value is stored in the second parameter.
+ ******************************************************************************/
+int fdt_osc_read_freq(const char *name, uint32_t *freq)
+{
+       int node, subnode;
+       void *fdt;
+
+       if (fdt_get_address(&fdt) == 0) {
+               return -ENOENT;
+       }
+
+       node = fdt_path_offset(fdt, "/clocks");
+       if (node < 0) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       fdt_for_each_subnode(subnode, fdt, node) {
+               const char *cchar;
+               int ret;
+
+               cchar = fdt_get_name(fdt, subnode, &ret);
+               if (cchar == NULL) {
+                       return ret;
+               }
+
+               if (strncmp(cchar, name, (size_t)ret) == 0) {
+                       const fdt32_t *cuint;
+
+                       cuint = fdt_getprop(fdt, subnode, "clock-frequency",
+                                           &ret);
+                       if (cuint == NULL) {
+                               return ret;
+                       }
+
+                       *freq = fdt32_to_cpu(*cuint);
+
+                       return 0;
+               }
+       }
+
+       /* Oscillator not found, freq=0 */
+       *freq = 0;
+       return 0;
+}
+
+/*******************************************************************************
+ * This function checks the presence of an oscillator property from its id.
+ * The search is done inside the device tree.
+ * Returns true/false regarding search result.
+ ******************************************************************************/
+bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
+{
+       int node, subnode;
+       void *fdt;
+
+       if (fdt_get_address(&fdt) == 0) {
+               return false;
+       }
+
+       if (osc_id >= NB_OSC) {
+               return false;
+       }
+
+       node = fdt_path_offset(fdt, "/clocks");
+       if (node < 0) {
+               return false;
+       }
+
+       fdt_for_each_subnode(subnode, fdt, node) {
+               const char *cchar;
+               int ret;
+
+               cchar = fdt_get_name(fdt, subnode, &ret);
+               if (cchar == NULL) {
+                       return false;
+               }
+
+               if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
+                           (size_t)ret) != 0) {
+                       continue;
+               }
+
+               if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+/*******************************************************************************
+ * This function reads a value of a oscillator property from its id.
+ * Returns value if success, and a default value if property not found.
+ * Default value is passed as parameter.
+ ******************************************************************************/
+uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
+                                    const char *prop_name, uint32_t dflt_value)
+{
+       int node, subnode;
+       void *fdt;
+
+       if (fdt_get_address(&fdt) == 0) {
+               return dflt_value;
+       }
+
+       if (osc_id >= NB_OSC) {
+               return dflt_value;
+       }
+
+       node = fdt_path_offset(fdt, "/clocks");
+       if (node < 0) {
+               return dflt_value;
+       }
+
+       fdt_for_each_subnode(subnode, fdt, node) {
+               const char *cchar;
+               int ret;
+
+               cchar = fdt_get_name(fdt, subnode, &ret);
+               if (cchar == NULL) {
+                       return dflt_value;
+               }
+
+               if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
+                           (size_t)ret) != 0) {
+                       continue;
+               }
+
+               return fdt_read_uint32_default(subnode, prop_name, dflt_value);
+       }
+
+       return dflt_value;
+}
+
+/*******************************************************************************
+ * This function reads the rcc base address.
+ * It reads the value indicated inside the device tree.
+ * Returns address if success, and 0 value else.
+ ******************************************************************************/
+uint32_t fdt_rcc_read_addr(void)
+{
+       int node, subnode;
+       void *fdt;
+
+       if (fdt_get_address(&fdt) == 0) {
+               return 0;
+       }
+
+       node = fdt_path_offset(fdt, "/soc");
+       if (node < 0) {
+               return 0;
+       }
+
+       fdt_for_each_subnode(subnode, fdt, node) {
+               const char *cchar;
+               int ret;
+
+               cchar = fdt_get_name(fdt, subnode, &ret);
+               if (cchar == NULL) {
+                       return 0;
+               }
+
+               if (strncmp(cchar, DT_RCC_NODE_NAME, (size_t)ret) == 0) {
+                       const fdt32_t *cuint;
+
+                       cuint = fdt_getprop(fdt, subnode, "reg", NULL);
+                       if (cuint == NULL) {
+                               return 0;
+                       }
+
+                       return fdt32_to_cpu(*cuint);
+               }
+       }
+
+       return 0;
+}
+
+/*******************************************************************************
+ * This function reads a series of parameters in rcc-clk section.
+ * It reads the values indicated inside the device tree, from property name.
+ * The number of parameters is also indicated as entry parameter.
+ * Returns 0 if success, and a negative value else.
+ * If success, values are stored at the second parameter address.
+ ******************************************************************************/
+int fdt_rcc_read_uint32_array(const char *prop_name,
+                             uint32_t *array, uint32_t count)
+{
+       int node;
+       void *fdt;
+
+       if (fdt_get_address(&fdt) == 0) {
+               return -ENOENT;
+       }
+
+       node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
+       if (node < 0) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       return fdt_read_uint32_array(node, prop_name, array, count);
+}
+
+/*******************************************************************************
+ * This function gets the subnode offset in rcc-clk section from its name.
+ * It reads the values indicated inside the device tree.
+ * Returns offset if success, and a negative value else.
+ ******************************************************************************/
+int fdt_rcc_subnode_offset(const char *name)
+{
+       int node, subnode;
+       void *fdt;
+
+       if (fdt_get_address(&fdt) == 0) {
+               return -ENOENT;
+       }
+
+       node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
+       if (node < 0) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       subnode = fdt_subnode_offset(fdt, node, name);
+       if (subnode <= 0) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       return subnode;
+}
+
+/*******************************************************************************
+ * This function gets the pointer to a rcc-clk property from its name.
+ * It reads the values indicated inside the device tree.
+ * Length of the property is stored in the second parameter.
+ * Returns pointer if success, and NULL value else.
+ ******************************************************************************/
+const uint32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
+{
+       const uint32_t *cuint;
+       int node, len;
+       void *fdt;
+
+       if (fdt_get_address(&fdt) == 0) {
+               return NULL;
+       }
+
+       node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
+       if (node < 0) {
+               return NULL;
+       }
+
+       cuint = fdt_getprop(fdt, node, prop_name, &len);
+       if (cuint == NULL) {
+               return NULL;
+       }
+
+       *lenp = len;
+       return cuint;
+}
+
+/*******************************************************************************
+ * This function gets the secure status for rcc node.
+ * It reads secure-status in device tree.
+ * Returns 1 if rcc is available from secure world, 0 else.
+ ******************************************************************************/
+bool fdt_get_rcc_secure_status(void)
+{
+       int node;
+       void *fdt;
+
+       if (fdt_get_address(&fdt) == 0) {
+               return false;
+       }
+
+       node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_COMPAT);
+       if (node < 0) {
+               return false;
+       }
+
+       return fdt_check_secure_status(node);
+}
+
+/*******************************************************************************
+ * This function reads the stgen base address.
+ * It reads the value indicated inside the device tree.
+ * Returns address if success, and NULL value else.
+ ******************************************************************************/
+uintptr_t fdt_get_stgen_base(void)
+{
+       int node;
+       const fdt32_t *cuint;
+       void *fdt;
+
+       if (fdt_get_address(&fdt) == 0) {
+               return 0;
+       }
+
+       node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT);
+       if (node < 0) {
+               return 0;
+       }
+
+       cuint = fdt_getprop(fdt, node, "reg", NULL);
+       if (cuint == NULL) {
+               return 0;
+       }
+
+       return fdt32_to_cpu(*cuint);
+}
+
+/*******************************************************************************
+ * This function gets the clock ID of the given node.
+ * It reads the value indicated inside the device tree.
+ * Returns ID if success, and a negative value else.
+ ******************************************************************************/
+int fdt_get_clock_id(int node)
+{
+       const fdt32_t *cuint;
+       void *fdt;
+
+       if (fdt_get_address(&fdt) == 0) {
+               return -ENOENT;
+       }
+
+       cuint = fdt_getprop(fdt, node, "clocks", NULL);
+       if (cuint == NULL) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       cuint++;
+       return (int)fdt32_to_cpu(*cuint);
+}
diff --git a/drivers/st/reset/stm32mp1_reset.c b/drivers/st/reset/stm32mp1_reset.c
new file mode 100644 (file)
index 0000000..106bbfe
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <bl_common.h>
+#include <debug.h>
+#include <limits.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <stm32mp1_rcc.h>
+#include <stm32mp1_reset.h>
+#include <utils_def.h>
+
+#define RST_CLR_OFFSET 4U
+
+void stm32mp1_reset_assert(uint32_t id)
+{
+       uint32_t offset = (id / (uint32_t)__LONG_BIT) * sizeof(uintptr_t);
+       uint32_t bit = id % (uint32_t)__LONG_BIT;
+
+       mmio_write_32(RCC_BASE + offset, BIT(bit));
+       while ((mmio_read_32(RCC_BASE + offset) & BIT(bit)) == 0U) {
+               ;
+       }
+}
+
+void stm32mp1_reset_deassert(uint32_t id)
+{
+       uint32_t offset = ((id / (uint32_t)__LONG_BIT) * sizeof(uintptr_t)) +
+                         RST_CLR_OFFSET;
+       uint32_t bit = id % (uint32_t)__LONG_BIT;
+
+       mmio_write_32(RCC_BASE + offset, BIT(bit));
+       while ((mmio_read_32(RCC_BASE + offset) & BIT(bit)) != 0U) {
+               ;
+       }
+}
diff --git a/include/drivers/st/stm32mp1_clk.h b/include/drivers/st/stm32mp1_clk.h
new file mode 100644 (file)
index 0000000..85a1eb8
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __STM32MP1_CLK_H__
+#define __STM32MP1_CLK_H__
+
+#include <arch_helpers.h>
+#include <stdbool.h>
+
+int stm32mp1_clk_probe(void);
+int stm32mp1_clk_init(void);
+bool stm32mp1_clk_is_enabled(unsigned long id);
+int stm32mp1_clk_enable(unsigned long id);
+int stm32mp1_clk_disable(unsigned long id);
+unsigned long stm32mp1_clk_get_rate(unsigned long id);
+void stm32mp1_stgen_increment(unsigned long long offset_in_ms);
+
+static inline uint32_t get_timer(uint32_t base)
+{
+       if (base == 0U) {
+               return (uint32_t)(~read_cntpct_el0());
+       }
+
+       return base - (uint32_t)(~read_cntpct_el0());
+}
+
+#endif /* __STM32MP1_CLK_H__ */
diff --git a/include/drivers/st/stm32mp1_clkfunc.h b/include/drivers/st/stm32mp1_clkfunc.h
new file mode 100644 (file)
index 0000000..635a9cd
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __STM32MP1_CLKFUNC_H__
+#define __STM32MP1_CLKFUNC_H__
+
+#include <stdbool.h>
+
+enum stm32mp_osc_id {
+       _HSI,
+       _HSE,
+       _CSI,
+       _LSI,
+       _LSE,
+       _I2S_CKIN,
+       _USB_PHY_48,
+       NB_OSC,
+       _UNKNOWN_OSC_ID = 0xFF
+};
+
+extern const char *stm32mp_osc_node_label[NB_OSC];
+
+int fdt_osc_read_freq(const char *name, uint32_t *freq);
+bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name);
+uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
+                                    const char *prop_name,
+                                    uint32_t dflt_value);
+
+uint32_t fdt_rcc_read_addr(void);
+int fdt_rcc_read_uint32_array(const char *prop_name,
+                             uint32_t *array, uint32_t count);
+int fdt_rcc_subnode_offset(const char *name);
+const uint32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp);
+bool fdt_get_rcc_secure_status(void);
+
+uintptr_t fdt_get_stgen_base(void);
+int fdt_get_clock_id(int node);
+
+#endif /* __STM32MP1_CLKFUNC_H__ */
diff --git a/include/drivers/st/stm32mp1_reset.h b/include/drivers/st/stm32mp1_reset.h
new file mode 100644 (file)
index 0000000..76ee09d
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __STM32MP1_RESET_H__
+#define __STM32MP1_RESET_H__
+
+#include <stdint.h>
+
+void stm32mp1_reset_assert(uint32_t reset_id);
+void stm32mp1_reset_deassert(uint32_t reset_id);
+
+#endif /* __STM32MP1_RESET_H__ */
diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h
new file mode 100644 (file)
index 0000000..18bdb57
--- /dev/null
@@ -0,0 +1,251 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Gabriel Fernandez <[email protected]> for STMicroelectronics.
+ */
+
+#ifndef _DT_BINDINGS_STM32MP1_CLKS_H_
+#define _DT_BINDINGS_STM32MP1_CLKS_H_
+
+/* OSCILLATOR clocks */
+#define CK_HSE         0
+#define CK_CSI         1
+#define CK_LSI         2
+#define CK_LSE         3
+#define CK_HSI         4
+#define CK_HSE_DIV2    5
+
+/* Bus clocks */
+#define TIM2           6
+#define TIM3           7
+#define TIM4           8
+#define TIM5           9
+#define TIM6           10
+#define TIM7           11
+#define TIM12          12
+#define TIM13          13
+#define TIM14          14
+#define LPTIM1         15
+#define SPI2           16
+#define SPI3           17
+#define USART2         18
+#define USART3         19
+#define UART4          20
+#define UART5          21
+#define UART7          22
+#define UART8          23
+#define I2C1           24
+#define I2C2           25
+#define I2C3           26
+#define I2C5           27
+#define SPDIF          28
+#define CEC            29
+#define DAC12          30
+#define MDIO           31
+#define TIM1           32
+#define TIM8           33
+#define TIM15          34
+#define TIM16          35
+#define TIM17          36
+#define SPI1           37
+#define SPI4           38
+#define SPI5           39
+#define USART6         40
+#define SAI1           41
+#define SAI2           42
+#define SAI3           43
+#define DFSDM          44
+#define FDCAN          45
+#define LPTIM2         46
+#define LPTIM3         47
+#define LPTIM4         48
+#define LPTIM5         49
+#define SAI4           50
+#define SYSCFG         51
+#define VREF           52
+#define TMPSENS                53
+#define PMBCTRL                54
+#define HDP            55
+#define LTDC           56
+#define DSI            57
+#define IWDG2          58
+#define USBPHY         59
+#define STGENRO                60
+#define SPI6           61
+#define I2C4           62
+#define I2C6           63
+#define USART1         64
+#define RTCAPB         65
+#define TZC1           66
+#define TZPC           67
+#define IWDG1          68
+#define BSEC           69
+#define STGEN          70
+#define DMA1           71
+#define DMA2           72
+#define DMAMUX         73
+#define ADC12          74
+#define USBO           75
+#define SDMMC3         76
+#define DCMI           77
+#define CRYP2          78
+#define HASH2          79
+#define RNG2           80
+#define CRC2           81
+#define HSEM           82
+#define IPCC           83
+#define GPIOA          84
+#define GPIOB          85
+#define GPIOC          86
+#define GPIOD          87
+#define GPIOE          88
+#define GPIOF          89
+#define GPIOG          90
+#define GPIOH          91
+#define GPIOI          92
+#define GPIOJ          93
+#define GPIOK          94
+#define GPIOZ          95
+#define CRYP1          96
+#define HASH1          97
+#define RNG1           98
+#define BKPSRAM                99
+#define MDMA           100
+#define GPU            101
+#define ETHCK          102
+#define ETHTX          103
+#define ETHRX          104
+#define ETHMAC         105
+#define FMC            106
+#define QSPI           107
+#define SDMMC1         108
+#define SDMMC2         109
+#define CRC1           110
+#define USBH           111
+#define ETHSTP         112
+#define TZC2           113
+
+/* Kernel clocks */
+#define SDMMC1_K       118
+#define SDMMC2_K       119
+#define SDMMC3_K       120
+#define FMC_K          121
+#define QSPI_K         122
+#define ETHCK_K                123
+#define RNG1_K         124
+#define RNG2_K         125
+#define GPU_K          126
+#define USBPHY_K       127
+#define STGEN_K                128
+#define SPDIF_K                129
+#define SPI1_K         130
+#define SPI2_K         131
+#define SPI3_K         132
+#define SPI4_K         133
+#define SPI5_K         134
+#define SPI6_K         135
+#define CEC_K          136
+#define I2C1_K         137
+#define I2C2_K         138
+#define I2C3_K         139
+#define I2C4_K         140
+#define I2C5_K         141
+#define I2C6_K         142
+#define LPTIM1_K       143
+#define LPTIM2_K       144
+#define LPTIM3_K       145
+#define LPTIM4_K       146
+#define LPTIM5_K       147
+#define USART1_K       148
+#define USART2_K       149
+#define USART3_K       150
+#define UART4_K                151
+#define UART5_K                152
+#define USART6_K       153
+#define UART7_K                154
+#define UART8_K                155
+#define DFSDM_K                156
+#define FDCAN_K                157
+#define SAI1_K         158
+#define SAI2_K         159
+#define SAI3_K         160
+#define SAI4_K         161
+#define ADC12_K                162
+#define DSI_K          163
+#define DSI_PX         164
+#define ADFSDM_K       165
+#define USBO_K         166
+#define LTDC_PX                167
+#define DAC12_K                168
+#define ETHPTP_K       169
+
+/* PLL */
+#define PLL1           176
+#define PLL2           177
+#define PLL3           178
+#define PLL4           179
+
+/* ODF */
+#define PLL1_P         180
+#define PLL1_Q         181
+#define PLL1_R         182
+#define PLL2_P         183
+#define PLL2_Q         184
+#define PLL2_R         185
+#define PLL3_P         186
+#define PLL3_Q         187
+#define PLL3_R         188
+#define PLL4_P         189
+#define PLL4_Q         190
+#define PLL4_R         191
+
+/* AUX */
+#define RTC            192
+
+/* MCLK */
+#define CK_PER         193
+#define CK_MPU         194
+#define CK_AXI         195
+#define CK_MCU         196
+
+/* Time base */
+#define TIM2_K         197
+#define TIM3_K         198
+#define TIM4_K         199
+#define TIM5_K         200
+#define TIM6_K         201
+#define TIM7_K         202
+#define TIM12_K                203
+#define TIM13_K                204
+#define TIM14_K                205
+#define TIM1_K         206
+#define TIM8_K         207
+#define TIM15_K                208
+#define TIM16_K                209
+#define TIM17_K                210
+
+/* MCO clocks */
+#define CK_MCO1                211
+#define CK_MCO2                212
+
+/* TRACE & DEBUG clocks */
+#define CK_DBG         214
+#define CK_TRACE       215
+
+/* DDR */
+#define DDRC1          220
+#define DDRC1LP                221
+#define DDRC2          222
+#define DDRC2LP                223
+#define DDRPHYC                224
+#define DDRPHYCLP      225
+#define DDRCAPB                226
+#define DDRCAPBLP      227
+#define AXIDCG         228
+#define DDRPHYCAPB     229
+#define DDRPHYCAPBLP   230
+#define DDRPERFM       231
+
+#define STM32MP1_LAST_CLK 232
+
+#endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */
diff --git a/include/dt-bindings/clock/stm32mp1-clksrc.h b/include/dt-bindings/clock/stm32mp1-clksrc.h
new file mode 100644 (file)
index 0000000..818f4b7
--- /dev/null
@@ -0,0 +1,283 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_STM32MP1_CLKSRC_H_
+#define _DT_BINDINGS_CLOCK_STM32MP1_CLKSRC_H_
+
+/* PLL output is enable when x=1, with x=p,q or r */
+#define PQR(p, q, r)   (((p) & 1) | (((q) & 1) << 1) | (((r) & 1) << 2))
+
+/* st,clksrc: mandatory clock source */
+
+#define CLK_MPU_HSI            0x00000200
+#define CLK_MPU_HSE            0x00000201
+#define CLK_MPU_PLL1P          0x00000202
+#define CLK_MPU_PLL1P_DIV      0x00000203
+
+#define CLK_AXI_HSI            0x00000240
+#define CLK_AXI_HSE            0x00000241
+#define CLK_AXI_PLL2P          0x00000242
+
+#define CLK_MCU_HSI            0x00000480
+#define CLK_MCU_HSE            0x00000481
+#define CLK_MCU_CSI            0x00000482
+#define CLK_MCU_PLL3P          0x00000483
+
+#define CLK_PLL12_HSI          0x00000280
+#define CLK_PLL12_HSE          0x00000281
+
+#define CLK_PLL3_HSI           0x00008200
+#define CLK_PLL3_HSE           0x00008201
+#define CLK_PLL3_CSI           0x00008202
+
+#define CLK_PLL4_HSI           0x00008240
+#define CLK_PLL4_HSE           0x00008241
+#define CLK_PLL4_CSI           0x00008242
+#define CLK_PLL4_I2SCKIN       0x00008243
+
+#define CLK_RTC_DISABLED       0x00001400
+#define CLK_RTC_LSE            0x00001401
+#define CLK_RTC_LSI            0x00001402
+#define CLK_RTC_HSE            0x00001403
+
+#define CLK_MCO1_HSI           0x00008000
+#define CLK_MCO1_HSE           0x00008001
+#define CLK_MCO1_CSI           0x00008002
+#define CLK_MCO1_LSI           0x00008003
+#define CLK_MCO1_LSE           0x00008004
+#define CLK_MCO1_DISABLED      0x0000800F
+
+#define CLK_MCO2_MPU           0x00008040
+#define CLK_MCO2_AXI           0x00008041
+#define CLK_MCO2_MCU           0x00008042
+#define CLK_MCO2_PLL4P         0x00008043
+#define CLK_MCO2_HSE           0x00008044
+#define CLK_MCO2_HSI           0x00008045
+#define CLK_MCO2_DISABLED      0x0000804F
+
+/* st,pkcs: peripheral kernel clock source */
+
+#define CLK_I2C12_PCLK1                0x00008C00
+#define CLK_I2C12_PLL4R                0x00008C01
+#define CLK_I2C12_HSI          0x00008C02
+#define CLK_I2C12_CSI          0x00008C03
+#define CLK_I2C12_DISABLED     0x00008C07
+
+#define CLK_I2C35_PCLK1                0x00008C40
+#define CLK_I2C35_PLL4R                0x00008C41
+#define CLK_I2C35_HSI          0x00008C42
+#define CLK_I2C35_CSI          0x00008C43
+#define CLK_I2C35_DISABLED     0x00008C47
+
+#define CLK_I2C46_PCLK5                0x00000C00
+#define CLK_I2C46_PLL3Q                0x00000C01
+#define CLK_I2C46_HSI          0x00000C02
+#define CLK_I2C46_CSI          0x00000C03
+#define CLK_I2C46_DISABLED     0x00000C07
+
+#define CLK_SAI1_PLL4Q         0x00008C80
+#define CLK_SAI1_PLL3Q         0x00008C81
+#define CLK_SAI1_I2SCKIN       0x00008C82
+#define CLK_SAI1_CKPER         0x00008C83
+#define CLK_SAI1_PLL3R         0x00008C84
+#define CLK_SAI1_DISABLED      0x00008C87
+
+#define CLK_SAI2_PLL4Q         0x00008CC0
+#define CLK_SAI2_PLL3Q         0x00008CC1
+#define CLK_SAI2_I2SCKIN       0x00008CC2
+#define CLK_SAI2_CKPER         0x00008CC3
+#define CLK_SAI2_SPDIF         0x00008CC4
+#define CLK_SAI2_PLL3R         0x00008CC5
+#define CLK_SAI2_DISABLED      0x00008CC7
+
+#define CLK_SAI3_PLL4Q         0x00008D00
+#define CLK_SAI3_PLL3Q         0x00008D01
+#define CLK_SAI3_I2SCKIN       0x00008D02
+#define CLK_SAI3_CKPER         0x00008D03
+#define CLK_SAI3_PLL3R         0x00008D04
+#define CLK_SAI3_DISABLED      0x00008D07
+
+#define CLK_SAI4_PLL4Q         0x00008D40
+#define CLK_SAI4_PLL3Q         0x00008D41
+#define CLK_SAI4_I2SCKIN       0x00008D42
+#define CLK_SAI4_CKPER         0x00008D43
+#define CLK_SAI4_PLL3R         0x00008D44
+#define CLK_SAI4_DISABLED      0x00008D47
+
+#define CLK_SPI2S1_PLL4P       0x00008D80
+#define CLK_SPI2S1_PLL3Q       0x00008D81
+#define CLK_SPI2S1_I2SCKIN     0x00008D82
+#define CLK_SPI2S1_CKPER       0x00008D83
+#define CLK_SPI2S1_PLL3R       0x00008D84
+#define CLK_SPI2S1_DISABLED    0x00008D87
+
+#define CLK_SPI2S23_PLL4P      0x00008DC0
+#define CLK_SPI2S23_PLL3Q      0x00008DC1
+#define CLK_SPI2S23_I2SCKIN    0x00008DC2
+#define CLK_SPI2S23_CKPER      0x00008DC3
+#define CLK_SPI2S23_PLL3R      0x00008DC4
+#define CLK_SPI2S23_DISABLED   0x00008DC7
+
+#define CLK_SPI45_PCLK2                0x00008E00
+#define CLK_SPI45_PLL4Q                0x00008E01
+#define CLK_SPI45_HSI          0x00008E02
+#define CLK_SPI45_CSI          0x00008E03
+#define CLK_SPI45_HSE          0x00008E04
+#define CLK_SPI45_DISABLED     0x00008E07
+
+#define CLK_SPI6_PCLK5         0x00000C40
+#define CLK_SPI6_PLL4Q         0x00000C41
+#define CLK_SPI6_HSI           0x00000C42
+#define CLK_SPI6_CSI           0x00000C43
+#define CLK_SPI6_HSE           0x00000C44
+#define CLK_SPI6_PLL3Q         0x00000C45
+#define CLK_SPI6_DISABLED      0x00000C47
+
+#define CLK_UART6_PCLK2                0x00008E40
+#define CLK_UART6_PLL4Q                0x00008E41
+#define CLK_UART6_HSI          0x00008E42
+#define CLK_UART6_CSI          0x00008E43
+#define CLK_UART6_HSE          0x00008E44
+#define CLK_UART6_DISABLED     0x00008E47
+
+#define CLK_UART24_PCLK1       0x00008E80
+#define CLK_UART24_PLL4Q       0x00008E81
+#define CLK_UART24_HSI         0x00008E82
+#define CLK_UART24_CSI         0x00008E83
+#define CLK_UART24_HSE         0x00008E84
+#define CLK_UART24_DISABLED    0x00008E87
+
+#define CLK_UART35_PCLK1       0x00008EC0
+#define CLK_UART35_PLL4Q       0x00008EC1
+#define CLK_UART35_HSI         0x00008EC2
+#define CLK_UART35_CSI         0x00008EC3
+#define CLK_UART35_HSE         0x00008EC4
+#define CLK_UART35_DISABLED    0x00008EC7
+
+#define CLK_UART78_PCLK1       0x00008F00
+#define CLK_UART78_PLL4Q       0x00008F01
+#define CLK_UART78_HSI         0x00008F02
+#define CLK_UART78_CSI         0x00008F03
+#define CLK_UART78_HSE         0x00008F04
+#define CLK_UART78_DISABLED    0x00008F07
+
+#define CLK_UART1_PCLK5                0x00000C80
+#define CLK_UART1_PLL3Q                0x00000C81
+#define CLK_UART1_HSI          0x00000C82
+#define CLK_UART1_CSI          0x00000C83
+#define CLK_UART1_PLL4Q                0x00000C84
+#define CLK_UART1_HSE          0x00000C85
+#define CLK_UART1_DISABLED     0x00000C87
+
+#define CLK_SDMMC12_HCLK6      0x00008F40
+#define CLK_SDMMC12_PLL3R      0x00008F41
+#define CLK_SDMMC12_PLL4P      0x00008F42
+#define CLK_SDMMC12_HSI                0x00008F43
+#define CLK_SDMMC12_DISABLED   0x00008F47
+
+#define CLK_SDMMC3_HCLK2       0x00008F80
+#define CLK_SDMMC3_PLL3R       0x00008F81
+#define CLK_SDMMC3_PLL4P       0x00008F82
+#define CLK_SDMMC3_HSI         0x00008F83
+#define CLK_SDMMC3_DISABLED    0x00008F87
+
+#define CLK_ETH_PLL4P          0x00008FC0
+#define CLK_ETH_PLL3Q          0x00008FC1
+#define CLK_ETH_DISABLED       0x00008FC3
+
+#define CLK_QSPI_ACLK          0x00009000
+#define CLK_QSPI_PLL3R         0x00009001
+#define CLK_QSPI_PLL4P         0x00009002
+#define CLK_QSPI_CKPER         0x00009003
+
+#define CLK_FMC_ACLK           0x00009040
+#define CLK_FMC_PLL3R          0x00009041
+#define CLK_FMC_PLL4P          0x00009042
+#define CLK_FMC_CKPER          0x00009043
+
+#define CLK_FDCAN_HSE          0x000090C0
+#define CLK_FDCAN_PLL3Q                0x000090C1
+#define CLK_FDCAN_PLL4Q                0x000090C2
+#define CLK_FDCAN_PLL4R                0x000090C3
+
+#define CLK_SPDIF_PLL4P                0x00009140
+#define CLK_SPDIF_PLL3Q                0x00009141
+#define CLK_SPDIF_HSI          0x00009142
+#define CLK_SPDIF_DISABLED     0x00009143
+
+#define CLK_CEC_LSE            0x00009180
+#define CLK_CEC_LSI            0x00009181
+#define CLK_CEC_CSI_DIV122     0x00009182
+#define CLK_CEC_DISABLED       0x00009183
+
+#define CLK_USBPHY_HSE         0x000091C0
+#define CLK_USBPHY_PLL4R       0x000091C1
+#define CLK_USBPHY_HSE_DIV2    0x000091C2
+#define CLK_USBPHY_DISABLED    0x000091C3
+
+#define CLK_USBO_PLL4R         0x800091C0
+#define CLK_USBO_USBPHY                0x800091C1
+
+#define CLK_RNG1_CSI           0x00000CC0
+#define CLK_RNG1_PLL4R         0x00000CC1
+#define CLK_RNG1_LSE           0x00000CC2
+#define CLK_RNG1_LSI           0x00000CC3
+
+#define CLK_RNG2_CSI           0x00009200
+#define CLK_RNG2_PLL4R         0x00009201
+#define CLK_RNG2_LSE           0x00009202
+#define CLK_RNG2_LSI           0x00009203
+
+#define CLK_CKPER_HSI          0x00000D00
+#define CLK_CKPER_CSI          0x00000D01
+#define CLK_CKPER_HSE          0x00000D02
+#define CLK_CKPER_DISABLED     0x00000D03
+
+#define CLK_STGEN_HSI          0x00000D40
+#define CLK_STGEN_HSE          0x00000D41
+#define CLK_STGEN_DISABLED     0x00000D43
+
+#define CLK_DSI_DSIPLL         0x00009240
+#define CLK_DSI_PLL4P          0x00009241
+
+#define CLK_ADC_PLL4R          0x00009280
+#define CLK_ADC_CKPER          0x00009281
+#define CLK_ADC_PLL3Q          0x00009282
+#define CLK_ADC_DISABLED       0x00009283
+
+#define CLK_LPTIM45_PCLK3      0x000092C0
+#define CLK_LPTIM45_PLL4P      0x000092C1
+#define CLK_LPTIM45_PLL3Q      0x000092C2
+#define CLK_LPTIM45_LSE                0x000092C3
+#define CLK_LPTIM45_LSI                0x000092C4
+#define CLK_LPTIM45_CKPER      0x000092C5
+#define CLK_LPTIM45_DISABLED   0x000092C7
+
+#define CLK_LPTIM23_PCLK3      0x00009300
+#define CLK_LPTIM23_PLL4Q      0x00009301
+#define CLK_LPTIM23_CKPER      0x00009302
+#define CLK_LPTIM23_LSE                0x00009303
+#define CLK_LPTIM23_LSI                0x00009304
+#define CLK_LPTIM23_DISABLED   0x00009307
+
+#define CLK_LPTIM1_PCLK1       0x00009340
+#define CLK_LPTIM1_PLL4P       0x00009341
+#define CLK_LPTIM1_PLL3Q       0x00009342
+#define CLK_LPTIM1_LSE         0x00009343
+#define CLK_LPTIM1_LSI         0x00009344
+#define CLK_LPTIM1_CKPER       0x00009345
+#define CLK_LPTIM1_DISABLED    0x00009347
+
+/* define for st,pll /csg */
+#define SSCG_MODE_CENTER_SPREAD        0
+#define SSCG_MODE_DOWN_SPREAD  1
+
+/* define for st,drive */
+#define LSEDRV_LOWEST          0
+#define LSEDRV_MEDIUM_LOW      1
+#define LSEDRV_MEDIUM_HIGH     2
+#define LSEDRV_HIGHEST         3
+
+#endif
index d3862029ff3aae33a03c2c92defc41530f19ca09..6128c5e97fa846ddf1d812e75f07e2ce471763e3 100644 (file)
@@ -16,6 +16,8 @@
 #include <mmio.h>
 #include <platform.h>
 #include <platform_def.h>
+#include <stm32mp1_clk.h>
+#include <stm32mp1_dt.h>
 #include <stm32mp1_private.h>
 #include <stm32mp1_pwr.h>
 #include <stm32mp1_rcc.h>
@@ -76,5 +78,17 @@ void bl2_el3_plat_arch_setup(void)
 
        generic_delay_timer_init();
 
+       if (dt_open_and_check() < 0) {
+               panic();
+       }
+
+       if (stm32mp1_clk_probe() < 0) {
+               panic();
+       }
+
+       if (stm32mp1_clk_init() < 0) {
+               panic();
+       }
+
        stm32mp1_io_setup();
 }
diff --git a/plat/st/stm32mp1/include/stm32mp1_dt.h b/plat/st/stm32mp1/include/stm32mp1_dt.h
new file mode 100644 (file)
index 0000000..da203a7
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __STM32MP1_DT_H__
+#define __STM32MP1_DT_H__
+
+#include <stdbool.h>
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+int dt_open_and_check(void);
+int fdt_get_address(void **fdt_addr);
+bool fdt_check_node(int node);
+bool fdt_check_status(int node);
+bool fdt_check_secure_status(int node);
+uint32_t fdt_read_uint32_default(int node, const char *prop_name,
+                                uint32_t dflt_value);
+int fdt_read_uint32_array(int node, const char *prop_name,
+                         uint32_t *array, uint32_t count);
+
+#endif /* __STM32MP1_DT_H__ */
index ff390d5c3924e10ea73041d38d91ca47a49dbf00..e26504f7a49bab8a42fe5d27f93f46e3f8d03263 100644 (file)
@@ -39,6 +39,10 @@ PLAT_BL_COMMON_SOURCES       +=      lib/cpus/aarch32/cortex_a7.S
 PLAT_BL_COMMON_SOURCES +=      ${LIBFDT_SRCS}                                          \
                                drivers/delay_timer/delay_timer.c                       \
                                drivers/delay_timer/generic_delay_timer.c               \
+                               drivers/st/clk/stm32mp1_clk.c                           \
+                               drivers/st/clk/stm32mp1_clkfunc.c                       \
+                               drivers/st/reset/stm32mp1_reset.c                       \
+                               plat/st/stm32mp1/stm32mp1_dt.c                          \
                                plat/st/stm32mp1/stm32mp1_helper.S
 
 BL2_SOURCES            +=      drivers/io/io_dummy.c                                   \
diff --git a/plat/st/stm32mp1/stm32mp1_dt.c b/plat/st/stm32mp1/stm32mp1_dt.c
new file mode 100644 (file)
index 0000000..6098759
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <libfdt.h>
+#include <platform_def.h>
+#include <stm32mp1_clk.h>
+#include <stm32mp1_clkfunc.h>
+#include <stm32mp1_dt.h>
+
+#define DT_GPIO_BANK_SHIFT     12
+#define DT_GPIO_BANK_MASK      0x1F000U
+#define DT_GPIO_PIN_SHIFT      8
+#define DT_GPIO_PIN_MASK       0xF00U
+#define DT_GPIO_MODE_MASK      0xFFU
+
+static int fdt_checked;
+
+static void *fdt = (void *)(uintptr_t)STM32MP1_DTB_BASE;
+
+/*******************************************************************************
+ * This function checks device tree file with its header.
+ * Returns 0 if success, and a negative value else.
+ ******************************************************************************/
+int dt_open_and_check(void)
+{
+       int ret = fdt_check_header(fdt);
+
+       if (ret == 0) {
+               fdt_checked = 1;
+       }
+
+       return ret;
+}
+
+/*******************************************************************************
+ * This function gets the address of the DT.
+ * If DT is OK, fdt_addr is filled with DT address.
+ * Returns 1 if success, 0 otherwise.
+ ******************************************************************************/
+int fdt_get_address(void **fdt_addr)
+{
+       if (fdt_checked == 1) {
+               *fdt_addr = fdt;
+       }
+
+       return fdt_checked;
+}
+
+/*******************************************************************************
+ * This function check the presence of a node (generic use of fdt library).
+ * Returns true if present, false else.
+ ******************************************************************************/
+bool fdt_check_node(int node)
+{
+       int len;
+       const char *cchar;
+
+       cchar = fdt_get_name(fdt, node, &len);
+
+       return (cchar != NULL) && (len >= 0);
+}
+
+/*******************************************************************************
+ * This function check the status of a node (generic use of fdt library).
+ * Returns true if "okay" or missing, false else.
+ ******************************************************************************/
+bool fdt_check_status(int node)
+{
+       int len;
+       const char *cchar;
+
+       cchar = fdt_getprop(fdt, node, "status", &len);
+       if (cchar == NULL) {
+               return true;
+       }
+
+       return strncmp(cchar, "okay", (size_t)len) == 0;
+}
+
+/*******************************************************************************
+ * This function check the secure-status of a node (generic use of fdt library).
+ * Returns true if "okay" or missing, false else.
+ ******************************************************************************/
+bool fdt_check_secure_status(int node)
+{
+       int len;
+       const char *cchar;
+
+       cchar = fdt_getprop(fdt, node, "secure-status", &len);
+       if (cchar == NULL) {
+               return true;
+       }
+
+       return strncmp(cchar, "okay", (size_t)len) == 0;
+}
+
+/*******************************************************************************
+ * This function reads a value of a node property (generic use of fdt
+ * library).
+ * Returns value if success, and a default value if property not found.
+ * Default value is passed as parameter.
+ ******************************************************************************/
+uint32_t fdt_read_uint32_default(int node, const char *prop_name,
+                                uint32_t dflt_value)
+{
+       const fdt32_t *cuint;
+       int lenp;
+
+       cuint = fdt_getprop(fdt, node, prop_name, &lenp);
+       if (cuint == NULL) {
+               return dflt_value;
+       }
+
+       return fdt32_to_cpu(*cuint);
+}
+
+/*******************************************************************************
+ * This function reads a series of parameters in a node property
+ * (generic use of fdt library).
+ * It reads the values inside the device tree, from property name and node.
+ * The number of parameters is also indicated as entry parameter.
+ * Returns 0 if success, and a negative value else.
+ * If success, values are stored at the third parameter address.
+ ******************************************************************************/
+int fdt_read_uint32_array(int node, const char *prop_name, uint32_t *array,
+                         uint32_t count)
+{
+       const fdt32_t *cuint;
+       int len;
+       uint32_t i;
+
+       cuint = fdt_getprop(fdt, node, prop_name, &len);
+       if (cuint == NULL) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       if ((uint32_t)len != (count * sizeof(uint32_t))) {
+               return -FDT_ERR_BADLAYOUT;
+       }
+
+       for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
+               *array = fdt32_to_cpu(*cuint);
+               array++;
+               cuint++;
+       }
+
+       return 0;
+}