xref: /rk3399_ARM-atf/drivers/st/clk/stm32mp1_clk.c (revision 3d69149a7e9e9a899d57f48bee26f98614f88935)
17839a050SYann Gautier /*
2964e5ff1SNicolas Le Bayon  * Copyright (C) 2018-2022, 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>
1809d40e0eSAntonio Nino Diaz #include <drivers/generic_delay_timer.h>
19447b2b13SYann Gautier #include <drivers/st/stm32mp_clkfunc.h>
2009d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_clk.h>
2109d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_rcc.h>
2209d40e0eSAntonio Nino Diaz #include <dt-bindings/clock/stm32mp1-clksrc.h>
2309d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
240d21680cSYann Gautier #include <lib/spinlock.h>
2509d40e0eSAntonio Nino Diaz #include <lib/utils_def.h>
26964e5ff1SNicolas Le Bayon #include <libfdt.h>
2709d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
2809d40e0eSAntonio Nino Diaz 
29964e5ff1SNicolas Le Bayon #include <platform_def.h>
30964e5ff1SNicolas Le Bayon 
317839a050SYann Gautier #define MAX_HSI_HZ		64000000
320d21680cSYann Gautier #define USB_PHY_48_MHZ		48000000
337839a050SYann Gautier 
34dfdb057aSYann Gautier #define TIMEOUT_US_200MS	U(200000)
35dfdb057aSYann Gautier #define TIMEOUT_US_1S		U(1000000)
367839a050SYann Gautier 
37dfdb057aSYann Gautier #define PLLRDY_TIMEOUT		TIMEOUT_US_200MS
38dfdb057aSYann Gautier #define CLKSRC_TIMEOUT		TIMEOUT_US_200MS
39dfdb057aSYann Gautier #define CLKDIV_TIMEOUT		TIMEOUT_US_200MS
40dfdb057aSYann Gautier #define HSIDIV_TIMEOUT		TIMEOUT_US_200MS
41dfdb057aSYann Gautier #define OSCRDY_TIMEOUT		TIMEOUT_US_1S
427839a050SYann Gautier 
43f66358afSYann Gautier const char *stm32mp_osc_node_label[NB_OSC] = {
44f66358afSYann Gautier 	[_LSI] = "clk-lsi",
45f66358afSYann Gautier 	[_LSE] = "clk-lse",
46f66358afSYann Gautier 	[_HSI] = "clk-hsi",
47f66358afSYann Gautier 	[_HSE] = "clk-hse",
48f66358afSYann Gautier 	[_CSI] = "clk-csi",
49f66358afSYann Gautier 	[_I2S_CKIN] = "i2s_ckin",
50f66358afSYann Gautier };
51f66358afSYann Gautier 
527839a050SYann Gautier enum stm32mp1_parent_id {
537839a050SYann Gautier /* Oscillators are defined in enum stm32mp_osc_id */
547839a050SYann Gautier 
557839a050SYann Gautier /* Other parent source */
567839a050SYann Gautier 	_HSI_KER = NB_OSC,
577839a050SYann Gautier 	_HSE_KER,
587839a050SYann Gautier 	_HSE_KER_DIV2,
59cbd2e8a6SGabriel Fernandez 	_HSE_RTC,
607839a050SYann Gautier 	_CSI_KER,
617839a050SYann Gautier 	_PLL1_P,
627839a050SYann Gautier 	_PLL1_Q,
637839a050SYann Gautier 	_PLL1_R,
647839a050SYann Gautier 	_PLL2_P,
657839a050SYann Gautier 	_PLL2_Q,
667839a050SYann Gautier 	_PLL2_R,
677839a050SYann Gautier 	_PLL3_P,
687839a050SYann Gautier 	_PLL3_Q,
697839a050SYann Gautier 	_PLL3_R,
707839a050SYann Gautier 	_PLL4_P,
717839a050SYann Gautier 	_PLL4_Q,
727839a050SYann Gautier 	_PLL4_R,
737839a050SYann Gautier 	_ACLK,
747839a050SYann Gautier 	_PCLK1,
757839a050SYann Gautier 	_PCLK2,
767839a050SYann Gautier 	_PCLK3,
777839a050SYann Gautier 	_PCLK4,
787839a050SYann Gautier 	_PCLK5,
797839a050SYann Gautier 	_HCLK6,
807839a050SYann Gautier 	_HCLK2,
817839a050SYann Gautier 	_CK_PER,
827839a050SYann Gautier 	_CK_MPU,
83b053a22eSYann Gautier 	_CK_MCU,
840d21680cSYann Gautier 	_USB_PHY_48,
857839a050SYann Gautier 	_PARENT_NB,
867839a050SYann Gautier 	_UNKNOWN_ID = 0xff,
877839a050SYann Gautier };
887839a050SYann Gautier 
890d21680cSYann Gautier /* Lists only the parent clock we are interested in */
907839a050SYann Gautier enum stm32mp1_parent_sel {
910d21680cSYann Gautier 	_I2C12_SEL,
920d21680cSYann Gautier 	_I2C35_SEL,
930d21680cSYann Gautier 	_STGEN_SEL,
947839a050SYann Gautier 	_I2C46_SEL,
950d21680cSYann Gautier 	_SPI6_SEL,
96d4151d2fSYann Gautier 	_UART1_SEL,
970d21680cSYann Gautier 	_RNG1_SEL,
987839a050SYann Gautier 	_UART6_SEL,
997839a050SYann Gautier 	_UART24_SEL,
1007839a050SYann Gautier 	_UART35_SEL,
1017839a050SYann Gautier 	_UART78_SEL,
1027839a050SYann Gautier 	_SDMMC12_SEL,
1037839a050SYann Gautier 	_SDMMC3_SEL,
1047839a050SYann Gautier 	_QSPI_SEL,
1057839a050SYann Gautier 	_FMC_SEL,
106d4151d2fSYann Gautier 	_AXIS_SEL,
107d4151d2fSYann Gautier 	_MCUS_SEL,
1087839a050SYann Gautier 	_USBPHY_SEL,
1097839a050SYann Gautier 	_USBO_SEL,
1108fbcd9e4SEtienne Carriere 	_MPU_SEL,
111288f5cf2SYann Gautier 	_CKPER_SEL,
112016af006SEtienne Carriere 	_RTC_SEL,
1137839a050SYann Gautier 	_PARENT_SEL_NB,
1147839a050SYann Gautier 	_UNKNOWN_SEL = 0xff,
1157839a050SYann Gautier };
1167839a050SYann Gautier 
1178fbcd9e4SEtienne Carriere /* State the parent clock ID straight related to a clock */
1188fbcd9e4SEtienne Carriere static const uint8_t parent_id_clock_id[_PARENT_NB] = {
1198fbcd9e4SEtienne Carriere 	[_HSE] = CK_HSE,
1208fbcd9e4SEtienne Carriere 	[_HSI] = CK_HSI,
1218fbcd9e4SEtienne Carriere 	[_CSI] = CK_CSI,
1228fbcd9e4SEtienne Carriere 	[_LSE] = CK_LSE,
1238fbcd9e4SEtienne Carriere 	[_LSI] = CK_LSI,
1248fbcd9e4SEtienne Carriere 	[_I2S_CKIN] = _UNKNOWN_ID,
1258fbcd9e4SEtienne Carriere 	[_USB_PHY_48] = _UNKNOWN_ID,
1268fbcd9e4SEtienne Carriere 	[_HSI_KER] = CK_HSI,
1278fbcd9e4SEtienne Carriere 	[_HSE_KER] = CK_HSE,
1288fbcd9e4SEtienne Carriere 	[_HSE_KER_DIV2] = CK_HSE_DIV2,
129cbd2e8a6SGabriel Fernandez 	[_HSE_RTC] = _UNKNOWN_ID,
1308fbcd9e4SEtienne Carriere 	[_CSI_KER] = CK_CSI,
1318fbcd9e4SEtienne Carriere 	[_PLL1_P] = PLL1_P,
1328fbcd9e4SEtienne Carriere 	[_PLL1_Q] = PLL1_Q,
1338fbcd9e4SEtienne Carriere 	[_PLL1_R] = PLL1_R,
1348fbcd9e4SEtienne Carriere 	[_PLL2_P] = PLL2_P,
1358fbcd9e4SEtienne Carriere 	[_PLL2_Q] = PLL2_Q,
1368fbcd9e4SEtienne Carriere 	[_PLL2_R] = PLL2_R,
1378fbcd9e4SEtienne Carriere 	[_PLL3_P] = PLL3_P,
1388fbcd9e4SEtienne Carriere 	[_PLL3_Q] = PLL3_Q,
1398fbcd9e4SEtienne Carriere 	[_PLL3_R] = PLL3_R,
1408fbcd9e4SEtienne Carriere 	[_PLL4_P] = PLL4_P,
1418fbcd9e4SEtienne Carriere 	[_PLL4_Q] = PLL4_Q,
1428fbcd9e4SEtienne Carriere 	[_PLL4_R] = PLL4_R,
1438fbcd9e4SEtienne Carriere 	[_ACLK] = CK_AXI,
1448fbcd9e4SEtienne Carriere 	[_PCLK1] = CK_AXI,
1458fbcd9e4SEtienne Carriere 	[_PCLK2] = CK_AXI,
1468fbcd9e4SEtienne Carriere 	[_PCLK3] = CK_AXI,
1478fbcd9e4SEtienne Carriere 	[_PCLK4] = CK_AXI,
1488fbcd9e4SEtienne Carriere 	[_PCLK5] = CK_AXI,
1498fbcd9e4SEtienne Carriere 	[_CK_PER] = CK_PER,
1508fbcd9e4SEtienne Carriere 	[_CK_MPU] = CK_MPU,
1518fbcd9e4SEtienne Carriere 	[_CK_MCU] = CK_MCU,
1528fbcd9e4SEtienne Carriere };
1538fbcd9e4SEtienne Carriere 
1548fbcd9e4SEtienne Carriere static unsigned int clock_id2parent_id(unsigned long id)
1558fbcd9e4SEtienne Carriere {
1568fbcd9e4SEtienne Carriere 	unsigned int n;
1578fbcd9e4SEtienne Carriere 
1588fbcd9e4SEtienne Carriere 	for (n = 0U; n < ARRAY_SIZE(parent_id_clock_id); n++) {
1598fbcd9e4SEtienne Carriere 		if (parent_id_clock_id[n] == id) {
1608fbcd9e4SEtienne Carriere 			return n;
1618fbcd9e4SEtienne Carriere 		}
1628fbcd9e4SEtienne Carriere 	}
1638fbcd9e4SEtienne Carriere 
1648fbcd9e4SEtienne Carriere 	return _UNKNOWN_ID;
1658fbcd9e4SEtienne Carriere }
1668fbcd9e4SEtienne Carriere 
1677839a050SYann Gautier enum stm32mp1_pll_id {
1687839a050SYann Gautier 	_PLL1,
1697839a050SYann Gautier 	_PLL2,
1707839a050SYann Gautier 	_PLL3,
1717839a050SYann Gautier 	_PLL4,
1727839a050SYann Gautier 	_PLL_NB
1737839a050SYann Gautier };
1747839a050SYann Gautier 
1757839a050SYann Gautier enum stm32mp1_div_id {
1767839a050SYann Gautier 	_DIV_P,
1777839a050SYann Gautier 	_DIV_Q,
1787839a050SYann Gautier 	_DIV_R,
1797839a050SYann Gautier 	_DIV_NB,
1807839a050SYann Gautier };
1817839a050SYann Gautier 
1827839a050SYann Gautier enum stm32mp1_clksrc_id {
1837839a050SYann Gautier 	CLKSRC_MPU,
1847839a050SYann Gautier 	CLKSRC_AXI,
185b053a22eSYann Gautier 	CLKSRC_MCU,
1867839a050SYann Gautier 	CLKSRC_PLL12,
1877839a050SYann Gautier 	CLKSRC_PLL3,
1887839a050SYann Gautier 	CLKSRC_PLL4,
1897839a050SYann Gautier 	CLKSRC_RTC,
1907839a050SYann Gautier 	CLKSRC_MCO1,
1917839a050SYann Gautier 	CLKSRC_MCO2,
1927839a050SYann Gautier 	CLKSRC_NB
1937839a050SYann Gautier };
1947839a050SYann Gautier 
1957839a050SYann Gautier enum stm32mp1_clkdiv_id {
1967839a050SYann Gautier 	CLKDIV_MPU,
1977839a050SYann Gautier 	CLKDIV_AXI,
198b053a22eSYann Gautier 	CLKDIV_MCU,
1997839a050SYann Gautier 	CLKDIV_APB1,
2007839a050SYann Gautier 	CLKDIV_APB2,
2017839a050SYann Gautier 	CLKDIV_APB3,
2027839a050SYann Gautier 	CLKDIV_APB4,
2037839a050SYann Gautier 	CLKDIV_APB5,
2047839a050SYann Gautier 	CLKDIV_RTC,
2057839a050SYann Gautier 	CLKDIV_MCO1,
2067839a050SYann Gautier 	CLKDIV_MCO2,
2077839a050SYann Gautier 	CLKDIV_NB
2087839a050SYann Gautier };
2097839a050SYann Gautier 
2107839a050SYann Gautier enum stm32mp1_pllcfg {
2117839a050SYann Gautier 	PLLCFG_M,
2127839a050SYann Gautier 	PLLCFG_N,
2137839a050SYann Gautier 	PLLCFG_P,
2147839a050SYann Gautier 	PLLCFG_Q,
2157839a050SYann Gautier 	PLLCFG_R,
2167839a050SYann Gautier 	PLLCFG_O,
2177839a050SYann Gautier 	PLLCFG_NB
2187839a050SYann Gautier };
2197839a050SYann Gautier 
2207839a050SYann Gautier enum stm32mp1_pllcsg {
2217839a050SYann Gautier 	PLLCSG_MOD_PER,
2227839a050SYann Gautier 	PLLCSG_INC_STEP,
2237839a050SYann Gautier 	PLLCSG_SSCG_MODE,
2247839a050SYann Gautier 	PLLCSG_NB
2257839a050SYann Gautier };
2267839a050SYann Gautier 
2277839a050SYann Gautier enum stm32mp1_plltype {
2287839a050SYann Gautier 	PLL_800,
2297839a050SYann Gautier 	PLL_1600,
2307839a050SYann Gautier 	PLL_TYPE_NB
2317839a050SYann Gautier };
2327839a050SYann Gautier 
2337839a050SYann Gautier struct stm32mp1_pll {
2347839a050SYann Gautier 	uint8_t refclk_min;
2357839a050SYann Gautier 	uint8_t refclk_max;
2367839a050SYann Gautier 	uint8_t divn_max;
2377839a050SYann Gautier };
2387839a050SYann Gautier 
2397839a050SYann Gautier struct stm32mp1_clk_gate {
2407839a050SYann Gautier 	uint16_t offset;
2417839a050SYann Gautier 	uint8_t bit;
2427839a050SYann Gautier 	uint8_t index;
2437839a050SYann Gautier 	uint8_t set_clr;
244aaa09b71SYann Gautier 	uint8_t secure;
2450d21680cSYann Gautier 	uint8_t sel; /* Relates to enum stm32mp1_parent_sel */
2460d21680cSYann Gautier 	uint8_t fixed; /* Relates to enum stm32mp1_parent_id */
2477839a050SYann Gautier };
2487839a050SYann Gautier 
2497839a050SYann Gautier struct stm32mp1_clk_sel {
2507839a050SYann Gautier 	uint16_t offset;
2517839a050SYann Gautier 	uint8_t src;
2527839a050SYann Gautier 	uint8_t msk;
2537839a050SYann Gautier 	uint8_t nb_parent;
2547839a050SYann Gautier 	const uint8_t *parent;
2557839a050SYann Gautier };
2567839a050SYann Gautier 
2577839a050SYann Gautier #define REFCLK_SIZE 4
2587839a050SYann Gautier struct stm32mp1_clk_pll {
2597839a050SYann Gautier 	enum stm32mp1_plltype plltype;
2607839a050SYann Gautier 	uint16_t rckxselr;
2617839a050SYann Gautier 	uint16_t pllxcfgr1;
2627839a050SYann Gautier 	uint16_t pllxcfgr2;
2637839a050SYann Gautier 	uint16_t pllxfracr;
2647839a050SYann Gautier 	uint16_t pllxcr;
2657839a050SYann Gautier 	uint16_t pllxcsgr;
2667839a050SYann Gautier 	enum stm32mp_osc_id refclk[REFCLK_SIZE];
2677839a050SYann Gautier };
2687839a050SYann Gautier 
2690d21680cSYann Gautier /* Clocks with selectable source and non set/clr register access */
270aaa09b71SYann Gautier #define _CLK_SELEC(sec, off, b, idx, s)			\
2717839a050SYann Gautier 	{						\
2727839a050SYann Gautier 		.offset = (off),			\
2737839a050SYann Gautier 		.bit = (b),				\
2747839a050SYann Gautier 		.index = (idx),				\
2757839a050SYann Gautier 		.set_clr = 0,				\
276aaa09b71SYann Gautier 		.secure = (sec),			\
2777839a050SYann Gautier 		.sel = (s),				\
2787839a050SYann Gautier 		.fixed = _UNKNOWN_ID,			\
2797839a050SYann Gautier 	}
2807839a050SYann Gautier 
2810d21680cSYann Gautier /* Clocks with fixed source and non set/clr register access */
282aaa09b71SYann Gautier #define _CLK_FIXED(sec, off, b, idx, f)			\
2837839a050SYann Gautier 	{						\
2847839a050SYann Gautier 		.offset = (off),			\
2857839a050SYann Gautier 		.bit = (b),				\
2867839a050SYann Gautier 		.index = (idx),				\
2877839a050SYann Gautier 		.set_clr = 0,				\
288aaa09b71SYann Gautier 		.secure = (sec),			\
2897839a050SYann Gautier 		.sel = _UNKNOWN_SEL,			\
2907839a050SYann Gautier 		.fixed = (f),				\
2917839a050SYann Gautier 	}
2927839a050SYann Gautier 
2930d21680cSYann Gautier /* Clocks with selectable source and set/clr register access */
294aaa09b71SYann Gautier #define _CLK_SC_SELEC(sec, off, b, idx, s)			\
2957839a050SYann Gautier 	{						\
2967839a050SYann Gautier 		.offset = (off),			\
2977839a050SYann Gautier 		.bit = (b),				\
2987839a050SYann Gautier 		.index = (idx),				\
2997839a050SYann Gautier 		.set_clr = 1,				\
300aaa09b71SYann Gautier 		.secure = (sec),			\
3017839a050SYann Gautier 		.sel = (s),				\
3027839a050SYann Gautier 		.fixed = _UNKNOWN_ID,			\
3037839a050SYann Gautier 	}
3047839a050SYann Gautier 
3050d21680cSYann Gautier /* Clocks with fixed source and set/clr register access */
306aaa09b71SYann Gautier #define _CLK_SC_FIXED(sec, off, b, idx, f)			\
3077839a050SYann Gautier 	{						\
3087839a050SYann Gautier 		.offset = (off),			\
3097839a050SYann Gautier 		.bit = (b),				\
3107839a050SYann Gautier 		.index = (idx),				\
3117839a050SYann Gautier 		.set_clr = 1,				\
312aaa09b71SYann Gautier 		.secure = (sec),			\
3137839a050SYann Gautier 		.sel = _UNKNOWN_SEL,			\
3147839a050SYann Gautier 		.fixed = (f),				\
3157839a050SYann Gautier 	}
3167839a050SYann Gautier 
317d4151d2fSYann Gautier #define _CLK_PARENT_SEL(_label, _rcc_selr, _parents)		\
318d4151d2fSYann Gautier 	[_ ## _label ## _SEL] = {				\
319d4151d2fSYann Gautier 		.offset = _rcc_selr,				\
320d4151d2fSYann Gautier 		.src = _rcc_selr ## _ ## _label ## SRC_SHIFT,	\
3218ae08dcdSEtienne Carriere 		.msk = (_rcc_selr ## _ ## _label ## SRC_MASK) >> \
3228ae08dcdSEtienne Carriere 		       (_rcc_selr ## _ ## _label ## SRC_SHIFT), \
323d4151d2fSYann Gautier 		.parent = (_parents),				\
324d4151d2fSYann Gautier 		.nb_parent = ARRAY_SIZE(_parents)		\
3257839a050SYann Gautier 	}
3267839a050SYann Gautier 
3270d21680cSYann Gautier #define _CLK_PLL(idx, type, off1, off2, off3,		\
3287839a050SYann Gautier 		 off4, off5, off6,			\
3297839a050SYann Gautier 		 p1, p2, p3, p4)			\
3307839a050SYann Gautier 	[(idx)] = {					\
3317839a050SYann Gautier 		.plltype = (type),			\
3327839a050SYann Gautier 		.rckxselr = (off1),			\
3337839a050SYann Gautier 		.pllxcfgr1 = (off2),			\
3347839a050SYann Gautier 		.pllxcfgr2 = (off3),			\
3357839a050SYann Gautier 		.pllxfracr = (off4),			\
3367839a050SYann Gautier 		.pllxcr = (off5),			\
3377839a050SYann Gautier 		.pllxcsgr = (off6),			\
3387839a050SYann Gautier 		.refclk[0] = (p1),			\
3397839a050SYann Gautier 		.refclk[1] = (p2),			\
3407839a050SYann Gautier 		.refclk[2] = (p3),			\
3417839a050SYann Gautier 		.refclk[3] = (p4),			\
3427839a050SYann Gautier 	}
3437839a050SYann Gautier 
3440d21680cSYann Gautier #define NB_GATES	ARRAY_SIZE(stm32mp1_clk_gate)
3450d21680cSYann Gautier 
346aaa09b71SYann Gautier #define SEC		1
347aaa09b71SYann Gautier #define N_S		0
348aaa09b71SYann Gautier 
3497839a050SYann Gautier static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
350aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK),
351aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
352aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK),
353aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
354aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
355aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
356aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
357aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
358aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK),
359aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
360aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
3617839a050SYann Gautier 
362aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
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 
374aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
375aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
3767839a050SYann Gautier 
377aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID),
378f33b2433SYann Gautier 
379aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
380aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
381aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
3827839a050SYann Gautier 
383aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL),
384aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
385aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL),
386aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL),
387aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
388aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5),
389aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5),
390aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5),
391aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5),
392aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5),
393aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
3947839a050SYann Gautier 
395aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
396aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
3977839a050SYann Gautier 
398aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
399aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
400aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
401aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
402aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
403aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
404aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
405aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
406aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
407aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
408aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
4097839a050SYann Gautier 
410aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5),
411aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5),
412aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5),
413aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL),
414aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5),
4157839a050SYann Gautier 
416aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
417aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
418aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
419aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
420aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
4217839a050SYann Gautier 
422aaa09b71SYann Gautier 	_CLK_SELEC(SEC, RCC_BDCR, 20, RTC, _RTC_SEL),
423aaa09b71SYann Gautier 	_CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
4247839a050SYann Gautier };
4257839a050SYann Gautier 
4260d21680cSYann Gautier static const uint8_t i2c12_parents[] = {
4270d21680cSYann Gautier 	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
4280d21680cSYann Gautier };
4290d21680cSYann Gautier 
4300d21680cSYann Gautier static const uint8_t i2c35_parents[] = {
4310d21680cSYann Gautier 	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
4320d21680cSYann Gautier };
4330d21680cSYann Gautier 
4340d21680cSYann Gautier static const uint8_t stgen_parents[] = {
4350d21680cSYann Gautier 	_HSI_KER, _HSE_KER
4360d21680cSYann Gautier };
4370d21680cSYann Gautier 
4380d21680cSYann Gautier static const uint8_t i2c46_parents[] = {
4390d21680cSYann Gautier 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER
4400d21680cSYann Gautier };
4410d21680cSYann Gautier 
4420d21680cSYann Gautier static const uint8_t spi6_parents[] = {
4430d21680cSYann Gautier 	_PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q
4440d21680cSYann Gautier };
4450d21680cSYann Gautier 
4460d21680cSYann Gautier static const uint8_t usart1_parents[] = {
4470d21680cSYann Gautier 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER
4480d21680cSYann Gautier };
4490d21680cSYann Gautier 
4500d21680cSYann Gautier static const uint8_t rng1_parents[] = {
4510d21680cSYann Gautier 	_CSI, _PLL4_R, _LSE, _LSI
4520d21680cSYann Gautier };
4530d21680cSYann Gautier 
4540d21680cSYann Gautier static const uint8_t uart6_parents[] = {
4550d21680cSYann Gautier 	_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
4560d21680cSYann Gautier };
4570d21680cSYann Gautier 
4580d21680cSYann Gautier static const uint8_t uart234578_parents[] = {
4590d21680cSYann Gautier 	_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
4600d21680cSYann Gautier };
4610d21680cSYann Gautier 
4620d21680cSYann Gautier static const uint8_t sdmmc12_parents[] = {
4630d21680cSYann Gautier 	_HCLK6, _PLL3_R, _PLL4_P, _HSI_KER
4640d21680cSYann Gautier };
4650d21680cSYann Gautier 
4660d21680cSYann Gautier static const uint8_t sdmmc3_parents[] = {
4670d21680cSYann Gautier 	_HCLK2, _PLL3_R, _PLL4_P, _HSI_KER
4680d21680cSYann Gautier };
4690d21680cSYann Gautier 
4700d21680cSYann Gautier static const uint8_t qspi_parents[] = {
4710d21680cSYann Gautier 	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
4720d21680cSYann Gautier };
4730d21680cSYann Gautier 
4740d21680cSYann Gautier static const uint8_t fmc_parents[] = {
4750d21680cSYann Gautier 	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
4760d21680cSYann Gautier };
4770d21680cSYann Gautier 
478b8fe48b6SEtienne Carriere static const uint8_t axiss_parents[] = {
479b8fe48b6SEtienne Carriere 	_HSI, _HSE, _PLL2_P
4800d21680cSYann Gautier };
4810d21680cSYann Gautier 
482b8fe48b6SEtienne Carriere static const uint8_t mcuss_parents[] = {
483b8fe48b6SEtienne Carriere 	_HSI, _HSE, _CSI, _PLL3_P
484b053a22eSYann Gautier };
485b053a22eSYann Gautier 
4860d21680cSYann Gautier static const uint8_t usbphy_parents[] = {
4870d21680cSYann Gautier 	_HSE_KER, _PLL4_R, _HSE_KER_DIV2
4880d21680cSYann Gautier };
4890d21680cSYann Gautier 
4900d21680cSYann Gautier static const uint8_t usbo_parents[] = {
4910d21680cSYann Gautier 	_PLL4_R, _USB_PHY_48
4920d21680cSYann Gautier };
4937839a050SYann Gautier 
4948fbcd9e4SEtienne Carriere static const uint8_t mpu_parents[] = {
4958fbcd9e4SEtienne Carriere 	_HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */
4968fbcd9e4SEtienne Carriere };
4978fbcd9e4SEtienne Carriere 
4988fbcd9e4SEtienne Carriere static const uint8_t per_parents[] = {
4998fbcd9e4SEtienne Carriere 	_HSI, _HSE, _CSI,
5008fbcd9e4SEtienne Carriere };
5018fbcd9e4SEtienne Carriere 
502016af006SEtienne Carriere static const uint8_t rtc_parents[] = {
503cbd2e8a6SGabriel Fernandez 	_UNKNOWN_ID, _LSE, _LSI, _HSE_RTC
504016af006SEtienne Carriere };
505016af006SEtienne Carriere 
5067839a050SYann Gautier static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
507d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents),
508d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents),
509d4151d2fSYann Gautier 	_CLK_PARENT_SEL(STGEN, RCC_STGENCKSELR, stgen_parents),
510d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C46, RCC_I2C46CKSELR, i2c46_parents),
511d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents),
512d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents),
513d4151d2fSYann Gautier 	_CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents),
5148fbcd9e4SEtienne Carriere 	_CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents),
515288f5cf2SYann Gautier 	_CLK_PARENT_SEL(CKPER, RCC_CPERCKSELR, per_parents),
516016af006SEtienne Carriere 	_CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents),
517d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents),
518d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents),
519d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents),
520d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART78, RCC_UART78CKSELR, uart234578_parents),
521d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SDMMC12, RCC_SDMMC12CKSELR, sdmmc12_parents),
522d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents),
523d4151d2fSYann Gautier 	_CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents),
524d4151d2fSYann Gautier 	_CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents),
525b8fe48b6SEtienne Carriere 	_CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, axiss_parents),
526b8fe48b6SEtienne Carriere 	_CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mcuss_parents),
527d4151d2fSYann Gautier 	_CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents),
528d4151d2fSYann Gautier 	_CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents),
5297839a050SYann Gautier };
5307839a050SYann Gautier 
5317839a050SYann Gautier /* Define characteristic of PLL according type */
5327839a050SYann Gautier #define DIVN_MIN	24
5337839a050SYann Gautier static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
5347839a050SYann Gautier 	[PLL_800] = {
5357839a050SYann Gautier 		.refclk_min = 4,
5367839a050SYann Gautier 		.refclk_max = 16,
5377839a050SYann Gautier 		.divn_max = 99,
5387839a050SYann Gautier 	},
5397839a050SYann Gautier 	[PLL_1600] = {
5407839a050SYann Gautier 		.refclk_min = 8,
5417839a050SYann Gautier 		.refclk_max = 16,
5427839a050SYann Gautier 		.divn_max = 199,
5437839a050SYann Gautier 	},
5447839a050SYann Gautier };
5457839a050SYann Gautier 
5467839a050SYann Gautier /* PLLNCFGR2 register divider by output */
5477839a050SYann Gautier static const uint8_t pllncfgr2[_DIV_NB] = {
5487839a050SYann Gautier 	[_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT,
5497839a050SYann Gautier 	[_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT,
5500d21680cSYann Gautier 	[_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT,
5517839a050SYann Gautier };
5527839a050SYann Gautier 
5537839a050SYann Gautier static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = {
5540d21680cSYann Gautier 	_CLK_PLL(_PLL1, PLL_1600,
5557839a050SYann Gautier 		 RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2,
5567839a050SYann Gautier 		 RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR,
5577839a050SYann Gautier 		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
5580d21680cSYann Gautier 	_CLK_PLL(_PLL2, PLL_1600,
5597839a050SYann Gautier 		 RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2,
5607839a050SYann Gautier 		 RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR,
5617839a050SYann Gautier 		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
5620d21680cSYann Gautier 	_CLK_PLL(_PLL3, PLL_800,
5637839a050SYann Gautier 		 RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2,
5647839a050SYann Gautier 		 RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR,
5657839a050SYann Gautier 		 _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID),
5660d21680cSYann Gautier 	_CLK_PLL(_PLL4, PLL_800,
5677839a050SYann Gautier 		 RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2,
5687839a050SYann Gautier 		 RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR,
5697839a050SYann Gautier 		 _HSI, _HSE, _CSI, _I2S_CKIN),
5707839a050SYann Gautier };
5717839a050SYann Gautier 
5727839a050SYann Gautier /* Prescaler table lookups for clock computation */
573b053a22eSYann Gautier /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */
574b053a22eSYann Gautier static const uint8_t stm32mp1_mcu_div[16] = {
575b053a22eSYann Gautier 	0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9
576b053a22eSYann Gautier };
5777839a050SYann Gautier 
5787839a050SYann Gautier /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */
5797839a050SYann Gautier #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div
5807839a050SYann Gautier #define stm32mp1_apbx_div stm32mp1_mpu_apbx_div
5817839a050SYann Gautier static const uint8_t stm32mp1_mpu_apbx_div[8] = {
5827839a050SYann Gautier 	0, 1, 2, 3, 4, 4, 4, 4
5837839a050SYann Gautier };
5847839a050SYann Gautier 
5857839a050SYann Gautier /* div = /1 /2 /3 /4 */
5867839a050SYann Gautier static const uint8_t stm32mp1_axi_div[8] = {
5877839a050SYann Gautier 	1, 2, 3, 4, 4, 4, 4, 4
5887839a050SYann Gautier };
5897839a050SYann Gautier 
59037e8295aSEtienne Carriere static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = {
59137e8295aSEtienne Carriere 	[_HSI] = "HSI",
59237e8295aSEtienne Carriere 	[_HSE] = "HSE",
59337e8295aSEtienne Carriere 	[_CSI] = "CSI",
59437e8295aSEtienne Carriere 	[_LSI] = "LSI",
59537e8295aSEtienne Carriere 	[_LSE] = "LSE",
59637e8295aSEtienne Carriere 	[_I2S_CKIN] = "I2S_CKIN",
59737e8295aSEtienne Carriere 	[_HSI_KER] = "HSI_KER",
59837e8295aSEtienne Carriere 	[_HSE_KER] = "HSE_KER",
59937e8295aSEtienne Carriere 	[_HSE_KER_DIV2] = "HSE_KER_DIV2",
600cbd2e8a6SGabriel Fernandez 	[_HSE_RTC] = "HSE_RTC",
60137e8295aSEtienne Carriere 	[_CSI_KER] = "CSI_KER",
60237e8295aSEtienne Carriere 	[_PLL1_P] = "PLL1_P",
60337e8295aSEtienne Carriere 	[_PLL1_Q] = "PLL1_Q",
60437e8295aSEtienne Carriere 	[_PLL1_R] = "PLL1_R",
60537e8295aSEtienne Carriere 	[_PLL2_P] = "PLL2_P",
60637e8295aSEtienne Carriere 	[_PLL2_Q] = "PLL2_Q",
60737e8295aSEtienne Carriere 	[_PLL2_R] = "PLL2_R",
60837e8295aSEtienne Carriere 	[_PLL3_P] = "PLL3_P",
60937e8295aSEtienne Carriere 	[_PLL3_Q] = "PLL3_Q",
61037e8295aSEtienne Carriere 	[_PLL3_R] = "PLL3_R",
61137e8295aSEtienne Carriere 	[_PLL4_P] = "PLL4_P",
61237e8295aSEtienne Carriere 	[_PLL4_Q] = "PLL4_Q",
61337e8295aSEtienne Carriere 	[_PLL4_R] = "PLL4_R",
61437e8295aSEtienne Carriere 	[_ACLK] = "ACLK",
61537e8295aSEtienne Carriere 	[_PCLK1] = "PCLK1",
61637e8295aSEtienne Carriere 	[_PCLK2] = "PCLK2",
61737e8295aSEtienne Carriere 	[_PCLK3] = "PCLK3",
61837e8295aSEtienne Carriere 	[_PCLK4] = "PCLK4",
61937e8295aSEtienne Carriere 	[_PCLK5] = "PCLK5",
62037e8295aSEtienne Carriere 	[_HCLK6] = "KCLK6",
62137e8295aSEtienne Carriere 	[_HCLK2] = "HCLK2",
62237e8295aSEtienne Carriere 	[_CK_PER] = "CK_PER",
62337e8295aSEtienne Carriere 	[_CK_MPU] = "CK_MPU",
62437e8295aSEtienne Carriere 	[_CK_MCU] = "CK_MCU",
62537e8295aSEtienne Carriere 	[_USB_PHY_48] = "USB_PHY_48",
62637e8295aSEtienne Carriere };
62737e8295aSEtienne Carriere 
6280d21680cSYann Gautier /* RCC clock device driver private */
6290d21680cSYann Gautier static unsigned long stm32mp1_osc[NB_OSC];
6300d21680cSYann Gautier static struct spinlock reg_lock;
6310d21680cSYann Gautier static unsigned int gate_refcounts[NB_GATES];
6320d21680cSYann Gautier static struct spinlock refcount_lock;
6337839a050SYann Gautier 
6340d21680cSYann Gautier static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx)
6350d21680cSYann Gautier {
6360d21680cSYann Gautier 	return &stm32mp1_clk_gate[idx];
6370d21680cSYann Gautier }
6387839a050SYann Gautier 
639*3d69149aSYann Gautier #if defined(IMAGE_BL32)
640*3d69149aSYann Gautier static bool gate_is_non_secure(const struct stm32mp1_clk_gate *gate)
641*3d69149aSYann Gautier {
642*3d69149aSYann Gautier 	return gate->secure == N_S;
643*3d69149aSYann Gautier }
644*3d69149aSYann Gautier #endif
645*3d69149aSYann Gautier 
6460d21680cSYann Gautier static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx)
6470d21680cSYann Gautier {
6480d21680cSYann Gautier 	return &stm32mp1_clk_sel[idx];
6490d21680cSYann Gautier }
6500d21680cSYann Gautier 
6510d21680cSYann Gautier static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx)
6520d21680cSYann Gautier {
6530d21680cSYann Gautier 	return &stm32mp1_clk_pll[idx];
6540d21680cSYann Gautier }
6550d21680cSYann Gautier 
6560d21680cSYann Gautier static void stm32mp1_clk_lock(struct spinlock *lock)
6570d21680cSYann Gautier {
658e463d3f4SYann Gautier 	if (stm32mp_lock_available()) {
6590d21680cSYann Gautier 		/* Assume interrupts are masked */
6600d21680cSYann Gautier 		spin_lock(lock);
6610d21680cSYann Gautier 	}
662e463d3f4SYann Gautier }
6630d21680cSYann Gautier 
6640d21680cSYann Gautier static void stm32mp1_clk_unlock(struct spinlock *lock)
6650d21680cSYann Gautier {
666e463d3f4SYann Gautier 	if (stm32mp_lock_available()) {
6670d21680cSYann Gautier 		spin_unlock(lock);
6680d21680cSYann Gautier 	}
669e463d3f4SYann Gautier }
6700d21680cSYann Gautier 
6710d21680cSYann Gautier bool stm32mp1_rcc_is_secure(void)
6720d21680cSYann Gautier {
6730d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
6741bb9072aSEtienne Carriere 	uint32_t mask = RCC_TZCR_TZEN;
6750d21680cSYann Gautier 
6761bb9072aSEtienne Carriere 	return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
6770d21680cSYann Gautier }
6780d21680cSYann Gautier 
679b053a22eSYann Gautier bool stm32mp1_rcc_is_mckprot(void)
680b053a22eSYann Gautier {
681b053a22eSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
6821bb9072aSEtienne Carriere 	uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT;
683b053a22eSYann Gautier 
6841bb9072aSEtienne Carriere 	return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
685b053a22eSYann Gautier }
686b053a22eSYann Gautier 
6870d21680cSYann Gautier void stm32mp1_clk_rcc_regs_lock(void)
6880d21680cSYann Gautier {
6890d21680cSYann Gautier 	stm32mp1_clk_lock(&reg_lock);
6900d21680cSYann Gautier }
6910d21680cSYann Gautier 
6920d21680cSYann Gautier void stm32mp1_clk_rcc_regs_unlock(void)
6930d21680cSYann Gautier {
6940d21680cSYann Gautier 	stm32mp1_clk_unlock(&reg_lock);
6950d21680cSYann Gautier }
6960d21680cSYann Gautier 
6970d21680cSYann Gautier static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx)
6987839a050SYann Gautier {
6997839a050SYann Gautier 	if (idx >= NB_OSC) {
7007839a050SYann Gautier 		return 0;
7017839a050SYann Gautier 	}
7027839a050SYann Gautier 
7030d21680cSYann Gautier 	return stm32mp1_osc[idx];
7047839a050SYann Gautier }
7057839a050SYann Gautier 
7060d21680cSYann Gautier static int stm32mp1_clk_get_gated_id(unsigned long id)
7077839a050SYann Gautier {
7080d21680cSYann Gautier 	unsigned int i;
7097839a050SYann Gautier 
7100d21680cSYann Gautier 	for (i = 0U; i < NB_GATES; i++) {
7110d21680cSYann Gautier 		if (gate_ref(i)->index == id) {
7127839a050SYann Gautier 			return i;
7137839a050SYann Gautier 		}
7147839a050SYann Gautier 	}
7157839a050SYann Gautier 
71644fb470bSYann Gautier 	ERROR("%s: clk id %lu not found\n", __func__, id);
7177839a050SYann Gautier 
7187839a050SYann Gautier 	return -EINVAL;
7197839a050SYann Gautier }
7207839a050SYann Gautier 
7210d21680cSYann Gautier static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i)
7227839a050SYann Gautier {
7230d21680cSYann Gautier 	return (enum stm32mp1_parent_sel)(gate_ref(i)->sel);
7247839a050SYann Gautier }
7257839a050SYann Gautier 
7260d21680cSYann Gautier static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i)
7277839a050SYann Gautier {
7280d21680cSYann Gautier 	return (enum stm32mp1_parent_id)(gate_ref(i)->fixed);
7297839a050SYann Gautier }
7307839a050SYann Gautier 
7310d21680cSYann Gautier static int stm32mp1_clk_get_parent(unsigned long id)
7327839a050SYann Gautier {
7330d21680cSYann Gautier 	const struct stm32mp1_clk_sel *sel;
7348fbcd9e4SEtienne Carriere 	uint32_t p_sel;
7357839a050SYann Gautier 	int i;
7367839a050SYann Gautier 	enum stm32mp1_parent_id p;
7377839a050SYann Gautier 	enum stm32mp1_parent_sel s;
7380d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
7397839a050SYann Gautier 
7408fbcd9e4SEtienne Carriere 	/* Few non gateable clock have a static parent ID, find them */
7418fbcd9e4SEtienne Carriere 	i = (int)clock_id2parent_id(id);
7428fbcd9e4SEtienne Carriere 	if (i != _UNKNOWN_ID) {
7438fbcd9e4SEtienne Carriere 		return i;
7447839a050SYann Gautier 	}
7457839a050SYann Gautier 
7460d21680cSYann Gautier 	i = stm32mp1_clk_get_gated_id(id);
7477839a050SYann Gautier 	if (i < 0) {
7480d21680cSYann Gautier 		panic();
7497839a050SYann Gautier 	}
7507839a050SYann Gautier 
7510d21680cSYann Gautier 	p = stm32mp1_clk_get_fixed_parent(i);
7527839a050SYann Gautier 	if (p < _PARENT_NB) {
7537839a050SYann Gautier 		return (int)p;
7547839a050SYann Gautier 	}
7557839a050SYann Gautier 
7560d21680cSYann Gautier 	s = stm32mp1_clk_get_sel(i);
7570d21680cSYann Gautier 	if (s == _UNKNOWN_SEL) {
7580d21680cSYann Gautier 		return -EINVAL;
7590d21680cSYann Gautier 	}
7607839a050SYann Gautier 	if (s >= _PARENT_SEL_NB) {
7610d21680cSYann Gautier 		panic();
7627839a050SYann Gautier 	}
7637839a050SYann Gautier 
7640d21680cSYann Gautier 	sel = clk_sel_ref(s);
7658ae08dcdSEtienne Carriere 	p_sel = (mmio_read_32(rcc_base + sel->offset) &
7668ae08dcdSEtienne Carriere 		 (sel->msk << sel->src)) >> sel->src;
7670d21680cSYann Gautier 	if (p_sel < sel->nb_parent) {
7680d21680cSYann Gautier 		return (int)sel->parent[p_sel];
7697839a050SYann Gautier 	}
7707839a050SYann Gautier 
7717839a050SYann Gautier 	return -EINVAL;
7727839a050SYann Gautier }
7737839a050SYann Gautier 
7740d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll)
7757839a050SYann Gautier {
7760d21680cSYann Gautier 	uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr);
7770d21680cSYann Gautier 	uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK;
7787839a050SYann Gautier 
7790d21680cSYann Gautier 	return stm32mp1_clk_get_fixed(pll->refclk[src]);
7807839a050SYann Gautier }
7817839a050SYann Gautier 
7827839a050SYann Gautier /*
7837839a050SYann Gautier  * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL
7847839a050SYann Gautier  * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1)
7857839a050SYann Gautier  * - PLL3 & PLL4 => return VCO     with Fpll_y_ck = FVCO / (DIVy + 1)
7867839a050SYann Gautier  * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1)
7877839a050SYann Gautier  */
7880d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll)
7897839a050SYann Gautier {
7907839a050SYann Gautier 	unsigned long refclk, fvco;
7917839a050SYann Gautier 	uint32_t cfgr1, fracr, divm, divn;
7920d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
7937839a050SYann Gautier 
7940d21680cSYann Gautier 	cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1);
7950d21680cSYann Gautier 	fracr = mmio_read_32(rcc_base + pll->pllxfracr);
7967839a050SYann Gautier 
7977839a050SYann Gautier 	divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT;
7987839a050SYann Gautier 	divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK;
7997839a050SYann Gautier 
8000d21680cSYann Gautier 	refclk = stm32mp1_pll_get_fref(pll);
8017839a050SYann Gautier 
8027839a050SYann Gautier 	/*
8037839a050SYann Gautier 	 * With FRACV :
8047839a050SYann Gautier 	 *   Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1)
8057839a050SYann Gautier 	 * Without FRACV
8067839a050SYann Gautier 	 *   Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1)
8077839a050SYann Gautier 	 */
8087839a050SYann Gautier 	if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) {
8090d21680cSYann Gautier 		uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >>
8100d21680cSYann Gautier 				 RCC_PLLNFRACR_FRACV_SHIFT;
8117839a050SYann Gautier 		unsigned long long numerator, denominator;
8127839a050SYann Gautier 
8130d21680cSYann Gautier 		numerator = (((unsigned long long)divn + 1U) << 13) + fracv;
8140d21680cSYann Gautier 		numerator = refclk * numerator;
8157839a050SYann Gautier 		denominator = ((unsigned long long)divm + 1U) << 13;
8167839a050SYann Gautier 		fvco = (unsigned long)(numerator / denominator);
8177839a050SYann Gautier 	} else {
8187839a050SYann Gautier 		fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U));
8197839a050SYann Gautier 	}
8207839a050SYann Gautier 
8217839a050SYann Gautier 	return fvco;
8227839a050SYann Gautier }
8237839a050SYann Gautier 
8240d21680cSYann Gautier static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id,
8257839a050SYann Gautier 					    enum stm32mp1_div_id div_id)
8267839a050SYann Gautier {
8270d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
8287839a050SYann Gautier 	unsigned long dfout;
8297839a050SYann Gautier 	uint32_t cfgr2, divy;
8307839a050SYann Gautier 
8317839a050SYann Gautier 	if (div_id >= _DIV_NB) {
8327839a050SYann Gautier 		return 0;
8337839a050SYann Gautier 	}
8347839a050SYann Gautier 
8350d21680cSYann Gautier 	cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2);
8367839a050SYann Gautier 	divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK;
8377839a050SYann Gautier 
8380d21680cSYann Gautier 	dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U);
8397839a050SYann Gautier 
8407839a050SYann Gautier 	return dfout;
8417839a050SYann Gautier }
8427839a050SYann Gautier 
8430d21680cSYann Gautier static unsigned long get_clock_rate(int p)
8447839a050SYann Gautier {
8457839a050SYann Gautier 	uint32_t reg, clkdiv;
8467839a050SYann Gautier 	unsigned long clock = 0;
8470d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
8487839a050SYann Gautier 
8497839a050SYann Gautier 	switch (p) {
8507839a050SYann Gautier 	case _CK_MPU:
8517839a050SYann Gautier 	/* MPU sub system */
8520d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MPCKSELR);
8537839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
8547839a050SYann Gautier 		case RCC_MPCKSELR_HSI:
8550d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
8567839a050SYann Gautier 			break;
8577839a050SYann Gautier 		case RCC_MPCKSELR_HSE:
8580d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
8597839a050SYann Gautier 			break;
8607839a050SYann Gautier 		case RCC_MPCKSELR_PLL:
8610d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
8627839a050SYann Gautier 			break;
8637839a050SYann Gautier 		case RCC_MPCKSELR_PLL_MPUDIV:
8640d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
8657839a050SYann Gautier 
8660d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_MPCKDIVR);
8677839a050SYann Gautier 			clkdiv = reg & RCC_MPUDIV_MASK;
868602ae2f2SGabriel Fernandez 			clock >>= stm32mp1_mpu_div[clkdiv];
8697839a050SYann Gautier 			break;
8707839a050SYann Gautier 		default:
8717839a050SYann Gautier 			break;
8727839a050SYann Gautier 		}
8737839a050SYann Gautier 		break;
8747839a050SYann Gautier 	/* AXI sub system */
8757839a050SYann Gautier 	case _ACLK:
8767839a050SYann Gautier 	case _HCLK2:
8777839a050SYann Gautier 	case _HCLK6:
8787839a050SYann Gautier 	case _PCLK4:
8797839a050SYann Gautier 	case _PCLK5:
8800d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_ASSCKSELR);
8817839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
8827839a050SYann Gautier 		case RCC_ASSCKSELR_HSI:
8830d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
8847839a050SYann Gautier 			break;
8857839a050SYann Gautier 		case RCC_ASSCKSELR_HSE:
8860d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
8877839a050SYann Gautier 			break;
8887839a050SYann Gautier 		case RCC_ASSCKSELR_PLL:
8890d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
8907839a050SYann Gautier 			break;
8917839a050SYann Gautier 		default:
8927839a050SYann Gautier 			break;
8937839a050SYann Gautier 		}
8947839a050SYann Gautier 
8957839a050SYann Gautier 		/* System clock divider */
8960d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_AXIDIVR);
8977839a050SYann Gautier 		clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK];
8987839a050SYann Gautier 
8997839a050SYann Gautier 		switch (p) {
9007839a050SYann Gautier 		case _PCLK4:
9010d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB4DIVR);
9027839a050SYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
9037839a050SYann Gautier 			break;
9047839a050SYann Gautier 		case _PCLK5:
9050d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB5DIVR);
9067839a050SYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
9077839a050SYann Gautier 			break;
9087839a050SYann Gautier 		default:
9097839a050SYann Gautier 			break;
9107839a050SYann Gautier 		}
9117839a050SYann Gautier 		break;
912b053a22eSYann Gautier 	/* MCU sub system */
913b053a22eSYann Gautier 	case _CK_MCU:
914b053a22eSYann Gautier 	case _PCLK1:
915b053a22eSYann Gautier 	case _PCLK2:
916b053a22eSYann Gautier 	case _PCLK3:
917b053a22eSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MSSCKSELR);
918b053a22eSYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
919b053a22eSYann Gautier 		case RCC_MSSCKSELR_HSI:
920b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
921b053a22eSYann Gautier 			break;
922b053a22eSYann Gautier 		case RCC_MSSCKSELR_HSE:
923b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
924b053a22eSYann Gautier 			break;
925b053a22eSYann Gautier 		case RCC_MSSCKSELR_CSI:
926b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_CSI);
927b053a22eSYann Gautier 			break;
928b053a22eSYann Gautier 		case RCC_MSSCKSELR_PLL:
929b053a22eSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
930b053a22eSYann Gautier 			break;
931b053a22eSYann Gautier 		default:
932b053a22eSYann Gautier 			break;
933b053a22eSYann Gautier 		}
934b053a22eSYann Gautier 
935b053a22eSYann Gautier 		/* MCU clock divider */
936b053a22eSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MCUDIVR);
937b053a22eSYann Gautier 		clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK];
938b053a22eSYann Gautier 
939b053a22eSYann Gautier 		switch (p) {
940b053a22eSYann Gautier 		case _PCLK1:
941b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB1DIVR);
942b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
943b053a22eSYann Gautier 			break;
944b053a22eSYann Gautier 		case _PCLK2:
945b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB2DIVR);
946b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
947b053a22eSYann Gautier 			break;
948b053a22eSYann Gautier 		case _PCLK3:
949b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB3DIVR);
950b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
951b053a22eSYann Gautier 			break;
952b053a22eSYann Gautier 		case _CK_MCU:
953b053a22eSYann Gautier 		default:
954b053a22eSYann Gautier 			break;
955b053a22eSYann Gautier 		}
956b053a22eSYann Gautier 		break;
9577839a050SYann Gautier 	case _CK_PER:
9580d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_CPERCKSELR);
9597839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
9607839a050SYann Gautier 		case RCC_CPERCKSELR_HSI:
9610d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
9627839a050SYann Gautier 			break;
9637839a050SYann Gautier 		case RCC_CPERCKSELR_HSE:
9640d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
9657839a050SYann Gautier 			break;
9667839a050SYann Gautier 		case RCC_CPERCKSELR_CSI:
9670d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_CSI);
9687839a050SYann Gautier 			break;
9697839a050SYann Gautier 		default:
9707839a050SYann Gautier 			break;
9717839a050SYann Gautier 		}
9727839a050SYann Gautier 		break;
9737839a050SYann Gautier 	case _HSI:
9747839a050SYann Gautier 	case _HSI_KER:
9750d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSI);
9767839a050SYann Gautier 		break;
9777839a050SYann Gautier 	case _CSI:
9787839a050SYann Gautier 	case _CSI_KER:
9790d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_CSI);
9807839a050SYann Gautier 		break;
9817839a050SYann Gautier 	case _HSE:
9827839a050SYann Gautier 	case _HSE_KER:
9830d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSE);
9847839a050SYann Gautier 		break;
9857839a050SYann Gautier 	case _HSE_KER_DIV2:
9860d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSE) >> 1;
9877839a050SYann Gautier 		break;
988cbd2e8a6SGabriel Fernandez 	case _HSE_RTC:
989cbd2e8a6SGabriel Fernandez 		clock = stm32mp1_clk_get_fixed(_HSE);
990cbd2e8a6SGabriel Fernandez 		clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U;
991cbd2e8a6SGabriel Fernandez 		break;
9927839a050SYann Gautier 	case _LSI:
9930d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_LSI);
9947839a050SYann Gautier 		break;
9957839a050SYann Gautier 	case _LSE:
9960d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_LSE);
9977839a050SYann Gautier 		break;
9987839a050SYann Gautier 	/* PLL */
9997839a050SYann Gautier 	case _PLL1_P:
10000d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
10017839a050SYann Gautier 		break;
10027839a050SYann Gautier 	case _PLL1_Q:
10030d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q);
10047839a050SYann Gautier 		break;
10057839a050SYann Gautier 	case _PLL1_R:
10060d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R);
10077839a050SYann Gautier 		break;
10087839a050SYann Gautier 	case _PLL2_P:
10090d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
10107839a050SYann Gautier 		break;
10117839a050SYann Gautier 	case _PLL2_Q:
10120d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q);
10137839a050SYann Gautier 		break;
10147839a050SYann Gautier 	case _PLL2_R:
10150d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R);
10167839a050SYann Gautier 		break;
10177839a050SYann Gautier 	case _PLL3_P:
10180d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
10197839a050SYann Gautier 		break;
10207839a050SYann Gautier 	case _PLL3_Q:
10210d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q);
10227839a050SYann Gautier 		break;
10237839a050SYann Gautier 	case _PLL3_R:
10240d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R);
10257839a050SYann Gautier 		break;
10267839a050SYann Gautier 	case _PLL4_P:
10270d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P);
10287839a050SYann Gautier 		break;
10297839a050SYann Gautier 	case _PLL4_Q:
10300d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q);
10317839a050SYann Gautier 		break;
10327839a050SYann Gautier 	case _PLL4_R:
10330d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R);
10347839a050SYann Gautier 		break;
10357839a050SYann Gautier 	/* Other */
10367839a050SYann Gautier 	case _USB_PHY_48:
10370d21680cSYann Gautier 		clock = USB_PHY_48_MHZ;
10387839a050SYann Gautier 		break;
10397839a050SYann Gautier 	default:
10407839a050SYann Gautier 		break;
10417839a050SYann Gautier 	}
10427839a050SYann Gautier 
10437839a050SYann Gautier 	return clock;
10447839a050SYann Gautier }
10457839a050SYann Gautier 
10460d21680cSYann Gautier static void __clk_enable(struct stm32mp1_clk_gate const *gate)
10470d21680cSYann Gautier {
10480d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10490d21680cSYann Gautier 
105025be845eSEtienne Carriere 	VERBOSE("Enable clock %u\n", gate->index);
105125be845eSEtienne Carriere 
10520d21680cSYann Gautier 	if (gate->set_clr != 0U) {
10530d21680cSYann Gautier 		mmio_write_32(rcc_base + gate->offset, BIT(gate->bit));
10540d21680cSYann Gautier 	} else {
10550d21680cSYann Gautier 		mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit));
10560d21680cSYann Gautier 	}
10570d21680cSYann Gautier }
10580d21680cSYann Gautier 
10590d21680cSYann Gautier static void __clk_disable(struct stm32mp1_clk_gate const *gate)
10600d21680cSYann Gautier {
10610d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10620d21680cSYann Gautier 
106325be845eSEtienne Carriere 	VERBOSE("Disable clock %u\n", gate->index);
106425be845eSEtienne Carriere 
10650d21680cSYann Gautier 	if (gate->set_clr != 0U) {
10660d21680cSYann Gautier 		mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET,
10670d21680cSYann Gautier 			      BIT(gate->bit));
10680d21680cSYann Gautier 	} else {
10690d21680cSYann Gautier 		mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit));
10700d21680cSYann Gautier 	}
10710d21680cSYann Gautier }
10720d21680cSYann Gautier 
10730d21680cSYann Gautier static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate)
10740d21680cSYann Gautier {
10750d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10760d21680cSYann Gautier 
10770d21680cSYann Gautier 	return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit);
10780d21680cSYann Gautier }
10790d21680cSYann Gautier 
108035848200SEtienne Carriere /* Oscillators and PLLs are not gated at runtime */
108135848200SEtienne Carriere static bool clock_is_always_on(unsigned long id)
108235848200SEtienne Carriere {
108335848200SEtienne Carriere 	switch (id) {
108435848200SEtienne Carriere 	case CK_HSE:
108535848200SEtienne Carriere 	case CK_CSI:
108635848200SEtienne Carriere 	case CK_LSI:
108735848200SEtienne Carriere 	case CK_LSE:
108835848200SEtienne Carriere 	case CK_HSI:
108935848200SEtienne Carriere 	case CK_HSE_DIV2:
109035848200SEtienne Carriere 	case PLL1_Q:
109135848200SEtienne Carriere 	case PLL1_R:
109235848200SEtienne Carriere 	case PLL2_P:
109335848200SEtienne Carriere 	case PLL2_Q:
109435848200SEtienne Carriere 	case PLL2_R:
109535848200SEtienne Carriere 	case PLL3_P:
109635848200SEtienne Carriere 	case PLL3_Q:
109735848200SEtienne Carriere 	case PLL3_R:
1098bf39318dSYann Gautier 	case CK_AXI:
1099bf39318dSYann Gautier 	case CK_MPU:
1100bf39318dSYann Gautier 	case CK_MCU:
11015b111c74SHE Shushan 	case RTC:
110235848200SEtienne Carriere 		return true;
110335848200SEtienne Carriere 	default:
110435848200SEtienne Carriere 		return false;
110535848200SEtienne Carriere 	}
110635848200SEtienne Carriere }
110735848200SEtienne Carriere 
11082444d231SYann Gautier static void __stm32mp1_clk_enable(unsigned long id, bool with_refcnt)
11090d21680cSYann Gautier {
11100d21680cSYann Gautier 	const struct stm32mp1_clk_gate *gate;
111135848200SEtienne Carriere 	int i;
11120d21680cSYann Gautier 
111335848200SEtienne Carriere 	if (clock_is_always_on(id)) {
111435848200SEtienne Carriere 		return;
111535848200SEtienne Carriere 	}
111635848200SEtienne Carriere 
111735848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
11180d21680cSYann Gautier 	if (i < 0) {
111944fb470bSYann Gautier 		ERROR("Clock %lu can't be enabled\n", id);
11200d21680cSYann Gautier 		panic();
11210d21680cSYann Gautier 	}
11220d21680cSYann Gautier 
11230d21680cSYann Gautier 	gate = gate_ref(i);
11242444d231SYann Gautier 
11252444d231SYann Gautier 	if (!with_refcnt) {
11262444d231SYann Gautier 		__clk_enable(gate);
11272444d231SYann Gautier 		return;
11282444d231SYann Gautier 	}
11290d21680cSYann Gautier 
1130*3d69149aSYann Gautier #if defined(IMAGE_BL32)
1131*3d69149aSYann Gautier 	if (gate_is_non_secure(gate)) {
1132*3d69149aSYann Gautier 		/* Enable non-secure clock w/o any refcounting */
1133*3d69149aSYann Gautier 		__clk_enable(gate);
1134*3d69149aSYann Gautier 		return;
1135*3d69149aSYann Gautier 	}
1136*3d69149aSYann Gautier #endif
1137*3d69149aSYann Gautier 
11380d21680cSYann Gautier 	stm32mp1_clk_lock(&refcount_lock);
11390d21680cSYann Gautier 
11402444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
11410d21680cSYann Gautier 		__clk_enable(gate);
11420d21680cSYann Gautier 	}
11430d21680cSYann Gautier 
11442444d231SYann Gautier 	gate_refcounts[i]++;
11452444d231SYann Gautier 	if (gate_refcounts[i] == UINT_MAX) {
11462444d231SYann Gautier 		ERROR("Clock %lu refcount reached max value\n", id);
11472444d231SYann Gautier 		panic();
11482444d231SYann Gautier 	}
11492444d231SYann Gautier 
11500d21680cSYann Gautier 	stm32mp1_clk_unlock(&refcount_lock);
11510d21680cSYann Gautier }
11520d21680cSYann Gautier 
11532444d231SYann Gautier static void __stm32mp1_clk_disable(unsigned long id, bool with_refcnt)
11540d21680cSYann Gautier {
11550d21680cSYann Gautier 	const struct stm32mp1_clk_gate *gate;
115635848200SEtienne Carriere 	int i;
11570d21680cSYann Gautier 
115835848200SEtienne Carriere 	if (clock_is_always_on(id)) {
115935848200SEtienne Carriere 		return;
116035848200SEtienne Carriere 	}
116135848200SEtienne Carriere 
116235848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
11630d21680cSYann Gautier 	if (i < 0) {
116444fb470bSYann Gautier 		ERROR("Clock %lu can't be disabled\n", id);
11650d21680cSYann Gautier 		panic();
11660d21680cSYann Gautier 	}
11670d21680cSYann Gautier 
11680d21680cSYann Gautier 	gate = gate_ref(i);
11692444d231SYann Gautier 
11702444d231SYann Gautier 	if (!with_refcnt) {
11712444d231SYann Gautier 		__clk_disable(gate);
11722444d231SYann Gautier 		return;
11732444d231SYann Gautier 	}
11740d21680cSYann Gautier 
1175*3d69149aSYann Gautier #if defined(IMAGE_BL32)
1176*3d69149aSYann Gautier 	if (gate_is_non_secure(gate)) {
1177*3d69149aSYann Gautier 		/* Don't disable non-secure clocks */
1178*3d69149aSYann Gautier 		return;
1179*3d69149aSYann Gautier 	}
1180*3d69149aSYann Gautier #endif
1181*3d69149aSYann Gautier 
11820d21680cSYann Gautier 	stm32mp1_clk_lock(&refcount_lock);
11830d21680cSYann Gautier 
11842444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
11852444d231SYann Gautier 		ERROR("Clock %lu refcount reached 0\n", id);
11862444d231SYann Gautier 		panic();
11872444d231SYann Gautier 	}
11882444d231SYann Gautier 	gate_refcounts[i]--;
11892444d231SYann Gautier 
11902444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
11910d21680cSYann Gautier 		__clk_disable(gate);
11920d21680cSYann Gautier 	}
11930d21680cSYann Gautier 
11940d21680cSYann Gautier 	stm32mp1_clk_unlock(&refcount_lock);
11950d21680cSYann Gautier }
11960d21680cSYann Gautier 
119733667d29SYann Gautier static int stm32mp_clk_enable(unsigned long id)
11980d21680cSYann Gautier {
11990d21680cSYann Gautier 	__stm32mp1_clk_enable(id, true);
120033667d29SYann Gautier 
120133667d29SYann Gautier 	return 0;
12020d21680cSYann Gautier }
12030d21680cSYann Gautier 
120433667d29SYann Gautier static void stm32mp_clk_disable(unsigned long id)
12050d21680cSYann Gautier {
12060d21680cSYann Gautier 	__stm32mp1_clk_disable(id, true);
12070d21680cSYann Gautier }
12080d21680cSYann Gautier 
120933667d29SYann Gautier static bool stm32mp_clk_is_enabled(unsigned long id)
12107839a050SYann Gautier {
121135848200SEtienne Carriere 	int i;
12127839a050SYann Gautier 
121335848200SEtienne Carriere 	if (clock_is_always_on(id)) {
121435848200SEtienne Carriere 		return true;
121535848200SEtienne Carriere 	}
121635848200SEtienne Carriere 
121735848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
12187839a050SYann Gautier 	if (i < 0) {
12190d21680cSYann Gautier 		panic();
12207839a050SYann Gautier 	}
12217839a050SYann Gautier 
12220d21680cSYann Gautier 	return __clk_is_enabled(gate_ref(i));
12237839a050SYann Gautier }
12247839a050SYann Gautier 
122533667d29SYann Gautier static unsigned long stm32mp_clk_get_rate(unsigned long id)
12267839a050SYann Gautier {
122733667d29SYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
12280d21680cSYann Gautier 	int p = stm32mp1_clk_get_parent(id);
122933667d29SYann Gautier 	uint32_t prescaler, timpre;
123033667d29SYann Gautier 	unsigned long parent_rate;
12317839a050SYann Gautier 
12327839a050SYann Gautier 	if (p < 0) {
12337839a050SYann Gautier 		return 0;
12347839a050SYann Gautier 	}
12357839a050SYann Gautier 
123633667d29SYann Gautier 	parent_rate = get_clock_rate(p);
123733667d29SYann Gautier 
123833667d29SYann Gautier 	switch (id) {
123933667d29SYann Gautier 	case TIM2_K:
124033667d29SYann Gautier 	case TIM3_K:
124133667d29SYann Gautier 	case TIM4_K:
124233667d29SYann Gautier 	case TIM5_K:
124333667d29SYann Gautier 	case TIM6_K:
124433667d29SYann Gautier 	case TIM7_K:
124533667d29SYann Gautier 	case TIM12_K:
124633667d29SYann Gautier 	case TIM13_K:
124733667d29SYann Gautier 	case TIM14_K:
124833667d29SYann Gautier 		prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) &
124933667d29SYann Gautier 			    RCC_APBXDIV_MASK;
125033667d29SYann Gautier 		timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) &
125133667d29SYann Gautier 			 RCC_TIMGXPRER_TIMGXPRE;
125233667d29SYann Gautier 		break;
125333667d29SYann Gautier 
125433667d29SYann Gautier 	case TIM1_K:
125533667d29SYann Gautier 	case TIM8_K:
125633667d29SYann Gautier 	case TIM15_K:
125733667d29SYann Gautier 	case TIM16_K:
125833667d29SYann Gautier 	case TIM17_K:
125933667d29SYann Gautier 		prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) &
126033667d29SYann Gautier 			    RCC_APBXDIV_MASK;
126133667d29SYann Gautier 		timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) &
126233667d29SYann Gautier 			 RCC_TIMGXPRER_TIMGXPRE;
126333667d29SYann Gautier 		break;
126433667d29SYann Gautier 
126533667d29SYann Gautier 	default:
126633667d29SYann Gautier 		return parent_rate;
126733667d29SYann Gautier 	}
126833667d29SYann Gautier 
126933667d29SYann Gautier 	if (prescaler == 0U) {
127033667d29SYann Gautier 		return parent_rate;
127133667d29SYann Gautier 	}
127233667d29SYann Gautier 
127333667d29SYann Gautier 	return parent_rate * (timpre + 1U) * 2U;
12747839a050SYann Gautier }
12757839a050SYann Gautier 
12760d21680cSYann Gautier static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on)
12777839a050SYann Gautier {
12780d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
12797839a050SYann Gautier 
12800d21680cSYann Gautier 	if (enable) {
12817839a050SYann Gautier 		mmio_setbits_32(address, mask_on);
12827839a050SYann Gautier 	} else {
12837839a050SYann Gautier 		mmio_clrbits_32(address, mask_on);
12847839a050SYann Gautier 	}
12857839a050SYann Gautier }
12867839a050SYann Gautier 
12870d21680cSYann Gautier static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on)
12887839a050SYann Gautier {
12890d21680cSYann Gautier 	uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR;
12900d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
12910d21680cSYann Gautier 
12920d21680cSYann Gautier 	mmio_write_32(address, mask_on);
12937839a050SYann Gautier }
12947839a050SYann Gautier 
12950d21680cSYann Gautier static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy)
12967839a050SYann Gautier {
1297dfdb057aSYann Gautier 	uint64_t timeout;
12987839a050SYann Gautier 	uint32_t mask_test;
12990d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
13007839a050SYann Gautier 
13010d21680cSYann Gautier 	if (enable) {
13027839a050SYann Gautier 		mask_test = mask_rdy;
13037839a050SYann Gautier 	} else {
13047839a050SYann Gautier 		mask_test = 0;
13057839a050SYann Gautier 	}
13067839a050SYann Gautier 
1307dfdb057aSYann Gautier 	timeout = timeout_init_us(OSCRDY_TIMEOUT);
13087839a050SYann Gautier 	while ((mmio_read_32(address) & mask_rdy) != mask_test) {
1309dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
13100d21680cSYann Gautier 			ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n",
13117839a050SYann Gautier 			      mask_rdy, address, enable, mmio_read_32(address));
13127839a050SYann Gautier 			return -ETIMEDOUT;
13137839a050SYann Gautier 		}
13147839a050SYann Gautier 	}
13157839a050SYann Gautier 
13167839a050SYann Gautier 	return 0;
13177839a050SYann Gautier }
13187839a050SYann Gautier 
13190d21680cSYann Gautier static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv)
13207839a050SYann Gautier {
13217839a050SYann Gautier 	uint32_t value;
13220d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13237839a050SYann Gautier 
13240d21680cSYann Gautier 	if (digbyp) {
13250d21680cSYann Gautier 		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP);
13260d21680cSYann Gautier 	}
13270d21680cSYann Gautier 
13280d21680cSYann Gautier 	if (bypass || digbyp) {
13290d21680cSYann Gautier 		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP);
13307839a050SYann Gautier 	}
13317839a050SYann Gautier 
13327839a050SYann Gautier 	/*
13337839a050SYann Gautier 	 * Warning: not recommended to switch directly from "high drive"
13347839a050SYann Gautier 	 * to "medium low drive", and vice-versa.
13357839a050SYann Gautier 	 */
13360d21680cSYann Gautier 	value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >>
13377839a050SYann Gautier 		RCC_BDCR_LSEDRV_SHIFT;
13387839a050SYann Gautier 
13397839a050SYann Gautier 	while (value != lsedrv) {
13407839a050SYann Gautier 		if (value > lsedrv) {
13417839a050SYann Gautier 			value--;
13427839a050SYann Gautier 		} else {
13437839a050SYann Gautier 			value++;
13447839a050SYann Gautier 		}
13457839a050SYann Gautier 
13460d21680cSYann Gautier 		mmio_clrsetbits_32(rcc_base + RCC_BDCR,
13477839a050SYann Gautier 				   RCC_BDCR_LSEDRV_MASK,
13487839a050SYann Gautier 				   value << RCC_BDCR_LSEDRV_SHIFT);
13497839a050SYann Gautier 	}
13507839a050SYann Gautier 
13510d21680cSYann Gautier 	stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON);
13527839a050SYann Gautier }
13537839a050SYann Gautier 
13540d21680cSYann Gautier static void stm32mp1_lse_wait(void)
13557839a050SYann Gautier {
13560d21680cSYann Gautier 	if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) {
13577839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
13587839a050SYann Gautier 	}
13597839a050SYann Gautier }
13607839a050SYann Gautier 
13610d21680cSYann Gautier static void stm32mp1_lsi_set(bool enable)
13627839a050SYann Gautier {
13630d21680cSYann Gautier 	stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION);
13640d21680cSYann Gautier 
13650d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) {
13667839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
13677839a050SYann Gautier 	}
13687839a050SYann Gautier }
13697839a050SYann Gautier 
13700d21680cSYann Gautier static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css)
13717839a050SYann Gautier {
13720d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13730d21680cSYann Gautier 
13740d21680cSYann Gautier 	if (digbyp) {
13750d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP);
13767839a050SYann Gautier 	}
13777839a050SYann Gautier 
13780d21680cSYann Gautier 	if (bypass || digbyp) {
13790d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP);
13800d21680cSYann Gautier 	}
13810d21680cSYann Gautier 
13820d21680cSYann Gautier 	stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON);
13830d21680cSYann Gautier 	if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) {
13847839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
13857839a050SYann Gautier 	}
13867839a050SYann Gautier 
13877839a050SYann Gautier 	if (css) {
13880d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON);
13897839a050SYann Gautier 	}
139031e9750bSLionel Debieve 
139131e9750bSLionel Debieve #if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
139231e9750bSLionel Debieve 	if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) &&
139331e9750bSLionel Debieve 	    (!(digbyp || bypass))) {
139431e9750bSLionel Debieve 		panic();
139531e9750bSLionel Debieve 	}
139631e9750bSLionel Debieve #endif
13977839a050SYann Gautier }
13987839a050SYann Gautier 
13990d21680cSYann Gautier static void stm32mp1_csi_set(bool enable)
14007839a050SYann Gautier {
14010d21680cSYann Gautier 	stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION);
14020d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) {
14037839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
14047839a050SYann Gautier 	}
14057839a050SYann Gautier }
14067839a050SYann Gautier 
14070d21680cSYann Gautier static void stm32mp1_hsi_set(bool enable)
14087839a050SYann Gautier {
14090d21680cSYann Gautier 	stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION);
14100d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) {
14117839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
14127839a050SYann Gautier 	}
14137839a050SYann Gautier }
14147839a050SYann Gautier 
14150d21680cSYann Gautier static int stm32mp1_set_hsidiv(uint8_t hsidiv)
14167839a050SYann Gautier {
1417dfdb057aSYann Gautier 	uint64_t timeout;
14180d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
14190d21680cSYann Gautier 	uintptr_t address = rcc_base + RCC_OCRDYR;
14207839a050SYann Gautier 
14210d21680cSYann Gautier 	mmio_clrsetbits_32(rcc_base + RCC_HSICFGR,
14227839a050SYann Gautier 			   RCC_HSICFGR_HSIDIV_MASK,
14237839a050SYann Gautier 			   RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv);
14247839a050SYann Gautier 
1425dfdb057aSYann Gautier 	timeout = timeout_init_us(HSIDIV_TIMEOUT);
14267839a050SYann Gautier 	while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) {
1427dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
14280d21680cSYann Gautier 			ERROR("HSIDIV failed @ 0x%lx: 0x%x\n",
14297839a050SYann Gautier 			      address, mmio_read_32(address));
14307839a050SYann Gautier 			return -ETIMEDOUT;
14317839a050SYann Gautier 		}
14327839a050SYann Gautier 	}
14337839a050SYann Gautier 
14347839a050SYann Gautier 	return 0;
14357839a050SYann Gautier }
14367839a050SYann Gautier 
14370d21680cSYann Gautier static int stm32mp1_hsidiv(unsigned long hsifreq)
14387839a050SYann Gautier {
14397839a050SYann Gautier 	uint8_t hsidiv;
14407839a050SYann Gautier 	uint32_t hsidivfreq = MAX_HSI_HZ;
14417839a050SYann Gautier 
14427839a050SYann Gautier 	for (hsidiv = 0; hsidiv < 4U; hsidiv++) {
14437839a050SYann Gautier 		if (hsidivfreq == hsifreq) {
14447839a050SYann Gautier 			break;
14457839a050SYann Gautier 		}
14467839a050SYann Gautier 
14477839a050SYann Gautier 		hsidivfreq /= 2U;
14487839a050SYann Gautier 	}
14497839a050SYann Gautier 
14507839a050SYann Gautier 	if (hsidiv == 4U) {
14517839a050SYann Gautier 		ERROR("Invalid clk-hsi frequency\n");
14527839a050SYann Gautier 		return -1;
14537839a050SYann Gautier 	}
14547839a050SYann Gautier 
14557839a050SYann Gautier 	if (hsidiv != 0U) {
14560d21680cSYann Gautier 		return stm32mp1_set_hsidiv(hsidiv);
14577839a050SYann Gautier 	}
14587839a050SYann Gautier 
14597839a050SYann Gautier 	return 0;
14607839a050SYann Gautier }
14617839a050SYann Gautier 
14620d21680cSYann Gautier static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id,
14630d21680cSYann Gautier 				    unsigned int clksrc,
14640d21680cSYann Gautier 				    uint32_t *pllcfg, int plloff)
14657839a050SYann Gautier {
14660d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
14670d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
14680d21680cSYann Gautier 	uintptr_t pllxcr = rcc_base + pll->pllxcr;
14690d21680cSYann Gautier 	enum stm32mp1_plltype type = pll->plltype;
14700d21680cSYann Gautier 	uintptr_t clksrc_address = rcc_base + (clksrc >> 4);
14710d21680cSYann Gautier 	unsigned long refclk;
14720d21680cSYann Gautier 	uint32_t ifrge = 0U;
1473be858cffSAndre Przywara 	uint32_t src, value, fracv = 0;
1474be858cffSAndre Przywara 	void *fdt;
14757839a050SYann Gautier 
14760d21680cSYann Gautier 	/* Check PLL output */
14770d21680cSYann Gautier 	if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) {
14780d21680cSYann Gautier 		return false;
14797839a050SYann Gautier 	}
14807839a050SYann Gautier 
14810d21680cSYann Gautier 	/* Check current clksrc */
14820d21680cSYann Gautier 	src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK;
14830d21680cSYann Gautier 	if (src != (clksrc & RCC_SELR_SRC_MASK)) {
14840d21680cSYann Gautier 		return false;
14850d21680cSYann Gautier 	}
14860d21680cSYann Gautier 
14870d21680cSYann Gautier 	/* Check Div */
14880d21680cSYann Gautier 	src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK;
14890d21680cSYann Gautier 
14900d21680cSYann Gautier 	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
14910d21680cSYann Gautier 		 (pllcfg[PLLCFG_M] + 1U);
14920d21680cSYann Gautier 
14930d21680cSYann Gautier 	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
14940d21680cSYann Gautier 	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
14950d21680cSYann Gautier 		return false;
14960d21680cSYann Gautier 	}
14970d21680cSYann Gautier 
14980d21680cSYann Gautier 	if ((type == PLL_800) && (refclk >= 8000000U)) {
14990d21680cSYann Gautier 		ifrge = 1U;
15000d21680cSYann Gautier 	}
15010d21680cSYann Gautier 
15020d21680cSYann Gautier 	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
15030d21680cSYann Gautier 		RCC_PLLNCFGR1_DIVN_MASK;
15040d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
15050d21680cSYann Gautier 		 RCC_PLLNCFGR1_DIVM_MASK;
15060d21680cSYann Gautier 	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
15070d21680cSYann Gautier 		 RCC_PLLNCFGR1_IFRGE_MASK;
15080d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) {
15090d21680cSYann Gautier 		return false;
15100d21680cSYann Gautier 	}
15110d21680cSYann Gautier 
15120d21680cSYann Gautier 	/* Fractional configuration */
1513be858cffSAndre Przywara 	if (fdt_get_address(&fdt) == 1) {
1514be858cffSAndre Przywara 		fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0);
1515be858cffSAndre Przywara 	}
15160d21680cSYann Gautier 
15170d21680cSYann Gautier 	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
15180d21680cSYann Gautier 	value |= RCC_PLLNFRACR_FRACLE;
15190d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxfracr) != value) {
15200d21680cSYann Gautier 		return false;
15210d21680cSYann Gautier 	}
15220d21680cSYann Gautier 
15230d21680cSYann Gautier 	/* Output config */
15240d21680cSYann Gautier 	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
15250d21680cSYann Gautier 		RCC_PLLNCFGR2_DIVP_MASK;
15260d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
15270d21680cSYann Gautier 		 RCC_PLLNCFGR2_DIVQ_MASK;
15280d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
15290d21680cSYann Gautier 		 RCC_PLLNCFGR2_DIVR_MASK;
15300d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) {
15310d21680cSYann Gautier 		return false;
15320d21680cSYann Gautier 	}
15330d21680cSYann Gautier 
15340d21680cSYann Gautier 	return true;
15350d21680cSYann Gautier }
15360d21680cSYann Gautier 
15370d21680cSYann Gautier static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id)
15387839a050SYann Gautier {
15390d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
15400d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
15410d21680cSYann Gautier 
1542dd98aec8SYann Gautier 	/* Preserve RCC_PLLNCR_SSCG_CTRL value */
1543dd98aec8SYann Gautier 	mmio_clrsetbits_32(pllxcr,
1544dd98aec8SYann Gautier 			   RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
1545dd98aec8SYann Gautier 			   RCC_PLLNCR_DIVREN,
1546dd98aec8SYann Gautier 			   RCC_PLLNCR_PLLON);
15470d21680cSYann Gautier }
15480d21680cSYann Gautier 
15490d21680cSYann Gautier static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output)
15500d21680cSYann Gautier {
15510d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
15520d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
1553dfdb057aSYann Gautier 	uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT);
15547839a050SYann Gautier 
15557839a050SYann Gautier 	/* Wait PLL lock */
15567839a050SYann Gautier 	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) {
1557dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
15580d21680cSYann Gautier 			ERROR("PLL%d start failed @ 0x%lx: 0x%x\n",
15597839a050SYann Gautier 			      pll_id, pllxcr, mmio_read_32(pllxcr));
15607839a050SYann Gautier 			return -ETIMEDOUT;
15617839a050SYann Gautier 		}
15627839a050SYann Gautier 	}
15637839a050SYann Gautier 
15647839a050SYann Gautier 	/* Start the requested output */
15657839a050SYann Gautier 	mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT);
15667839a050SYann Gautier 
15677839a050SYann Gautier 	return 0;
15687839a050SYann Gautier }
15697839a050SYann Gautier 
15700d21680cSYann Gautier static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id)
15717839a050SYann Gautier {
15720d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
15730d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
1574dfdb057aSYann Gautier 	uint64_t timeout;
15757839a050SYann Gautier 
15767839a050SYann Gautier 	/* Stop all output */
15777839a050SYann Gautier 	mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
15787839a050SYann Gautier 			RCC_PLLNCR_DIVREN);
15797839a050SYann Gautier 
15807839a050SYann Gautier 	/* Stop PLL */
15817839a050SYann Gautier 	mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON);
15827839a050SYann Gautier 
1583dfdb057aSYann Gautier 	timeout = timeout_init_us(PLLRDY_TIMEOUT);
15847839a050SYann Gautier 	/* Wait PLL stopped */
15857839a050SYann Gautier 	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) {
1586dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
15870d21680cSYann Gautier 			ERROR("PLL%d stop failed @ 0x%lx: 0x%x\n",
15887839a050SYann Gautier 			      pll_id, pllxcr, mmio_read_32(pllxcr));
15897839a050SYann Gautier 			return -ETIMEDOUT;
15907839a050SYann Gautier 		}
15917839a050SYann Gautier 	}
15927839a050SYann Gautier 
15937839a050SYann Gautier 	return 0;
15947839a050SYann Gautier }
15957839a050SYann Gautier 
15960d21680cSYann Gautier static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id,
15977839a050SYann Gautier 				       uint32_t *pllcfg)
15987839a050SYann Gautier {
15990d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
16000d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
16017839a050SYann Gautier 	uint32_t value;
16027839a050SYann Gautier 
16037839a050SYann Gautier 	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
16047839a050SYann Gautier 		RCC_PLLNCFGR2_DIVP_MASK;
16057839a050SYann Gautier 	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
16067839a050SYann Gautier 		 RCC_PLLNCFGR2_DIVQ_MASK;
16077839a050SYann Gautier 	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
16087839a050SYann Gautier 		 RCC_PLLNCFGR2_DIVR_MASK;
16090d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxcfgr2, value);
16107839a050SYann Gautier }
16117839a050SYann Gautier 
16120d21680cSYann Gautier static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id,
16137839a050SYann Gautier 			       uint32_t *pllcfg, uint32_t fracv)
16147839a050SYann Gautier {
16150d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
16160d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
16170d21680cSYann Gautier 	enum stm32mp1_plltype type = pll->plltype;
16187839a050SYann Gautier 	unsigned long refclk;
16197839a050SYann Gautier 	uint32_t ifrge = 0;
16207839a050SYann Gautier 	uint32_t src, value;
16217839a050SYann Gautier 
16220d21680cSYann Gautier 	src = mmio_read_32(rcc_base + pll->rckxselr) &
16237839a050SYann Gautier 		RCC_SELR_REFCLK_SRC_MASK;
16247839a050SYann Gautier 
16250d21680cSYann Gautier 	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
16267839a050SYann Gautier 		 (pllcfg[PLLCFG_M] + 1U);
16277839a050SYann Gautier 
16287839a050SYann Gautier 	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
16297839a050SYann Gautier 	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
16307839a050SYann Gautier 		return -EINVAL;
16317839a050SYann Gautier 	}
16327839a050SYann Gautier 
16337839a050SYann Gautier 	if ((type == PLL_800) && (refclk >= 8000000U)) {
16347839a050SYann Gautier 		ifrge = 1U;
16357839a050SYann Gautier 	}
16367839a050SYann Gautier 
16377839a050SYann Gautier 	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
16387839a050SYann Gautier 		RCC_PLLNCFGR1_DIVN_MASK;
16397839a050SYann Gautier 	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
16407839a050SYann Gautier 		 RCC_PLLNCFGR1_DIVM_MASK;
16417839a050SYann Gautier 	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
16427839a050SYann Gautier 		 RCC_PLLNCFGR1_IFRGE_MASK;
16430d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxcfgr1, value);
16447839a050SYann Gautier 
16457839a050SYann Gautier 	/* Fractional configuration */
16467839a050SYann Gautier 	value = 0;
16470d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
16487839a050SYann Gautier 
16497839a050SYann Gautier 	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
16500d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
16517839a050SYann Gautier 
16527839a050SYann Gautier 	value |= RCC_PLLNFRACR_FRACLE;
16530d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
16547839a050SYann Gautier 
16550d21680cSYann Gautier 	stm32mp1_pll_config_output(pll_id, pllcfg);
16567839a050SYann Gautier 
16577839a050SYann Gautier 	return 0;
16587839a050SYann Gautier }
16597839a050SYann Gautier 
16600d21680cSYann Gautier static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg)
16617839a050SYann Gautier {
16620d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
16637839a050SYann Gautier 	uint32_t pllxcsg = 0;
16647839a050SYann Gautier 
16657839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) &
16667839a050SYann Gautier 		    RCC_PLLNCSGR_MOD_PER_MASK;
16677839a050SYann Gautier 
16687839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) &
16697839a050SYann Gautier 		    RCC_PLLNCSGR_INC_STEP_MASK;
16707839a050SYann Gautier 
16717839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) &
16727839a050SYann Gautier 		    RCC_PLLNCSGR_SSCG_MODE_MASK;
16737839a050SYann Gautier 
16740d21680cSYann Gautier 	mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg);
1675dd98aec8SYann Gautier 
1676dd98aec8SYann Gautier 	mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr,
1677dd98aec8SYann Gautier 			RCC_PLLNCR_SSCG_CTRL);
16787839a050SYann Gautier }
16797839a050SYann Gautier 
16800d21680cSYann Gautier static int stm32mp1_set_clksrc(unsigned int clksrc)
16817839a050SYann Gautier {
16820d21680cSYann Gautier 	uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4);
1683dfdb057aSYann Gautier 	uint64_t timeout;
16847839a050SYann Gautier 
16850d21680cSYann Gautier 	mmio_clrsetbits_32(clksrc_address, RCC_SELR_SRC_MASK,
16867839a050SYann Gautier 			   clksrc & RCC_SELR_SRC_MASK);
16877839a050SYann Gautier 
1688dfdb057aSYann Gautier 	timeout = timeout_init_us(CLKSRC_TIMEOUT);
16890d21680cSYann Gautier 	while ((mmio_read_32(clksrc_address) & RCC_SELR_SRCRDY) == 0U) {
1690dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
16910d21680cSYann Gautier 			ERROR("CLKSRC %x start failed @ 0x%lx: 0x%x\n", clksrc,
16920d21680cSYann Gautier 			      clksrc_address, mmio_read_32(clksrc_address));
16937839a050SYann Gautier 			return -ETIMEDOUT;
16947839a050SYann Gautier 		}
16957839a050SYann Gautier 	}
16967839a050SYann Gautier 
16977839a050SYann Gautier 	return 0;
16987839a050SYann Gautier }
16997839a050SYann Gautier 
17000d21680cSYann Gautier static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address)
17017839a050SYann Gautier {
1702dfdb057aSYann Gautier 	uint64_t timeout;
17037839a050SYann Gautier 
17047839a050SYann Gautier 	mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK,
17057839a050SYann Gautier 			   clkdiv & RCC_DIVR_DIV_MASK);
17067839a050SYann Gautier 
1707dfdb057aSYann Gautier 	timeout = timeout_init_us(CLKDIV_TIMEOUT);
17087839a050SYann Gautier 	while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) {
1709dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
17100d21680cSYann Gautier 			ERROR("CLKDIV %x start failed @ 0x%lx: 0x%x\n",
17117839a050SYann Gautier 			      clkdiv, address, mmio_read_32(address));
17127839a050SYann Gautier 			return -ETIMEDOUT;
17137839a050SYann Gautier 		}
17147839a050SYann Gautier 	}
17157839a050SYann Gautier 
17167839a050SYann Gautier 	return 0;
17177839a050SYann Gautier }
17187839a050SYann Gautier 
17190d21680cSYann Gautier static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv)
17207839a050SYann Gautier {
17210d21680cSYann Gautier 	uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4);
17227839a050SYann Gautier 
17237839a050SYann Gautier 	/*
17247839a050SYann Gautier 	 * Binding clksrc :
17257839a050SYann Gautier 	 *      bit15-4 offset
17267839a050SYann Gautier 	 *      bit3:   disable
17277839a050SYann Gautier 	 *      bit2-0: MCOSEL[2:0]
17287839a050SYann Gautier 	 */
17297839a050SYann Gautier 	if ((clksrc & 0x8U) != 0U) {
17300d21680cSYann Gautier 		mmio_clrbits_32(clksrc_address, RCC_MCOCFG_MCOON);
17317839a050SYann Gautier 	} else {
17320d21680cSYann Gautier 		mmio_clrsetbits_32(clksrc_address,
17337839a050SYann Gautier 				   RCC_MCOCFG_MCOSRC_MASK,
17347839a050SYann Gautier 				   clksrc & RCC_MCOCFG_MCOSRC_MASK);
17350d21680cSYann Gautier 		mmio_clrsetbits_32(clksrc_address,
17367839a050SYann Gautier 				   RCC_MCOCFG_MCODIV_MASK,
17377839a050SYann Gautier 				   clkdiv << RCC_MCOCFG_MCODIV_SHIFT);
17380d21680cSYann Gautier 		mmio_setbits_32(clksrc_address, RCC_MCOCFG_MCOON);
17397839a050SYann Gautier 	}
17407839a050SYann Gautier }
17417839a050SYann Gautier 
17420d21680cSYann Gautier static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css)
17437839a050SYann Gautier {
17440d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + RCC_BDCR;
17457839a050SYann Gautier 
17467839a050SYann Gautier 	if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) ||
17477839a050SYann Gautier 	    (clksrc != (uint32_t)CLK_RTC_DISABLED)) {
17487839a050SYann Gautier 		mmio_clrsetbits_32(address,
17497839a050SYann Gautier 				   RCC_BDCR_RTCSRC_MASK,
175015509093SYann Gautier 				   (clksrc & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT);
17517839a050SYann Gautier 
17527839a050SYann Gautier 		mmio_setbits_32(address, RCC_BDCR_RTCCKEN);
17537839a050SYann Gautier 	}
17547839a050SYann Gautier 
17557839a050SYann Gautier 	if (lse_css) {
17567839a050SYann Gautier 		mmio_setbits_32(address, RCC_BDCR_LSECSSON);
17577839a050SYann Gautier 	}
17587839a050SYann Gautier }
17597839a050SYann Gautier 
17600d21680cSYann Gautier static void stm32mp1_stgen_config(void)
17617839a050SYann Gautier {
17627839a050SYann Gautier 	uint32_t cntfid0;
17637839a050SYann Gautier 	unsigned long rate;
17647839a050SYann Gautier 	unsigned long long counter;
17657839a050SYann Gautier 
1766ade9ce03SYann Gautier 	cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF);
17670d21680cSYann Gautier 	rate = get_clock_rate(stm32mp1_clk_get_parent(STGEN_K));
17680d21680cSYann Gautier 
17690d21680cSYann Gautier 	if (cntfid0 == rate) {
17700d21680cSYann Gautier 		return;
17710d21680cSYann Gautier 	}
17720d21680cSYann Gautier 
1773ade9ce03SYann Gautier 	mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
1774ade9ce03SYann Gautier 	counter = (unsigned long long)mmio_read_32(STGEN_BASE + CNTCVL_OFF);
1775ade9ce03SYann Gautier 	counter |= ((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF)) << 32;
17767839a050SYann Gautier 	counter = (counter * rate / cntfid0);
17770d21680cSYann Gautier 
1778ade9ce03SYann Gautier 	mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter);
1779ade9ce03SYann Gautier 	mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32));
1780ade9ce03SYann Gautier 	mmio_write_32(STGEN_BASE + CNTFID_OFF, rate);
1781ade9ce03SYann Gautier 	mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
17827839a050SYann Gautier 
17837839a050SYann Gautier 	write_cntfrq((u_register_t)rate);
17847839a050SYann Gautier 
17857839a050SYann Gautier 	/* Need to update timer with new frequency */
17867839a050SYann Gautier 	generic_delay_timer_init();
17877839a050SYann Gautier }
17887839a050SYann Gautier 
17897839a050SYann Gautier void stm32mp1_stgen_increment(unsigned long long offset_in_ms)
17907839a050SYann Gautier {
17917839a050SYann Gautier 	unsigned long long cnt;
17927839a050SYann Gautier 
1793ade9ce03SYann Gautier 	cnt = ((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) |
1794ade9ce03SYann Gautier 		mmio_read_32(STGEN_BASE + CNTCVL_OFF);
17957839a050SYann Gautier 
1796ade9ce03SYann Gautier 	cnt += (offset_in_ms * mmio_read_32(STGEN_BASE + CNTFID_OFF)) / 1000U;
17977839a050SYann Gautier 
1798ade9ce03SYann Gautier 	mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
1799ade9ce03SYann Gautier 	mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)cnt);
1800ade9ce03SYann Gautier 	mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(cnt >> 32));
1801ade9ce03SYann Gautier 	mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
18027839a050SYann Gautier }
18037839a050SYann Gautier 
18040d21680cSYann Gautier static void stm32mp1_pkcs_config(uint32_t pkcs)
18057839a050SYann Gautier {
18060d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU);
18077839a050SYann Gautier 	uint32_t value = pkcs & 0xFU;
18087839a050SYann Gautier 	uint32_t mask = 0xFU;
18097839a050SYann Gautier 
18107839a050SYann Gautier 	if ((pkcs & BIT(31)) != 0U) {
18117839a050SYann Gautier 		mask <<= 4;
18127839a050SYann Gautier 		value <<= 4;
18137839a050SYann Gautier 	}
18147839a050SYann Gautier 
18157839a050SYann Gautier 	mmio_clrsetbits_32(address, mask, value);
18167839a050SYann Gautier }
18177839a050SYann Gautier 
1818964e5ff1SNicolas Le Bayon static int clk_get_pll_settings_from_dt(int plloff, unsigned int *pllcfg,
1819964e5ff1SNicolas Le Bayon 					uint32_t *fracv, uint32_t *csg,
1820964e5ff1SNicolas Le Bayon 					bool *csg_set)
1821964e5ff1SNicolas Le Bayon {
1822964e5ff1SNicolas Le Bayon 	void *fdt;
1823964e5ff1SNicolas Le Bayon 	int ret;
1824964e5ff1SNicolas Le Bayon 
1825964e5ff1SNicolas Le Bayon 	if (fdt_get_address(&fdt) == 0) {
1826964e5ff1SNicolas Le Bayon 		return -FDT_ERR_NOTFOUND;
1827964e5ff1SNicolas Le Bayon 	}
1828964e5ff1SNicolas Le Bayon 
1829964e5ff1SNicolas Le Bayon 	ret = fdt_read_uint32_array(fdt, plloff, "cfg", (uint32_t)PLLCFG_NB,
1830964e5ff1SNicolas Le Bayon 				    pllcfg);
1831964e5ff1SNicolas Le Bayon 	if (ret < 0) {
1832964e5ff1SNicolas Le Bayon 		return -FDT_ERR_NOTFOUND;
1833964e5ff1SNicolas Le Bayon 	}
1834964e5ff1SNicolas Le Bayon 
1835964e5ff1SNicolas Le Bayon 	*fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0);
1836964e5ff1SNicolas Le Bayon 
1837964e5ff1SNicolas Le Bayon 	ret = fdt_read_uint32_array(fdt, plloff, "csg", (uint32_t)PLLCSG_NB,
1838964e5ff1SNicolas Le Bayon 				    csg);
1839964e5ff1SNicolas Le Bayon 
1840964e5ff1SNicolas Le Bayon 	*csg_set = (ret == 0);
1841964e5ff1SNicolas Le Bayon 
1842964e5ff1SNicolas Le Bayon 	if (ret == -FDT_ERR_NOTFOUND) {
1843964e5ff1SNicolas Le Bayon 		ret = 0;
1844964e5ff1SNicolas Le Bayon 	}
1845964e5ff1SNicolas Le Bayon 
1846964e5ff1SNicolas Le Bayon 	return ret;
1847964e5ff1SNicolas Le Bayon }
1848964e5ff1SNicolas Le Bayon 
18497839a050SYann Gautier int stm32mp1_clk_init(void)
18507839a050SYann Gautier {
18510d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
1852964e5ff1SNicolas Le Bayon 	uint32_t pllfracv[_PLL_NB];
1853964e5ff1SNicolas Le Bayon 	uint32_t pllcsg[_PLL_NB][PLLCSG_NB];
18547839a050SYann Gautier 	unsigned int clksrc[CLKSRC_NB];
18557839a050SYann Gautier 	unsigned int clkdiv[CLKDIV_NB];
18567839a050SYann Gautier 	unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
18577839a050SYann Gautier 	int plloff[_PLL_NB];
18587839a050SYann Gautier 	int ret, len;
18597839a050SYann Gautier 	enum stm32mp1_pll_id i;
1860964e5ff1SNicolas Le Bayon 	bool pllcsg_set[_PLL_NB];
1861964e5ff1SNicolas Le Bayon 	bool pllcfg_valid[_PLL_NB];
18627839a050SYann Gautier 	bool lse_css = false;
18630d21680cSYann Gautier 	bool pll3_preserve = false;
18640d21680cSYann Gautier 	bool pll4_preserve = false;
18650d21680cSYann Gautier 	bool pll4_bootrom = false;
18663e6fab43SYann Gautier 	const fdt32_t *pkcs_cell;
186752a616b4SAndre Przywara 	void *fdt;
1868bf1af154SPatrick Delaunay 	int stgen_p = stm32mp1_clk_get_parent(STGEN_K);
1869bf1af154SPatrick Delaunay 	int usbphy_p = stm32mp1_clk_get_parent(USBPHY_K);
187052a616b4SAndre Przywara 
187152a616b4SAndre Przywara 	if (fdt_get_address(&fdt) == 0) {
18728f97c4faSYann Gautier 		return -FDT_ERR_NOTFOUND;
187352a616b4SAndre Przywara 	}
18747839a050SYann Gautier 
18757839a050SYann Gautier 	/* Check status field to disable security */
18767839a050SYann Gautier 	if (!fdt_get_rcc_secure_status()) {
18770d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_TZCR, 0);
18787839a050SYann Gautier 	}
18797839a050SYann Gautier 
188052a616b4SAndre Przywara 	ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB,
188152a616b4SAndre Przywara 					clksrc);
18827839a050SYann Gautier 	if (ret < 0) {
18837839a050SYann Gautier 		return -FDT_ERR_NOTFOUND;
18847839a050SYann Gautier 	}
18857839a050SYann Gautier 
188652a616b4SAndre Przywara 	ret = fdt_rcc_read_uint32_array("st,clkdiv", (uint32_t)CLKDIV_NB,
188752a616b4SAndre Przywara 					clkdiv);
18887839a050SYann Gautier 	if (ret < 0) {
18897839a050SYann Gautier 		return -FDT_ERR_NOTFOUND;
18907839a050SYann Gautier 	}
18917839a050SYann Gautier 
18927839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
18937839a050SYann Gautier 		char name[12];
18947839a050SYann Gautier 
189539b6cc66SAntonio Nino Diaz 		snprintf(name, sizeof(name), "st,pll@%d", i);
18967839a050SYann Gautier 		plloff[i] = fdt_rcc_subnode_offset(name);
18977839a050SYann Gautier 
1898964e5ff1SNicolas Le Bayon 		pllcfg_valid[i] = fdt_check_node(plloff[i]);
1899964e5ff1SNicolas Le Bayon 		if (!pllcfg_valid[i]) {
19007839a050SYann Gautier 			continue;
19017839a050SYann Gautier 		}
19027839a050SYann Gautier 
1903964e5ff1SNicolas Le Bayon 		ret = clk_get_pll_settings_from_dt(plloff[i], pllcfg[i],
1904964e5ff1SNicolas Le Bayon 						   &pllfracv[i], pllcsg[i],
1905964e5ff1SNicolas Le Bayon 						   &pllcsg_set[i]);
1906964e5ff1SNicolas Le Bayon 		if (ret != 0) {
1907964e5ff1SNicolas Le Bayon 			return ret;
19087839a050SYann Gautier 		}
19097839a050SYann Gautier 	}
19107839a050SYann Gautier 
19110d21680cSYann Gautier 	stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]);
19120d21680cSYann Gautier 	stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]);
19137839a050SYann Gautier 
19147839a050SYann Gautier 	/*
19157839a050SYann Gautier 	 * Switch ON oscillator found in device-tree.
19167839a050SYann Gautier 	 * Note: HSI already ON after BootROM stage.
19177839a050SYann Gautier 	 */
19180d21680cSYann Gautier 	if (stm32mp1_osc[_LSI] != 0U) {
19190d21680cSYann Gautier 		stm32mp1_lsi_set(true);
19207839a050SYann Gautier 	}
19210d21680cSYann Gautier 	if (stm32mp1_osc[_LSE] != 0U) {
1922b208e3daSGabriel Fernandez 		const char *name = stm32mp_osc_node_label[_LSE];
19230d21680cSYann Gautier 		bool bypass, digbyp;
19247839a050SYann Gautier 		uint32_t lsedrv;
19257839a050SYann Gautier 
1926b208e3daSGabriel Fernandez 		bypass = fdt_clk_read_bool(name, "st,bypass");
1927b208e3daSGabriel Fernandez 		digbyp = fdt_clk_read_bool(name, "st,digbypass");
1928b208e3daSGabriel Fernandez 		lse_css = fdt_clk_read_bool(name, "st,css");
1929b208e3daSGabriel Fernandez 		lsedrv = fdt_clk_read_uint32_default(name, "st,drive",
19307839a050SYann Gautier 						     LSEDRV_MEDIUM_HIGH);
19310d21680cSYann Gautier 		stm32mp1_lse_enable(bypass, digbyp, lsedrv);
19327839a050SYann Gautier 	}
19330d21680cSYann Gautier 	if (stm32mp1_osc[_HSE] != 0U) {
1934b208e3daSGabriel Fernandez 		const char *name = stm32mp_osc_node_label[_HSE];
19350d21680cSYann Gautier 		bool bypass, digbyp, css;
19367839a050SYann Gautier 
1937b208e3daSGabriel Fernandez 		bypass = fdt_clk_read_bool(name, "st,bypass");
1938b208e3daSGabriel Fernandez 		digbyp = fdt_clk_read_bool(name, "st,digbypass");
1939b208e3daSGabriel Fernandez 		css = fdt_clk_read_bool(name, "st,css");
19400d21680cSYann Gautier 		stm32mp1_hse_enable(bypass, digbyp, css);
19417839a050SYann Gautier 	}
19427839a050SYann Gautier 	/*
19437839a050SYann Gautier 	 * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR)
19447839a050SYann Gautier 	 * => switch on CSI even if node is not present in device tree
19457839a050SYann Gautier 	 */
19460d21680cSYann Gautier 	stm32mp1_csi_set(true);
19477839a050SYann Gautier 
19487839a050SYann Gautier 	/* Come back to HSI */
19490d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(CLK_MPU_HSI);
19507839a050SYann Gautier 	if (ret != 0) {
19517839a050SYann Gautier 		return ret;
19527839a050SYann Gautier 	}
19530d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(CLK_AXI_HSI);
19547839a050SYann Gautier 	if (ret != 0) {
19557839a050SYann Gautier 		return ret;
19567839a050SYann Gautier 	}
1957b053a22eSYann Gautier 	ret = stm32mp1_set_clksrc(CLK_MCU_HSI);
1958b053a22eSYann Gautier 	if (ret != 0) {
1959b053a22eSYann Gautier 		return ret;
1960b053a22eSYann Gautier 	}
19617839a050SYann Gautier 
19620d21680cSYann Gautier 	if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) &
19630d21680cSYann Gautier 	     RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) {
19640d21680cSYann Gautier 		pll3_preserve = stm32mp1_check_pll_conf(_PLL3,
19650d21680cSYann Gautier 							clksrc[CLKSRC_PLL3],
19660d21680cSYann Gautier 							pllcfg[_PLL3],
19670d21680cSYann Gautier 							plloff[_PLL3]);
19680d21680cSYann Gautier 		pll4_preserve = stm32mp1_check_pll_conf(_PLL4,
19690d21680cSYann Gautier 							clksrc[CLKSRC_PLL4],
19700d21680cSYann Gautier 							pllcfg[_PLL4],
19710d21680cSYann Gautier 							plloff[_PLL4]);
19720d21680cSYann Gautier 	}
1973bf1af154SPatrick Delaunay 	/* Don't initialize PLL4, when used by BOOTROM */
1974bf1af154SPatrick Delaunay 	if ((stm32mp_get_boot_itf_selected() ==
1975bf1af154SPatrick Delaunay 	     BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) &&
1976bf1af154SPatrick Delaunay 	    ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) {
1977bf1af154SPatrick Delaunay 		pll4_bootrom = true;
1978bf1af154SPatrick Delaunay 		pll4_preserve = true;
1979bf1af154SPatrick Delaunay 	}
19800d21680cSYann Gautier 
19817839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
19820d21680cSYann Gautier 		if (((i == _PLL3) && pll3_preserve) ||
19830d21680cSYann Gautier 		    ((i == _PLL4) && pll4_preserve)) {
19847839a050SYann Gautier 			continue;
19850d21680cSYann Gautier 		}
19860d21680cSYann Gautier 
19870d21680cSYann Gautier 		ret = stm32mp1_pll_stop(i);
19887839a050SYann Gautier 		if (ret != 0) {
19897839a050SYann Gautier 			return ret;
19907839a050SYann Gautier 		}
19917839a050SYann Gautier 	}
19927839a050SYann Gautier 
19937839a050SYann Gautier 	/* Configure HSIDIV */
19940d21680cSYann Gautier 	if (stm32mp1_osc[_HSI] != 0U) {
19950d21680cSYann Gautier 		ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]);
19967839a050SYann Gautier 		if (ret != 0) {
19977839a050SYann Gautier 			return ret;
19987839a050SYann Gautier 		}
19990d21680cSYann Gautier 		stm32mp1_stgen_config();
20007839a050SYann Gautier 	}
20017839a050SYann Gautier 
20027839a050SYann Gautier 	/* Select DIV */
20037839a050SYann Gautier 	/* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */
20040d21680cSYann Gautier 	mmio_write_32(rcc_base + RCC_MPCKDIVR,
20057839a050SYann Gautier 		      clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK);
20060d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR);
20077839a050SYann Gautier 	if (ret != 0) {
20087839a050SYann Gautier 		return ret;
20097839a050SYann Gautier 	}
20100d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR);
20117839a050SYann Gautier 	if (ret != 0) {
20127839a050SYann Gautier 		return ret;
20137839a050SYann Gautier 	}
20140d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR);
20157839a050SYann Gautier 	if (ret != 0) {
20167839a050SYann Gautier 		return ret;
20177839a050SYann Gautier 	}
2018b053a22eSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR);
2019b053a22eSYann Gautier 	if (ret != 0) {
2020b053a22eSYann Gautier 		return ret;
2021b053a22eSYann Gautier 	}
20220d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR);
20237839a050SYann Gautier 	if (ret != 0) {
20247839a050SYann Gautier 		return ret;
20257839a050SYann Gautier 	}
20260d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR);
20277839a050SYann Gautier 	if (ret != 0) {
20287839a050SYann Gautier 		return ret;
20297839a050SYann Gautier 	}
20300d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR);
20317839a050SYann Gautier 	if (ret != 0) {
20327839a050SYann Gautier 		return ret;
20337839a050SYann Gautier 	}
20347839a050SYann Gautier 
20357839a050SYann Gautier 	/* No ready bit for RTC */
20360d21680cSYann Gautier 	mmio_write_32(rcc_base + RCC_RTCDIVR,
20377839a050SYann Gautier 		      clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK);
20387839a050SYann Gautier 
20397839a050SYann Gautier 	/* Configure PLLs source */
20400d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]);
20417839a050SYann Gautier 	if (ret != 0) {
20427839a050SYann Gautier 		return ret;
20437839a050SYann Gautier 	}
20447839a050SYann Gautier 
20450d21680cSYann Gautier 	if (!pll3_preserve) {
20460d21680cSYann Gautier 		ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]);
20477839a050SYann Gautier 		if (ret != 0) {
20487839a050SYann Gautier 			return ret;
20497839a050SYann Gautier 		}
20500d21680cSYann Gautier 	}
20510d21680cSYann Gautier 
20520d21680cSYann Gautier 	if (!pll4_preserve) {
20530d21680cSYann Gautier 		ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]);
20540d21680cSYann Gautier 		if (ret != 0) {
20550d21680cSYann Gautier 			return ret;
20560d21680cSYann Gautier 		}
20570d21680cSYann Gautier 	}
20587839a050SYann Gautier 
20597839a050SYann Gautier 	/* Configure and start PLLs */
20607839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
20610d21680cSYann Gautier 		if (((i == _PLL3) && pll3_preserve) ||
20620d21680cSYann Gautier 		    ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) {
20630d21680cSYann Gautier 			continue;
20640d21680cSYann Gautier 		}
20650d21680cSYann Gautier 
2066964e5ff1SNicolas Le Bayon 		if (!pllcfg_valid[i]) {
20677839a050SYann Gautier 			continue;
20687839a050SYann Gautier 		}
20697839a050SYann Gautier 
20700d21680cSYann Gautier 		if ((i == _PLL4) && pll4_bootrom) {
20710d21680cSYann Gautier 			/* Set output divider if not done by the Bootrom */
20720d21680cSYann Gautier 			stm32mp1_pll_config_output(i, pllcfg[i]);
20730d21680cSYann Gautier 			continue;
20740d21680cSYann Gautier 		}
20750d21680cSYann Gautier 
2076964e5ff1SNicolas Le Bayon 		ret = stm32mp1_pll_config(i, pllcfg[i], pllfracv[i]);
20777839a050SYann Gautier 		if (ret != 0) {
20787839a050SYann Gautier 			return ret;
20797839a050SYann Gautier 		}
2080964e5ff1SNicolas Le Bayon 
2081964e5ff1SNicolas Le Bayon 		if (pllcsg_set[i]) {
2082964e5ff1SNicolas Le Bayon 			stm32mp1_pll_csg(i, pllcsg[i]);
20837839a050SYann Gautier 		}
20847839a050SYann Gautier 
20850d21680cSYann Gautier 		stm32mp1_pll_start(i);
20867839a050SYann Gautier 	}
20877839a050SYann Gautier 	/* Wait and start PLLs ouptut when ready */
20887839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
2089964e5ff1SNicolas Le Bayon 		if (!pllcfg_valid[i]) {
20907839a050SYann Gautier 			continue;
20917839a050SYann Gautier 		}
20927839a050SYann Gautier 
20930d21680cSYann Gautier 		ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]);
20947839a050SYann Gautier 		if (ret != 0) {
20957839a050SYann Gautier 			return ret;
20967839a050SYann Gautier 		}
20977839a050SYann Gautier 	}
20987839a050SYann Gautier 	/* Wait LSE ready before to use it */
20990d21680cSYann Gautier 	if (stm32mp1_osc[_LSE] != 0U) {
21000d21680cSYann Gautier 		stm32mp1_lse_wait();
21017839a050SYann Gautier 	}
21027839a050SYann Gautier 
21037839a050SYann Gautier 	/* Configure with expected clock source */
21040d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]);
21057839a050SYann Gautier 	if (ret != 0) {
21067839a050SYann Gautier 		return ret;
21077839a050SYann Gautier 	}
21080d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]);
21097839a050SYann Gautier 	if (ret != 0) {
21107839a050SYann Gautier 		return ret;
21117839a050SYann Gautier 	}
2112b053a22eSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]);
2113b053a22eSYann Gautier 	if (ret != 0) {
2114b053a22eSYann Gautier 		return ret;
2115b053a22eSYann Gautier 	}
21160d21680cSYann Gautier 	stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css);
21177839a050SYann Gautier 
21187839a050SYann Gautier 	/* Configure PKCK */
21197839a050SYann Gautier 	pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len);
21207839a050SYann Gautier 	if (pkcs_cell != NULL) {
21217839a050SYann Gautier 		bool ckper_disabled = false;
21227839a050SYann Gautier 		uint32_t j;
2123bf1af154SPatrick Delaunay 		uint32_t usbreg_bootrom = 0U;
2124bf1af154SPatrick Delaunay 
2125bf1af154SPatrick Delaunay 		if (pll4_bootrom) {
2126bf1af154SPatrick Delaunay 			usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR);
2127bf1af154SPatrick Delaunay 		}
21287839a050SYann Gautier 
21297839a050SYann Gautier 		for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) {
21303e6fab43SYann Gautier 			uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]);
21317839a050SYann Gautier 
21327839a050SYann Gautier 			if (pkcs == (uint32_t)CLK_CKPER_DISABLED) {
21337839a050SYann Gautier 				ckper_disabled = true;
21347839a050SYann Gautier 				continue;
21357839a050SYann Gautier 			}
21360d21680cSYann Gautier 			stm32mp1_pkcs_config(pkcs);
21377839a050SYann Gautier 		}
21387839a050SYann Gautier 
21397839a050SYann Gautier 		/*
21407839a050SYann Gautier 		 * CKPER is source for some peripheral clocks
21417839a050SYann Gautier 		 * (FMC-NAND / QPSI-NOR) and switching source is allowed
21427839a050SYann Gautier 		 * only if previous clock is still ON
21437839a050SYann Gautier 		 * => deactivated CKPER only after switching clock
21447839a050SYann Gautier 		 */
21457839a050SYann Gautier 		if (ckper_disabled) {
21460d21680cSYann Gautier 			stm32mp1_pkcs_config(CLK_CKPER_DISABLED);
21477839a050SYann Gautier 		}
2148bf1af154SPatrick Delaunay 
2149bf1af154SPatrick Delaunay 		if (pll4_bootrom) {
2150bf1af154SPatrick Delaunay 			uint32_t usbreg_value, usbreg_mask;
2151bf1af154SPatrick Delaunay 			const struct stm32mp1_clk_sel *sel;
2152bf1af154SPatrick Delaunay 
2153bf1af154SPatrick Delaunay 			sel = clk_sel_ref(_USBPHY_SEL);
2154bf1af154SPatrick Delaunay 			usbreg_mask = (uint32_t)sel->msk << sel->src;
2155bf1af154SPatrick Delaunay 			sel = clk_sel_ref(_USBO_SEL);
2156bf1af154SPatrick Delaunay 			usbreg_mask |= (uint32_t)sel->msk << sel->src;
2157bf1af154SPatrick Delaunay 
2158bf1af154SPatrick Delaunay 			usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) &
2159bf1af154SPatrick Delaunay 				       usbreg_mask;
2160bf1af154SPatrick Delaunay 			usbreg_bootrom &= usbreg_mask;
2161bf1af154SPatrick Delaunay 			if (usbreg_bootrom != usbreg_value) {
2162bf1af154SPatrick Delaunay 				VERBOSE("forbidden new USB clk path\n");
2163bf1af154SPatrick Delaunay 				VERBOSE("vs bootrom on USB boot\n");
2164bf1af154SPatrick Delaunay 				return -FDT_ERR_BADVALUE;
2165bf1af154SPatrick Delaunay 			}
2166bf1af154SPatrick Delaunay 		}
21677839a050SYann Gautier 	}
21687839a050SYann Gautier 
21697839a050SYann Gautier 	/* Switch OFF HSI if not found in device-tree */
21700d21680cSYann Gautier 	if (stm32mp1_osc[_HSI] == 0U) {
21710d21680cSYann Gautier 		stm32mp1_hsi_set(false);
21727839a050SYann Gautier 	}
21730d21680cSYann Gautier 	stm32mp1_stgen_config();
21747839a050SYann Gautier 
21757839a050SYann Gautier 	/* Software Self-Refresh mode (SSR) during DDR initilialization */
21760d21680cSYann Gautier 	mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR,
21777839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_MASK,
21787839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_SSR <<
21797839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_SHIFT);
21807839a050SYann Gautier 
21817839a050SYann Gautier 	return 0;
21827839a050SYann Gautier }
21837839a050SYann Gautier 
21847839a050SYann Gautier static void stm32mp1_osc_clk_init(const char *name,
21857839a050SYann Gautier 				  enum stm32mp_osc_id index)
21867839a050SYann Gautier {
21877839a050SYann Gautier 	uint32_t frequency;
21887839a050SYann Gautier 
21890d21680cSYann Gautier 	if (fdt_osc_read_freq(name, &frequency) == 0) {
21900d21680cSYann Gautier 		stm32mp1_osc[index] = frequency;
21917839a050SYann Gautier 	}
21927839a050SYann Gautier }
21937839a050SYann Gautier 
21947839a050SYann Gautier static void stm32mp1_osc_init(void)
21957839a050SYann Gautier {
21967839a050SYann Gautier 	enum stm32mp_osc_id i;
21977839a050SYann Gautier 
21987839a050SYann Gautier 	for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) {
21990d21680cSYann Gautier 		stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i);
22007839a050SYann Gautier 	}
22017839a050SYann Gautier }
22027839a050SYann Gautier 
220337e8295aSEtienne Carriere #ifdef STM32MP_SHARED_RESOURCES
220437e8295aSEtienne Carriere /*
220537e8295aSEtienne Carriere  * Get the parent ID of the target parent clock, for tagging as secure
220637e8295aSEtienne Carriere  * shared clock dependencies.
220737e8295aSEtienne Carriere  */
220837e8295aSEtienne Carriere static int get_parent_id_parent(unsigned int parent_id)
220937e8295aSEtienne Carriere {
221037e8295aSEtienne Carriere 	enum stm32mp1_parent_sel s = _UNKNOWN_SEL;
221137e8295aSEtienne Carriere 	enum stm32mp1_pll_id pll_id;
221237e8295aSEtienne Carriere 	uint32_t p_sel;
221337e8295aSEtienne Carriere 	uintptr_t rcc_base = stm32mp_rcc_base();
221437e8295aSEtienne Carriere 
221537e8295aSEtienne Carriere 	switch (parent_id) {
221637e8295aSEtienne Carriere 	case _ACLK:
221737e8295aSEtienne Carriere 	case _PCLK4:
221837e8295aSEtienne Carriere 	case _PCLK5:
221937e8295aSEtienne Carriere 		s = _AXIS_SEL;
222037e8295aSEtienne Carriere 		break;
222137e8295aSEtienne Carriere 	case _PLL1_P:
222237e8295aSEtienne Carriere 	case _PLL1_Q:
222337e8295aSEtienne Carriere 	case _PLL1_R:
222437e8295aSEtienne Carriere 		pll_id = _PLL1;
222537e8295aSEtienne Carriere 		break;
222637e8295aSEtienne Carriere 	case _PLL2_P:
222737e8295aSEtienne Carriere 	case _PLL2_Q:
222837e8295aSEtienne Carriere 	case _PLL2_R:
222937e8295aSEtienne Carriere 		pll_id = _PLL2;
223037e8295aSEtienne Carriere 		break;
223137e8295aSEtienne Carriere 	case _PLL3_P:
223237e8295aSEtienne Carriere 	case _PLL3_Q:
223337e8295aSEtienne Carriere 	case _PLL3_R:
223437e8295aSEtienne Carriere 		pll_id = _PLL3;
223537e8295aSEtienne Carriere 		break;
223637e8295aSEtienne Carriere 	case _PLL4_P:
223737e8295aSEtienne Carriere 	case _PLL4_Q:
223837e8295aSEtienne Carriere 	case _PLL4_R:
223937e8295aSEtienne Carriere 		pll_id = _PLL4;
224037e8295aSEtienne Carriere 		break;
224137e8295aSEtienne Carriere 	case _PCLK1:
224237e8295aSEtienne Carriere 	case _PCLK2:
224337e8295aSEtienne Carriere 	case _HCLK2:
224437e8295aSEtienne Carriere 	case _HCLK6:
224537e8295aSEtienne Carriere 	case _CK_PER:
224637e8295aSEtienne Carriere 	case _CK_MPU:
224737e8295aSEtienne Carriere 	case _CK_MCU:
224837e8295aSEtienne Carriere 	case _USB_PHY_48:
224937e8295aSEtienne Carriere 		/* We do not expect to access these */
225037e8295aSEtienne Carriere 		panic();
225137e8295aSEtienne Carriere 		break;
225237e8295aSEtienne Carriere 	default:
225337e8295aSEtienne Carriere 		/* Other parents have no parent */
225437e8295aSEtienne Carriere 		return -1;
225537e8295aSEtienne Carriere 	}
225637e8295aSEtienne Carriere 
225737e8295aSEtienne Carriere 	if (s != _UNKNOWN_SEL) {
225837e8295aSEtienne Carriere 		const struct stm32mp1_clk_sel *sel = clk_sel_ref(s);
225937e8295aSEtienne Carriere 
226037e8295aSEtienne Carriere 		p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) &
226137e8295aSEtienne Carriere 			sel->msk;
226237e8295aSEtienne Carriere 
226337e8295aSEtienne Carriere 		if (p_sel < sel->nb_parent) {
226437e8295aSEtienne Carriere 			return (int)sel->parent[p_sel];
226537e8295aSEtienne Carriere 		}
226637e8295aSEtienne Carriere 	} else {
226737e8295aSEtienne Carriere 		const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
226837e8295aSEtienne Carriere 
226937e8295aSEtienne Carriere 		p_sel = mmio_read_32(rcc_base + pll->rckxselr) &
227037e8295aSEtienne Carriere 			RCC_SELR_REFCLK_SRC_MASK;
227137e8295aSEtienne Carriere 
227237e8295aSEtienne Carriere 		if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) {
227337e8295aSEtienne Carriere 			return (int)pll->refclk[p_sel];
227437e8295aSEtienne Carriere 		}
227537e8295aSEtienne Carriere 	}
227637e8295aSEtienne Carriere 
227737e8295aSEtienne Carriere 	VERBOSE("No parent selected for %s\n",
227837e8295aSEtienne Carriere 		stm32mp1_clk_parent_name[parent_id]);
227937e8295aSEtienne Carriere 
228037e8295aSEtienne Carriere 	return -1;
228137e8295aSEtienne Carriere }
228237e8295aSEtienne Carriere 
228337e8295aSEtienne Carriere static void secure_parent_clocks(unsigned long parent_id)
228437e8295aSEtienne Carriere {
228537e8295aSEtienne Carriere 	int grandparent_id;
228637e8295aSEtienne Carriere 
228737e8295aSEtienne Carriere 	switch (parent_id) {
228837e8295aSEtienne Carriere 	case _PLL3_P:
228937e8295aSEtienne Carriere 	case _PLL3_Q:
229037e8295aSEtienne Carriere 	case _PLL3_R:
229137e8295aSEtienne Carriere 		stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
229237e8295aSEtienne Carriere 		break;
229337e8295aSEtienne Carriere 
229437e8295aSEtienne Carriere 	/* These clocks are always secure when RCC is secure */
229537e8295aSEtienne Carriere 	case _ACLK:
229637e8295aSEtienne Carriere 	case _HCLK2:
229737e8295aSEtienne Carriere 	case _HCLK6:
229837e8295aSEtienne Carriere 	case _PCLK4:
229937e8295aSEtienne Carriere 	case _PCLK5:
230037e8295aSEtienne Carriere 	case _PLL1_P:
230137e8295aSEtienne Carriere 	case _PLL1_Q:
230237e8295aSEtienne Carriere 	case _PLL1_R:
230337e8295aSEtienne Carriere 	case _PLL2_P:
230437e8295aSEtienne Carriere 	case _PLL2_Q:
230537e8295aSEtienne Carriere 	case _PLL2_R:
230637e8295aSEtienne Carriere 	case _HSI:
230737e8295aSEtienne Carriere 	case _HSI_KER:
230837e8295aSEtienne Carriere 	case _LSI:
230937e8295aSEtienne Carriere 	case _CSI:
231037e8295aSEtienne Carriere 	case _CSI_KER:
231137e8295aSEtienne Carriere 	case _HSE:
231237e8295aSEtienne Carriere 	case _HSE_KER:
231337e8295aSEtienne Carriere 	case _HSE_KER_DIV2:
2314cbd2e8a6SGabriel Fernandez 	case _HSE_RTC:
231537e8295aSEtienne Carriere 	case _LSE:
231637e8295aSEtienne Carriere 		break;
231737e8295aSEtienne Carriere 
231837e8295aSEtienne Carriere 	default:
231937e8295aSEtienne Carriere 		VERBOSE("Cannot secure parent clock %s\n",
232037e8295aSEtienne Carriere 			stm32mp1_clk_parent_name[parent_id]);
232137e8295aSEtienne Carriere 		panic();
232237e8295aSEtienne Carriere 	}
232337e8295aSEtienne Carriere 
232437e8295aSEtienne Carriere 	grandparent_id = get_parent_id_parent(parent_id);
232537e8295aSEtienne Carriere 	if (grandparent_id >= 0) {
232637e8295aSEtienne Carriere 		secure_parent_clocks(grandparent_id);
232737e8295aSEtienne Carriere 	}
232837e8295aSEtienne Carriere }
232937e8295aSEtienne Carriere 
233037e8295aSEtienne Carriere void stm32mp1_register_clock_parents_secure(unsigned long clock_id)
233137e8295aSEtienne Carriere {
233237e8295aSEtienne Carriere 	int parent_id;
233337e8295aSEtienne Carriere 
233437e8295aSEtienne Carriere 	if (!stm32mp1_rcc_is_secure()) {
233537e8295aSEtienne Carriere 		return;
233637e8295aSEtienne Carriere 	}
233737e8295aSEtienne Carriere 
233837e8295aSEtienne Carriere 	switch (clock_id) {
233937e8295aSEtienne Carriere 	case PLL1:
234037e8295aSEtienne Carriere 	case PLL2:
234137e8295aSEtienne Carriere 		/* PLL1/PLL2 are always secure: nothing to do */
234237e8295aSEtienne Carriere 		break;
234337e8295aSEtienne Carriere 	case PLL3:
234437e8295aSEtienne Carriere 		stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
234537e8295aSEtienne Carriere 		break;
234637e8295aSEtienne Carriere 	case PLL4:
234737e8295aSEtienne Carriere 		ERROR("PLL4 cannot be secured\n");
234837e8295aSEtienne Carriere 		panic();
234937e8295aSEtienne Carriere 		break;
235037e8295aSEtienne Carriere 	default:
235137e8295aSEtienne Carriere 		/* Others are expected gateable clock */
235237e8295aSEtienne Carriere 		parent_id = stm32mp1_clk_get_parent(clock_id);
235337e8295aSEtienne Carriere 		if (parent_id < 0) {
235437e8295aSEtienne Carriere 			INFO("No parent found for clock %lu\n", clock_id);
235537e8295aSEtienne Carriere 		} else {
235637e8295aSEtienne Carriere 			secure_parent_clocks(parent_id);
235737e8295aSEtienne Carriere 		}
235837e8295aSEtienne Carriere 		break;
235937e8295aSEtienne Carriere 	}
236037e8295aSEtienne Carriere }
236137e8295aSEtienne Carriere #endif /* STM32MP_SHARED_RESOURCES */
236237e8295aSEtienne Carriere 
23636cb45f89SYann Gautier static void sync_earlyboot_clocks_state(void)
23646cb45f89SYann Gautier {
2365033b6c3aSEtienne Carriere 	unsigned int idx;
2366033b6c3aSEtienne Carriere 	const unsigned long secure_enable[] = {
2367033b6c3aSEtienne Carriere 		AXIDCG,
2368033b6c3aSEtienne Carriere 		BSEC,
2369033b6c3aSEtienne Carriere 		DDRC1, DDRC1LP,
2370033b6c3aSEtienne Carriere 		DDRC2, DDRC2LP,
2371033b6c3aSEtienne Carriere 		DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP,
2372033b6c3aSEtienne Carriere 		DDRPHYC, DDRPHYCLP,
2373373f06beSLionel Debieve 		RTCAPB,
2374033b6c3aSEtienne Carriere 		TZC1, TZC2,
2375033b6c3aSEtienne Carriere 		TZPC,
2376033b6c3aSEtienne Carriere 		STGEN_K,
2377033b6c3aSEtienne Carriere 	};
2378033b6c3aSEtienne Carriere 
2379033b6c3aSEtienne Carriere 	for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) {
2380033b6c3aSEtienne Carriere 		stm32mp_clk_enable(secure_enable[idx]);
2381033b6c3aSEtienne Carriere 	}
23826cb45f89SYann Gautier }
23836cb45f89SYann Gautier 
238433667d29SYann Gautier static const struct clk_ops stm32mp_clk_ops = {
238533667d29SYann Gautier 	.enable		= stm32mp_clk_enable,
238633667d29SYann Gautier 	.disable	= stm32mp_clk_disable,
238733667d29SYann Gautier 	.is_enabled	= stm32mp_clk_is_enabled,
238833667d29SYann Gautier 	.get_rate	= stm32mp_clk_get_rate,
238933667d29SYann Gautier 	.get_parent	= stm32mp1_clk_get_parent,
239033667d29SYann Gautier };
239133667d29SYann Gautier 
23927839a050SYann Gautier int stm32mp1_clk_probe(void)
23937839a050SYann Gautier {
23947839a050SYann Gautier 	stm32mp1_osc_init();
23957839a050SYann Gautier 
23966cb45f89SYann Gautier 	sync_earlyboot_clocks_state();
23976cb45f89SYann Gautier 
239833667d29SYann Gautier 	clk_register(&stm32mp_clk_ops);
239933667d29SYann Gautier 
24007839a050SYann Gautier 	return 0;
24017839a050SYann Gautier }
2402