xref: /rk3399_ARM-atf/drivers/st/clk/stm32mp1_clk.c (revision f65592278869951330325085cf373c3306ccab57)
17839a050SYann Gautier /*
277b4ca0bSLionel Debieve  * Copyright (C) 2018-2024, STMicroelectronics - All Rights Reserved
37839a050SYann Gautier  *
47839a050SYann Gautier  * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
57839a050SYann Gautier  */
67839a050SYann Gautier 
77839a050SYann Gautier #include <assert.h>
87839a050SYann Gautier #include <errno.h>
97839a050SYann Gautier #include <stdint.h>
1039b6cc66SAntonio Nino Diaz #include <stdio.h>
1109d40e0eSAntonio Nino Diaz 
1209d40e0eSAntonio Nino Diaz #include <arch.h>
1309d40e0eSAntonio Nino Diaz #include <arch_helpers.h>
1409d40e0eSAntonio Nino Diaz #include <common/debug.h>
1552a616b4SAndre Przywara #include <common/fdt_wrappers.h>
1633667d29SYann Gautier #include <drivers/clk.h>
1709d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h>
18447b2b13SYann Gautier #include <drivers/st/stm32mp_clkfunc.h>
1909d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_clk.h>
2009d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_rcc.h>
2109d40e0eSAntonio Nino Diaz #include <dt-bindings/clock/stm32mp1-clksrc.h>
2209d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
230d21680cSYann Gautier #include <lib/spinlock.h>
2409d40e0eSAntonio Nino Diaz #include <lib/utils_def.h>
25964e5ff1SNicolas Le Bayon #include <libfdt.h>
2609d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
2709d40e0eSAntonio Nino Diaz 
28964e5ff1SNicolas Le Bayon #include <platform_def.h>
29964e5ff1SNicolas Le Bayon 
307839a050SYann Gautier #define MAX_HSI_HZ		64000000
310d21680cSYann Gautier #define USB_PHY_48_MHZ		48000000
327839a050SYann Gautier 
33dfdb057aSYann Gautier #define TIMEOUT_US_200MS	U(200000)
34dfdb057aSYann Gautier #define TIMEOUT_US_1S		U(1000000)
357839a050SYann Gautier 
36dfdb057aSYann Gautier #define PLLRDY_TIMEOUT		TIMEOUT_US_200MS
37dfdb057aSYann Gautier #define CLKSRC_TIMEOUT		TIMEOUT_US_200MS
38dfdb057aSYann Gautier #define CLKDIV_TIMEOUT		TIMEOUT_US_200MS
39dfdb057aSYann Gautier #define HSIDIV_TIMEOUT		TIMEOUT_US_200MS
40dfdb057aSYann Gautier #define OSCRDY_TIMEOUT		TIMEOUT_US_1S
417839a050SYann Gautier 
42f66358afSYann Gautier const char *stm32mp_osc_node_label[NB_OSC] = {
43f66358afSYann Gautier 	[_LSI] = "clk-lsi",
44f66358afSYann Gautier 	[_LSE] = "clk-lse",
45f66358afSYann Gautier 	[_HSI] = "clk-hsi",
46f66358afSYann Gautier 	[_HSE] = "clk-hse",
47f66358afSYann Gautier 	[_CSI] = "clk-csi",
48f66358afSYann Gautier 	[_I2S_CKIN] = "i2s_ckin",
49f66358afSYann Gautier };
50f66358afSYann Gautier 
517839a050SYann Gautier enum stm32mp1_parent_id {
527839a050SYann Gautier /* Oscillators are defined in enum stm32mp_osc_id */
537839a050SYann Gautier 
547839a050SYann Gautier /* Other parent source */
557839a050SYann Gautier 	_HSI_KER = NB_OSC,
567839a050SYann Gautier 	_HSE_KER,
577839a050SYann Gautier 	_HSE_KER_DIV2,
58cbd2e8a6SGabriel Fernandez 	_HSE_RTC,
597839a050SYann Gautier 	_CSI_KER,
607839a050SYann Gautier 	_PLL1_P,
617839a050SYann Gautier 	_PLL1_Q,
627839a050SYann Gautier 	_PLL1_R,
637839a050SYann Gautier 	_PLL2_P,
647839a050SYann Gautier 	_PLL2_Q,
657839a050SYann Gautier 	_PLL2_R,
667839a050SYann Gautier 	_PLL3_P,
677839a050SYann Gautier 	_PLL3_Q,
687839a050SYann Gautier 	_PLL3_R,
697839a050SYann Gautier 	_PLL4_P,
707839a050SYann Gautier 	_PLL4_Q,
717839a050SYann Gautier 	_PLL4_R,
727839a050SYann Gautier 	_ACLK,
737839a050SYann Gautier 	_PCLK1,
747839a050SYann Gautier 	_PCLK2,
757839a050SYann Gautier 	_PCLK3,
767839a050SYann Gautier 	_PCLK4,
777839a050SYann Gautier 	_PCLK5,
787839a050SYann Gautier 	_HCLK6,
797839a050SYann Gautier 	_HCLK2,
807839a050SYann Gautier 	_CK_PER,
817839a050SYann Gautier 	_CK_MPU,
82b053a22eSYann Gautier 	_CK_MCU,
830d21680cSYann Gautier 	_USB_PHY_48,
847839a050SYann Gautier 	_PARENT_NB,
857839a050SYann Gautier 	_UNKNOWN_ID = 0xff,
867839a050SYann Gautier };
877839a050SYann Gautier 
880d21680cSYann Gautier /* Lists only the parent clock we are interested in */
897839a050SYann Gautier enum stm32mp1_parent_sel {
900d21680cSYann Gautier 	_I2C12_SEL,
910d21680cSYann Gautier 	_I2C35_SEL,
920d21680cSYann Gautier 	_STGEN_SEL,
937839a050SYann Gautier 	_I2C46_SEL,
940d21680cSYann Gautier 	_SPI6_SEL,
95d4151d2fSYann Gautier 	_UART1_SEL,
960d21680cSYann Gautier 	_RNG1_SEL,
977839a050SYann Gautier 	_UART6_SEL,
987839a050SYann Gautier 	_UART24_SEL,
997839a050SYann Gautier 	_UART35_SEL,
1007839a050SYann Gautier 	_UART78_SEL,
1017839a050SYann Gautier 	_SDMMC12_SEL,
1027839a050SYann Gautier 	_SDMMC3_SEL,
1037839a050SYann Gautier 	_QSPI_SEL,
1047839a050SYann Gautier 	_FMC_SEL,
105d4151d2fSYann Gautier 	_AXIS_SEL,
106d4151d2fSYann Gautier 	_MCUS_SEL,
1077839a050SYann Gautier 	_USBPHY_SEL,
1087839a050SYann Gautier 	_USBO_SEL,
1098fbcd9e4SEtienne Carriere 	_MPU_SEL,
110288f5cf2SYann Gautier 	_CKPER_SEL,
111016af006SEtienne Carriere 	_RTC_SEL,
1127839a050SYann Gautier 	_PARENT_SEL_NB,
1137839a050SYann Gautier 	_UNKNOWN_SEL = 0xff,
1147839a050SYann Gautier };
1157839a050SYann Gautier 
1168fbcd9e4SEtienne Carriere /* State the parent clock ID straight related to a clock */
1178fbcd9e4SEtienne Carriere static const uint8_t parent_id_clock_id[_PARENT_NB] = {
1188fbcd9e4SEtienne Carriere 	[_HSE] = CK_HSE,
1198fbcd9e4SEtienne Carriere 	[_HSI] = CK_HSI,
1208fbcd9e4SEtienne Carriere 	[_CSI] = CK_CSI,
1218fbcd9e4SEtienne Carriere 	[_LSE] = CK_LSE,
1228fbcd9e4SEtienne Carriere 	[_LSI] = CK_LSI,
1238fbcd9e4SEtienne Carriere 	[_I2S_CKIN] = _UNKNOWN_ID,
1248fbcd9e4SEtienne Carriere 	[_USB_PHY_48] = _UNKNOWN_ID,
1258fbcd9e4SEtienne Carriere 	[_HSI_KER] = CK_HSI,
1268fbcd9e4SEtienne Carriere 	[_HSE_KER] = CK_HSE,
1278fbcd9e4SEtienne Carriere 	[_HSE_KER_DIV2] = CK_HSE_DIV2,
128cbd2e8a6SGabriel Fernandez 	[_HSE_RTC] = _UNKNOWN_ID,
1298fbcd9e4SEtienne Carriere 	[_CSI_KER] = CK_CSI,
1308fbcd9e4SEtienne Carriere 	[_PLL1_P] = PLL1_P,
1318fbcd9e4SEtienne Carriere 	[_PLL1_Q] = PLL1_Q,
1328fbcd9e4SEtienne Carriere 	[_PLL1_R] = PLL1_R,
1338fbcd9e4SEtienne Carriere 	[_PLL2_P] = PLL2_P,
1348fbcd9e4SEtienne Carriere 	[_PLL2_Q] = PLL2_Q,
1358fbcd9e4SEtienne Carriere 	[_PLL2_R] = PLL2_R,
1368fbcd9e4SEtienne Carriere 	[_PLL3_P] = PLL3_P,
1378fbcd9e4SEtienne Carriere 	[_PLL3_Q] = PLL3_Q,
1388fbcd9e4SEtienne Carriere 	[_PLL3_R] = PLL3_R,
1398fbcd9e4SEtienne Carriere 	[_PLL4_P] = PLL4_P,
1408fbcd9e4SEtienne Carriere 	[_PLL4_Q] = PLL4_Q,
1418fbcd9e4SEtienne Carriere 	[_PLL4_R] = PLL4_R,
1428fbcd9e4SEtienne Carriere 	[_ACLK] = CK_AXI,
1438fbcd9e4SEtienne Carriere 	[_PCLK1] = CK_AXI,
1448fbcd9e4SEtienne Carriere 	[_PCLK2] = CK_AXI,
1458fbcd9e4SEtienne Carriere 	[_PCLK3] = CK_AXI,
1468fbcd9e4SEtienne Carriere 	[_PCLK4] = CK_AXI,
1478fbcd9e4SEtienne Carriere 	[_PCLK5] = CK_AXI,
1488fbcd9e4SEtienne Carriere 	[_CK_PER] = CK_PER,
1498fbcd9e4SEtienne Carriere 	[_CK_MPU] = CK_MPU,
1508fbcd9e4SEtienne Carriere 	[_CK_MCU] = CK_MCU,
1518fbcd9e4SEtienne Carriere };
1528fbcd9e4SEtienne Carriere 
1538fbcd9e4SEtienne Carriere static unsigned int clock_id2parent_id(unsigned long id)
1548fbcd9e4SEtienne Carriere {
1558fbcd9e4SEtienne Carriere 	unsigned int n;
1568fbcd9e4SEtienne Carriere 
1578fbcd9e4SEtienne Carriere 	for (n = 0U; n < ARRAY_SIZE(parent_id_clock_id); n++) {
1588fbcd9e4SEtienne Carriere 		if (parent_id_clock_id[n] == id) {
1598fbcd9e4SEtienne Carriere 			return n;
1608fbcd9e4SEtienne Carriere 		}
1618fbcd9e4SEtienne Carriere 	}
1628fbcd9e4SEtienne Carriere 
1638fbcd9e4SEtienne Carriere 	return _UNKNOWN_ID;
1648fbcd9e4SEtienne Carriere }
1658fbcd9e4SEtienne Carriere 
1667839a050SYann Gautier enum stm32mp1_pll_id {
1677839a050SYann Gautier 	_PLL1,
1687839a050SYann Gautier 	_PLL2,
1697839a050SYann Gautier 	_PLL3,
1707839a050SYann Gautier 	_PLL4,
1717839a050SYann Gautier 	_PLL_NB
1727839a050SYann Gautier };
1737839a050SYann Gautier 
1747839a050SYann Gautier enum stm32mp1_div_id {
1757839a050SYann Gautier 	_DIV_P,
1767839a050SYann Gautier 	_DIV_Q,
1777839a050SYann Gautier 	_DIV_R,
1787839a050SYann Gautier 	_DIV_NB,
1797839a050SYann Gautier };
1807839a050SYann Gautier 
1817839a050SYann Gautier enum stm32mp1_clksrc_id {
1827839a050SYann Gautier 	CLKSRC_MPU,
1837839a050SYann Gautier 	CLKSRC_AXI,
184b053a22eSYann Gautier 	CLKSRC_MCU,
1857839a050SYann Gautier 	CLKSRC_PLL12,
1867839a050SYann Gautier 	CLKSRC_PLL3,
1877839a050SYann Gautier 	CLKSRC_PLL4,
1887839a050SYann Gautier 	CLKSRC_RTC,
1897839a050SYann Gautier 	CLKSRC_MCO1,
1907839a050SYann Gautier 	CLKSRC_MCO2,
1917839a050SYann Gautier 	CLKSRC_NB
1927839a050SYann Gautier };
1937839a050SYann Gautier 
1947839a050SYann Gautier enum stm32mp1_clkdiv_id {
1957839a050SYann Gautier 	CLKDIV_MPU,
1967839a050SYann Gautier 	CLKDIV_AXI,
197b053a22eSYann Gautier 	CLKDIV_MCU,
1987839a050SYann Gautier 	CLKDIV_APB1,
1997839a050SYann Gautier 	CLKDIV_APB2,
2007839a050SYann Gautier 	CLKDIV_APB3,
2017839a050SYann Gautier 	CLKDIV_APB4,
2027839a050SYann Gautier 	CLKDIV_APB5,
2037839a050SYann Gautier 	CLKDIV_RTC,
2047839a050SYann Gautier 	CLKDIV_MCO1,
2057839a050SYann Gautier 	CLKDIV_MCO2,
2067839a050SYann Gautier 	CLKDIV_NB
2077839a050SYann Gautier };
2087839a050SYann Gautier 
2097839a050SYann Gautier enum stm32mp1_pllcfg {
2107839a050SYann Gautier 	PLLCFG_M,
2117839a050SYann Gautier 	PLLCFG_N,
2127839a050SYann Gautier 	PLLCFG_P,
2137839a050SYann Gautier 	PLLCFG_Q,
2147839a050SYann Gautier 	PLLCFG_R,
2157839a050SYann Gautier 	PLLCFG_O,
2167839a050SYann Gautier 	PLLCFG_NB
2177839a050SYann Gautier };
2187839a050SYann Gautier 
2197839a050SYann Gautier enum stm32mp1_pllcsg {
2207839a050SYann Gautier 	PLLCSG_MOD_PER,
2217839a050SYann Gautier 	PLLCSG_INC_STEP,
2227839a050SYann Gautier 	PLLCSG_SSCG_MODE,
2237839a050SYann Gautier 	PLLCSG_NB
2247839a050SYann Gautier };
2257839a050SYann Gautier 
2267839a050SYann Gautier enum stm32mp1_plltype {
2277839a050SYann Gautier 	PLL_800,
2287839a050SYann Gautier 	PLL_1600,
2297839a050SYann Gautier 	PLL_TYPE_NB
2307839a050SYann Gautier };
2317839a050SYann Gautier 
2327839a050SYann Gautier struct stm32mp1_pll {
2337839a050SYann Gautier 	uint8_t refclk_min;
2347839a050SYann Gautier 	uint8_t refclk_max;
2357839a050SYann Gautier };
2367839a050SYann Gautier 
2377839a050SYann Gautier struct stm32mp1_clk_gate {
2387839a050SYann Gautier 	uint16_t offset;
2397839a050SYann Gautier 	uint8_t bit;
2407839a050SYann Gautier 	uint8_t index;
2417839a050SYann Gautier 	uint8_t set_clr;
242aaa09b71SYann Gautier 	uint8_t secure;
2430d21680cSYann Gautier 	uint8_t sel; /* Relates to enum stm32mp1_parent_sel */
2440d21680cSYann Gautier 	uint8_t fixed; /* Relates to enum stm32mp1_parent_id */
2457839a050SYann Gautier };
2467839a050SYann Gautier 
2477839a050SYann Gautier struct stm32mp1_clk_sel {
2487839a050SYann Gautier 	uint16_t offset;
2497839a050SYann Gautier 	uint8_t src;
2507839a050SYann Gautier 	uint8_t msk;
2517839a050SYann Gautier 	uint8_t nb_parent;
2527839a050SYann Gautier 	const uint8_t *parent;
2537839a050SYann Gautier };
2547839a050SYann Gautier 
2557839a050SYann Gautier #define REFCLK_SIZE 4
2567839a050SYann Gautier struct stm32mp1_clk_pll {
2577839a050SYann Gautier 	enum stm32mp1_plltype plltype;
2587839a050SYann Gautier 	uint16_t rckxselr;
2597839a050SYann Gautier 	uint16_t pllxcfgr1;
2607839a050SYann Gautier 	uint16_t pllxcfgr2;
2617839a050SYann Gautier 	uint16_t pllxfracr;
2627839a050SYann Gautier 	uint16_t pllxcr;
2637839a050SYann Gautier 	uint16_t pllxcsgr;
2647839a050SYann Gautier 	enum stm32mp_osc_id refclk[REFCLK_SIZE];
2657839a050SYann Gautier };
2667839a050SYann Gautier 
2670d21680cSYann Gautier /* Clocks with selectable source and non set/clr register access */
268aaa09b71SYann Gautier #define _CLK_SELEC(sec, off, b, idx, s)			\
2697839a050SYann Gautier 	{						\
2707839a050SYann Gautier 		.offset = (off),			\
2717839a050SYann Gautier 		.bit = (b),				\
2727839a050SYann Gautier 		.index = (idx),				\
2737839a050SYann Gautier 		.set_clr = 0,				\
274aaa09b71SYann Gautier 		.secure = (sec),			\
2757839a050SYann Gautier 		.sel = (s),				\
2767839a050SYann Gautier 		.fixed = _UNKNOWN_ID,			\
2777839a050SYann Gautier 	}
2787839a050SYann Gautier 
2790d21680cSYann Gautier /* Clocks with fixed source and non set/clr register access */
280aaa09b71SYann Gautier #define _CLK_FIXED(sec, off, b, idx, f)			\
2817839a050SYann Gautier 	{						\
2827839a050SYann Gautier 		.offset = (off),			\
2837839a050SYann Gautier 		.bit = (b),				\
2847839a050SYann Gautier 		.index = (idx),				\
2857839a050SYann Gautier 		.set_clr = 0,				\
286aaa09b71SYann Gautier 		.secure = (sec),			\
2877839a050SYann Gautier 		.sel = _UNKNOWN_SEL,			\
2887839a050SYann Gautier 		.fixed = (f),				\
2897839a050SYann Gautier 	}
2907839a050SYann Gautier 
2910d21680cSYann Gautier /* Clocks with selectable source and set/clr register access */
292aaa09b71SYann Gautier #define _CLK_SC_SELEC(sec, off, b, idx, s)			\
2937839a050SYann Gautier 	{						\
2947839a050SYann Gautier 		.offset = (off),			\
2957839a050SYann Gautier 		.bit = (b),				\
2967839a050SYann Gautier 		.index = (idx),				\
2977839a050SYann Gautier 		.set_clr = 1,				\
298aaa09b71SYann Gautier 		.secure = (sec),			\
2997839a050SYann Gautier 		.sel = (s),				\
3007839a050SYann Gautier 		.fixed = _UNKNOWN_ID,			\
3017839a050SYann Gautier 	}
3027839a050SYann Gautier 
3030d21680cSYann Gautier /* Clocks with fixed source and set/clr register access */
304aaa09b71SYann Gautier #define _CLK_SC_FIXED(sec, off, b, idx, f)			\
3057839a050SYann Gautier 	{						\
3067839a050SYann Gautier 		.offset = (off),			\
3077839a050SYann Gautier 		.bit = (b),				\
3087839a050SYann Gautier 		.index = (idx),				\
3097839a050SYann Gautier 		.set_clr = 1,				\
310aaa09b71SYann Gautier 		.secure = (sec),			\
3117839a050SYann Gautier 		.sel = _UNKNOWN_SEL,			\
3127839a050SYann Gautier 		.fixed = (f),				\
3137839a050SYann Gautier 	}
3147839a050SYann Gautier 
315d4151d2fSYann Gautier #define _CLK_PARENT_SEL(_label, _rcc_selr, _parents)		\
316d4151d2fSYann Gautier 	[_ ## _label ## _SEL] = {				\
317d4151d2fSYann Gautier 		.offset = _rcc_selr,				\
318d4151d2fSYann Gautier 		.src = _rcc_selr ## _ ## _label ## SRC_SHIFT,	\
3198ae08dcdSEtienne Carriere 		.msk = (_rcc_selr ## _ ## _label ## SRC_MASK) >> \
3208ae08dcdSEtienne Carriere 		       (_rcc_selr ## _ ## _label ## SRC_SHIFT), \
321d4151d2fSYann Gautier 		.parent = (_parents),				\
322d4151d2fSYann Gautier 		.nb_parent = ARRAY_SIZE(_parents)		\
3237839a050SYann Gautier 	}
3247839a050SYann Gautier 
3250d21680cSYann Gautier #define _CLK_PLL(idx, type, off1, off2, off3,		\
3267839a050SYann Gautier 		 off4, off5, off6,			\
3277839a050SYann Gautier 		 p1, p2, p3, p4)			\
3287839a050SYann Gautier 	[(idx)] = {					\
3297839a050SYann Gautier 		.plltype = (type),			\
3307839a050SYann Gautier 		.rckxselr = (off1),			\
3317839a050SYann Gautier 		.pllxcfgr1 = (off2),			\
3327839a050SYann Gautier 		.pllxcfgr2 = (off3),			\
3337839a050SYann Gautier 		.pllxfracr = (off4),			\
3347839a050SYann Gautier 		.pllxcr = (off5),			\
3357839a050SYann Gautier 		.pllxcsgr = (off6),			\
3367839a050SYann Gautier 		.refclk[0] = (p1),			\
3377839a050SYann Gautier 		.refclk[1] = (p2),			\
3387839a050SYann Gautier 		.refclk[2] = (p3),			\
3397839a050SYann Gautier 		.refclk[3] = (p4),			\
3407839a050SYann Gautier 	}
3417839a050SYann Gautier 
3420d21680cSYann Gautier #define NB_GATES	ARRAY_SIZE(stm32mp1_clk_gate)
3430d21680cSYann Gautier 
344aaa09b71SYann Gautier #define SEC		1
345aaa09b71SYann Gautier #define N_S		0
346aaa09b71SYann Gautier 
3477839a050SYann Gautier static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
348aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK),
349aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
350aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK),
351aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
352aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
353aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
354aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
355aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
356aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK),
357aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
358aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
3597839a050SYann Gautier 
3607418cf39SYann Gautier #if defined(IMAGE_BL32)
361aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
3627418cf39SYann Gautier #endif
363aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
364aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
365aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
366aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
367aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
368aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
369aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL),
370aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL),
371aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL),
372aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL),
3737839a050SYann Gautier 
3747418cf39SYann Gautier #if defined(IMAGE_BL32)
375aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
3767418cf39SYann Gautier #endif
377aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
3787839a050SYann Gautier 
379aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID),
380f33b2433SYann Gautier 
381aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
382aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
383aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
3847839a050SYann Gautier 
385aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL),
386aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
387aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL),
388aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL),
389aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
390aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5),
391aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5),
392aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5),
393aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5),
394aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5),
395aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
3967839a050SYann Gautier 
3977418cf39SYann Gautier #if defined(IMAGE_BL32)
398aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
399aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
4007418cf39SYann Gautier #endif
4017839a050SYann Gautier 
402aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
403aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
404aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
405aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
406aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
407aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
408aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
409aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
410aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
411aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
412aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
4137839a050SYann Gautier 
414aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5),
415aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5),
416aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5),
417aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL),
418aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5),
4197839a050SYann Gautier 
4207418cf39SYann Gautier #if defined(IMAGE_BL2)
421aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
422aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
4237418cf39SYann Gautier #endif
424aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
425aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
4267418cf39SYann Gautier #if defined(IMAGE_BL32)
427aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
4287418cf39SYann Gautier #endif
4297839a050SYann Gautier 
430aaa09b71SYann Gautier 	_CLK_SELEC(SEC, RCC_BDCR, 20, RTC, _RTC_SEL),
431aaa09b71SYann Gautier 	_CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
4327839a050SYann Gautier };
4337839a050SYann Gautier 
4340d21680cSYann Gautier static const uint8_t i2c12_parents[] = {
4350d21680cSYann Gautier 	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
4360d21680cSYann Gautier };
4370d21680cSYann Gautier 
4380d21680cSYann Gautier static const uint8_t i2c35_parents[] = {
4390d21680cSYann Gautier 	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
4400d21680cSYann Gautier };
4410d21680cSYann Gautier 
4420d21680cSYann Gautier static const uint8_t stgen_parents[] = {
4430d21680cSYann Gautier 	_HSI_KER, _HSE_KER
4440d21680cSYann Gautier };
4450d21680cSYann Gautier 
4460d21680cSYann Gautier static const uint8_t i2c46_parents[] = {
4470d21680cSYann Gautier 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER
4480d21680cSYann Gautier };
4490d21680cSYann Gautier 
4500d21680cSYann Gautier static const uint8_t spi6_parents[] = {
4510d21680cSYann Gautier 	_PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q
4520d21680cSYann Gautier };
4530d21680cSYann Gautier 
4540d21680cSYann Gautier static const uint8_t usart1_parents[] = {
4550d21680cSYann Gautier 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER
4560d21680cSYann Gautier };
4570d21680cSYann Gautier 
4580d21680cSYann Gautier static const uint8_t rng1_parents[] = {
4590d21680cSYann Gautier 	_CSI, _PLL4_R, _LSE, _LSI
4600d21680cSYann Gautier };
4610d21680cSYann Gautier 
4620d21680cSYann Gautier static const uint8_t uart6_parents[] = {
4630d21680cSYann Gautier 	_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
4640d21680cSYann Gautier };
4650d21680cSYann Gautier 
4660d21680cSYann Gautier static const uint8_t uart234578_parents[] = {
4670d21680cSYann Gautier 	_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
4680d21680cSYann Gautier };
4690d21680cSYann Gautier 
4700d21680cSYann Gautier static const uint8_t sdmmc12_parents[] = {
4710d21680cSYann Gautier 	_HCLK6, _PLL3_R, _PLL4_P, _HSI_KER
4720d21680cSYann Gautier };
4730d21680cSYann Gautier 
4740d21680cSYann Gautier static const uint8_t sdmmc3_parents[] = {
4750d21680cSYann Gautier 	_HCLK2, _PLL3_R, _PLL4_P, _HSI_KER
4760d21680cSYann Gautier };
4770d21680cSYann Gautier 
4780d21680cSYann Gautier static const uint8_t qspi_parents[] = {
4790d21680cSYann Gautier 	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
4800d21680cSYann Gautier };
4810d21680cSYann Gautier 
4820d21680cSYann Gautier static const uint8_t fmc_parents[] = {
4830d21680cSYann Gautier 	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
4840d21680cSYann Gautier };
4850d21680cSYann Gautier 
486b8fe48b6SEtienne Carriere static const uint8_t axiss_parents[] = {
487b8fe48b6SEtienne Carriere 	_HSI, _HSE, _PLL2_P
4880d21680cSYann Gautier };
4890d21680cSYann Gautier 
490b8fe48b6SEtienne Carriere static const uint8_t mcuss_parents[] = {
491b8fe48b6SEtienne Carriere 	_HSI, _HSE, _CSI, _PLL3_P
492b053a22eSYann Gautier };
493b053a22eSYann Gautier 
4940d21680cSYann Gautier static const uint8_t usbphy_parents[] = {
4950d21680cSYann Gautier 	_HSE_KER, _PLL4_R, _HSE_KER_DIV2
4960d21680cSYann Gautier };
4970d21680cSYann Gautier 
4980d21680cSYann Gautier static const uint8_t usbo_parents[] = {
4990d21680cSYann Gautier 	_PLL4_R, _USB_PHY_48
5000d21680cSYann Gautier };
5017839a050SYann Gautier 
5028fbcd9e4SEtienne Carriere static const uint8_t mpu_parents[] = {
5038fbcd9e4SEtienne Carriere 	_HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */
5048fbcd9e4SEtienne Carriere };
5058fbcd9e4SEtienne Carriere 
5068fbcd9e4SEtienne Carriere static const uint8_t per_parents[] = {
5078fbcd9e4SEtienne Carriere 	_HSI, _HSE, _CSI,
5088fbcd9e4SEtienne Carriere };
5098fbcd9e4SEtienne Carriere 
510016af006SEtienne Carriere static const uint8_t rtc_parents[] = {
511cbd2e8a6SGabriel Fernandez 	_UNKNOWN_ID, _LSE, _LSI, _HSE_RTC
512016af006SEtienne Carriere };
513016af006SEtienne Carriere 
5147839a050SYann Gautier static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
515d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents),
516d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents),
517d4151d2fSYann Gautier 	_CLK_PARENT_SEL(STGEN, RCC_STGENCKSELR, stgen_parents),
518d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C46, RCC_I2C46CKSELR, i2c46_parents),
519d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents),
520d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents),
521d4151d2fSYann Gautier 	_CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents),
5228fbcd9e4SEtienne Carriere 	_CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents),
523288f5cf2SYann Gautier 	_CLK_PARENT_SEL(CKPER, RCC_CPERCKSELR, per_parents),
524016af006SEtienne Carriere 	_CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents),
525d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents),
526d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents),
527d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents),
528d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART78, RCC_UART78CKSELR, uart234578_parents),
529d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SDMMC12, RCC_SDMMC12CKSELR, sdmmc12_parents),
530d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents),
531d4151d2fSYann Gautier 	_CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents),
532d4151d2fSYann Gautier 	_CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents),
533b8fe48b6SEtienne Carriere 	_CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, axiss_parents),
534b8fe48b6SEtienne Carriere 	_CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mcuss_parents),
535d4151d2fSYann Gautier 	_CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents),
536d4151d2fSYann Gautier 	_CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents),
5377839a050SYann Gautier };
5387839a050SYann Gautier 
5397839a050SYann Gautier /* Define characteristic of PLL according type */
540*f6559227SYann Gautier #define POST_DIVM_MIN	8000000U
541*f6559227SYann Gautier #define POST_DIVM_MAX	16000000U
542*f6559227SYann Gautier #define DIVM_MIN	0U
543*f6559227SYann Gautier #define DIVM_MAX	63U
544*f6559227SYann Gautier #define DIVN_MIN	24U
545*f6559227SYann Gautier #define DIVN_MAX	99U
546*f6559227SYann Gautier #define DIVP_MIN	0U
547*f6559227SYann Gautier #define DIVP_MAX	127U
548*f6559227SYann Gautier #define FRAC_MAX	8192U
549*f6559227SYann Gautier #define VCO_MIN		800000000U
550*f6559227SYann Gautier #define VCO_MAX		1600000000U
551*f6559227SYann Gautier 
5527839a050SYann Gautier static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
5537839a050SYann Gautier 	[PLL_800] = {
5547839a050SYann Gautier 		.refclk_min = 4,
5557839a050SYann Gautier 		.refclk_max = 16,
5567839a050SYann Gautier 	},
5577839a050SYann Gautier 	[PLL_1600] = {
5587839a050SYann Gautier 		.refclk_min = 8,
5597839a050SYann Gautier 		.refclk_max = 16,
5607839a050SYann Gautier 	},
5617839a050SYann Gautier };
5627839a050SYann Gautier 
5637839a050SYann Gautier /* PLLNCFGR2 register divider by output */
5647839a050SYann Gautier static const uint8_t pllncfgr2[_DIV_NB] = {
5657839a050SYann Gautier 	[_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT,
5667839a050SYann Gautier 	[_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT,
5670d21680cSYann Gautier 	[_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT,
5687839a050SYann Gautier };
5697839a050SYann Gautier 
5707839a050SYann Gautier static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = {
5710d21680cSYann Gautier 	_CLK_PLL(_PLL1, PLL_1600,
5727839a050SYann Gautier 		 RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2,
5737839a050SYann Gautier 		 RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR,
5747839a050SYann Gautier 		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
5750d21680cSYann Gautier 	_CLK_PLL(_PLL2, PLL_1600,
5767839a050SYann Gautier 		 RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2,
5777839a050SYann Gautier 		 RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR,
5787839a050SYann Gautier 		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
5790d21680cSYann Gautier 	_CLK_PLL(_PLL3, PLL_800,
5807839a050SYann Gautier 		 RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2,
5817839a050SYann Gautier 		 RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR,
5827839a050SYann Gautier 		 _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID),
5830d21680cSYann Gautier 	_CLK_PLL(_PLL4, PLL_800,
5847839a050SYann Gautier 		 RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2,
5857839a050SYann Gautier 		 RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR,
5867839a050SYann Gautier 		 _HSI, _HSE, _CSI, _I2S_CKIN),
5877839a050SYann Gautier };
5887839a050SYann Gautier 
5897839a050SYann Gautier /* Prescaler table lookups for clock computation */
590b053a22eSYann Gautier /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */
591b053a22eSYann Gautier static const uint8_t stm32mp1_mcu_div[16] = {
592b053a22eSYann Gautier 	0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9
593b053a22eSYann Gautier };
5947839a050SYann Gautier 
5957839a050SYann Gautier /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */
5967839a050SYann Gautier #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div
5977839a050SYann Gautier #define stm32mp1_apbx_div stm32mp1_mpu_apbx_div
5987839a050SYann Gautier static const uint8_t stm32mp1_mpu_apbx_div[8] = {
5997839a050SYann Gautier 	0, 1, 2, 3, 4, 4, 4, 4
6007839a050SYann Gautier };
6017839a050SYann Gautier 
6027839a050SYann Gautier /* div = /1 /2 /3 /4 */
6037839a050SYann Gautier static const uint8_t stm32mp1_axi_div[8] = {
6047839a050SYann Gautier 	1, 2, 3, 4, 4, 4, 4, 4
6057839a050SYann Gautier };
6067839a050SYann Gautier 
60737e8295aSEtienne Carriere static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = {
60837e8295aSEtienne Carriere 	[_HSI] = "HSI",
60937e8295aSEtienne Carriere 	[_HSE] = "HSE",
61037e8295aSEtienne Carriere 	[_CSI] = "CSI",
61137e8295aSEtienne Carriere 	[_LSI] = "LSI",
61237e8295aSEtienne Carriere 	[_LSE] = "LSE",
61337e8295aSEtienne Carriere 	[_I2S_CKIN] = "I2S_CKIN",
61437e8295aSEtienne Carriere 	[_HSI_KER] = "HSI_KER",
61537e8295aSEtienne Carriere 	[_HSE_KER] = "HSE_KER",
61637e8295aSEtienne Carriere 	[_HSE_KER_DIV2] = "HSE_KER_DIV2",
617cbd2e8a6SGabriel Fernandez 	[_HSE_RTC] = "HSE_RTC",
61837e8295aSEtienne Carriere 	[_CSI_KER] = "CSI_KER",
61937e8295aSEtienne Carriere 	[_PLL1_P] = "PLL1_P",
62037e8295aSEtienne Carriere 	[_PLL1_Q] = "PLL1_Q",
62137e8295aSEtienne Carriere 	[_PLL1_R] = "PLL1_R",
62237e8295aSEtienne Carriere 	[_PLL2_P] = "PLL2_P",
62337e8295aSEtienne Carriere 	[_PLL2_Q] = "PLL2_Q",
62437e8295aSEtienne Carriere 	[_PLL2_R] = "PLL2_R",
62537e8295aSEtienne Carriere 	[_PLL3_P] = "PLL3_P",
62637e8295aSEtienne Carriere 	[_PLL3_Q] = "PLL3_Q",
62737e8295aSEtienne Carriere 	[_PLL3_R] = "PLL3_R",
62837e8295aSEtienne Carriere 	[_PLL4_P] = "PLL4_P",
62937e8295aSEtienne Carriere 	[_PLL4_Q] = "PLL4_Q",
63037e8295aSEtienne Carriere 	[_PLL4_R] = "PLL4_R",
63137e8295aSEtienne Carriere 	[_ACLK] = "ACLK",
63237e8295aSEtienne Carriere 	[_PCLK1] = "PCLK1",
63337e8295aSEtienne Carriere 	[_PCLK2] = "PCLK2",
63437e8295aSEtienne Carriere 	[_PCLK3] = "PCLK3",
63537e8295aSEtienne Carriere 	[_PCLK4] = "PCLK4",
63637e8295aSEtienne Carriere 	[_PCLK5] = "PCLK5",
63737e8295aSEtienne Carriere 	[_HCLK6] = "KCLK6",
63837e8295aSEtienne Carriere 	[_HCLK2] = "HCLK2",
63937e8295aSEtienne Carriere 	[_CK_PER] = "CK_PER",
64037e8295aSEtienne Carriere 	[_CK_MPU] = "CK_MPU",
64137e8295aSEtienne Carriere 	[_CK_MCU] = "CK_MCU",
64237e8295aSEtienne Carriere 	[_USB_PHY_48] = "USB_PHY_48",
64337e8295aSEtienne Carriere };
64437e8295aSEtienne Carriere 
6450d21680cSYann Gautier /* RCC clock device driver private */
6460d21680cSYann Gautier static unsigned long stm32mp1_osc[NB_OSC];
6470d21680cSYann Gautier static struct spinlock reg_lock;
6480d21680cSYann Gautier static unsigned int gate_refcounts[NB_GATES];
6490d21680cSYann Gautier static struct spinlock refcount_lock;
6507839a050SYann Gautier 
6510d21680cSYann Gautier static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx)
6520d21680cSYann Gautier {
6530d21680cSYann Gautier 	return &stm32mp1_clk_gate[idx];
6540d21680cSYann Gautier }
6557839a050SYann Gautier 
6563d69149aSYann Gautier #if defined(IMAGE_BL32)
6573d69149aSYann Gautier static bool gate_is_non_secure(const struct stm32mp1_clk_gate *gate)
6583d69149aSYann Gautier {
6593d69149aSYann Gautier 	return gate->secure == N_S;
6603d69149aSYann Gautier }
6613d69149aSYann Gautier #endif
6623d69149aSYann Gautier 
6630d21680cSYann Gautier static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx)
6640d21680cSYann Gautier {
6650d21680cSYann Gautier 	return &stm32mp1_clk_sel[idx];
6660d21680cSYann Gautier }
6670d21680cSYann Gautier 
6680d21680cSYann Gautier static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx)
6690d21680cSYann Gautier {
6700d21680cSYann Gautier 	return &stm32mp1_clk_pll[idx];
6710d21680cSYann Gautier }
6720d21680cSYann Gautier 
6730d21680cSYann Gautier static void stm32mp1_clk_lock(struct spinlock *lock)
6740d21680cSYann Gautier {
675e463d3f4SYann Gautier 	if (stm32mp_lock_available()) {
6760d21680cSYann Gautier 		/* Assume interrupts are masked */
6770d21680cSYann Gautier 		spin_lock(lock);
6780d21680cSYann Gautier 	}
679e463d3f4SYann Gautier }
6800d21680cSYann Gautier 
6810d21680cSYann Gautier static void stm32mp1_clk_unlock(struct spinlock *lock)
6820d21680cSYann Gautier {
683e463d3f4SYann Gautier 	if (stm32mp_lock_available()) {
6840d21680cSYann Gautier 		spin_unlock(lock);
6850d21680cSYann Gautier 	}
686e463d3f4SYann Gautier }
6870d21680cSYann Gautier 
6880d21680cSYann Gautier bool stm32mp1_rcc_is_secure(void)
6890d21680cSYann Gautier {
6900d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
6911bb9072aSEtienne Carriere 	uint32_t mask = RCC_TZCR_TZEN;
6920d21680cSYann Gautier 
6931bb9072aSEtienne Carriere 	return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
6940d21680cSYann Gautier }
6950d21680cSYann Gautier 
696b053a22eSYann Gautier bool stm32mp1_rcc_is_mckprot(void)
697b053a22eSYann Gautier {
698b053a22eSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
6991bb9072aSEtienne Carriere 	uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT;
700b053a22eSYann Gautier 
7011bb9072aSEtienne Carriere 	return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
702b053a22eSYann Gautier }
703b053a22eSYann Gautier 
7040d21680cSYann Gautier void stm32mp1_clk_rcc_regs_lock(void)
7050d21680cSYann Gautier {
7060d21680cSYann Gautier 	stm32mp1_clk_lock(&reg_lock);
7070d21680cSYann Gautier }
7080d21680cSYann Gautier 
7090d21680cSYann Gautier void stm32mp1_clk_rcc_regs_unlock(void)
7100d21680cSYann Gautier {
7110d21680cSYann Gautier 	stm32mp1_clk_unlock(&reg_lock);
7120d21680cSYann Gautier }
7130d21680cSYann Gautier 
7140d21680cSYann Gautier static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx)
7157839a050SYann Gautier {
7167839a050SYann Gautier 	if (idx >= NB_OSC) {
7177839a050SYann Gautier 		return 0;
7187839a050SYann Gautier 	}
7197839a050SYann Gautier 
7200d21680cSYann Gautier 	return stm32mp1_osc[idx];
7217839a050SYann Gautier }
7227839a050SYann Gautier 
7230d21680cSYann Gautier static int stm32mp1_clk_get_gated_id(unsigned long id)
7247839a050SYann Gautier {
7250d21680cSYann Gautier 	unsigned int i;
7267839a050SYann Gautier 
7270d21680cSYann Gautier 	for (i = 0U; i < NB_GATES; i++) {
7280d21680cSYann Gautier 		if (gate_ref(i)->index == id) {
7297839a050SYann Gautier 			return i;
7307839a050SYann Gautier 		}
7317839a050SYann Gautier 	}
7327839a050SYann Gautier 
73344fb470bSYann Gautier 	ERROR("%s: clk id %lu not found\n", __func__, id);
7347839a050SYann Gautier 
7357839a050SYann Gautier 	return -EINVAL;
7367839a050SYann Gautier }
7377839a050SYann Gautier 
7380d21680cSYann Gautier static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i)
7397839a050SYann Gautier {
7400d21680cSYann Gautier 	return (enum stm32mp1_parent_sel)(gate_ref(i)->sel);
7417839a050SYann Gautier }
7427839a050SYann Gautier 
7430d21680cSYann Gautier static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i)
7447839a050SYann Gautier {
7450d21680cSYann Gautier 	return (enum stm32mp1_parent_id)(gate_ref(i)->fixed);
7467839a050SYann Gautier }
7477839a050SYann Gautier 
7480d21680cSYann Gautier static int stm32mp1_clk_get_parent(unsigned long id)
7497839a050SYann Gautier {
7500d21680cSYann Gautier 	const struct stm32mp1_clk_sel *sel;
7518fbcd9e4SEtienne Carriere 	uint32_t p_sel;
7527839a050SYann Gautier 	int i;
7537839a050SYann Gautier 	enum stm32mp1_parent_id p;
7547839a050SYann Gautier 	enum stm32mp1_parent_sel s;
7550d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
7567839a050SYann Gautier 
7578fbcd9e4SEtienne Carriere 	/* Few non gateable clock have a static parent ID, find them */
7588fbcd9e4SEtienne Carriere 	i = (int)clock_id2parent_id(id);
7598fbcd9e4SEtienne Carriere 	if (i != _UNKNOWN_ID) {
7608fbcd9e4SEtienne Carriere 		return i;
7617839a050SYann Gautier 	}
7627839a050SYann Gautier 
7630d21680cSYann Gautier 	i = stm32mp1_clk_get_gated_id(id);
7647839a050SYann Gautier 	if (i < 0) {
7650d21680cSYann Gautier 		panic();
7667839a050SYann Gautier 	}
7677839a050SYann Gautier 
7680d21680cSYann Gautier 	p = stm32mp1_clk_get_fixed_parent(i);
7697839a050SYann Gautier 	if (p < _PARENT_NB) {
7707839a050SYann Gautier 		return (int)p;
7717839a050SYann Gautier 	}
7727839a050SYann Gautier 
7730d21680cSYann Gautier 	s = stm32mp1_clk_get_sel(i);
7740d21680cSYann Gautier 	if (s == _UNKNOWN_SEL) {
7750d21680cSYann Gautier 		return -EINVAL;
7760d21680cSYann Gautier 	}
7777839a050SYann Gautier 	if (s >= _PARENT_SEL_NB) {
7780d21680cSYann Gautier 		panic();
7797839a050SYann Gautier 	}
7807839a050SYann Gautier 
7810d21680cSYann Gautier 	sel = clk_sel_ref(s);
7828ae08dcdSEtienne Carriere 	p_sel = (mmio_read_32(rcc_base + sel->offset) &
7838ae08dcdSEtienne Carriere 		 (sel->msk << sel->src)) >> sel->src;
7840d21680cSYann Gautier 	if (p_sel < sel->nb_parent) {
7850d21680cSYann Gautier 		return (int)sel->parent[p_sel];
7867839a050SYann Gautier 	}
7877839a050SYann Gautier 
7887839a050SYann Gautier 	return -EINVAL;
7897839a050SYann Gautier }
7907839a050SYann Gautier 
7910d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll)
7927839a050SYann Gautier {
7930d21680cSYann Gautier 	uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr);
7940d21680cSYann Gautier 	uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK;
7957839a050SYann Gautier 
7960d21680cSYann Gautier 	return stm32mp1_clk_get_fixed(pll->refclk[src]);
7977839a050SYann Gautier }
7987839a050SYann Gautier 
7997839a050SYann Gautier /*
8007839a050SYann Gautier  * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL
8017839a050SYann Gautier  * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1)
8027839a050SYann Gautier  * - PLL3 & PLL4 => return VCO     with Fpll_y_ck = FVCO / (DIVy + 1)
8037839a050SYann Gautier  * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1)
8047839a050SYann Gautier  */
8050d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll)
8067839a050SYann Gautier {
8077839a050SYann Gautier 	unsigned long refclk, fvco;
8087839a050SYann Gautier 	uint32_t cfgr1, fracr, divm, divn;
8090d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
8107839a050SYann Gautier 
8110d21680cSYann Gautier 	cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1);
8120d21680cSYann Gautier 	fracr = mmio_read_32(rcc_base + pll->pllxfracr);
8137839a050SYann Gautier 
8147839a050SYann Gautier 	divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT;
8157839a050SYann Gautier 	divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK;
8167839a050SYann Gautier 
8170d21680cSYann Gautier 	refclk = stm32mp1_pll_get_fref(pll);
8187839a050SYann Gautier 
8197839a050SYann Gautier 	/*
8207839a050SYann Gautier 	 * With FRACV :
8217839a050SYann Gautier 	 *   Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1)
8227839a050SYann Gautier 	 * Without FRACV
8237839a050SYann Gautier 	 *   Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1)
8247839a050SYann Gautier 	 */
8257839a050SYann Gautier 	if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) {
8260d21680cSYann Gautier 		uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >>
8270d21680cSYann Gautier 				 RCC_PLLNFRACR_FRACV_SHIFT;
8287839a050SYann Gautier 		unsigned long long numerator, denominator;
8297839a050SYann Gautier 
8300d21680cSYann Gautier 		numerator = (((unsigned long long)divn + 1U) << 13) + fracv;
8310d21680cSYann Gautier 		numerator = refclk * numerator;
8327839a050SYann Gautier 		denominator = ((unsigned long long)divm + 1U) << 13;
8337839a050SYann Gautier 		fvco = (unsigned long)(numerator / denominator);
8347839a050SYann Gautier 	} else {
8357839a050SYann Gautier 		fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U));
8367839a050SYann Gautier 	}
8377839a050SYann Gautier 
8387839a050SYann Gautier 	return fvco;
8397839a050SYann Gautier }
8407839a050SYann Gautier 
8410d21680cSYann Gautier static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id,
8427839a050SYann Gautier 					    enum stm32mp1_div_id div_id)
8437839a050SYann Gautier {
8440d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
8457839a050SYann Gautier 	unsigned long dfout;
8467839a050SYann Gautier 	uint32_t cfgr2, divy;
8477839a050SYann Gautier 
8487839a050SYann Gautier 	if (div_id >= _DIV_NB) {
8497839a050SYann Gautier 		return 0;
8507839a050SYann Gautier 	}
8517839a050SYann Gautier 
8520d21680cSYann Gautier 	cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2);
8537839a050SYann Gautier 	divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK;
8547839a050SYann Gautier 
8550d21680cSYann Gautier 	dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U);
8567839a050SYann Gautier 
8577839a050SYann Gautier 	return dfout;
8587839a050SYann Gautier }
8597839a050SYann Gautier 
8600d21680cSYann Gautier static unsigned long get_clock_rate(int p)
8617839a050SYann Gautier {
8627839a050SYann Gautier 	uint32_t reg, clkdiv;
8637839a050SYann Gautier 	unsigned long clock = 0;
8640d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
8657839a050SYann Gautier 
8667839a050SYann Gautier 	switch (p) {
8677839a050SYann Gautier 	case _CK_MPU:
8687839a050SYann Gautier 	/* MPU sub system */
8690d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MPCKSELR);
8707839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
8717839a050SYann Gautier 		case RCC_MPCKSELR_HSI:
8720d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
8737839a050SYann Gautier 			break;
8747839a050SYann Gautier 		case RCC_MPCKSELR_HSE:
8750d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
8767839a050SYann Gautier 			break;
8777839a050SYann Gautier 		case RCC_MPCKSELR_PLL:
8780d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
8797839a050SYann Gautier 			break;
8807839a050SYann Gautier 		case RCC_MPCKSELR_PLL_MPUDIV:
8810d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
8827839a050SYann Gautier 
8830d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_MPCKDIVR);
8847839a050SYann Gautier 			clkdiv = reg & RCC_MPUDIV_MASK;
885602ae2f2SGabriel Fernandez 			clock >>= stm32mp1_mpu_div[clkdiv];
8867839a050SYann Gautier 			break;
8877839a050SYann Gautier 		default:
8887839a050SYann Gautier 			break;
8897839a050SYann Gautier 		}
8907839a050SYann Gautier 		break;
8917839a050SYann Gautier 	/* AXI sub system */
8927839a050SYann Gautier 	case _ACLK:
8937839a050SYann Gautier 	case _HCLK2:
8947839a050SYann Gautier 	case _HCLK6:
8957839a050SYann Gautier 	case _PCLK4:
8967839a050SYann Gautier 	case _PCLK5:
8970d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_ASSCKSELR);
8987839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
8997839a050SYann Gautier 		case RCC_ASSCKSELR_HSI:
9000d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
9017839a050SYann Gautier 			break;
9027839a050SYann Gautier 		case RCC_ASSCKSELR_HSE:
9030d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
9047839a050SYann Gautier 			break;
9057839a050SYann Gautier 		case RCC_ASSCKSELR_PLL:
9060d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
9077839a050SYann Gautier 			break;
9087839a050SYann Gautier 		default:
9097839a050SYann Gautier 			break;
9107839a050SYann Gautier 		}
9117839a050SYann Gautier 
9127839a050SYann Gautier 		/* System clock divider */
9130d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_AXIDIVR);
9147839a050SYann Gautier 		clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK];
9157839a050SYann Gautier 
9167839a050SYann Gautier 		switch (p) {
9177839a050SYann Gautier 		case _PCLK4:
9180d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB4DIVR);
9197839a050SYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
9207839a050SYann Gautier 			break;
9217839a050SYann Gautier 		case _PCLK5:
9220d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB5DIVR);
9237839a050SYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
9247839a050SYann Gautier 			break;
9257839a050SYann Gautier 		default:
9267839a050SYann Gautier 			break;
9277839a050SYann Gautier 		}
9287839a050SYann Gautier 		break;
929b053a22eSYann Gautier 	/* MCU sub system */
930b053a22eSYann Gautier 	case _CK_MCU:
931b053a22eSYann Gautier 	case _PCLK1:
932b053a22eSYann Gautier 	case _PCLK2:
933b053a22eSYann Gautier 	case _PCLK3:
934b053a22eSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MSSCKSELR);
935b053a22eSYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
936b053a22eSYann Gautier 		case RCC_MSSCKSELR_HSI:
937b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
938b053a22eSYann Gautier 			break;
939b053a22eSYann Gautier 		case RCC_MSSCKSELR_HSE:
940b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
941b053a22eSYann Gautier 			break;
942b053a22eSYann Gautier 		case RCC_MSSCKSELR_CSI:
943b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_CSI);
944b053a22eSYann Gautier 			break;
945b053a22eSYann Gautier 		case RCC_MSSCKSELR_PLL:
946b053a22eSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
947b053a22eSYann Gautier 			break;
948b053a22eSYann Gautier 		default:
949b053a22eSYann Gautier 			break;
950b053a22eSYann Gautier 		}
951b053a22eSYann Gautier 
952b053a22eSYann Gautier 		/* MCU clock divider */
953b053a22eSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MCUDIVR);
954b053a22eSYann Gautier 		clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK];
955b053a22eSYann Gautier 
956b053a22eSYann Gautier 		switch (p) {
957b053a22eSYann Gautier 		case _PCLK1:
958b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB1DIVR);
959b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
960b053a22eSYann Gautier 			break;
961b053a22eSYann Gautier 		case _PCLK2:
962b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB2DIVR);
963b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
964b053a22eSYann Gautier 			break;
965b053a22eSYann Gautier 		case _PCLK3:
966b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB3DIVR);
967b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
968b053a22eSYann Gautier 			break;
969b053a22eSYann Gautier 		case _CK_MCU:
970b053a22eSYann Gautier 		default:
971b053a22eSYann Gautier 			break;
972b053a22eSYann Gautier 		}
973b053a22eSYann Gautier 		break;
9747839a050SYann Gautier 	case _CK_PER:
9750d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_CPERCKSELR);
9767839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
9777839a050SYann Gautier 		case RCC_CPERCKSELR_HSI:
9780d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
9797839a050SYann Gautier 			break;
9807839a050SYann Gautier 		case RCC_CPERCKSELR_HSE:
9810d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
9827839a050SYann Gautier 			break;
9837839a050SYann Gautier 		case RCC_CPERCKSELR_CSI:
9840d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_CSI);
9857839a050SYann Gautier 			break;
9867839a050SYann Gautier 		default:
9877839a050SYann Gautier 			break;
9887839a050SYann Gautier 		}
9897839a050SYann Gautier 		break;
9907839a050SYann Gautier 	case _HSI:
9917839a050SYann Gautier 	case _HSI_KER:
9920d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSI);
9937839a050SYann Gautier 		break;
9947839a050SYann Gautier 	case _CSI:
9957839a050SYann Gautier 	case _CSI_KER:
9960d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_CSI);
9977839a050SYann Gautier 		break;
9987839a050SYann Gautier 	case _HSE:
9997839a050SYann Gautier 	case _HSE_KER:
10000d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSE);
10017839a050SYann Gautier 		break;
10027839a050SYann Gautier 	case _HSE_KER_DIV2:
10030d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSE) >> 1;
10047839a050SYann Gautier 		break;
1005cbd2e8a6SGabriel Fernandez 	case _HSE_RTC:
1006cbd2e8a6SGabriel Fernandez 		clock = stm32mp1_clk_get_fixed(_HSE);
1007cbd2e8a6SGabriel Fernandez 		clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U;
1008cbd2e8a6SGabriel Fernandez 		break;
10097839a050SYann Gautier 	case _LSI:
10100d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_LSI);
10117839a050SYann Gautier 		break;
10127839a050SYann Gautier 	case _LSE:
10130d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_LSE);
10147839a050SYann Gautier 		break;
10157839a050SYann Gautier 	/* PLL */
10167839a050SYann Gautier 	case _PLL1_P:
10170d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
10187839a050SYann Gautier 		break;
10197839a050SYann Gautier 	case _PLL1_Q:
10200d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q);
10217839a050SYann Gautier 		break;
10227839a050SYann Gautier 	case _PLL1_R:
10230d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R);
10247839a050SYann Gautier 		break;
10257839a050SYann Gautier 	case _PLL2_P:
10260d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
10277839a050SYann Gautier 		break;
10287839a050SYann Gautier 	case _PLL2_Q:
10290d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q);
10307839a050SYann Gautier 		break;
10317839a050SYann Gautier 	case _PLL2_R:
10320d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R);
10337839a050SYann Gautier 		break;
10347839a050SYann Gautier 	case _PLL3_P:
10350d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
10367839a050SYann Gautier 		break;
10377839a050SYann Gautier 	case _PLL3_Q:
10380d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q);
10397839a050SYann Gautier 		break;
10407839a050SYann Gautier 	case _PLL3_R:
10410d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R);
10427839a050SYann Gautier 		break;
10437839a050SYann Gautier 	case _PLL4_P:
10440d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P);
10457839a050SYann Gautier 		break;
10467839a050SYann Gautier 	case _PLL4_Q:
10470d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q);
10487839a050SYann Gautier 		break;
10497839a050SYann Gautier 	case _PLL4_R:
10500d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R);
10517839a050SYann Gautier 		break;
10527839a050SYann Gautier 	/* Other */
10537839a050SYann Gautier 	case _USB_PHY_48:
10540d21680cSYann Gautier 		clock = USB_PHY_48_MHZ;
10557839a050SYann Gautier 		break;
10567839a050SYann Gautier 	default:
10577839a050SYann Gautier 		break;
10587839a050SYann Gautier 	}
10597839a050SYann Gautier 
10607839a050SYann Gautier 	return clock;
10617839a050SYann Gautier }
10627839a050SYann Gautier 
10630d21680cSYann Gautier static void __clk_enable(struct stm32mp1_clk_gate const *gate)
10640d21680cSYann Gautier {
10650d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10660d21680cSYann Gautier 
106725be845eSEtienne Carriere 	VERBOSE("Enable clock %u\n", gate->index);
106825be845eSEtienne Carriere 
10690d21680cSYann Gautier 	if (gate->set_clr != 0U) {
10700d21680cSYann Gautier 		mmio_write_32(rcc_base + gate->offset, BIT(gate->bit));
10710d21680cSYann Gautier 	} else {
10720d21680cSYann Gautier 		mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit));
10730d21680cSYann Gautier 	}
10740d21680cSYann Gautier }
10750d21680cSYann Gautier 
10760d21680cSYann Gautier static void __clk_disable(struct stm32mp1_clk_gate const *gate)
10770d21680cSYann Gautier {
10780d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10790d21680cSYann Gautier 
108025be845eSEtienne Carriere 	VERBOSE("Disable clock %u\n", gate->index);
108125be845eSEtienne Carriere 
10820d21680cSYann Gautier 	if (gate->set_clr != 0U) {
10830d21680cSYann Gautier 		mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET,
10840d21680cSYann Gautier 			      BIT(gate->bit));
10850d21680cSYann Gautier 	} else {
10860d21680cSYann Gautier 		mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit));
10870d21680cSYann Gautier 	}
10880d21680cSYann Gautier }
10890d21680cSYann Gautier 
10900d21680cSYann Gautier static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate)
10910d21680cSYann Gautier {
10920d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10930d21680cSYann Gautier 
10940d21680cSYann Gautier 	return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit);
10950d21680cSYann Gautier }
10960d21680cSYann Gautier 
109735848200SEtienne Carriere /* Oscillators and PLLs are not gated at runtime */
109835848200SEtienne Carriere static bool clock_is_always_on(unsigned long id)
109935848200SEtienne Carriere {
110035848200SEtienne Carriere 	switch (id) {
110135848200SEtienne Carriere 	case CK_HSE:
110235848200SEtienne Carriere 	case CK_CSI:
110335848200SEtienne Carriere 	case CK_LSI:
110435848200SEtienne Carriere 	case CK_LSE:
110535848200SEtienne Carriere 	case CK_HSI:
110635848200SEtienne Carriere 	case CK_HSE_DIV2:
110735848200SEtienne Carriere 	case PLL1_Q:
110835848200SEtienne Carriere 	case PLL1_R:
110935848200SEtienne Carriere 	case PLL2_P:
111035848200SEtienne Carriere 	case PLL2_Q:
111135848200SEtienne Carriere 	case PLL2_R:
111235848200SEtienne Carriere 	case PLL3_P:
111335848200SEtienne Carriere 	case PLL3_Q:
111435848200SEtienne Carriere 	case PLL3_R:
1115bf39318dSYann Gautier 	case CK_AXI:
1116bf39318dSYann Gautier 	case CK_MPU:
1117bf39318dSYann Gautier 	case CK_MCU:
11185b111c74SHE Shushan 	case RTC:
111935848200SEtienne Carriere 		return true;
112035848200SEtienne Carriere 	default:
112135848200SEtienne Carriere 		return false;
112235848200SEtienne Carriere 	}
112335848200SEtienne Carriere }
112435848200SEtienne Carriere 
11252444d231SYann Gautier static void __stm32mp1_clk_enable(unsigned long id, bool with_refcnt)
11260d21680cSYann Gautier {
11270d21680cSYann Gautier 	const struct stm32mp1_clk_gate *gate;
112835848200SEtienne Carriere 	int i;
11290d21680cSYann Gautier 
113035848200SEtienne Carriere 	if (clock_is_always_on(id)) {
113135848200SEtienne Carriere 		return;
113235848200SEtienne Carriere 	}
113335848200SEtienne Carriere 
113435848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
11350d21680cSYann Gautier 	if (i < 0) {
113644fb470bSYann Gautier 		ERROR("Clock %lu can't be enabled\n", id);
11370d21680cSYann Gautier 		panic();
11380d21680cSYann Gautier 	}
11390d21680cSYann Gautier 
11400d21680cSYann Gautier 	gate = gate_ref(i);
11412444d231SYann Gautier 
11422444d231SYann Gautier 	if (!with_refcnt) {
11432444d231SYann Gautier 		__clk_enable(gate);
11442444d231SYann Gautier 		return;
11452444d231SYann Gautier 	}
11460d21680cSYann Gautier 
11473d69149aSYann Gautier #if defined(IMAGE_BL32)
11483d69149aSYann Gautier 	if (gate_is_non_secure(gate)) {
11493d69149aSYann Gautier 		/* Enable non-secure clock w/o any refcounting */
11503d69149aSYann Gautier 		__clk_enable(gate);
11513d69149aSYann Gautier 		return;
11523d69149aSYann Gautier 	}
11533d69149aSYann Gautier #endif
11543d69149aSYann Gautier 
11550d21680cSYann Gautier 	stm32mp1_clk_lock(&refcount_lock);
11560d21680cSYann Gautier 
11572444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
11580d21680cSYann Gautier 		__clk_enable(gate);
11590d21680cSYann Gautier 	}
11600d21680cSYann Gautier 
11612444d231SYann Gautier 	gate_refcounts[i]++;
11622444d231SYann Gautier 	if (gate_refcounts[i] == UINT_MAX) {
11632444d231SYann Gautier 		ERROR("Clock %lu refcount reached max value\n", id);
11642444d231SYann Gautier 		panic();
11652444d231SYann Gautier 	}
11662444d231SYann Gautier 
11670d21680cSYann Gautier 	stm32mp1_clk_unlock(&refcount_lock);
11680d21680cSYann Gautier }
11690d21680cSYann Gautier 
11702444d231SYann Gautier static void __stm32mp1_clk_disable(unsigned long id, bool with_refcnt)
11710d21680cSYann Gautier {
11720d21680cSYann Gautier 	const struct stm32mp1_clk_gate *gate;
117335848200SEtienne Carriere 	int i;
11740d21680cSYann Gautier 
117535848200SEtienne Carriere 	if (clock_is_always_on(id)) {
117635848200SEtienne Carriere 		return;
117735848200SEtienne Carriere 	}
117835848200SEtienne Carriere 
117935848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
11800d21680cSYann Gautier 	if (i < 0) {
118144fb470bSYann Gautier 		ERROR("Clock %lu can't be disabled\n", id);
11820d21680cSYann Gautier 		panic();
11830d21680cSYann Gautier 	}
11840d21680cSYann Gautier 
11850d21680cSYann Gautier 	gate = gate_ref(i);
11862444d231SYann Gautier 
11872444d231SYann Gautier 	if (!with_refcnt) {
11882444d231SYann Gautier 		__clk_disable(gate);
11892444d231SYann Gautier 		return;
11902444d231SYann Gautier 	}
11910d21680cSYann Gautier 
11923d69149aSYann Gautier #if defined(IMAGE_BL32)
11933d69149aSYann Gautier 	if (gate_is_non_secure(gate)) {
11943d69149aSYann Gautier 		/* Don't disable non-secure clocks */
11953d69149aSYann Gautier 		return;
11963d69149aSYann Gautier 	}
11973d69149aSYann Gautier #endif
11983d69149aSYann Gautier 
11990d21680cSYann Gautier 	stm32mp1_clk_lock(&refcount_lock);
12000d21680cSYann Gautier 
12012444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
12022444d231SYann Gautier 		ERROR("Clock %lu refcount reached 0\n", id);
12032444d231SYann Gautier 		panic();
12042444d231SYann Gautier 	}
12052444d231SYann Gautier 	gate_refcounts[i]--;
12062444d231SYann Gautier 
12072444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
12080d21680cSYann Gautier 		__clk_disable(gate);
12090d21680cSYann Gautier 	}
12100d21680cSYann Gautier 
12110d21680cSYann Gautier 	stm32mp1_clk_unlock(&refcount_lock);
12120d21680cSYann Gautier }
12130d21680cSYann Gautier 
121433667d29SYann Gautier static int stm32mp_clk_enable(unsigned long id)
12150d21680cSYann Gautier {
12160d21680cSYann Gautier 	__stm32mp1_clk_enable(id, true);
121733667d29SYann Gautier 
121833667d29SYann Gautier 	return 0;
12190d21680cSYann Gautier }
12200d21680cSYann Gautier 
122133667d29SYann Gautier static void stm32mp_clk_disable(unsigned long id)
12220d21680cSYann Gautier {
12230d21680cSYann Gautier 	__stm32mp1_clk_disable(id, true);
12240d21680cSYann Gautier }
12250d21680cSYann Gautier 
122633667d29SYann Gautier static bool stm32mp_clk_is_enabled(unsigned long id)
12277839a050SYann Gautier {
122835848200SEtienne Carriere 	int i;
12297839a050SYann Gautier 
123035848200SEtienne Carriere 	if (clock_is_always_on(id)) {
123135848200SEtienne Carriere 		return true;
123235848200SEtienne Carriere 	}
123335848200SEtienne Carriere 
123435848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
12357839a050SYann Gautier 	if (i < 0) {
12360d21680cSYann Gautier 		panic();
12377839a050SYann Gautier 	}
12387839a050SYann Gautier 
12390d21680cSYann Gautier 	return __clk_is_enabled(gate_ref(i));
12407839a050SYann Gautier }
12417839a050SYann Gautier 
124233667d29SYann Gautier static unsigned long stm32mp_clk_get_rate(unsigned long id)
12437839a050SYann Gautier {
124433667d29SYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
12450d21680cSYann Gautier 	int p = stm32mp1_clk_get_parent(id);
124633667d29SYann Gautier 	uint32_t prescaler, timpre;
124733667d29SYann Gautier 	unsigned long parent_rate;
12487839a050SYann Gautier 
12497839a050SYann Gautier 	if (p < 0) {
12507839a050SYann Gautier 		return 0;
12517839a050SYann Gautier 	}
12527839a050SYann Gautier 
125333667d29SYann Gautier 	parent_rate = get_clock_rate(p);
125433667d29SYann Gautier 
125533667d29SYann Gautier 	switch (id) {
125633667d29SYann Gautier 	case TIM2_K:
125733667d29SYann Gautier 	case TIM3_K:
125833667d29SYann Gautier 	case TIM4_K:
125933667d29SYann Gautier 	case TIM5_K:
126033667d29SYann Gautier 	case TIM6_K:
126133667d29SYann Gautier 	case TIM7_K:
126233667d29SYann Gautier 	case TIM12_K:
126333667d29SYann Gautier 	case TIM13_K:
126433667d29SYann Gautier 	case TIM14_K:
126533667d29SYann Gautier 		prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) &
126633667d29SYann Gautier 			    RCC_APBXDIV_MASK;
126733667d29SYann Gautier 		timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) &
126833667d29SYann Gautier 			 RCC_TIMGXPRER_TIMGXPRE;
126933667d29SYann Gautier 		break;
127033667d29SYann Gautier 
127133667d29SYann Gautier 	case TIM1_K:
127233667d29SYann Gautier 	case TIM8_K:
127333667d29SYann Gautier 	case TIM15_K:
127433667d29SYann Gautier 	case TIM16_K:
127533667d29SYann Gautier 	case TIM17_K:
127633667d29SYann Gautier 		prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) &
127733667d29SYann Gautier 			    RCC_APBXDIV_MASK;
127833667d29SYann Gautier 		timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) &
127933667d29SYann Gautier 			 RCC_TIMGXPRER_TIMGXPRE;
128033667d29SYann Gautier 		break;
128133667d29SYann Gautier 
128233667d29SYann Gautier 	default:
128333667d29SYann Gautier 		return parent_rate;
128433667d29SYann Gautier 	}
128533667d29SYann Gautier 
128633667d29SYann Gautier 	if (prescaler == 0U) {
128733667d29SYann Gautier 		return parent_rate;
128833667d29SYann Gautier 	}
128933667d29SYann Gautier 
129033667d29SYann Gautier 	return parent_rate * (timpre + 1U) * 2U;
12917839a050SYann Gautier }
12927839a050SYann Gautier 
12930d21680cSYann Gautier static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on)
12947839a050SYann Gautier {
12950d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
12967839a050SYann Gautier 
12970d21680cSYann Gautier 	if (enable) {
12987839a050SYann Gautier 		mmio_setbits_32(address, mask_on);
12997839a050SYann Gautier 	} else {
13007839a050SYann Gautier 		mmio_clrbits_32(address, mask_on);
13017839a050SYann Gautier 	}
13027839a050SYann Gautier }
13037839a050SYann Gautier 
13040d21680cSYann Gautier static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on)
13057839a050SYann Gautier {
13060d21680cSYann Gautier 	uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR;
13070d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
13080d21680cSYann Gautier 
13090d21680cSYann Gautier 	mmio_write_32(address, mask_on);
13107839a050SYann Gautier }
13117839a050SYann Gautier 
13120d21680cSYann Gautier static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy)
13137839a050SYann Gautier {
1314dfdb057aSYann Gautier 	uint64_t timeout;
13157839a050SYann Gautier 	uint32_t mask_test;
13160d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
13177839a050SYann Gautier 
13180d21680cSYann Gautier 	if (enable) {
13197839a050SYann Gautier 		mask_test = mask_rdy;
13207839a050SYann Gautier 	} else {
13217839a050SYann Gautier 		mask_test = 0;
13227839a050SYann Gautier 	}
13237839a050SYann Gautier 
1324dfdb057aSYann Gautier 	timeout = timeout_init_us(OSCRDY_TIMEOUT);
13257839a050SYann Gautier 	while ((mmio_read_32(address) & mask_rdy) != mask_test) {
1326dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
13270d21680cSYann Gautier 			ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n",
13287839a050SYann Gautier 			      mask_rdy, address, enable, mmio_read_32(address));
13297839a050SYann Gautier 			return -ETIMEDOUT;
13307839a050SYann Gautier 		}
13317839a050SYann Gautier 	}
13327839a050SYann Gautier 
13337839a050SYann Gautier 	return 0;
13347839a050SYann Gautier }
13357839a050SYann Gautier 
13360d21680cSYann Gautier static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv)
13377839a050SYann Gautier {
13387839a050SYann Gautier 	uint32_t value;
13390d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13407839a050SYann Gautier 
1341f4a2bb98SYann Gautier 	/* Do not reconfigure LSE if it is already ON */
1342f4a2bb98SYann Gautier 	if ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEON) == RCC_BDCR_LSEON) {
1343f4a2bb98SYann Gautier 		return;
1344f4a2bb98SYann Gautier 	}
1345f4a2bb98SYann Gautier 
13460d21680cSYann Gautier 	if (digbyp) {
13470d21680cSYann Gautier 		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP);
13480d21680cSYann Gautier 	}
13490d21680cSYann Gautier 
13500d21680cSYann Gautier 	if (bypass || digbyp) {
13510d21680cSYann Gautier 		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP);
13527839a050SYann Gautier 	}
13537839a050SYann Gautier 
13547839a050SYann Gautier 	/*
13557839a050SYann Gautier 	 * Warning: not recommended to switch directly from "high drive"
13567839a050SYann Gautier 	 * to "medium low drive", and vice-versa.
13577839a050SYann Gautier 	 */
13580d21680cSYann Gautier 	value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >>
13597839a050SYann Gautier 		RCC_BDCR_LSEDRV_SHIFT;
13607839a050SYann Gautier 
13617839a050SYann Gautier 	while (value != lsedrv) {
13627839a050SYann Gautier 		if (value > lsedrv) {
13637839a050SYann Gautier 			value--;
13647839a050SYann Gautier 		} else {
13657839a050SYann Gautier 			value++;
13667839a050SYann Gautier 		}
13677839a050SYann Gautier 
13680d21680cSYann Gautier 		mmio_clrsetbits_32(rcc_base + RCC_BDCR,
13697839a050SYann Gautier 				   RCC_BDCR_LSEDRV_MASK,
13707839a050SYann Gautier 				   value << RCC_BDCR_LSEDRV_SHIFT);
13717839a050SYann Gautier 	}
13727839a050SYann Gautier 
13730d21680cSYann Gautier 	stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON);
13747839a050SYann Gautier }
13757839a050SYann Gautier 
13760d21680cSYann Gautier static void stm32mp1_lse_wait(void)
13777839a050SYann Gautier {
13780d21680cSYann Gautier 	if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) {
13797839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
13807839a050SYann Gautier 	}
13817839a050SYann Gautier }
13827839a050SYann Gautier 
13830d21680cSYann Gautier static void stm32mp1_lsi_set(bool enable)
13847839a050SYann Gautier {
13850d21680cSYann Gautier 	stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION);
13860d21680cSYann Gautier 
13870d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) {
13887839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
13897839a050SYann Gautier 	}
13907839a050SYann Gautier }
13917839a050SYann Gautier 
13920d21680cSYann Gautier static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css)
13937839a050SYann Gautier {
13940d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13950d21680cSYann Gautier 
13960d21680cSYann Gautier 	if (digbyp) {
13970d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP);
13987839a050SYann Gautier 	}
13997839a050SYann Gautier 
14000d21680cSYann Gautier 	if (bypass || digbyp) {
14010d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP);
14020d21680cSYann Gautier 	}
14030d21680cSYann Gautier 
14040d21680cSYann Gautier 	stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON);
14050d21680cSYann Gautier 	if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) {
14067839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
14077839a050SYann Gautier 	}
14087839a050SYann Gautier 
14097839a050SYann Gautier 	if (css) {
14100d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON);
14117839a050SYann Gautier 	}
141231e9750bSLionel Debieve 
141331e9750bSLionel Debieve #if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
141431e9750bSLionel Debieve 	if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) &&
141531e9750bSLionel Debieve 	    (!(digbyp || bypass))) {
141631e9750bSLionel Debieve 		panic();
141731e9750bSLionel Debieve 	}
141831e9750bSLionel Debieve #endif
14197839a050SYann Gautier }
14207839a050SYann Gautier 
14210d21680cSYann Gautier static void stm32mp1_csi_set(bool enable)
14227839a050SYann Gautier {
14230d21680cSYann Gautier 	stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION);
14240d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) {
14257839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
14267839a050SYann Gautier 	}
14277839a050SYann Gautier }
14287839a050SYann Gautier 
14290d21680cSYann Gautier static void stm32mp1_hsi_set(bool enable)
14307839a050SYann Gautier {
14310d21680cSYann Gautier 	stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION);
14320d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) {
14337839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
14347839a050SYann Gautier 	}
14357839a050SYann Gautier }
14367839a050SYann Gautier 
14370d21680cSYann Gautier static int stm32mp1_set_hsidiv(uint8_t hsidiv)
14387839a050SYann Gautier {
1439dfdb057aSYann Gautier 	uint64_t timeout;
14400d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
14410d21680cSYann Gautier 	uintptr_t address = rcc_base + RCC_OCRDYR;
14427839a050SYann Gautier 
14430d21680cSYann Gautier 	mmio_clrsetbits_32(rcc_base + RCC_HSICFGR,
14447839a050SYann Gautier 			   RCC_HSICFGR_HSIDIV_MASK,
14457839a050SYann Gautier 			   RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv);
14467839a050SYann Gautier 
1447dfdb057aSYann Gautier 	timeout = timeout_init_us(HSIDIV_TIMEOUT);
14487839a050SYann Gautier 	while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) {
1449dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
14500d21680cSYann Gautier 			ERROR("HSIDIV failed @ 0x%lx: 0x%x\n",
14517839a050SYann Gautier 			      address, mmio_read_32(address));
14527839a050SYann Gautier 			return -ETIMEDOUT;
14537839a050SYann Gautier 		}
14547839a050SYann Gautier 	}
14557839a050SYann Gautier 
14567839a050SYann Gautier 	return 0;
14577839a050SYann Gautier }
14587839a050SYann Gautier 
14590d21680cSYann Gautier static int stm32mp1_hsidiv(unsigned long hsifreq)
14607839a050SYann Gautier {
14617839a050SYann Gautier 	uint8_t hsidiv;
14627839a050SYann Gautier 	uint32_t hsidivfreq = MAX_HSI_HZ;
14637839a050SYann Gautier 
14647839a050SYann Gautier 	for (hsidiv = 0; hsidiv < 4U; hsidiv++) {
14657839a050SYann Gautier 		if (hsidivfreq == hsifreq) {
14667839a050SYann Gautier 			break;
14677839a050SYann Gautier 		}
14687839a050SYann Gautier 
14697839a050SYann Gautier 		hsidivfreq /= 2U;
14707839a050SYann Gautier 	}
14717839a050SYann Gautier 
14727839a050SYann Gautier 	if (hsidiv == 4U) {
14737839a050SYann Gautier 		ERROR("Invalid clk-hsi frequency\n");
14747839a050SYann Gautier 		return -1;
14757839a050SYann Gautier 	}
14767839a050SYann Gautier 
14777839a050SYann Gautier 	if (hsidiv != 0U) {
14780d21680cSYann Gautier 		return stm32mp1_set_hsidiv(hsidiv);
14797839a050SYann Gautier 	}
14807839a050SYann Gautier 
14817839a050SYann Gautier 	return 0;
14827839a050SYann Gautier }
14837839a050SYann Gautier 
14840d21680cSYann Gautier static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id,
14850d21680cSYann Gautier 				    unsigned int clksrc,
14860d21680cSYann Gautier 				    uint32_t *pllcfg, int plloff)
14877839a050SYann Gautier {
14880d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
14890d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
14900d21680cSYann Gautier 	uintptr_t pllxcr = rcc_base + pll->pllxcr;
14910d21680cSYann Gautier 	enum stm32mp1_plltype type = pll->plltype;
14920d21680cSYann Gautier 	uintptr_t clksrc_address = rcc_base + (clksrc >> 4);
14930d21680cSYann Gautier 	unsigned long refclk;
14940d21680cSYann Gautier 	uint32_t ifrge = 0U;
1495be858cffSAndre Przywara 	uint32_t src, value, fracv = 0;
1496be858cffSAndre Przywara 	void *fdt;
14977839a050SYann Gautier 
14980d21680cSYann Gautier 	/* Check PLL output */
14990d21680cSYann Gautier 	if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) {
15000d21680cSYann Gautier 		return false;
15017839a050SYann Gautier 	}
15027839a050SYann Gautier 
15030d21680cSYann Gautier 	/* Check current clksrc */
15040d21680cSYann Gautier 	src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK;
15050d21680cSYann Gautier 	if (src != (clksrc & RCC_SELR_SRC_MASK)) {
15060d21680cSYann Gautier 		return false;
15070d21680cSYann Gautier 	}
15080d21680cSYann Gautier 
15090d21680cSYann Gautier 	/* Check Div */
15100d21680cSYann Gautier 	src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK;
15110d21680cSYann Gautier 
15120d21680cSYann Gautier 	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
15130d21680cSYann Gautier 		 (pllcfg[PLLCFG_M] + 1U);
15140d21680cSYann Gautier 
15150d21680cSYann Gautier 	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
15160d21680cSYann Gautier 	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
15170d21680cSYann Gautier 		return false;
15180d21680cSYann Gautier 	}
15190d21680cSYann Gautier 
15200d21680cSYann Gautier 	if ((type == PLL_800) && (refclk >= 8000000U)) {
15210d21680cSYann Gautier 		ifrge = 1U;
15220d21680cSYann Gautier 	}
15230d21680cSYann Gautier 
15240d21680cSYann Gautier 	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
15250d21680cSYann Gautier 		RCC_PLLNCFGR1_DIVN_MASK;
15260d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
15270d21680cSYann Gautier 		 RCC_PLLNCFGR1_DIVM_MASK;
15280d21680cSYann Gautier 	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
15290d21680cSYann Gautier 		 RCC_PLLNCFGR1_IFRGE_MASK;
15300d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) {
15310d21680cSYann Gautier 		return false;
15320d21680cSYann Gautier 	}
15330d21680cSYann Gautier 
15340d21680cSYann Gautier 	/* Fractional configuration */
1535be858cffSAndre Przywara 	if (fdt_get_address(&fdt) == 1) {
1536be858cffSAndre Przywara 		fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0);
1537be858cffSAndre Przywara 	}
15380d21680cSYann Gautier 
15390d21680cSYann Gautier 	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
15400d21680cSYann Gautier 	value |= RCC_PLLNFRACR_FRACLE;
15410d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxfracr) != value) {
15420d21680cSYann Gautier 		return false;
15430d21680cSYann Gautier 	}
15440d21680cSYann Gautier 
15450d21680cSYann Gautier 	/* Output config */
15460d21680cSYann Gautier 	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
15470d21680cSYann Gautier 		RCC_PLLNCFGR2_DIVP_MASK;
15480d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
15490d21680cSYann Gautier 		 RCC_PLLNCFGR2_DIVQ_MASK;
15500d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
15510d21680cSYann Gautier 		 RCC_PLLNCFGR2_DIVR_MASK;
15520d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) {
15530d21680cSYann Gautier 		return false;
15540d21680cSYann Gautier 	}
15550d21680cSYann Gautier 
15560d21680cSYann Gautier 	return true;
15570d21680cSYann Gautier }
15580d21680cSYann Gautier 
15590d21680cSYann Gautier static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id)
15607839a050SYann Gautier {
15610d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
15620d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
15630d21680cSYann Gautier 
1564dd98aec8SYann Gautier 	/* Preserve RCC_PLLNCR_SSCG_CTRL value */
1565dd98aec8SYann Gautier 	mmio_clrsetbits_32(pllxcr,
1566dd98aec8SYann Gautier 			   RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
1567dd98aec8SYann Gautier 			   RCC_PLLNCR_DIVREN,
1568dd98aec8SYann Gautier 			   RCC_PLLNCR_PLLON);
15690d21680cSYann Gautier }
15700d21680cSYann Gautier 
15710d21680cSYann Gautier static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output)
15720d21680cSYann Gautier {
15730d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
15740d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
1575dfdb057aSYann Gautier 	uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT);
15767839a050SYann Gautier 
15777839a050SYann Gautier 	/* Wait PLL lock */
15787839a050SYann Gautier 	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) {
1579dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
15809fa9a0c5SYann Gautier 			ERROR("PLL%u start failed @ 0x%lx: 0x%x\n",
15817839a050SYann Gautier 			      pll_id, pllxcr, mmio_read_32(pllxcr));
15827839a050SYann Gautier 			return -ETIMEDOUT;
15837839a050SYann Gautier 		}
15847839a050SYann Gautier 	}
15857839a050SYann Gautier 
15867839a050SYann Gautier 	/* Start the requested output */
15877839a050SYann Gautier 	mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT);
15887839a050SYann Gautier 
15897839a050SYann Gautier 	return 0;
15907839a050SYann Gautier }
15917839a050SYann Gautier 
15920d21680cSYann Gautier static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id)
15937839a050SYann Gautier {
15940d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
15950d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
1596dfdb057aSYann Gautier 	uint64_t timeout;
15977839a050SYann Gautier 
15987839a050SYann Gautier 	/* Stop all output */
15997839a050SYann Gautier 	mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
16007839a050SYann Gautier 			RCC_PLLNCR_DIVREN);
16017839a050SYann Gautier 
16027839a050SYann Gautier 	/* Stop PLL */
16037839a050SYann Gautier 	mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON);
16047839a050SYann Gautier 
1605dfdb057aSYann Gautier 	timeout = timeout_init_us(PLLRDY_TIMEOUT);
16067839a050SYann Gautier 	/* Wait PLL stopped */
16077839a050SYann Gautier 	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) {
1608dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
16099fa9a0c5SYann Gautier 			ERROR("PLL%u stop failed @ 0x%lx: 0x%x\n",
16107839a050SYann Gautier 			      pll_id, pllxcr, mmio_read_32(pllxcr));
16117839a050SYann Gautier 			return -ETIMEDOUT;
16127839a050SYann Gautier 		}
16137839a050SYann Gautier 	}
16147839a050SYann Gautier 
16157839a050SYann Gautier 	return 0;
16167839a050SYann Gautier }
16177839a050SYann Gautier 
16180d21680cSYann Gautier static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id,
16197839a050SYann Gautier 				       uint32_t *pllcfg)
16207839a050SYann Gautier {
16210d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
16220d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
16237839a050SYann Gautier 	uint32_t value;
16247839a050SYann Gautier 
16257839a050SYann Gautier 	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
16267839a050SYann Gautier 		RCC_PLLNCFGR2_DIVP_MASK;
16277839a050SYann Gautier 	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
16287839a050SYann Gautier 		 RCC_PLLNCFGR2_DIVQ_MASK;
16297839a050SYann Gautier 	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
16307839a050SYann Gautier 		 RCC_PLLNCFGR2_DIVR_MASK;
16310d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxcfgr2, value);
16327839a050SYann Gautier }
16337839a050SYann Gautier 
16340d21680cSYann Gautier static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id,
16357839a050SYann Gautier 			       uint32_t *pllcfg, uint32_t fracv)
16367839a050SYann Gautier {
16370d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
16380d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
16390d21680cSYann Gautier 	enum stm32mp1_plltype type = pll->plltype;
16407839a050SYann Gautier 	unsigned long refclk;
16417839a050SYann Gautier 	uint32_t ifrge = 0;
16427839a050SYann Gautier 	uint32_t src, value;
16437839a050SYann Gautier 
16440d21680cSYann Gautier 	src = mmio_read_32(rcc_base + pll->rckxselr) &
16457839a050SYann Gautier 		RCC_SELR_REFCLK_SRC_MASK;
16467839a050SYann Gautier 
16470d21680cSYann Gautier 	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
16487839a050SYann Gautier 		 (pllcfg[PLLCFG_M] + 1U);
16497839a050SYann Gautier 
16507839a050SYann Gautier 	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
16517839a050SYann Gautier 	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
16527839a050SYann Gautier 		return -EINVAL;
16537839a050SYann Gautier 	}
16547839a050SYann Gautier 
16557839a050SYann Gautier 	if ((type == PLL_800) && (refclk >= 8000000U)) {
16567839a050SYann Gautier 		ifrge = 1U;
16577839a050SYann Gautier 	}
16587839a050SYann Gautier 
16597839a050SYann Gautier 	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
16607839a050SYann Gautier 		RCC_PLLNCFGR1_DIVN_MASK;
16617839a050SYann Gautier 	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
16627839a050SYann Gautier 		 RCC_PLLNCFGR1_DIVM_MASK;
16637839a050SYann Gautier 	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
16647839a050SYann Gautier 		 RCC_PLLNCFGR1_IFRGE_MASK;
16650d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxcfgr1, value);
16667839a050SYann Gautier 
16677839a050SYann Gautier 	/* Fractional configuration */
16687839a050SYann Gautier 	value = 0;
16690d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
16707839a050SYann Gautier 
16717839a050SYann Gautier 	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
16720d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
16737839a050SYann Gautier 
16747839a050SYann Gautier 	value |= RCC_PLLNFRACR_FRACLE;
16750d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
16767839a050SYann Gautier 
16770d21680cSYann Gautier 	stm32mp1_pll_config_output(pll_id, pllcfg);
16787839a050SYann Gautier 
16797839a050SYann Gautier 	return 0;
16807839a050SYann Gautier }
16817839a050SYann Gautier 
16820d21680cSYann Gautier static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg)
16837839a050SYann Gautier {
16840d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
16857839a050SYann Gautier 	uint32_t pllxcsg = 0;
16867839a050SYann Gautier 
16877839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) &
16887839a050SYann Gautier 		    RCC_PLLNCSGR_MOD_PER_MASK;
16897839a050SYann Gautier 
16907839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) &
16917839a050SYann Gautier 		    RCC_PLLNCSGR_INC_STEP_MASK;
16927839a050SYann Gautier 
16937839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) &
16947839a050SYann Gautier 		    RCC_PLLNCSGR_SSCG_MODE_MASK;
16957839a050SYann Gautier 
16960d21680cSYann Gautier 	mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg);
1697dd98aec8SYann Gautier 
1698dd98aec8SYann Gautier 	mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr,
1699dd98aec8SYann Gautier 			RCC_PLLNCR_SSCG_CTRL);
17007839a050SYann Gautier }
17017839a050SYann Gautier 
17020d21680cSYann Gautier static int stm32mp1_set_clksrc(unsigned int clksrc)
17037839a050SYann Gautier {
17040d21680cSYann Gautier 	uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4);
1705dfdb057aSYann Gautier 	uint64_t timeout;
17067839a050SYann Gautier 
17070d21680cSYann Gautier 	mmio_clrsetbits_32(clksrc_address, RCC_SELR_SRC_MASK,
17087839a050SYann Gautier 			   clksrc & RCC_SELR_SRC_MASK);
17097839a050SYann Gautier 
1710dfdb057aSYann Gautier 	timeout = timeout_init_us(CLKSRC_TIMEOUT);
17110d21680cSYann Gautier 	while ((mmio_read_32(clksrc_address) & RCC_SELR_SRCRDY) == 0U) {
1712dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
17130d21680cSYann Gautier 			ERROR("CLKSRC %x start failed @ 0x%lx: 0x%x\n", clksrc,
17140d21680cSYann Gautier 			      clksrc_address, mmio_read_32(clksrc_address));
17157839a050SYann Gautier 			return -ETIMEDOUT;
17167839a050SYann Gautier 		}
17177839a050SYann Gautier 	}
17187839a050SYann Gautier 
17197839a050SYann Gautier 	return 0;
17207839a050SYann Gautier }
17217839a050SYann Gautier 
17220d21680cSYann Gautier static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address)
17237839a050SYann Gautier {
1724dfdb057aSYann Gautier 	uint64_t timeout;
17257839a050SYann Gautier 
17267839a050SYann Gautier 	mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK,
17277839a050SYann Gautier 			   clkdiv & RCC_DIVR_DIV_MASK);
17287839a050SYann Gautier 
1729dfdb057aSYann Gautier 	timeout = timeout_init_us(CLKDIV_TIMEOUT);
17307839a050SYann Gautier 	while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) {
1731dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
17320d21680cSYann Gautier 			ERROR("CLKDIV %x start failed @ 0x%lx: 0x%x\n",
17337839a050SYann Gautier 			      clkdiv, address, mmio_read_32(address));
17347839a050SYann Gautier 			return -ETIMEDOUT;
17357839a050SYann Gautier 		}
17367839a050SYann Gautier 	}
17377839a050SYann Gautier 
17387839a050SYann Gautier 	return 0;
17397839a050SYann Gautier }
17407839a050SYann Gautier 
17410d21680cSYann Gautier static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv)
17427839a050SYann Gautier {
17430d21680cSYann Gautier 	uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4);
17447839a050SYann Gautier 
17457839a050SYann Gautier 	/*
17467839a050SYann Gautier 	 * Binding clksrc :
17477839a050SYann Gautier 	 *      bit15-4 offset
17487839a050SYann Gautier 	 *      bit3:   disable
17497839a050SYann Gautier 	 *      bit2-0: MCOSEL[2:0]
17507839a050SYann Gautier 	 */
17517839a050SYann Gautier 	if ((clksrc & 0x8U) != 0U) {
17520d21680cSYann Gautier 		mmio_clrbits_32(clksrc_address, RCC_MCOCFG_MCOON);
17537839a050SYann Gautier 	} else {
17540d21680cSYann Gautier 		mmio_clrsetbits_32(clksrc_address,
17557839a050SYann Gautier 				   RCC_MCOCFG_MCOSRC_MASK,
17567839a050SYann Gautier 				   clksrc & RCC_MCOCFG_MCOSRC_MASK);
17570d21680cSYann Gautier 		mmio_clrsetbits_32(clksrc_address,
17587839a050SYann Gautier 				   RCC_MCOCFG_MCODIV_MASK,
17597839a050SYann Gautier 				   clkdiv << RCC_MCOCFG_MCODIV_SHIFT);
17600d21680cSYann Gautier 		mmio_setbits_32(clksrc_address, RCC_MCOCFG_MCOON);
17617839a050SYann Gautier 	}
17627839a050SYann Gautier }
17637839a050SYann Gautier 
17640d21680cSYann Gautier static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css)
17657839a050SYann Gautier {
17660d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + RCC_BDCR;
17677839a050SYann Gautier 
17687839a050SYann Gautier 	if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) ||
17697839a050SYann Gautier 	    (clksrc != (uint32_t)CLK_RTC_DISABLED)) {
17707839a050SYann Gautier 		mmio_clrsetbits_32(address,
17717839a050SYann Gautier 				   RCC_BDCR_RTCSRC_MASK,
177215509093SYann Gautier 				   (clksrc & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT);
17737839a050SYann Gautier 
17747839a050SYann Gautier 		mmio_setbits_32(address, RCC_BDCR_RTCCKEN);
17757839a050SYann Gautier 	}
17767839a050SYann Gautier 
17777839a050SYann Gautier 	if (lse_css) {
17787839a050SYann Gautier 		mmio_setbits_32(address, RCC_BDCR_LSECSSON);
17797839a050SYann Gautier 	}
17807839a050SYann Gautier }
17817839a050SYann Gautier 
17820d21680cSYann Gautier static void stm32mp1_pkcs_config(uint32_t pkcs)
17837839a050SYann Gautier {
17840d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU);
17857839a050SYann Gautier 	uint32_t value = pkcs & 0xFU;
17867839a050SYann Gautier 	uint32_t mask = 0xFU;
17877839a050SYann Gautier 
17887839a050SYann Gautier 	if ((pkcs & BIT(31)) != 0U) {
17897839a050SYann Gautier 		mask <<= 4;
17907839a050SYann Gautier 		value <<= 4;
17917839a050SYann Gautier 	}
17927839a050SYann Gautier 
17937839a050SYann Gautier 	mmio_clrsetbits_32(address, mask, value);
17947839a050SYann Gautier }
17957839a050SYann Gautier 
1796964e5ff1SNicolas Le Bayon static int clk_get_pll_settings_from_dt(int plloff, unsigned int *pllcfg,
1797964e5ff1SNicolas Le Bayon 					uint32_t *fracv, uint32_t *csg,
1798964e5ff1SNicolas Le Bayon 					bool *csg_set)
1799964e5ff1SNicolas Le Bayon {
1800964e5ff1SNicolas Le Bayon 	void *fdt;
1801964e5ff1SNicolas Le Bayon 	int ret;
1802964e5ff1SNicolas Le Bayon 
1803964e5ff1SNicolas Le Bayon 	if (fdt_get_address(&fdt) == 0) {
1804964e5ff1SNicolas Le Bayon 		return -FDT_ERR_NOTFOUND;
1805964e5ff1SNicolas Le Bayon 	}
1806964e5ff1SNicolas Le Bayon 
1807964e5ff1SNicolas Le Bayon 	ret = fdt_read_uint32_array(fdt, plloff, "cfg", (uint32_t)PLLCFG_NB,
1808964e5ff1SNicolas Le Bayon 				    pllcfg);
1809964e5ff1SNicolas Le Bayon 	if (ret < 0) {
1810964e5ff1SNicolas Le Bayon 		return -FDT_ERR_NOTFOUND;
1811964e5ff1SNicolas Le Bayon 	}
1812964e5ff1SNicolas Le Bayon 
1813964e5ff1SNicolas Le Bayon 	*fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0);
1814964e5ff1SNicolas Le Bayon 
1815964e5ff1SNicolas Le Bayon 	ret = fdt_read_uint32_array(fdt, plloff, "csg", (uint32_t)PLLCSG_NB,
1816964e5ff1SNicolas Le Bayon 				    csg);
1817964e5ff1SNicolas Le Bayon 
1818964e5ff1SNicolas Le Bayon 	*csg_set = (ret == 0);
1819964e5ff1SNicolas Le Bayon 
1820964e5ff1SNicolas Le Bayon 	if (ret == -FDT_ERR_NOTFOUND) {
1821964e5ff1SNicolas Le Bayon 		ret = 0;
1822964e5ff1SNicolas Le Bayon 	}
1823964e5ff1SNicolas Le Bayon 
1824964e5ff1SNicolas Le Bayon 	return ret;
1825964e5ff1SNicolas Le Bayon }
1826964e5ff1SNicolas Le Bayon 
1827*f6559227SYann Gautier static int clk_compute_pll1_settings(unsigned long input_freq,
1828*f6559227SYann Gautier 				     uint32_t freq_khz,
1829*f6559227SYann Gautier 				     uint32_t *pllcfg, uint32_t *fracv)
1830*f6559227SYann Gautier {
1831*f6559227SYann Gautier 	unsigned long long best_diff = ULLONG_MAX;
1832*f6559227SYann Gautier 	unsigned int divm;
1833*f6559227SYann Gautier 
1834*f6559227SYann Gautier 	/* Following parameters have always the same value */
1835*f6559227SYann Gautier 	pllcfg[PLLCFG_Q] = 0U;
1836*f6559227SYann Gautier 	pllcfg[PLLCFG_R] = 0U;
1837*f6559227SYann Gautier 	pllcfg[PLLCFG_O] = PQR(1, 0, 0);
1838*f6559227SYann Gautier 
1839*f6559227SYann Gautier 	for (divm = (DIVM_MAX + 1U); divm != DIVM_MIN; divm--) {
1840*f6559227SYann Gautier 		unsigned long post_divm = input_freq / divm;
1841*f6559227SYann Gautier 		unsigned int divp;
1842*f6559227SYann Gautier 
1843*f6559227SYann Gautier 		if ((post_divm < POST_DIVM_MIN) || (post_divm > POST_DIVM_MAX)) {
1844*f6559227SYann Gautier 			continue;
1845*f6559227SYann Gautier 		}
1846*f6559227SYann Gautier 
1847*f6559227SYann Gautier 		for (divp = DIVP_MIN; divp <= DIVP_MAX; divp++) {
1848*f6559227SYann Gautier 			unsigned long long output_freq = freq_khz * 1000ULL;
1849*f6559227SYann Gautier 			unsigned long long freq;
1850*f6559227SYann Gautier 			unsigned long long divn;
1851*f6559227SYann Gautier 			unsigned long long frac;
1852*f6559227SYann Gautier 			unsigned int i;
1853*f6559227SYann Gautier 
1854*f6559227SYann Gautier 			freq = output_freq * divm * (divp + 1U);
1855*f6559227SYann Gautier 
1856*f6559227SYann Gautier 			divn = (freq / input_freq) - 1U;
1857*f6559227SYann Gautier 			if ((divn < DIVN_MIN) || (divn > DIVN_MAX)) {
1858*f6559227SYann Gautier 				continue;
1859*f6559227SYann Gautier 			}
1860*f6559227SYann Gautier 
1861*f6559227SYann Gautier 			frac = ((freq * FRAC_MAX) / input_freq) - ((divn + 1U) * FRAC_MAX);
1862*f6559227SYann Gautier 
1863*f6559227SYann Gautier 			/* 2 loops to refine the fractional part */
1864*f6559227SYann Gautier 			for (i = 2U; i != 0U; i--) {
1865*f6559227SYann Gautier 				unsigned long long diff;
1866*f6559227SYann Gautier 				unsigned long long vco;
1867*f6559227SYann Gautier 
1868*f6559227SYann Gautier 				if (frac > FRAC_MAX) {
1869*f6559227SYann Gautier 					break;
1870*f6559227SYann Gautier 				}
1871*f6559227SYann Gautier 
1872*f6559227SYann Gautier 				vco = (post_divm * (divn + 1U)) + ((post_divm * frac) / FRAC_MAX);
1873*f6559227SYann Gautier 
1874*f6559227SYann Gautier 				if ((vco < (VCO_MIN / 2U)) || (vco > (VCO_MAX / 2U))) {
1875*f6559227SYann Gautier 					frac++;
1876*f6559227SYann Gautier 					continue;
1877*f6559227SYann Gautier 				}
1878*f6559227SYann Gautier 
1879*f6559227SYann Gautier 				freq = vco / (divp + 1U);
1880*f6559227SYann Gautier 				if (output_freq < freq) {
1881*f6559227SYann Gautier 					diff = freq - output_freq;
1882*f6559227SYann Gautier 				} else {
1883*f6559227SYann Gautier 					diff = output_freq - freq;
1884*f6559227SYann Gautier 				}
1885*f6559227SYann Gautier 
1886*f6559227SYann Gautier 				if (diff < best_diff)  {
1887*f6559227SYann Gautier 					pllcfg[PLLCFG_M] = divm - 1U;
1888*f6559227SYann Gautier 					pllcfg[PLLCFG_N] = (uint32_t)divn;
1889*f6559227SYann Gautier 					pllcfg[PLLCFG_P] = divp;
1890*f6559227SYann Gautier 					*fracv = (uint32_t)frac;
1891*f6559227SYann Gautier 
1892*f6559227SYann Gautier 					if (diff == 0U) {
1893*f6559227SYann Gautier 						return 0;
1894*f6559227SYann Gautier 					}
1895*f6559227SYann Gautier 
1896*f6559227SYann Gautier 					best_diff = diff;
1897*f6559227SYann Gautier 				}
1898*f6559227SYann Gautier 
1899*f6559227SYann Gautier 				frac++;
1900*f6559227SYann Gautier 			}
1901*f6559227SYann Gautier 		}
1902*f6559227SYann Gautier 	}
1903*f6559227SYann Gautier 
1904*f6559227SYann Gautier 	if (best_diff == ULLONG_MAX) {
1905*f6559227SYann Gautier 		return -EINVAL;
1906*f6559227SYann Gautier 	}
1907*f6559227SYann Gautier 
1908*f6559227SYann Gautier 	return 0;
1909*f6559227SYann Gautier }
1910*f6559227SYann Gautier 
1911*f6559227SYann Gautier static int clk_get_pll1_settings(uint32_t clksrc, uint32_t freq_khz,
1912*f6559227SYann Gautier 				 uint32_t *pllcfg, uint32_t *fracv)
1913*f6559227SYann Gautier {
1914*f6559227SYann Gautier 	unsigned long input_freq = 0UL;
1915*f6559227SYann Gautier 
1916*f6559227SYann Gautier 	assert(pllcfg != NULL);
1917*f6559227SYann Gautier 	assert(fracv != NULL);
1918*f6559227SYann Gautier 
1919*f6559227SYann Gautier 	switch (clksrc) {
1920*f6559227SYann Gautier 	case CLK_PLL12_HSI:
1921*f6559227SYann Gautier 		input_freq = stm32mp_clk_get_rate(CK_HSI);
1922*f6559227SYann Gautier 		break;
1923*f6559227SYann Gautier 	case CLK_PLL12_HSE:
1924*f6559227SYann Gautier 		input_freq = stm32mp_clk_get_rate(CK_HSE);
1925*f6559227SYann Gautier 		break;
1926*f6559227SYann Gautier 	default:
1927*f6559227SYann Gautier 		break;
1928*f6559227SYann Gautier 	}
1929*f6559227SYann Gautier 
1930*f6559227SYann Gautier 	if (input_freq == 0UL) {
1931*f6559227SYann Gautier 		panic();
1932*f6559227SYann Gautier 	}
1933*f6559227SYann Gautier 
1934*f6559227SYann Gautier 	return clk_compute_pll1_settings(input_freq, freq_khz, pllcfg, fracv);
1935*f6559227SYann Gautier }
1936*f6559227SYann Gautier 
19377839a050SYann Gautier int stm32mp1_clk_init(void)
19387839a050SYann Gautier {
19390d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
1940964e5ff1SNicolas Le Bayon 	uint32_t pllfracv[_PLL_NB];
1941964e5ff1SNicolas Le Bayon 	uint32_t pllcsg[_PLL_NB][PLLCSG_NB];
19427839a050SYann Gautier 	unsigned int clksrc[CLKSRC_NB];
19437839a050SYann Gautier 	unsigned int clkdiv[CLKDIV_NB];
19447839a050SYann Gautier 	unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
19457839a050SYann Gautier 	int plloff[_PLL_NB];
19467839a050SYann Gautier 	int ret, len;
19477839a050SYann Gautier 	enum stm32mp1_pll_id i;
1948964e5ff1SNicolas Le Bayon 	bool pllcsg_set[_PLL_NB];
1949964e5ff1SNicolas Le Bayon 	bool pllcfg_valid[_PLL_NB];
19507839a050SYann Gautier 	bool lse_css = false;
19510d21680cSYann Gautier 	bool pll3_preserve = false;
19520d21680cSYann Gautier 	bool pll4_preserve = false;
19530d21680cSYann Gautier 	bool pll4_bootrom = false;
19543e6fab43SYann Gautier 	const fdt32_t *pkcs_cell;
195552a616b4SAndre Przywara 	void *fdt;
1956bf1af154SPatrick Delaunay 	int stgen_p = stm32mp1_clk_get_parent(STGEN_K);
1957bf1af154SPatrick Delaunay 	int usbphy_p = stm32mp1_clk_get_parent(USBPHY_K);
195852a616b4SAndre Przywara 
195952a616b4SAndre Przywara 	if (fdt_get_address(&fdt) == 0) {
19608f97c4faSYann Gautier 		return -FDT_ERR_NOTFOUND;
196152a616b4SAndre Przywara 	}
19627839a050SYann Gautier 
196352a616b4SAndre Przywara 	ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB,
196452a616b4SAndre Przywara 					clksrc);
19657839a050SYann Gautier 	if (ret < 0) {
19667839a050SYann Gautier 		return -FDT_ERR_NOTFOUND;
19677839a050SYann Gautier 	}
19687839a050SYann Gautier 
196952a616b4SAndre Przywara 	ret = fdt_rcc_read_uint32_array("st,clkdiv", (uint32_t)CLKDIV_NB,
197052a616b4SAndre Przywara 					clkdiv);
19717839a050SYann Gautier 	if (ret < 0) {
19727839a050SYann Gautier 		return -FDT_ERR_NOTFOUND;
19737839a050SYann Gautier 	}
19747839a050SYann Gautier 
19757839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
19767839a050SYann Gautier 		char name[12];
19777839a050SYann Gautier 
19789fa9a0c5SYann Gautier 		snprintf(name, sizeof(name), "st,pll@%u", i);
19797839a050SYann Gautier 		plloff[i] = fdt_rcc_subnode_offset(name);
19807839a050SYann Gautier 
1981964e5ff1SNicolas Le Bayon 		pllcfg_valid[i] = fdt_check_node(plloff[i]);
1982*f6559227SYann Gautier 		if (pllcfg_valid[i]) {
1983964e5ff1SNicolas Le Bayon 			ret = clk_get_pll_settings_from_dt(plloff[i], pllcfg[i],
1984*f6559227SYann Gautier 							   &pllfracv[i],
1985*f6559227SYann Gautier 							   pllcsg[i],
1986964e5ff1SNicolas Le Bayon 							   &pllcsg_set[i]);
1987964e5ff1SNicolas Le Bayon 			if (ret != 0) {
1988964e5ff1SNicolas Le Bayon 				return ret;
19897839a050SYann Gautier 			}
1990*f6559227SYann Gautier 
1991*f6559227SYann Gautier 			continue;
1992*f6559227SYann Gautier 		}
1993*f6559227SYann Gautier 
1994*f6559227SYann Gautier 		if (i == _PLL1) {
1995*f6559227SYann Gautier 			ret = clk_get_pll1_settings(clksrc[CLKSRC_PLL12],
1996*f6559227SYann Gautier 						    PLL1_NOMINAL_FREQ_IN_KHZ,
1997*f6559227SYann Gautier 						    pllcfg[i], &pllfracv[i]);
1998*f6559227SYann Gautier 			if (ret != 0) {
1999*f6559227SYann Gautier 				return ret;
2000*f6559227SYann Gautier 			}
2001*f6559227SYann Gautier 
2002*f6559227SYann Gautier 			pllcfg_valid[i] = true;
2003*f6559227SYann Gautier 		}
20047839a050SYann Gautier 	}
20057839a050SYann Gautier 
20060d21680cSYann Gautier 	stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]);
20070d21680cSYann Gautier 	stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]);
20087839a050SYann Gautier 
20097839a050SYann Gautier 	/*
20107839a050SYann Gautier 	 * Switch ON oscillator found in device-tree.
20117839a050SYann Gautier 	 * Note: HSI already ON after BootROM stage.
20127839a050SYann Gautier 	 */
20130d21680cSYann Gautier 	if (stm32mp1_osc[_LSI] != 0U) {
20140d21680cSYann Gautier 		stm32mp1_lsi_set(true);
20157839a050SYann Gautier 	}
20160d21680cSYann Gautier 	if (stm32mp1_osc[_LSE] != 0U) {
2017b208e3daSGabriel Fernandez 		const char *name = stm32mp_osc_node_label[_LSE];
20180d21680cSYann Gautier 		bool bypass, digbyp;
20197839a050SYann Gautier 		uint32_t lsedrv;
20207839a050SYann Gautier 
2021b208e3daSGabriel Fernandez 		bypass = fdt_clk_read_bool(name, "st,bypass");
2022b208e3daSGabriel Fernandez 		digbyp = fdt_clk_read_bool(name, "st,digbypass");
2023b208e3daSGabriel Fernandez 		lse_css = fdt_clk_read_bool(name, "st,css");
2024b208e3daSGabriel Fernandez 		lsedrv = fdt_clk_read_uint32_default(name, "st,drive",
20257839a050SYann Gautier 						     LSEDRV_MEDIUM_HIGH);
20260d21680cSYann Gautier 		stm32mp1_lse_enable(bypass, digbyp, lsedrv);
20277839a050SYann Gautier 	}
20280d21680cSYann Gautier 	if (stm32mp1_osc[_HSE] != 0U) {
2029b208e3daSGabriel Fernandez 		const char *name = stm32mp_osc_node_label[_HSE];
20300d21680cSYann Gautier 		bool bypass, digbyp, css;
20317839a050SYann Gautier 
2032b208e3daSGabriel Fernandez 		bypass = fdt_clk_read_bool(name, "st,bypass");
2033b208e3daSGabriel Fernandez 		digbyp = fdt_clk_read_bool(name, "st,digbypass");
2034b208e3daSGabriel Fernandez 		css = fdt_clk_read_bool(name, "st,css");
20350d21680cSYann Gautier 		stm32mp1_hse_enable(bypass, digbyp, css);
20367839a050SYann Gautier 	}
20377839a050SYann Gautier 	/*
20387839a050SYann Gautier 	 * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR)
20397839a050SYann Gautier 	 * => switch on CSI even if node is not present in device tree
20407839a050SYann Gautier 	 */
20410d21680cSYann Gautier 	stm32mp1_csi_set(true);
20427839a050SYann Gautier 
20437839a050SYann Gautier 	/* Come back to HSI */
20440d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(CLK_MPU_HSI);
20457839a050SYann Gautier 	if (ret != 0) {
20467839a050SYann Gautier 		return ret;
20477839a050SYann Gautier 	}
20480d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(CLK_AXI_HSI);
20497839a050SYann Gautier 	if (ret != 0) {
20507839a050SYann Gautier 		return ret;
20517839a050SYann Gautier 	}
2052b053a22eSYann Gautier 	ret = stm32mp1_set_clksrc(CLK_MCU_HSI);
2053b053a22eSYann Gautier 	if (ret != 0) {
2054b053a22eSYann Gautier 		return ret;
2055b053a22eSYann Gautier 	}
20567839a050SYann Gautier 
20570d21680cSYann Gautier 	if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) &
20580d21680cSYann Gautier 	     RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) {
2059175758b2SYann Gautier 		if (pllcfg_valid[_PLL3]) {
2060175758b2SYann Gautier 			pll3_preserve =
2061175758b2SYann Gautier 				stm32mp1_check_pll_conf(_PLL3,
20620d21680cSYann Gautier 							clksrc[CLKSRC_PLL3],
20630d21680cSYann Gautier 							pllcfg[_PLL3],
20640d21680cSYann Gautier 							plloff[_PLL3]);
2065175758b2SYann Gautier 		}
2066175758b2SYann Gautier 
2067175758b2SYann Gautier 		if (pllcfg_valid[_PLL4]) {
2068175758b2SYann Gautier 			pll4_preserve =
2069175758b2SYann Gautier 				stm32mp1_check_pll_conf(_PLL4,
20700d21680cSYann Gautier 							clksrc[CLKSRC_PLL4],
20710d21680cSYann Gautier 							pllcfg[_PLL4],
20720d21680cSYann Gautier 							plloff[_PLL4]);
20730d21680cSYann Gautier 		}
2074175758b2SYann Gautier 	}
2075bf1af154SPatrick Delaunay 	/* Don't initialize PLL4, when used by BOOTROM */
2076bf1af154SPatrick Delaunay 	if ((stm32mp_get_boot_itf_selected() ==
2077bf1af154SPatrick Delaunay 	     BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) &&
2078bf1af154SPatrick Delaunay 	    ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) {
2079bf1af154SPatrick Delaunay 		pll4_bootrom = true;
2080bf1af154SPatrick Delaunay 		pll4_preserve = true;
2081bf1af154SPatrick Delaunay 	}
20820d21680cSYann Gautier 
20837839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
20840d21680cSYann Gautier 		if (((i == _PLL3) && pll3_preserve) ||
20850d21680cSYann Gautier 		    ((i == _PLL4) && pll4_preserve)) {
20867839a050SYann Gautier 			continue;
20870d21680cSYann Gautier 		}
20880d21680cSYann Gautier 
20890d21680cSYann Gautier 		ret = stm32mp1_pll_stop(i);
20907839a050SYann Gautier 		if (ret != 0) {
20917839a050SYann Gautier 			return ret;
20927839a050SYann Gautier 		}
20937839a050SYann Gautier 	}
20947839a050SYann Gautier 
20957839a050SYann Gautier 	/* Configure HSIDIV */
20960d21680cSYann Gautier 	if (stm32mp1_osc[_HSI] != 0U) {
20970d21680cSYann Gautier 		ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]);
20987839a050SYann Gautier 		if (ret != 0) {
20997839a050SYann Gautier 			return ret;
21007839a050SYann Gautier 		}
2101591d80c8SLionel Debieve 
2102591d80c8SLionel Debieve 		stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
21037839a050SYann Gautier 	}
21047839a050SYann Gautier 
21057839a050SYann Gautier 	/* Select DIV */
21067839a050SYann Gautier 	/* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */
21070d21680cSYann Gautier 	mmio_write_32(rcc_base + RCC_MPCKDIVR,
21087839a050SYann Gautier 		      clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK);
21090d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR);
21107839a050SYann Gautier 	if (ret != 0) {
21117839a050SYann Gautier 		return ret;
21127839a050SYann Gautier 	}
21130d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR);
21147839a050SYann Gautier 	if (ret != 0) {
21157839a050SYann Gautier 		return ret;
21167839a050SYann Gautier 	}
21170d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR);
21187839a050SYann Gautier 	if (ret != 0) {
21197839a050SYann Gautier 		return ret;
21207839a050SYann Gautier 	}
2121b053a22eSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR);
2122b053a22eSYann Gautier 	if (ret != 0) {
2123b053a22eSYann Gautier 		return ret;
2124b053a22eSYann Gautier 	}
21250d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR);
21267839a050SYann Gautier 	if (ret != 0) {
21277839a050SYann Gautier 		return ret;
21287839a050SYann Gautier 	}
21290d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR);
21307839a050SYann Gautier 	if (ret != 0) {
21317839a050SYann Gautier 		return ret;
21327839a050SYann Gautier 	}
21330d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR);
21347839a050SYann Gautier 	if (ret != 0) {
21357839a050SYann Gautier 		return ret;
21367839a050SYann Gautier 	}
21377839a050SYann Gautier 
21387839a050SYann Gautier 	/* No ready bit for RTC */
21390d21680cSYann Gautier 	mmio_write_32(rcc_base + RCC_RTCDIVR,
21407839a050SYann Gautier 		      clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK);
21417839a050SYann Gautier 
21427839a050SYann Gautier 	/* Configure PLLs source */
21430d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]);
21447839a050SYann Gautier 	if (ret != 0) {
21457839a050SYann Gautier 		return ret;
21467839a050SYann Gautier 	}
21477839a050SYann Gautier 
21480d21680cSYann Gautier 	if (!pll3_preserve) {
21490d21680cSYann Gautier 		ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]);
21507839a050SYann Gautier 		if (ret != 0) {
21517839a050SYann Gautier 			return ret;
21527839a050SYann Gautier 		}
21530d21680cSYann Gautier 	}
21540d21680cSYann Gautier 
21550d21680cSYann Gautier 	if (!pll4_preserve) {
21560d21680cSYann Gautier 		ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]);
21570d21680cSYann Gautier 		if (ret != 0) {
21580d21680cSYann Gautier 			return ret;
21590d21680cSYann Gautier 		}
21600d21680cSYann Gautier 	}
21617839a050SYann Gautier 
21627839a050SYann Gautier 	/* Configure and start PLLs */
21637839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
21640d21680cSYann Gautier 		if (((i == _PLL3) && pll3_preserve) ||
21650d21680cSYann Gautier 		    ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) {
21660d21680cSYann Gautier 			continue;
21670d21680cSYann Gautier 		}
21680d21680cSYann Gautier 
2169964e5ff1SNicolas Le Bayon 		if (!pllcfg_valid[i]) {
21707839a050SYann Gautier 			continue;
21717839a050SYann Gautier 		}
21727839a050SYann Gautier 
21730d21680cSYann Gautier 		if ((i == _PLL4) && pll4_bootrom) {
21740d21680cSYann Gautier 			/* Set output divider if not done by the Bootrom */
21750d21680cSYann Gautier 			stm32mp1_pll_config_output(i, pllcfg[i]);
21760d21680cSYann Gautier 			continue;
21770d21680cSYann Gautier 		}
21780d21680cSYann Gautier 
2179964e5ff1SNicolas Le Bayon 		ret = stm32mp1_pll_config(i, pllcfg[i], pllfracv[i]);
21807839a050SYann Gautier 		if (ret != 0) {
21817839a050SYann Gautier 			return ret;
21827839a050SYann Gautier 		}
2183964e5ff1SNicolas Le Bayon 
2184964e5ff1SNicolas Le Bayon 		if (pllcsg_set[i]) {
2185964e5ff1SNicolas Le Bayon 			stm32mp1_pll_csg(i, pllcsg[i]);
21867839a050SYann Gautier 		}
21877839a050SYann Gautier 
21880d21680cSYann Gautier 		stm32mp1_pll_start(i);
21897839a050SYann Gautier 	}
21901b491eeaSElyes Haouas 	/* Wait and start PLLs output when ready */
21917839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
2192964e5ff1SNicolas Le Bayon 		if (!pllcfg_valid[i]) {
21937839a050SYann Gautier 			continue;
21947839a050SYann Gautier 		}
21957839a050SYann Gautier 
21960d21680cSYann Gautier 		ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]);
21977839a050SYann Gautier 		if (ret != 0) {
21987839a050SYann Gautier 			return ret;
21997839a050SYann Gautier 		}
22007839a050SYann Gautier 	}
22017839a050SYann Gautier 	/* Wait LSE ready before to use it */
22020d21680cSYann Gautier 	if (stm32mp1_osc[_LSE] != 0U) {
22030d21680cSYann Gautier 		stm32mp1_lse_wait();
22047839a050SYann Gautier 	}
22057839a050SYann Gautier 
22067839a050SYann Gautier 	/* Configure with expected clock source */
22070d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]);
22087839a050SYann Gautier 	if (ret != 0) {
22097839a050SYann Gautier 		return ret;
22107839a050SYann Gautier 	}
22110d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]);
22127839a050SYann Gautier 	if (ret != 0) {
22137839a050SYann Gautier 		return ret;
22147839a050SYann Gautier 	}
2215b053a22eSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]);
2216b053a22eSYann Gautier 	if (ret != 0) {
2217b053a22eSYann Gautier 		return ret;
2218b053a22eSYann Gautier 	}
22190d21680cSYann Gautier 	stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css);
22207839a050SYann Gautier 
22217839a050SYann Gautier 	/* Configure PKCK */
22227839a050SYann Gautier 	pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len);
22237839a050SYann Gautier 	if (pkcs_cell != NULL) {
22247839a050SYann Gautier 		bool ckper_disabled = false;
22257839a050SYann Gautier 		uint32_t j;
2226bf1af154SPatrick Delaunay 		uint32_t usbreg_bootrom = 0U;
2227bf1af154SPatrick Delaunay 
2228bf1af154SPatrick Delaunay 		if (pll4_bootrom) {
2229bf1af154SPatrick Delaunay 			usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR);
2230bf1af154SPatrick Delaunay 		}
22317839a050SYann Gautier 
22327839a050SYann Gautier 		for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) {
22333e6fab43SYann Gautier 			uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]);
22347839a050SYann Gautier 
22357839a050SYann Gautier 			if (pkcs == (uint32_t)CLK_CKPER_DISABLED) {
22367839a050SYann Gautier 				ckper_disabled = true;
22377839a050SYann Gautier 				continue;
22387839a050SYann Gautier 			}
22390d21680cSYann Gautier 			stm32mp1_pkcs_config(pkcs);
22407839a050SYann Gautier 		}
22417839a050SYann Gautier 
22427839a050SYann Gautier 		/*
22437839a050SYann Gautier 		 * CKPER is source for some peripheral clocks
22447839a050SYann Gautier 		 * (FMC-NAND / QPSI-NOR) and switching source is allowed
22457839a050SYann Gautier 		 * only if previous clock is still ON
22467839a050SYann Gautier 		 * => deactivated CKPER only after switching clock
22477839a050SYann Gautier 		 */
22487839a050SYann Gautier 		if (ckper_disabled) {
22490d21680cSYann Gautier 			stm32mp1_pkcs_config(CLK_CKPER_DISABLED);
22507839a050SYann Gautier 		}
2251bf1af154SPatrick Delaunay 
2252bf1af154SPatrick Delaunay 		if (pll4_bootrom) {
2253bf1af154SPatrick Delaunay 			uint32_t usbreg_value, usbreg_mask;
2254bf1af154SPatrick Delaunay 			const struct stm32mp1_clk_sel *sel;
2255bf1af154SPatrick Delaunay 
2256bf1af154SPatrick Delaunay 			sel = clk_sel_ref(_USBPHY_SEL);
2257bf1af154SPatrick Delaunay 			usbreg_mask = (uint32_t)sel->msk << sel->src;
2258bf1af154SPatrick Delaunay 			sel = clk_sel_ref(_USBO_SEL);
2259bf1af154SPatrick Delaunay 			usbreg_mask |= (uint32_t)sel->msk << sel->src;
2260bf1af154SPatrick Delaunay 
2261bf1af154SPatrick Delaunay 			usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) &
2262bf1af154SPatrick Delaunay 				       usbreg_mask;
2263bf1af154SPatrick Delaunay 			usbreg_bootrom &= usbreg_mask;
2264bf1af154SPatrick Delaunay 			if (usbreg_bootrom != usbreg_value) {
2265bf1af154SPatrick Delaunay 				VERBOSE("forbidden new USB clk path\n");
2266bf1af154SPatrick Delaunay 				VERBOSE("vs bootrom on USB boot\n");
2267bf1af154SPatrick Delaunay 				return -FDT_ERR_BADVALUE;
2268bf1af154SPatrick Delaunay 			}
2269bf1af154SPatrick Delaunay 		}
22707839a050SYann Gautier 	}
22717839a050SYann Gautier 
22727839a050SYann Gautier 	/* Switch OFF HSI if not found in device-tree */
22730d21680cSYann Gautier 	if (stm32mp1_osc[_HSI] == 0U) {
22740d21680cSYann Gautier 		stm32mp1_hsi_set(false);
22757839a050SYann Gautier 	}
2276591d80c8SLionel Debieve 
2277591d80c8SLionel Debieve 	stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
22787839a050SYann Gautier 
22797839a050SYann Gautier 	/* Software Self-Refresh mode (SSR) during DDR initilialization */
22800d21680cSYann Gautier 	mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR,
22817839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_MASK,
22827839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_SSR <<
22837839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_SHIFT);
22847839a050SYann Gautier 
22857839a050SYann Gautier 	return 0;
22867839a050SYann Gautier }
22877839a050SYann Gautier 
22887839a050SYann Gautier static void stm32mp1_osc_clk_init(const char *name,
22897839a050SYann Gautier 				  enum stm32mp_osc_id index)
22907839a050SYann Gautier {
22917839a050SYann Gautier 	uint32_t frequency;
22927839a050SYann Gautier 
22930d21680cSYann Gautier 	if (fdt_osc_read_freq(name, &frequency) == 0) {
22940d21680cSYann Gautier 		stm32mp1_osc[index] = frequency;
22957839a050SYann Gautier 	}
22967839a050SYann Gautier }
22977839a050SYann Gautier 
22987839a050SYann Gautier static void stm32mp1_osc_init(void)
22997839a050SYann Gautier {
23007839a050SYann Gautier 	enum stm32mp_osc_id i;
23017839a050SYann Gautier 
23027839a050SYann Gautier 	for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) {
23030d21680cSYann Gautier 		stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i);
23047839a050SYann Gautier 	}
23057839a050SYann Gautier }
23067839a050SYann Gautier 
230737e8295aSEtienne Carriere #ifdef STM32MP_SHARED_RESOURCES
230837e8295aSEtienne Carriere /*
230937e8295aSEtienne Carriere  * Get the parent ID of the target parent clock, for tagging as secure
231037e8295aSEtienne Carriere  * shared clock dependencies.
231137e8295aSEtienne Carriere  */
231237e8295aSEtienne Carriere static int get_parent_id_parent(unsigned int parent_id)
231337e8295aSEtienne Carriere {
231437e8295aSEtienne Carriere 	enum stm32mp1_parent_sel s = _UNKNOWN_SEL;
231537e8295aSEtienne Carriere 	enum stm32mp1_pll_id pll_id;
231637e8295aSEtienne Carriere 	uint32_t p_sel;
231737e8295aSEtienne Carriere 	uintptr_t rcc_base = stm32mp_rcc_base();
231837e8295aSEtienne Carriere 
231937e8295aSEtienne Carriere 	switch (parent_id) {
232037e8295aSEtienne Carriere 	case _ACLK:
232137e8295aSEtienne Carriere 	case _PCLK4:
232237e8295aSEtienne Carriere 	case _PCLK5:
232337e8295aSEtienne Carriere 		s = _AXIS_SEL;
232437e8295aSEtienne Carriere 		break;
232537e8295aSEtienne Carriere 	case _PLL1_P:
232637e8295aSEtienne Carriere 	case _PLL1_Q:
232737e8295aSEtienne Carriere 	case _PLL1_R:
232837e8295aSEtienne Carriere 		pll_id = _PLL1;
232937e8295aSEtienne Carriere 		break;
233037e8295aSEtienne Carriere 	case _PLL2_P:
233137e8295aSEtienne Carriere 	case _PLL2_Q:
233237e8295aSEtienne Carriere 	case _PLL2_R:
233337e8295aSEtienne Carriere 		pll_id = _PLL2;
233437e8295aSEtienne Carriere 		break;
233537e8295aSEtienne Carriere 	case _PLL3_P:
233637e8295aSEtienne Carriere 	case _PLL3_Q:
233737e8295aSEtienne Carriere 	case _PLL3_R:
233837e8295aSEtienne Carriere 		pll_id = _PLL3;
233937e8295aSEtienne Carriere 		break;
234037e8295aSEtienne Carriere 	case _PLL4_P:
234137e8295aSEtienne Carriere 	case _PLL4_Q:
234237e8295aSEtienne Carriere 	case _PLL4_R:
234337e8295aSEtienne Carriere 		pll_id = _PLL4;
234437e8295aSEtienne Carriere 		break;
234537e8295aSEtienne Carriere 	case _PCLK1:
234637e8295aSEtienne Carriere 	case _PCLK2:
234737e8295aSEtienne Carriere 	case _HCLK2:
234837e8295aSEtienne Carriere 	case _HCLK6:
234937e8295aSEtienne Carriere 	case _CK_PER:
235037e8295aSEtienne Carriere 	case _CK_MPU:
235137e8295aSEtienne Carriere 	case _CK_MCU:
235237e8295aSEtienne Carriere 	case _USB_PHY_48:
235337e8295aSEtienne Carriere 		/* We do not expect to access these */
235437e8295aSEtienne Carriere 		panic();
235537e8295aSEtienne Carriere 		break;
235637e8295aSEtienne Carriere 	default:
235737e8295aSEtienne Carriere 		/* Other parents have no parent */
235837e8295aSEtienne Carriere 		return -1;
235937e8295aSEtienne Carriere 	}
236037e8295aSEtienne Carriere 
236137e8295aSEtienne Carriere 	if (s != _UNKNOWN_SEL) {
236237e8295aSEtienne Carriere 		const struct stm32mp1_clk_sel *sel = clk_sel_ref(s);
236337e8295aSEtienne Carriere 
236437e8295aSEtienne Carriere 		p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) &
236537e8295aSEtienne Carriere 			sel->msk;
236637e8295aSEtienne Carriere 
236737e8295aSEtienne Carriere 		if (p_sel < sel->nb_parent) {
236837e8295aSEtienne Carriere 			return (int)sel->parent[p_sel];
236937e8295aSEtienne Carriere 		}
237037e8295aSEtienne Carriere 	} else {
237137e8295aSEtienne Carriere 		const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
237237e8295aSEtienne Carriere 
237337e8295aSEtienne Carriere 		p_sel = mmio_read_32(rcc_base + pll->rckxselr) &
237437e8295aSEtienne Carriere 			RCC_SELR_REFCLK_SRC_MASK;
237537e8295aSEtienne Carriere 
237637e8295aSEtienne Carriere 		if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) {
237737e8295aSEtienne Carriere 			return (int)pll->refclk[p_sel];
237837e8295aSEtienne Carriere 		}
237937e8295aSEtienne Carriere 	}
238037e8295aSEtienne Carriere 
238137e8295aSEtienne Carriere 	VERBOSE("No parent selected for %s\n",
238237e8295aSEtienne Carriere 		stm32mp1_clk_parent_name[parent_id]);
238337e8295aSEtienne Carriere 
238437e8295aSEtienne Carriere 	return -1;
238537e8295aSEtienne Carriere }
238637e8295aSEtienne Carriere 
238737e8295aSEtienne Carriere static void secure_parent_clocks(unsigned long parent_id)
238837e8295aSEtienne Carriere {
238937e8295aSEtienne Carriere 	int grandparent_id;
239037e8295aSEtienne Carriere 
239137e8295aSEtienne Carriere 	switch (parent_id) {
239237e8295aSEtienne Carriere 	case _PLL3_P:
239337e8295aSEtienne Carriere 	case _PLL3_Q:
239437e8295aSEtienne Carriere 	case _PLL3_R:
239537e8295aSEtienne Carriere 		stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
239637e8295aSEtienne Carriere 		break;
239737e8295aSEtienne Carriere 
239837e8295aSEtienne Carriere 	/* These clocks are always secure when RCC is secure */
239937e8295aSEtienne Carriere 	case _ACLK:
240037e8295aSEtienne Carriere 	case _HCLK2:
240137e8295aSEtienne Carriere 	case _HCLK6:
240237e8295aSEtienne Carriere 	case _PCLK4:
240337e8295aSEtienne Carriere 	case _PCLK5:
240437e8295aSEtienne Carriere 	case _PLL1_P:
240537e8295aSEtienne Carriere 	case _PLL1_Q:
240637e8295aSEtienne Carriere 	case _PLL1_R:
240737e8295aSEtienne Carriere 	case _PLL2_P:
240837e8295aSEtienne Carriere 	case _PLL2_Q:
240937e8295aSEtienne Carriere 	case _PLL2_R:
241037e8295aSEtienne Carriere 	case _HSI:
241137e8295aSEtienne Carriere 	case _HSI_KER:
241237e8295aSEtienne Carriere 	case _LSI:
241337e8295aSEtienne Carriere 	case _CSI:
241437e8295aSEtienne Carriere 	case _CSI_KER:
241537e8295aSEtienne Carriere 	case _HSE:
241637e8295aSEtienne Carriere 	case _HSE_KER:
241737e8295aSEtienne Carriere 	case _HSE_KER_DIV2:
2418cbd2e8a6SGabriel Fernandez 	case _HSE_RTC:
241937e8295aSEtienne Carriere 	case _LSE:
242037e8295aSEtienne Carriere 		break;
242137e8295aSEtienne Carriere 
242237e8295aSEtienne Carriere 	default:
242337e8295aSEtienne Carriere 		VERBOSE("Cannot secure parent clock %s\n",
242437e8295aSEtienne Carriere 			stm32mp1_clk_parent_name[parent_id]);
242537e8295aSEtienne Carriere 		panic();
242637e8295aSEtienne Carriere 	}
242737e8295aSEtienne Carriere 
242837e8295aSEtienne Carriere 	grandparent_id = get_parent_id_parent(parent_id);
242937e8295aSEtienne Carriere 	if (grandparent_id >= 0) {
243037e8295aSEtienne Carriere 		secure_parent_clocks(grandparent_id);
243137e8295aSEtienne Carriere 	}
243237e8295aSEtienne Carriere }
243337e8295aSEtienne Carriere 
243437e8295aSEtienne Carriere void stm32mp1_register_clock_parents_secure(unsigned long clock_id)
243537e8295aSEtienne Carriere {
243637e8295aSEtienne Carriere 	int parent_id;
243737e8295aSEtienne Carriere 
243837e8295aSEtienne Carriere 	if (!stm32mp1_rcc_is_secure()) {
243937e8295aSEtienne Carriere 		return;
244037e8295aSEtienne Carriere 	}
244137e8295aSEtienne Carriere 
244237e8295aSEtienne Carriere 	switch (clock_id) {
244337e8295aSEtienne Carriere 	case PLL1:
244437e8295aSEtienne Carriere 	case PLL2:
244537e8295aSEtienne Carriere 		/* PLL1/PLL2 are always secure: nothing to do */
244637e8295aSEtienne Carriere 		break;
244737e8295aSEtienne Carriere 	case PLL3:
244837e8295aSEtienne Carriere 		stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
244937e8295aSEtienne Carriere 		break;
245037e8295aSEtienne Carriere 	case PLL4:
245137e8295aSEtienne Carriere 		ERROR("PLL4 cannot be secured\n");
245237e8295aSEtienne Carriere 		panic();
245337e8295aSEtienne Carriere 		break;
245437e8295aSEtienne Carriere 	default:
245537e8295aSEtienne Carriere 		/* Others are expected gateable clock */
245637e8295aSEtienne Carriere 		parent_id = stm32mp1_clk_get_parent(clock_id);
245737e8295aSEtienne Carriere 		if (parent_id < 0) {
245837e8295aSEtienne Carriere 			INFO("No parent found for clock %lu\n", clock_id);
245937e8295aSEtienne Carriere 		} else {
246037e8295aSEtienne Carriere 			secure_parent_clocks(parent_id);
246137e8295aSEtienne Carriere 		}
246237e8295aSEtienne Carriere 		break;
246337e8295aSEtienne Carriere 	}
246437e8295aSEtienne Carriere }
246537e8295aSEtienne Carriere #endif /* STM32MP_SHARED_RESOURCES */
246637e8295aSEtienne Carriere 
246777b4ca0bSLionel Debieve void stm32mp1_clk_mcuss_protect(bool enable)
246877b4ca0bSLionel Debieve {
246977b4ca0bSLionel Debieve 	uintptr_t rcc_base = stm32mp_rcc_base();
247077b4ca0bSLionel Debieve 
247177b4ca0bSLionel Debieve 	if (enable) {
247277b4ca0bSLionel Debieve 		mmio_setbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
247377b4ca0bSLionel Debieve 	} else {
247477b4ca0bSLionel Debieve 		mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
247577b4ca0bSLionel Debieve 	}
247677b4ca0bSLionel Debieve }
247777b4ca0bSLionel Debieve 
24786cb45f89SYann Gautier static void sync_earlyboot_clocks_state(void)
24796cb45f89SYann Gautier {
2480033b6c3aSEtienne Carriere 	unsigned int idx;
2481033b6c3aSEtienne Carriere 	const unsigned long secure_enable[] = {
2482033b6c3aSEtienne Carriere 		AXIDCG,
2483033b6c3aSEtienne Carriere 		BSEC,
2484033b6c3aSEtienne Carriere 		DDRC1, DDRC1LP,
2485033b6c3aSEtienne Carriere 		DDRC2, DDRC2LP,
2486033b6c3aSEtienne Carriere 		DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP,
2487033b6c3aSEtienne Carriere 		DDRPHYC, DDRPHYCLP,
2488373f06beSLionel Debieve 		RTCAPB,
2489033b6c3aSEtienne Carriere 		TZC1, TZC2,
2490033b6c3aSEtienne Carriere 		TZPC,
2491033b6c3aSEtienne Carriere 		STGEN_K,
2492033b6c3aSEtienne Carriere 	};
2493033b6c3aSEtienne Carriere 
2494033b6c3aSEtienne Carriere 	for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) {
2495033b6c3aSEtienne Carriere 		stm32mp_clk_enable(secure_enable[idx]);
2496033b6c3aSEtienne Carriere 	}
24976cb45f89SYann Gautier }
24986cb45f89SYann Gautier 
249933667d29SYann Gautier static const struct clk_ops stm32mp_clk_ops = {
250033667d29SYann Gautier 	.enable		= stm32mp_clk_enable,
250133667d29SYann Gautier 	.disable	= stm32mp_clk_disable,
250233667d29SYann Gautier 	.is_enabled	= stm32mp_clk_is_enabled,
250333667d29SYann Gautier 	.get_rate	= stm32mp_clk_get_rate,
250433667d29SYann Gautier 	.get_parent	= stm32mp1_clk_get_parent,
250533667d29SYann Gautier };
250633667d29SYann Gautier 
25077839a050SYann Gautier int stm32mp1_clk_probe(void)
25087839a050SYann Gautier {
2509812daf91SLionel Debieve #if defined(IMAGE_BL32)
2510812daf91SLionel Debieve 	if (!fdt_get_rcc_secure_state()) {
2511812daf91SLionel Debieve 		mmio_write_32(stm32mp_rcc_base() + RCC_TZCR, 0U);
2512812daf91SLionel Debieve 	}
2513812daf91SLionel Debieve #endif
2514812daf91SLionel Debieve 
25157839a050SYann Gautier 	stm32mp1_osc_init();
25167839a050SYann Gautier 
25176cb45f89SYann Gautier 	sync_earlyboot_clocks_state();
25186cb45f89SYann Gautier 
251933667d29SYann Gautier 	clk_register(&stm32mp_clk_ops);
252033667d29SYann Gautier 
25217839a050SYann Gautier 	return 0;
25227839a050SYann Gautier }
2523