xref: /rk3399_ARM-atf/drivers/st/clk/stm32mp1_clk.c (revision 15509093f0ba9a10f97c6f92bc3bb9fcf79a48ce)
17839a050SYann Gautier /*
28f97c4faSYann Gautier  * Copyright (C) 2018-2021, 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 <libfdt.h>
1309d40e0eSAntonio Nino Diaz 
146e6ab282SYann Gautier #include <platform_def.h>
156e6ab282SYann Gautier 
1609d40e0eSAntonio Nino Diaz #include <arch.h>
1709d40e0eSAntonio Nino Diaz #include <arch_helpers.h>
1809d40e0eSAntonio Nino Diaz #include <common/debug.h>
1952a616b4SAndre Przywara #include <common/fdt_wrappers.h>
2009d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h>
2109d40e0eSAntonio Nino Diaz #include <drivers/generic_delay_timer.h>
22447b2b13SYann Gautier #include <drivers/st/stm32mp_clkfunc.h>
2309d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_clk.h>
2409d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_rcc.h>
2509d40e0eSAntonio Nino Diaz #include <dt-bindings/clock/stm32mp1-clksrc.h>
2609d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
270d21680cSYann Gautier #include <lib/spinlock.h>
2809d40e0eSAntonio Nino Diaz #include <lib/utils_def.h>
2909d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
3009d40e0eSAntonio Nino Diaz 
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,
597839a050SYann Gautier 	_CSI_KER,
607839a050SYann Gautier 	_PLL1_P,
617839a050SYann Gautier 	_PLL1_Q,
627839a050SYann Gautier 	_PLL1_R,
637839a050SYann Gautier 	_PLL2_P,
647839a050SYann Gautier 	_PLL2_Q,
657839a050SYann Gautier 	_PLL2_R,
667839a050SYann Gautier 	_PLL3_P,
677839a050SYann Gautier 	_PLL3_Q,
687839a050SYann Gautier 	_PLL3_R,
697839a050SYann Gautier 	_PLL4_P,
707839a050SYann Gautier 	_PLL4_Q,
717839a050SYann Gautier 	_PLL4_R,
727839a050SYann Gautier 	_ACLK,
737839a050SYann Gautier 	_PCLK1,
747839a050SYann Gautier 	_PCLK2,
757839a050SYann Gautier 	_PCLK3,
767839a050SYann Gautier 	_PCLK4,
777839a050SYann Gautier 	_PCLK5,
787839a050SYann Gautier 	_HCLK6,
797839a050SYann Gautier 	_HCLK2,
807839a050SYann Gautier 	_CK_PER,
817839a050SYann Gautier 	_CK_MPU,
82b053a22eSYann Gautier 	_CK_MCU,
830d21680cSYann Gautier 	_USB_PHY_48,
847839a050SYann Gautier 	_PARENT_NB,
857839a050SYann Gautier 	_UNKNOWN_ID = 0xff,
867839a050SYann Gautier };
877839a050SYann Gautier 
880d21680cSYann Gautier /* Lists only the parent clock we are interested in */
897839a050SYann Gautier enum stm32mp1_parent_sel {
900d21680cSYann Gautier 	_I2C12_SEL,
910d21680cSYann Gautier 	_I2C35_SEL,
920d21680cSYann Gautier 	_STGEN_SEL,
937839a050SYann Gautier 	_I2C46_SEL,
940d21680cSYann Gautier 	_SPI6_SEL,
95d4151d2fSYann Gautier 	_UART1_SEL,
960d21680cSYann Gautier 	_RNG1_SEL,
977839a050SYann Gautier 	_UART6_SEL,
987839a050SYann Gautier 	_UART24_SEL,
997839a050SYann Gautier 	_UART35_SEL,
1007839a050SYann Gautier 	_UART78_SEL,
1017839a050SYann Gautier 	_SDMMC12_SEL,
1027839a050SYann Gautier 	_SDMMC3_SEL,
1037839a050SYann Gautier 	_QSPI_SEL,
1047839a050SYann Gautier 	_FMC_SEL,
105d4151d2fSYann Gautier 	_AXIS_SEL,
106d4151d2fSYann Gautier 	_MCUS_SEL,
1077839a050SYann Gautier 	_USBPHY_SEL,
1087839a050SYann Gautier 	_USBO_SEL,
1098fbcd9e4SEtienne Carriere 	_MPU_SEL,
1108fbcd9e4SEtienne Carriere 	_PER_SEL,
111016af006SEtienne Carriere 	_RTC_SEL,
1127839a050SYann Gautier 	_PARENT_SEL_NB,
1137839a050SYann Gautier 	_UNKNOWN_SEL = 0xff,
1147839a050SYann Gautier };
1157839a050SYann Gautier 
1168fbcd9e4SEtienne Carriere /* State the parent clock ID straight related to a clock */
1178fbcd9e4SEtienne Carriere static const uint8_t parent_id_clock_id[_PARENT_NB] = {
1188fbcd9e4SEtienne Carriere 	[_HSE] = CK_HSE,
1198fbcd9e4SEtienne Carriere 	[_HSI] = CK_HSI,
1208fbcd9e4SEtienne Carriere 	[_CSI] = CK_CSI,
1218fbcd9e4SEtienne Carriere 	[_LSE] = CK_LSE,
1228fbcd9e4SEtienne Carriere 	[_LSI] = CK_LSI,
1238fbcd9e4SEtienne Carriere 	[_I2S_CKIN] = _UNKNOWN_ID,
1248fbcd9e4SEtienne Carriere 	[_USB_PHY_48] = _UNKNOWN_ID,
1258fbcd9e4SEtienne Carriere 	[_HSI_KER] = CK_HSI,
1268fbcd9e4SEtienne Carriere 	[_HSE_KER] = CK_HSE,
1278fbcd9e4SEtienne Carriere 	[_HSE_KER_DIV2] = CK_HSE_DIV2,
1288fbcd9e4SEtienne Carriere 	[_CSI_KER] = CK_CSI,
1298fbcd9e4SEtienne Carriere 	[_PLL1_P] = PLL1_P,
1308fbcd9e4SEtienne Carriere 	[_PLL1_Q] = PLL1_Q,
1318fbcd9e4SEtienne Carriere 	[_PLL1_R] = PLL1_R,
1328fbcd9e4SEtienne Carriere 	[_PLL2_P] = PLL2_P,
1338fbcd9e4SEtienne Carriere 	[_PLL2_Q] = PLL2_Q,
1348fbcd9e4SEtienne Carriere 	[_PLL2_R] = PLL2_R,
1358fbcd9e4SEtienne Carriere 	[_PLL3_P] = PLL3_P,
1368fbcd9e4SEtienne Carriere 	[_PLL3_Q] = PLL3_Q,
1378fbcd9e4SEtienne Carriere 	[_PLL3_R] = PLL3_R,
1388fbcd9e4SEtienne Carriere 	[_PLL4_P] = PLL4_P,
1398fbcd9e4SEtienne Carriere 	[_PLL4_Q] = PLL4_Q,
1408fbcd9e4SEtienne Carriere 	[_PLL4_R] = PLL4_R,
1418fbcd9e4SEtienne Carriere 	[_ACLK] = CK_AXI,
1428fbcd9e4SEtienne Carriere 	[_PCLK1] = CK_AXI,
1438fbcd9e4SEtienne Carriere 	[_PCLK2] = CK_AXI,
1448fbcd9e4SEtienne Carriere 	[_PCLK3] = CK_AXI,
1458fbcd9e4SEtienne Carriere 	[_PCLK4] = CK_AXI,
1468fbcd9e4SEtienne Carriere 	[_PCLK5] = CK_AXI,
1478fbcd9e4SEtienne Carriere 	[_CK_PER] = CK_PER,
1488fbcd9e4SEtienne Carriere 	[_CK_MPU] = CK_MPU,
1498fbcd9e4SEtienne Carriere 	[_CK_MCU] = CK_MCU,
1508fbcd9e4SEtienne Carriere };
1518fbcd9e4SEtienne Carriere 
1528fbcd9e4SEtienne Carriere static unsigned int clock_id2parent_id(unsigned long id)
1538fbcd9e4SEtienne Carriere {
1548fbcd9e4SEtienne Carriere 	unsigned int n;
1558fbcd9e4SEtienne Carriere 
1568fbcd9e4SEtienne Carriere 	for (n = 0U; n < ARRAY_SIZE(parent_id_clock_id); n++) {
1578fbcd9e4SEtienne Carriere 		if (parent_id_clock_id[n] == id) {
1588fbcd9e4SEtienne Carriere 			return n;
1598fbcd9e4SEtienne Carriere 		}
1608fbcd9e4SEtienne Carriere 	}
1618fbcd9e4SEtienne Carriere 
1628fbcd9e4SEtienne Carriere 	return _UNKNOWN_ID;
1638fbcd9e4SEtienne Carriere }
1648fbcd9e4SEtienne Carriere 
1657839a050SYann Gautier enum stm32mp1_pll_id {
1667839a050SYann Gautier 	_PLL1,
1677839a050SYann Gautier 	_PLL2,
1687839a050SYann Gautier 	_PLL3,
1697839a050SYann Gautier 	_PLL4,
1707839a050SYann Gautier 	_PLL_NB
1717839a050SYann Gautier };
1727839a050SYann Gautier 
1737839a050SYann Gautier enum stm32mp1_div_id {
1747839a050SYann Gautier 	_DIV_P,
1757839a050SYann Gautier 	_DIV_Q,
1767839a050SYann Gautier 	_DIV_R,
1777839a050SYann Gautier 	_DIV_NB,
1787839a050SYann Gautier };
1797839a050SYann Gautier 
1807839a050SYann Gautier enum stm32mp1_clksrc_id {
1817839a050SYann Gautier 	CLKSRC_MPU,
1827839a050SYann Gautier 	CLKSRC_AXI,
183b053a22eSYann Gautier 	CLKSRC_MCU,
1847839a050SYann Gautier 	CLKSRC_PLL12,
1857839a050SYann Gautier 	CLKSRC_PLL3,
1867839a050SYann Gautier 	CLKSRC_PLL4,
1877839a050SYann Gautier 	CLKSRC_RTC,
1887839a050SYann Gautier 	CLKSRC_MCO1,
1897839a050SYann Gautier 	CLKSRC_MCO2,
1907839a050SYann Gautier 	CLKSRC_NB
1917839a050SYann Gautier };
1927839a050SYann Gautier 
1937839a050SYann Gautier enum stm32mp1_clkdiv_id {
1947839a050SYann Gautier 	CLKDIV_MPU,
1957839a050SYann Gautier 	CLKDIV_AXI,
196b053a22eSYann Gautier 	CLKDIV_MCU,
1977839a050SYann Gautier 	CLKDIV_APB1,
1987839a050SYann Gautier 	CLKDIV_APB2,
1997839a050SYann Gautier 	CLKDIV_APB3,
2007839a050SYann Gautier 	CLKDIV_APB4,
2017839a050SYann Gautier 	CLKDIV_APB5,
2027839a050SYann Gautier 	CLKDIV_RTC,
2037839a050SYann Gautier 	CLKDIV_MCO1,
2047839a050SYann Gautier 	CLKDIV_MCO2,
2057839a050SYann Gautier 	CLKDIV_NB
2067839a050SYann Gautier };
2077839a050SYann Gautier 
2087839a050SYann Gautier enum stm32mp1_pllcfg {
2097839a050SYann Gautier 	PLLCFG_M,
2107839a050SYann Gautier 	PLLCFG_N,
2117839a050SYann Gautier 	PLLCFG_P,
2127839a050SYann Gautier 	PLLCFG_Q,
2137839a050SYann Gautier 	PLLCFG_R,
2147839a050SYann Gautier 	PLLCFG_O,
2157839a050SYann Gautier 	PLLCFG_NB
2167839a050SYann Gautier };
2177839a050SYann Gautier 
2187839a050SYann Gautier enum stm32mp1_pllcsg {
2197839a050SYann Gautier 	PLLCSG_MOD_PER,
2207839a050SYann Gautier 	PLLCSG_INC_STEP,
2217839a050SYann Gautier 	PLLCSG_SSCG_MODE,
2227839a050SYann Gautier 	PLLCSG_NB
2237839a050SYann Gautier };
2247839a050SYann Gautier 
2257839a050SYann Gautier enum stm32mp1_plltype {
2267839a050SYann Gautier 	PLL_800,
2277839a050SYann Gautier 	PLL_1600,
2287839a050SYann Gautier 	PLL_TYPE_NB
2297839a050SYann Gautier };
2307839a050SYann Gautier 
2317839a050SYann Gautier struct stm32mp1_pll {
2327839a050SYann Gautier 	uint8_t refclk_min;
2337839a050SYann Gautier 	uint8_t refclk_max;
2347839a050SYann Gautier 	uint8_t divn_max;
2357839a050SYann Gautier };
2367839a050SYann Gautier 
2377839a050SYann Gautier struct stm32mp1_clk_gate {
2387839a050SYann Gautier 	uint16_t offset;
2397839a050SYann Gautier 	uint8_t bit;
2407839a050SYann Gautier 	uint8_t index;
2417839a050SYann Gautier 	uint8_t set_clr;
2420d21680cSYann Gautier 	uint8_t sel; /* Relates to enum stm32mp1_parent_sel */
2430d21680cSYann Gautier 	uint8_t fixed; /* Relates to enum stm32mp1_parent_id */
2447839a050SYann Gautier };
2457839a050SYann Gautier 
2467839a050SYann Gautier struct stm32mp1_clk_sel {
2477839a050SYann Gautier 	uint16_t offset;
2487839a050SYann Gautier 	uint8_t src;
2497839a050SYann Gautier 	uint8_t msk;
2507839a050SYann Gautier 	uint8_t nb_parent;
2517839a050SYann Gautier 	const uint8_t *parent;
2527839a050SYann Gautier };
2537839a050SYann Gautier 
2547839a050SYann Gautier #define REFCLK_SIZE 4
2557839a050SYann Gautier struct stm32mp1_clk_pll {
2567839a050SYann Gautier 	enum stm32mp1_plltype plltype;
2577839a050SYann Gautier 	uint16_t rckxselr;
2587839a050SYann Gautier 	uint16_t pllxcfgr1;
2597839a050SYann Gautier 	uint16_t pllxcfgr2;
2607839a050SYann Gautier 	uint16_t pllxfracr;
2617839a050SYann Gautier 	uint16_t pllxcr;
2627839a050SYann Gautier 	uint16_t pllxcsgr;
2637839a050SYann Gautier 	enum stm32mp_osc_id refclk[REFCLK_SIZE];
2647839a050SYann Gautier };
2657839a050SYann Gautier 
2660d21680cSYann Gautier /* Clocks with selectable source and non set/clr register access */
2670d21680cSYann Gautier #define _CLK_SELEC(off, b, idx, s)			\
2687839a050SYann Gautier 	{						\
2697839a050SYann Gautier 		.offset = (off),			\
2707839a050SYann Gautier 		.bit = (b),				\
2717839a050SYann Gautier 		.index = (idx),				\
2727839a050SYann Gautier 		.set_clr = 0,				\
2737839a050SYann Gautier 		.sel = (s),				\
2747839a050SYann Gautier 		.fixed = _UNKNOWN_ID,			\
2757839a050SYann Gautier 	}
2767839a050SYann Gautier 
2770d21680cSYann Gautier /* Clocks with fixed source and non set/clr register access */
2780d21680cSYann Gautier #define _CLK_FIXED(off, b, idx, f)			\
2797839a050SYann Gautier 	{						\
2807839a050SYann Gautier 		.offset = (off),			\
2817839a050SYann Gautier 		.bit = (b),				\
2827839a050SYann Gautier 		.index = (idx),				\
2837839a050SYann Gautier 		.set_clr = 0,				\
2847839a050SYann Gautier 		.sel = _UNKNOWN_SEL,			\
2857839a050SYann Gautier 		.fixed = (f),				\
2867839a050SYann Gautier 	}
2877839a050SYann Gautier 
2880d21680cSYann Gautier /* Clocks with selectable source and set/clr register access */
2890d21680cSYann Gautier #define _CLK_SC_SELEC(off, b, idx, s)			\
2907839a050SYann Gautier 	{						\
2917839a050SYann Gautier 		.offset = (off),			\
2927839a050SYann Gautier 		.bit = (b),				\
2937839a050SYann Gautier 		.index = (idx),				\
2947839a050SYann Gautier 		.set_clr = 1,				\
2957839a050SYann Gautier 		.sel = (s),				\
2967839a050SYann Gautier 		.fixed = _UNKNOWN_ID,			\
2977839a050SYann Gautier 	}
2987839a050SYann Gautier 
2990d21680cSYann Gautier /* Clocks with fixed source and set/clr register access */
3000d21680cSYann Gautier #define _CLK_SC_FIXED(off, b, idx, f)			\
3017839a050SYann Gautier 	{						\
3027839a050SYann Gautier 		.offset = (off),			\
3037839a050SYann Gautier 		.bit = (b),				\
3047839a050SYann Gautier 		.index = (idx),				\
3057839a050SYann Gautier 		.set_clr = 1,				\
3067839a050SYann Gautier 		.sel = _UNKNOWN_SEL,			\
3077839a050SYann Gautier 		.fixed = (f),				\
3087839a050SYann Gautier 	}
3097839a050SYann Gautier 
310d4151d2fSYann Gautier #define _CLK_PARENT_SEL(_label, _rcc_selr, _parents)		\
311d4151d2fSYann Gautier 	[_ ## _label ## _SEL] = {				\
312d4151d2fSYann Gautier 		.offset = _rcc_selr,				\
313d4151d2fSYann Gautier 		.src = _rcc_selr ## _ ## _label ## SRC_SHIFT,	\
3148ae08dcdSEtienne Carriere 		.msk = (_rcc_selr ## _ ## _label ## SRC_MASK) >> \
3158ae08dcdSEtienne Carriere 		       (_rcc_selr ## _ ## _label ## SRC_SHIFT), \
316d4151d2fSYann Gautier 		.parent = (_parents),				\
317d4151d2fSYann Gautier 		.nb_parent = ARRAY_SIZE(_parents)		\
3187839a050SYann Gautier 	}
3197839a050SYann Gautier 
3200d21680cSYann Gautier #define _CLK_PLL(idx, type, off1, off2, off3,		\
3217839a050SYann Gautier 		 off4, off5, off6,			\
3227839a050SYann Gautier 		 p1, p2, p3, p4)			\
3237839a050SYann Gautier 	[(idx)] = {					\
3247839a050SYann Gautier 		.plltype = (type),			\
3257839a050SYann Gautier 		.rckxselr = (off1),			\
3267839a050SYann Gautier 		.pllxcfgr1 = (off2),			\
3277839a050SYann Gautier 		.pllxcfgr2 = (off3),			\
3287839a050SYann Gautier 		.pllxfracr = (off4),			\
3297839a050SYann Gautier 		.pllxcr = (off5),			\
3307839a050SYann Gautier 		.pllxcsgr = (off6),			\
3317839a050SYann Gautier 		.refclk[0] = (p1),			\
3327839a050SYann Gautier 		.refclk[1] = (p2),			\
3337839a050SYann Gautier 		.refclk[2] = (p3),			\
3347839a050SYann Gautier 		.refclk[3] = (p4),			\
3357839a050SYann Gautier 	}
3367839a050SYann Gautier 
3370d21680cSYann Gautier #define NB_GATES	ARRAY_SIZE(stm32mp1_clk_gate)
3380d21680cSYann Gautier 
3397839a050SYann Gautier static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
3400d21680cSYann Gautier 	_CLK_FIXED(RCC_DDRITFCR, 0, DDRC1, _ACLK),
3410d21680cSYann Gautier 	_CLK_FIXED(RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
3420d21680cSYann Gautier 	_CLK_FIXED(RCC_DDRITFCR, 2, DDRC2, _ACLK),
3430d21680cSYann Gautier 	_CLK_FIXED(RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
3440d21680cSYann Gautier 	_CLK_FIXED(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
3450d21680cSYann Gautier 	_CLK_FIXED(RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
3460d21680cSYann Gautier 	_CLK_FIXED(RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
3470d21680cSYann Gautier 	_CLK_FIXED(RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
3480d21680cSYann Gautier 	_CLK_FIXED(RCC_DDRITFCR, 8, AXIDCG, _ACLK),
3490d21680cSYann Gautier 	_CLK_FIXED(RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
3500d21680cSYann Gautier 	_CLK_FIXED(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
3517839a050SYann Gautier 
3520d21680cSYann Gautier 	_CLK_SC_FIXED(RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
3530d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
3540d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
3550d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
3560d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
3570d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
3580d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
3590d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL),
3600d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL),
3610d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL),
3620d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL),
3637839a050SYann Gautier 
3640d21680cSYann Gautier 	_CLK_SC_FIXED(RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
3650d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
3667839a050SYann Gautier 
367f33b2433SYann Gautier 	_CLK_SC_FIXED(RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID),
368f33b2433SYann Gautier 
3690d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
3700d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
3710d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
3727839a050SYann Gautier 
3730d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL),
3740d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
3750d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL),
376d4151d2fSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL),
3770d21680cSYann Gautier 	_CLK_SC_FIXED(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
3780d21680cSYann Gautier 	_CLK_SC_FIXED(RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5),
3790d21680cSYann Gautier 	_CLK_SC_FIXED(RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5),
3800d21680cSYann Gautier 	_CLK_SC_FIXED(RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5),
3810d21680cSYann Gautier 	_CLK_SC_FIXED(RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5),
3820d21680cSYann Gautier 	_CLK_SC_FIXED(RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5),
3830d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
3847839a050SYann Gautier 
3850d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
3860d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
3877839a050SYann Gautier 
3880d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
3890d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
3900d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
3910d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
3920d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
3930d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
3940d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
3950d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
3960d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
3970d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
3980d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
3997839a050SYann Gautier 
4000d21680cSYann Gautier 	_CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5),
4010d21680cSYann Gautier 	_CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5),
4020d21680cSYann Gautier 	_CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5),
4030d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL),
4040d21680cSYann Gautier 	_CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5),
4057839a050SYann Gautier 
4060d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
4070d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
4080d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
4090d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
4100d21680cSYann Gautier 	_CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
4117839a050SYann Gautier 
412016af006SEtienne Carriere 	_CLK_SELEC(RCC_BDCR, 20, RTC, _RTC_SEL),
4130d21680cSYann Gautier 	_CLK_SELEC(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
4147839a050SYann Gautier };
4157839a050SYann Gautier 
4160d21680cSYann Gautier static const uint8_t i2c12_parents[] = {
4170d21680cSYann Gautier 	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
4180d21680cSYann Gautier };
4190d21680cSYann Gautier 
4200d21680cSYann Gautier static const uint8_t i2c35_parents[] = {
4210d21680cSYann Gautier 	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
4220d21680cSYann Gautier };
4230d21680cSYann Gautier 
4240d21680cSYann Gautier static const uint8_t stgen_parents[] = {
4250d21680cSYann Gautier 	_HSI_KER, _HSE_KER
4260d21680cSYann Gautier };
4270d21680cSYann Gautier 
4280d21680cSYann Gautier static const uint8_t i2c46_parents[] = {
4290d21680cSYann Gautier 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER
4300d21680cSYann Gautier };
4310d21680cSYann Gautier 
4320d21680cSYann Gautier static const uint8_t spi6_parents[] = {
4330d21680cSYann Gautier 	_PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q
4340d21680cSYann Gautier };
4350d21680cSYann Gautier 
4360d21680cSYann Gautier static const uint8_t usart1_parents[] = {
4370d21680cSYann Gautier 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER
4380d21680cSYann Gautier };
4390d21680cSYann Gautier 
4400d21680cSYann Gautier static const uint8_t rng1_parents[] = {
4410d21680cSYann Gautier 	_CSI, _PLL4_R, _LSE, _LSI
4420d21680cSYann Gautier };
4430d21680cSYann Gautier 
4440d21680cSYann Gautier static const uint8_t uart6_parents[] = {
4450d21680cSYann Gautier 	_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
4460d21680cSYann Gautier };
4470d21680cSYann Gautier 
4480d21680cSYann Gautier static const uint8_t uart234578_parents[] = {
4490d21680cSYann Gautier 	_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
4500d21680cSYann Gautier };
4510d21680cSYann Gautier 
4520d21680cSYann Gautier static const uint8_t sdmmc12_parents[] = {
4530d21680cSYann Gautier 	_HCLK6, _PLL3_R, _PLL4_P, _HSI_KER
4540d21680cSYann Gautier };
4550d21680cSYann Gautier 
4560d21680cSYann Gautier static const uint8_t sdmmc3_parents[] = {
4570d21680cSYann Gautier 	_HCLK2, _PLL3_R, _PLL4_P, _HSI_KER
4580d21680cSYann Gautier };
4590d21680cSYann Gautier 
4600d21680cSYann Gautier static const uint8_t qspi_parents[] = {
4610d21680cSYann Gautier 	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
4620d21680cSYann Gautier };
4630d21680cSYann Gautier 
4640d21680cSYann Gautier static const uint8_t fmc_parents[] = {
4650d21680cSYann Gautier 	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
4660d21680cSYann Gautier };
4670d21680cSYann Gautier 
4680d21680cSYann Gautier static const uint8_t ass_parents[] = {
4690d21680cSYann Gautier 	_HSI, _HSE, _PLL2
4700d21680cSYann Gautier };
4710d21680cSYann Gautier 
472b053a22eSYann Gautier static const uint8_t mss_parents[] = {
473b053a22eSYann Gautier 	_HSI, _HSE, _CSI, _PLL3
474b053a22eSYann Gautier };
475b053a22eSYann Gautier 
4760d21680cSYann Gautier static const uint8_t usbphy_parents[] = {
4770d21680cSYann Gautier 	_HSE_KER, _PLL4_R, _HSE_KER_DIV2
4780d21680cSYann Gautier };
4790d21680cSYann Gautier 
4800d21680cSYann Gautier static const uint8_t usbo_parents[] = {
4810d21680cSYann Gautier 	_PLL4_R, _USB_PHY_48
4820d21680cSYann Gautier };
4837839a050SYann Gautier 
4848fbcd9e4SEtienne Carriere static const uint8_t mpu_parents[] = {
4858fbcd9e4SEtienne Carriere 	_HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */
4868fbcd9e4SEtienne Carriere };
4878fbcd9e4SEtienne Carriere 
4888fbcd9e4SEtienne Carriere static const uint8_t per_parents[] = {
4898fbcd9e4SEtienne Carriere 	_HSI, _HSE, _CSI,
4908fbcd9e4SEtienne Carriere };
4918fbcd9e4SEtienne Carriere 
492016af006SEtienne Carriere static const uint8_t rtc_parents[] = {
493016af006SEtienne Carriere 	_UNKNOWN_ID, _LSE, _LSI, _HSE
494016af006SEtienne Carriere };
495016af006SEtienne Carriere 
4967839a050SYann Gautier static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
497d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents),
498d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents),
499d4151d2fSYann Gautier 	_CLK_PARENT_SEL(STGEN, RCC_STGENCKSELR, stgen_parents),
500d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C46, RCC_I2C46CKSELR, i2c46_parents),
501d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents),
502d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents),
503d4151d2fSYann Gautier 	_CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents),
5048fbcd9e4SEtienne Carriere 	_CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents),
5058fbcd9e4SEtienne Carriere 	_CLK_PARENT_SEL(PER, RCC_CPERCKSELR, per_parents),
506016af006SEtienne Carriere 	_CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents),
507d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents),
508d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents),
509d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents),
510d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART78, RCC_UART78CKSELR, uart234578_parents),
511d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SDMMC12, RCC_SDMMC12CKSELR, sdmmc12_parents),
512d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents),
513d4151d2fSYann Gautier 	_CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents),
514d4151d2fSYann Gautier 	_CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents),
515d4151d2fSYann Gautier 	_CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, ass_parents),
516d4151d2fSYann Gautier 	_CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mss_parents),
517d4151d2fSYann Gautier 	_CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents),
518d4151d2fSYann Gautier 	_CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents),
5197839a050SYann Gautier };
5207839a050SYann Gautier 
5217839a050SYann Gautier /* Define characteristic of PLL according type */
5227839a050SYann Gautier #define DIVN_MIN	24
5237839a050SYann Gautier static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
5247839a050SYann Gautier 	[PLL_800] = {
5257839a050SYann Gautier 		.refclk_min = 4,
5267839a050SYann Gautier 		.refclk_max = 16,
5277839a050SYann Gautier 		.divn_max = 99,
5287839a050SYann Gautier 	},
5297839a050SYann Gautier 	[PLL_1600] = {
5307839a050SYann Gautier 		.refclk_min = 8,
5317839a050SYann Gautier 		.refclk_max = 16,
5327839a050SYann Gautier 		.divn_max = 199,
5337839a050SYann Gautier 	},
5347839a050SYann Gautier };
5357839a050SYann Gautier 
5367839a050SYann Gautier /* PLLNCFGR2 register divider by output */
5377839a050SYann Gautier static const uint8_t pllncfgr2[_DIV_NB] = {
5387839a050SYann Gautier 	[_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT,
5397839a050SYann Gautier 	[_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT,
5400d21680cSYann Gautier 	[_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT,
5417839a050SYann Gautier };
5427839a050SYann Gautier 
5437839a050SYann Gautier static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = {
5440d21680cSYann Gautier 	_CLK_PLL(_PLL1, PLL_1600,
5457839a050SYann Gautier 		 RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2,
5467839a050SYann Gautier 		 RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR,
5477839a050SYann Gautier 		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
5480d21680cSYann Gautier 	_CLK_PLL(_PLL2, PLL_1600,
5497839a050SYann Gautier 		 RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2,
5507839a050SYann Gautier 		 RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR,
5517839a050SYann Gautier 		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
5520d21680cSYann Gautier 	_CLK_PLL(_PLL3, PLL_800,
5537839a050SYann Gautier 		 RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2,
5547839a050SYann Gautier 		 RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR,
5557839a050SYann Gautier 		 _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID),
5560d21680cSYann Gautier 	_CLK_PLL(_PLL4, PLL_800,
5577839a050SYann Gautier 		 RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2,
5587839a050SYann Gautier 		 RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR,
5597839a050SYann Gautier 		 _HSI, _HSE, _CSI, _I2S_CKIN),
5607839a050SYann Gautier };
5617839a050SYann Gautier 
5627839a050SYann Gautier /* Prescaler table lookups for clock computation */
563b053a22eSYann Gautier /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */
564b053a22eSYann Gautier static const uint8_t stm32mp1_mcu_div[16] = {
565b053a22eSYann Gautier 	0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9
566b053a22eSYann Gautier };
5677839a050SYann Gautier 
5687839a050SYann Gautier /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */
5697839a050SYann Gautier #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div
5707839a050SYann Gautier #define stm32mp1_apbx_div stm32mp1_mpu_apbx_div
5717839a050SYann Gautier static const uint8_t stm32mp1_mpu_apbx_div[8] = {
5727839a050SYann Gautier 	0, 1, 2, 3, 4, 4, 4, 4
5737839a050SYann Gautier };
5747839a050SYann Gautier 
5757839a050SYann Gautier /* div = /1 /2 /3 /4 */
5767839a050SYann Gautier static const uint8_t stm32mp1_axi_div[8] = {
5777839a050SYann Gautier 	1, 2, 3, 4, 4, 4, 4, 4
5787839a050SYann Gautier };
5797839a050SYann Gautier 
58037e8295aSEtienne Carriere static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = {
58137e8295aSEtienne Carriere 	[_HSI] = "HSI",
58237e8295aSEtienne Carriere 	[_HSE] = "HSE",
58337e8295aSEtienne Carriere 	[_CSI] = "CSI",
58437e8295aSEtienne Carriere 	[_LSI] = "LSI",
58537e8295aSEtienne Carriere 	[_LSE] = "LSE",
58637e8295aSEtienne Carriere 	[_I2S_CKIN] = "I2S_CKIN",
58737e8295aSEtienne Carriere 	[_HSI_KER] = "HSI_KER",
58837e8295aSEtienne Carriere 	[_HSE_KER] = "HSE_KER",
58937e8295aSEtienne Carriere 	[_HSE_KER_DIV2] = "HSE_KER_DIV2",
59037e8295aSEtienne Carriere 	[_CSI_KER] = "CSI_KER",
59137e8295aSEtienne Carriere 	[_PLL1_P] = "PLL1_P",
59237e8295aSEtienne Carriere 	[_PLL1_Q] = "PLL1_Q",
59337e8295aSEtienne Carriere 	[_PLL1_R] = "PLL1_R",
59437e8295aSEtienne Carriere 	[_PLL2_P] = "PLL2_P",
59537e8295aSEtienne Carriere 	[_PLL2_Q] = "PLL2_Q",
59637e8295aSEtienne Carriere 	[_PLL2_R] = "PLL2_R",
59737e8295aSEtienne Carriere 	[_PLL3_P] = "PLL3_P",
59837e8295aSEtienne Carriere 	[_PLL3_Q] = "PLL3_Q",
59937e8295aSEtienne Carriere 	[_PLL3_R] = "PLL3_R",
60037e8295aSEtienne Carriere 	[_PLL4_P] = "PLL4_P",
60137e8295aSEtienne Carriere 	[_PLL4_Q] = "PLL4_Q",
60237e8295aSEtienne Carriere 	[_PLL4_R] = "PLL4_R",
60337e8295aSEtienne Carriere 	[_ACLK] = "ACLK",
60437e8295aSEtienne Carriere 	[_PCLK1] = "PCLK1",
60537e8295aSEtienne Carriere 	[_PCLK2] = "PCLK2",
60637e8295aSEtienne Carriere 	[_PCLK3] = "PCLK3",
60737e8295aSEtienne Carriere 	[_PCLK4] = "PCLK4",
60837e8295aSEtienne Carriere 	[_PCLK5] = "PCLK5",
60937e8295aSEtienne Carriere 	[_HCLK6] = "KCLK6",
61037e8295aSEtienne Carriere 	[_HCLK2] = "HCLK2",
61137e8295aSEtienne Carriere 	[_CK_PER] = "CK_PER",
61237e8295aSEtienne Carriere 	[_CK_MPU] = "CK_MPU",
61337e8295aSEtienne Carriere 	[_CK_MCU] = "CK_MCU",
61437e8295aSEtienne Carriere 	[_USB_PHY_48] = "USB_PHY_48",
61537e8295aSEtienne Carriere };
61637e8295aSEtienne Carriere 
6170d21680cSYann Gautier /* RCC clock device driver private */
6180d21680cSYann Gautier static unsigned long stm32mp1_osc[NB_OSC];
6190d21680cSYann Gautier static struct spinlock reg_lock;
6200d21680cSYann Gautier static unsigned int gate_refcounts[NB_GATES];
6210d21680cSYann Gautier static struct spinlock refcount_lock;
6227839a050SYann Gautier 
6230d21680cSYann Gautier static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx)
6240d21680cSYann Gautier {
6250d21680cSYann Gautier 	return &stm32mp1_clk_gate[idx];
6260d21680cSYann Gautier }
6277839a050SYann Gautier 
6280d21680cSYann Gautier static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx)
6290d21680cSYann Gautier {
6300d21680cSYann Gautier 	return &stm32mp1_clk_sel[idx];
6310d21680cSYann Gautier }
6320d21680cSYann Gautier 
6330d21680cSYann Gautier static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx)
6340d21680cSYann Gautier {
6350d21680cSYann Gautier 	return &stm32mp1_clk_pll[idx];
6360d21680cSYann Gautier }
6370d21680cSYann Gautier 
6380d21680cSYann Gautier static void stm32mp1_clk_lock(struct spinlock *lock)
6390d21680cSYann Gautier {
640e463d3f4SYann Gautier 	if (stm32mp_lock_available()) {
6410d21680cSYann Gautier 		/* Assume interrupts are masked */
6420d21680cSYann Gautier 		spin_lock(lock);
6430d21680cSYann Gautier 	}
644e463d3f4SYann Gautier }
6450d21680cSYann Gautier 
6460d21680cSYann Gautier static void stm32mp1_clk_unlock(struct spinlock *lock)
6470d21680cSYann Gautier {
648e463d3f4SYann Gautier 	if (stm32mp_lock_available()) {
6490d21680cSYann Gautier 		spin_unlock(lock);
6500d21680cSYann Gautier 	}
651e463d3f4SYann Gautier }
6520d21680cSYann Gautier 
6530d21680cSYann Gautier bool stm32mp1_rcc_is_secure(void)
6540d21680cSYann Gautier {
6550d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
6561bb9072aSEtienne Carriere 	uint32_t mask = RCC_TZCR_TZEN;
6570d21680cSYann Gautier 
6581bb9072aSEtienne Carriere 	return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
6590d21680cSYann Gautier }
6600d21680cSYann Gautier 
661b053a22eSYann Gautier bool stm32mp1_rcc_is_mckprot(void)
662b053a22eSYann Gautier {
663b053a22eSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
6641bb9072aSEtienne Carriere 	uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT;
665b053a22eSYann Gautier 
6661bb9072aSEtienne Carriere 	return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
667b053a22eSYann Gautier }
668b053a22eSYann Gautier 
6690d21680cSYann Gautier void stm32mp1_clk_rcc_regs_lock(void)
6700d21680cSYann Gautier {
6710d21680cSYann Gautier 	stm32mp1_clk_lock(&reg_lock);
6720d21680cSYann Gautier }
6730d21680cSYann Gautier 
6740d21680cSYann Gautier void stm32mp1_clk_rcc_regs_unlock(void)
6750d21680cSYann Gautier {
6760d21680cSYann Gautier 	stm32mp1_clk_unlock(&reg_lock);
6770d21680cSYann Gautier }
6780d21680cSYann Gautier 
6790d21680cSYann Gautier static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx)
6807839a050SYann Gautier {
6817839a050SYann Gautier 	if (idx >= NB_OSC) {
6827839a050SYann Gautier 		return 0;
6837839a050SYann Gautier 	}
6847839a050SYann Gautier 
6850d21680cSYann Gautier 	return stm32mp1_osc[idx];
6867839a050SYann Gautier }
6877839a050SYann Gautier 
6880d21680cSYann Gautier static int stm32mp1_clk_get_gated_id(unsigned long id)
6897839a050SYann Gautier {
6900d21680cSYann Gautier 	unsigned int i;
6917839a050SYann Gautier 
6920d21680cSYann Gautier 	for (i = 0U; i < NB_GATES; i++) {
6930d21680cSYann Gautier 		if (gate_ref(i)->index == id) {
6947839a050SYann Gautier 			return i;
6957839a050SYann Gautier 		}
6967839a050SYann Gautier 	}
6977839a050SYann Gautier 
6987839a050SYann Gautier 	ERROR("%s: clk id %d not found\n", __func__, (uint32_t)id);
6997839a050SYann Gautier 
7007839a050SYann Gautier 	return -EINVAL;
7017839a050SYann Gautier }
7027839a050SYann Gautier 
7030d21680cSYann Gautier static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i)
7047839a050SYann Gautier {
7050d21680cSYann Gautier 	return (enum stm32mp1_parent_sel)(gate_ref(i)->sel);
7067839a050SYann Gautier }
7077839a050SYann Gautier 
7080d21680cSYann Gautier static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i)
7097839a050SYann Gautier {
7100d21680cSYann Gautier 	return (enum stm32mp1_parent_id)(gate_ref(i)->fixed);
7117839a050SYann Gautier }
7127839a050SYann Gautier 
7130d21680cSYann Gautier static int stm32mp1_clk_get_parent(unsigned long id)
7147839a050SYann Gautier {
7150d21680cSYann Gautier 	const struct stm32mp1_clk_sel *sel;
7168fbcd9e4SEtienne Carriere 	uint32_t p_sel;
7177839a050SYann Gautier 	int i;
7187839a050SYann Gautier 	enum stm32mp1_parent_id p;
7197839a050SYann Gautier 	enum stm32mp1_parent_sel s;
7200d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
7217839a050SYann Gautier 
7228fbcd9e4SEtienne Carriere 	/* Few non gateable clock have a static parent ID, find them */
7238fbcd9e4SEtienne Carriere 	i = (int)clock_id2parent_id(id);
7248fbcd9e4SEtienne Carriere 	if (i != _UNKNOWN_ID) {
7258fbcd9e4SEtienne Carriere 		return i;
7267839a050SYann Gautier 	}
7277839a050SYann Gautier 
7280d21680cSYann Gautier 	i = stm32mp1_clk_get_gated_id(id);
7297839a050SYann Gautier 	if (i < 0) {
7300d21680cSYann Gautier 		panic();
7317839a050SYann Gautier 	}
7327839a050SYann Gautier 
7330d21680cSYann Gautier 	p = stm32mp1_clk_get_fixed_parent(i);
7347839a050SYann Gautier 	if (p < _PARENT_NB) {
7357839a050SYann Gautier 		return (int)p;
7367839a050SYann Gautier 	}
7377839a050SYann Gautier 
7380d21680cSYann Gautier 	s = stm32mp1_clk_get_sel(i);
7390d21680cSYann Gautier 	if (s == _UNKNOWN_SEL) {
7400d21680cSYann Gautier 		return -EINVAL;
7410d21680cSYann Gautier 	}
7427839a050SYann Gautier 	if (s >= _PARENT_SEL_NB) {
7430d21680cSYann Gautier 		panic();
7447839a050SYann Gautier 	}
7457839a050SYann Gautier 
7460d21680cSYann Gautier 	sel = clk_sel_ref(s);
7478ae08dcdSEtienne Carriere 	p_sel = (mmio_read_32(rcc_base + sel->offset) &
7488ae08dcdSEtienne Carriere 		 (sel->msk << sel->src)) >> sel->src;
7490d21680cSYann Gautier 	if (p_sel < sel->nb_parent) {
7500d21680cSYann Gautier 		return (int)sel->parent[p_sel];
7517839a050SYann Gautier 	}
7527839a050SYann Gautier 
7537839a050SYann Gautier 	return -EINVAL;
7547839a050SYann Gautier }
7557839a050SYann Gautier 
7560d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll)
7577839a050SYann Gautier {
7580d21680cSYann Gautier 	uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr);
7590d21680cSYann Gautier 	uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK;
7607839a050SYann Gautier 
7610d21680cSYann Gautier 	return stm32mp1_clk_get_fixed(pll->refclk[src]);
7627839a050SYann Gautier }
7637839a050SYann Gautier 
7647839a050SYann Gautier /*
7657839a050SYann Gautier  * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL
7667839a050SYann Gautier  * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1)
7677839a050SYann Gautier  * - PLL3 & PLL4 => return VCO     with Fpll_y_ck = FVCO / (DIVy + 1)
7687839a050SYann Gautier  * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1)
7697839a050SYann Gautier  */
7700d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll)
7717839a050SYann Gautier {
7727839a050SYann Gautier 	unsigned long refclk, fvco;
7737839a050SYann Gautier 	uint32_t cfgr1, fracr, divm, divn;
7740d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
7757839a050SYann Gautier 
7760d21680cSYann Gautier 	cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1);
7770d21680cSYann Gautier 	fracr = mmio_read_32(rcc_base + pll->pllxfracr);
7787839a050SYann Gautier 
7797839a050SYann Gautier 	divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT;
7807839a050SYann Gautier 	divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK;
7817839a050SYann Gautier 
7820d21680cSYann Gautier 	refclk = stm32mp1_pll_get_fref(pll);
7837839a050SYann Gautier 
7847839a050SYann Gautier 	/*
7857839a050SYann Gautier 	 * With FRACV :
7867839a050SYann Gautier 	 *   Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1)
7877839a050SYann Gautier 	 * Without FRACV
7887839a050SYann Gautier 	 *   Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1)
7897839a050SYann Gautier 	 */
7907839a050SYann Gautier 	if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) {
7910d21680cSYann Gautier 		uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >>
7920d21680cSYann Gautier 				 RCC_PLLNFRACR_FRACV_SHIFT;
7937839a050SYann Gautier 		unsigned long long numerator, denominator;
7947839a050SYann Gautier 
7950d21680cSYann Gautier 		numerator = (((unsigned long long)divn + 1U) << 13) + fracv;
7960d21680cSYann Gautier 		numerator = refclk * numerator;
7977839a050SYann Gautier 		denominator = ((unsigned long long)divm + 1U) << 13;
7987839a050SYann Gautier 		fvco = (unsigned long)(numerator / denominator);
7997839a050SYann Gautier 	} else {
8007839a050SYann Gautier 		fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U));
8017839a050SYann Gautier 	}
8027839a050SYann Gautier 
8037839a050SYann Gautier 	return fvco;
8047839a050SYann Gautier }
8057839a050SYann Gautier 
8060d21680cSYann Gautier static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id,
8077839a050SYann Gautier 					    enum stm32mp1_div_id div_id)
8087839a050SYann Gautier {
8090d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
8107839a050SYann Gautier 	unsigned long dfout;
8117839a050SYann Gautier 	uint32_t cfgr2, divy;
8127839a050SYann Gautier 
8137839a050SYann Gautier 	if (div_id >= _DIV_NB) {
8147839a050SYann Gautier 		return 0;
8157839a050SYann Gautier 	}
8167839a050SYann Gautier 
8170d21680cSYann Gautier 	cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2);
8187839a050SYann Gautier 	divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK;
8197839a050SYann Gautier 
8200d21680cSYann Gautier 	dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U);
8217839a050SYann Gautier 
8227839a050SYann Gautier 	return dfout;
8237839a050SYann Gautier }
8247839a050SYann Gautier 
8250d21680cSYann Gautier static unsigned long get_clock_rate(int p)
8267839a050SYann Gautier {
8277839a050SYann Gautier 	uint32_t reg, clkdiv;
8287839a050SYann Gautier 	unsigned long clock = 0;
8290d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
8307839a050SYann Gautier 
8317839a050SYann Gautier 	switch (p) {
8327839a050SYann Gautier 	case _CK_MPU:
8337839a050SYann Gautier 	/* MPU sub system */
8340d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MPCKSELR);
8357839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
8367839a050SYann Gautier 		case RCC_MPCKSELR_HSI:
8370d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
8387839a050SYann Gautier 			break;
8397839a050SYann Gautier 		case RCC_MPCKSELR_HSE:
8400d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
8417839a050SYann Gautier 			break;
8427839a050SYann Gautier 		case RCC_MPCKSELR_PLL:
8430d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
8447839a050SYann Gautier 			break;
8457839a050SYann Gautier 		case RCC_MPCKSELR_PLL_MPUDIV:
8460d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
8477839a050SYann Gautier 
8480d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_MPCKDIVR);
8497839a050SYann Gautier 			clkdiv = reg & RCC_MPUDIV_MASK;
8507839a050SYann Gautier 			if (clkdiv != 0U) {
8517839a050SYann Gautier 				clock /= stm32mp1_mpu_div[clkdiv];
8527839a050SYann Gautier 			}
8537839a050SYann Gautier 			break;
8547839a050SYann Gautier 		default:
8557839a050SYann Gautier 			break;
8567839a050SYann Gautier 		}
8577839a050SYann Gautier 		break;
8587839a050SYann Gautier 	/* AXI sub system */
8597839a050SYann Gautier 	case _ACLK:
8607839a050SYann Gautier 	case _HCLK2:
8617839a050SYann Gautier 	case _HCLK6:
8627839a050SYann Gautier 	case _PCLK4:
8637839a050SYann Gautier 	case _PCLK5:
8640d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_ASSCKSELR);
8657839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
8667839a050SYann Gautier 		case RCC_ASSCKSELR_HSI:
8670d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
8687839a050SYann Gautier 			break;
8697839a050SYann Gautier 		case RCC_ASSCKSELR_HSE:
8700d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
8717839a050SYann Gautier 			break;
8727839a050SYann Gautier 		case RCC_ASSCKSELR_PLL:
8730d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
8747839a050SYann Gautier 			break;
8757839a050SYann Gautier 		default:
8767839a050SYann Gautier 			break;
8777839a050SYann Gautier 		}
8787839a050SYann Gautier 
8797839a050SYann Gautier 		/* System clock divider */
8800d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_AXIDIVR);
8817839a050SYann Gautier 		clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK];
8827839a050SYann Gautier 
8837839a050SYann Gautier 		switch (p) {
8847839a050SYann Gautier 		case _PCLK4:
8850d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB4DIVR);
8867839a050SYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
8877839a050SYann Gautier 			break;
8887839a050SYann Gautier 		case _PCLK5:
8890d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB5DIVR);
8907839a050SYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
8917839a050SYann Gautier 			break;
8927839a050SYann Gautier 		default:
8937839a050SYann Gautier 			break;
8947839a050SYann Gautier 		}
8957839a050SYann Gautier 		break;
896b053a22eSYann Gautier 	/* MCU sub system */
897b053a22eSYann Gautier 	case _CK_MCU:
898b053a22eSYann Gautier 	case _PCLK1:
899b053a22eSYann Gautier 	case _PCLK2:
900b053a22eSYann Gautier 	case _PCLK3:
901b053a22eSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MSSCKSELR);
902b053a22eSYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
903b053a22eSYann Gautier 		case RCC_MSSCKSELR_HSI:
904b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
905b053a22eSYann Gautier 			break;
906b053a22eSYann Gautier 		case RCC_MSSCKSELR_HSE:
907b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
908b053a22eSYann Gautier 			break;
909b053a22eSYann Gautier 		case RCC_MSSCKSELR_CSI:
910b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_CSI);
911b053a22eSYann Gautier 			break;
912b053a22eSYann Gautier 		case RCC_MSSCKSELR_PLL:
913b053a22eSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
914b053a22eSYann Gautier 			break;
915b053a22eSYann Gautier 		default:
916b053a22eSYann Gautier 			break;
917b053a22eSYann Gautier 		}
918b053a22eSYann Gautier 
919b053a22eSYann Gautier 		/* MCU clock divider */
920b053a22eSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MCUDIVR);
921b053a22eSYann Gautier 		clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK];
922b053a22eSYann Gautier 
923b053a22eSYann Gautier 		switch (p) {
924b053a22eSYann Gautier 		case _PCLK1:
925b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB1DIVR);
926b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
927b053a22eSYann Gautier 			break;
928b053a22eSYann Gautier 		case _PCLK2:
929b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB2DIVR);
930b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
931b053a22eSYann Gautier 			break;
932b053a22eSYann Gautier 		case _PCLK3:
933b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB3DIVR);
934b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
935b053a22eSYann Gautier 			break;
936b053a22eSYann Gautier 		case _CK_MCU:
937b053a22eSYann Gautier 		default:
938b053a22eSYann Gautier 			break;
939b053a22eSYann Gautier 		}
940b053a22eSYann Gautier 		break;
9417839a050SYann Gautier 	case _CK_PER:
9420d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_CPERCKSELR);
9437839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
9447839a050SYann Gautier 		case RCC_CPERCKSELR_HSI:
9450d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
9467839a050SYann Gautier 			break;
9477839a050SYann Gautier 		case RCC_CPERCKSELR_HSE:
9480d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
9497839a050SYann Gautier 			break;
9507839a050SYann Gautier 		case RCC_CPERCKSELR_CSI:
9510d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_CSI);
9527839a050SYann Gautier 			break;
9537839a050SYann Gautier 		default:
9547839a050SYann Gautier 			break;
9557839a050SYann Gautier 		}
9567839a050SYann Gautier 		break;
9577839a050SYann Gautier 	case _HSI:
9587839a050SYann Gautier 	case _HSI_KER:
9590d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSI);
9607839a050SYann Gautier 		break;
9617839a050SYann Gautier 	case _CSI:
9627839a050SYann Gautier 	case _CSI_KER:
9630d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_CSI);
9647839a050SYann Gautier 		break;
9657839a050SYann Gautier 	case _HSE:
9667839a050SYann Gautier 	case _HSE_KER:
9670d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSE);
9687839a050SYann Gautier 		break;
9697839a050SYann Gautier 	case _HSE_KER_DIV2:
9700d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSE) >> 1;
9717839a050SYann Gautier 		break;
9727839a050SYann Gautier 	case _LSI:
9730d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_LSI);
9747839a050SYann Gautier 		break;
9757839a050SYann Gautier 	case _LSE:
9760d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_LSE);
9777839a050SYann Gautier 		break;
9787839a050SYann Gautier 	/* PLL */
9797839a050SYann Gautier 	case _PLL1_P:
9800d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
9817839a050SYann Gautier 		break;
9827839a050SYann Gautier 	case _PLL1_Q:
9830d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q);
9847839a050SYann Gautier 		break;
9857839a050SYann Gautier 	case _PLL1_R:
9860d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R);
9877839a050SYann Gautier 		break;
9887839a050SYann Gautier 	case _PLL2_P:
9890d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
9907839a050SYann Gautier 		break;
9917839a050SYann Gautier 	case _PLL2_Q:
9920d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q);
9937839a050SYann Gautier 		break;
9947839a050SYann Gautier 	case _PLL2_R:
9950d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R);
9967839a050SYann Gautier 		break;
9977839a050SYann Gautier 	case _PLL3_P:
9980d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
9997839a050SYann Gautier 		break;
10007839a050SYann Gautier 	case _PLL3_Q:
10010d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q);
10027839a050SYann Gautier 		break;
10037839a050SYann Gautier 	case _PLL3_R:
10040d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R);
10057839a050SYann Gautier 		break;
10067839a050SYann Gautier 	case _PLL4_P:
10070d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P);
10087839a050SYann Gautier 		break;
10097839a050SYann Gautier 	case _PLL4_Q:
10100d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q);
10117839a050SYann Gautier 		break;
10127839a050SYann Gautier 	case _PLL4_R:
10130d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R);
10147839a050SYann Gautier 		break;
10157839a050SYann Gautier 	/* Other */
10167839a050SYann Gautier 	case _USB_PHY_48:
10170d21680cSYann Gautier 		clock = USB_PHY_48_MHZ;
10187839a050SYann Gautier 		break;
10197839a050SYann Gautier 	default:
10207839a050SYann Gautier 		break;
10217839a050SYann Gautier 	}
10227839a050SYann Gautier 
10237839a050SYann Gautier 	return clock;
10247839a050SYann Gautier }
10257839a050SYann Gautier 
10260d21680cSYann Gautier static void __clk_enable(struct stm32mp1_clk_gate const *gate)
10270d21680cSYann Gautier {
10280d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10290d21680cSYann Gautier 
103025be845eSEtienne Carriere 	VERBOSE("Enable clock %u\n", gate->index);
103125be845eSEtienne Carriere 
10320d21680cSYann Gautier 	if (gate->set_clr != 0U) {
10330d21680cSYann Gautier 		mmio_write_32(rcc_base + gate->offset, BIT(gate->bit));
10340d21680cSYann Gautier 	} else {
10350d21680cSYann Gautier 		mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit));
10360d21680cSYann Gautier 	}
10370d21680cSYann Gautier }
10380d21680cSYann Gautier 
10390d21680cSYann Gautier static void __clk_disable(struct stm32mp1_clk_gate const *gate)
10400d21680cSYann Gautier {
10410d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10420d21680cSYann Gautier 
104325be845eSEtienne Carriere 	VERBOSE("Disable clock %u\n", gate->index);
104425be845eSEtienne Carriere 
10450d21680cSYann Gautier 	if (gate->set_clr != 0U) {
10460d21680cSYann Gautier 		mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET,
10470d21680cSYann Gautier 			      BIT(gate->bit));
10480d21680cSYann Gautier 	} else {
10490d21680cSYann Gautier 		mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit));
10500d21680cSYann Gautier 	}
10510d21680cSYann Gautier }
10520d21680cSYann Gautier 
10530d21680cSYann Gautier static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate)
10540d21680cSYann Gautier {
10550d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10560d21680cSYann Gautier 
10570d21680cSYann Gautier 	return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit);
10580d21680cSYann Gautier }
10590d21680cSYann Gautier 
10600d21680cSYann Gautier unsigned int stm32mp1_clk_get_refcount(unsigned long id)
10610d21680cSYann Gautier {
10620d21680cSYann Gautier 	int i = stm32mp1_clk_get_gated_id(id);
10630d21680cSYann Gautier 
10640d21680cSYann Gautier 	if (i < 0) {
10650d21680cSYann Gautier 		panic();
10660d21680cSYann Gautier 	}
10670d21680cSYann Gautier 
10680d21680cSYann Gautier 	return gate_refcounts[i];
10690d21680cSYann Gautier }
10700d21680cSYann Gautier 
107135848200SEtienne Carriere /* Oscillators and PLLs are not gated at runtime */
107235848200SEtienne Carriere static bool clock_is_always_on(unsigned long id)
107335848200SEtienne Carriere {
107435848200SEtienne Carriere 	switch (id) {
107535848200SEtienne Carriere 	case CK_HSE:
107635848200SEtienne Carriere 	case CK_CSI:
107735848200SEtienne Carriere 	case CK_LSI:
107835848200SEtienne Carriere 	case CK_LSE:
107935848200SEtienne Carriere 	case CK_HSI:
108035848200SEtienne Carriere 	case CK_HSE_DIV2:
108135848200SEtienne Carriere 	case PLL1_Q:
108235848200SEtienne Carriere 	case PLL1_R:
108335848200SEtienne Carriere 	case PLL2_P:
108435848200SEtienne Carriere 	case PLL2_Q:
108535848200SEtienne Carriere 	case PLL2_R:
108635848200SEtienne Carriere 	case PLL3_P:
108735848200SEtienne Carriere 	case PLL3_Q:
108835848200SEtienne Carriere 	case PLL3_R:
108935848200SEtienne Carriere 		return true;
109035848200SEtienne Carriere 	default:
109135848200SEtienne Carriere 		return false;
109235848200SEtienne Carriere 	}
109335848200SEtienne Carriere }
109435848200SEtienne Carriere 
10950d21680cSYann Gautier void __stm32mp1_clk_enable(unsigned long id, bool secure)
10960d21680cSYann Gautier {
10970d21680cSYann Gautier 	const struct stm32mp1_clk_gate *gate;
109835848200SEtienne Carriere 	int i;
10990d21680cSYann Gautier 	unsigned int *refcnt;
11000d21680cSYann Gautier 
110135848200SEtienne Carriere 	if (clock_is_always_on(id)) {
110235848200SEtienne Carriere 		return;
110335848200SEtienne Carriere 	}
110435848200SEtienne Carriere 
110535848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
11060d21680cSYann Gautier 	if (i < 0) {
11070d21680cSYann Gautier 		ERROR("Clock %d can't be enabled\n", (uint32_t)id);
11080d21680cSYann Gautier 		panic();
11090d21680cSYann Gautier 	}
11100d21680cSYann Gautier 
11110d21680cSYann Gautier 	gate = gate_ref(i);
11120d21680cSYann Gautier 	refcnt = &gate_refcounts[i];
11130d21680cSYann Gautier 
11140d21680cSYann Gautier 	stm32mp1_clk_lock(&refcount_lock);
11150d21680cSYann Gautier 
11160d21680cSYann Gautier 	if (stm32mp_incr_shrefcnt(refcnt, secure) != 0) {
11170d21680cSYann Gautier 		__clk_enable(gate);
11180d21680cSYann Gautier 	}
11190d21680cSYann Gautier 
11200d21680cSYann Gautier 	stm32mp1_clk_unlock(&refcount_lock);
11210d21680cSYann Gautier }
11220d21680cSYann Gautier 
11230d21680cSYann Gautier void __stm32mp1_clk_disable(unsigned long id, bool secure)
11240d21680cSYann Gautier {
11250d21680cSYann Gautier 	const struct stm32mp1_clk_gate *gate;
112635848200SEtienne Carriere 	int i;
11270d21680cSYann Gautier 	unsigned int *refcnt;
11280d21680cSYann Gautier 
112935848200SEtienne Carriere 	if (clock_is_always_on(id)) {
113035848200SEtienne Carriere 		return;
113135848200SEtienne Carriere 	}
113235848200SEtienne Carriere 
113335848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
11340d21680cSYann Gautier 	if (i < 0) {
11350d21680cSYann Gautier 		ERROR("Clock %d can't be disabled\n", (uint32_t)id);
11360d21680cSYann Gautier 		panic();
11370d21680cSYann Gautier 	}
11380d21680cSYann Gautier 
11390d21680cSYann Gautier 	gate = gate_ref(i);
11400d21680cSYann Gautier 	refcnt = &gate_refcounts[i];
11410d21680cSYann Gautier 
11420d21680cSYann Gautier 	stm32mp1_clk_lock(&refcount_lock);
11430d21680cSYann Gautier 
11440d21680cSYann Gautier 	if (stm32mp_decr_shrefcnt(refcnt, secure) != 0) {
11450d21680cSYann Gautier 		__clk_disable(gate);
11460d21680cSYann Gautier 	}
11470d21680cSYann Gautier 
11480d21680cSYann Gautier 	stm32mp1_clk_unlock(&refcount_lock);
11490d21680cSYann Gautier }
11500d21680cSYann Gautier 
11510d21680cSYann Gautier void stm32mp_clk_enable(unsigned long id)
11520d21680cSYann Gautier {
11530d21680cSYann Gautier 	__stm32mp1_clk_enable(id, true);
11540d21680cSYann Gautier }
11550d21680cSYann Gautier 
11560d21680cSYann Gautier void stm32mp_clk_disable(unsigned long id)
11570d21680cSYann Gautier {
11580d21680cSYann Gautier 	__stm32mp1_clk_disable(id, true);
11590d21680cSYann Gautier }
11600d21680cSYann Gautier 
11613f9c9784SYann Gautier bool stm32mp_clk_is_enabled(unsigned long id)
11627839a050SYann Gautier {
116335848200SEtienne Carriere 	int i;
11647839a050SYann Gautier 
116535848200SEtienne Carriere 	if (clock_is_always_on(id)) {
116635848200SEtienne Carriere 		return true;
116735848200SEtienne Carriere 	}
116835848200SEtienne Carriere 
116935848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
11707839a050SYann Gautier 	if (i < 0) {
11710d21680cSYann Gautier 		panic();
11727839a050SYann Gautier 	}
11737839a050SYann Gautier 
11740d21680cSYann Gautier 	return __clk_is_enabled(gate_ref(i));
11757839a050SYann Gautier }
11767839a050SYann Gautier 
11773f9c9784SYann Gautier unsigned long stm32mp_clk_get_rate(unsigned long id)
11787839a050SYann Gautier {
11790d21680cSYann Gautier 	int p = stm32mp1_clk_get_parent(id);
11807839a050SYann Gautier 
11817839a050SYann Gautier 	if (p < 0) {
11827839a050SYann Gautier 		return 0;
11837839a050SYann Gautier 	}
11847839a050SYann Gautier 
11850d21680cSYann Gautier 	return get_clock_rate(p);
11867839a050SYann Gautier }
11877839a050SYann Gautier 
11880d21680cSYann Gautier static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on)
11897839a050SYann Gautier {
11900d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
11917839a050SYann Gautier 
11920d21680cSYann Gautier 	if (enable) {
11937839a050SYann Gautier 		mmio_setbits_32(address, mask_on);
11947839a050SYann Gautier 	} else {
11957839a050SYann Gautier 		mmio_clrbits_32(address, mask_on);
11967839a050SYann Gautier 	}
11977839a050SYann Gautier }
11987839a050SYann Gautier 
11990d21680cSYann Gautier static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on)
12007839a050SYann Gautier {
12010d21680cSYann Gautier 	uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR;
12020d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
12030d21680cSYann Gautier 
12040d21680cSYann Gautier 	mmio_write_32(address, mask_on);
12057839a050SYann Gautier }
12067839a050SYann Gautier 
12070d21680cSYann Gautier static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy)
12087839a050SYann Gautier {
1209dfdb057aSYann Gautier 	uint64_t timeout;
12107839a050SYann Gautier 	uint32_t mask_test;
12110d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
12127839a050SYann Gautier 
12130d21680cSYann Gautier 	if (enable) {
12147839a050SYann Gautier 		mask_test = mask_rdy;
12157839a050SYann Gautier 	} else {
12167839a050SYann Gautier 		mask_test = 0;
12177839a050SYann Gautier 	}
12187839a050SYann Gautier 
1219dfdb057aSYann Gautier 	timeout = timeout_init_us(OSCRDY_TIMEOUT);
12207839a050SYann Gautier 	while ((mmio_read_32(address) & mask_rdy) != mask_test) {
1221dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
12220d21680cSYann Gautier 			ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n",
12237839a050SYann Gautier 			      mask_rdy, address, enable, mmio_read_32(address));
12247839a050SYann Gautier 			return -ETIMEDOUT;
12257839a050SYann Gautier 		}
12267839a050SYann Gautier 	}
12277839a050SYann Gautier 
12287839a050SYann Gautier 	return 0;
12297839a050SYann Gautier }
12307839a050SYann Gautier 
12310d21680cSYann Gautier static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv)
12327839a050SYann Gautier {
12337839a050SYann Gautier 	uint32_t value;
12340d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
12357839a050SYann Gautier 
12360d21680cSYann Gautier 	if (digbyp) {
12370d21680cSYann Gautier 		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP);
12380d21680cSYann Gautier 	}
12390d21680cSYann Gautier 
12400d21680cSYann Gautier 	if (bypass || digbyp) {
12410d21680cSYann Gautier 		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP);
12427839a050SYann Gautier 	}
12437839a050SYann Gautier 
12447839a050SYann Gautier 	/*
12457839a050SYann Gautier 	 * Warning: not recommended to switch directly from "high drive"
12467839a050SYann Gautier 	 * to "medium low drive", and vice-versa.
12477839a050SYann Gautier 	 */
12480d21680cSYann Gautier 	value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >>
12497839a050SYann Gautier 		RCC_BDCR_LSEDRV_SHIFT;
12507839a050SYann Gautier 
12517839a050SYann Gautier 	while (value != lsedrv) {
12527839a050SYann Gautier 		if (value > lsedrv) {
12537839a050SYann Gautier 			value--;
12547839a050SYann Gautier 		} else {
12557839a050SYann Gautier 			value++;
12567839a050SYann Gautier 		}
12577839a050SYann Gautier 
12580d21680cSYann Gautier 		mmio_clrsetbits_32(rcc_base + RCC_BDCR,
12597839a050SYann Gautier 				   RCC_BDCR_LSEDRV_MASK,
12607839a050SYann Gautier 				   value << RCC_BDCR_LSEDRV_SHIFT);
12617839a050SYann Gautier 	}
12627839a050SYann Gautier 
12630d21680cSYann Gautier 	stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON);
12647839a050SYann Gautier }
12657839a050SYann Gautier 
12660d21680cSYann Gautier static void stm32mp1_lse_wait(void)
12677839a050SYann Gautier {
12680d21680cSYann Gautier 	if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) {
12697839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
12707839a050SYann Gautier 	}
12717839a050SYann Gautier }
12727839a050SYann Gautier 
12730d21680cSYann Gautier static void stm32mp1_lsi_set(bool enable)
12747839a050SYann Gautier {
12750d21680cSYann Gautier 	stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION);
12760d21680cSYann Gautier 
12770d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) {
12787839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
12797839a050SYann Gautier 	}
12807839a050SYann Gautier }
12817839a050SYann Gautier 
12820d21680cSYann Gautier static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css)
12837839a050SYann Gautier {
12840d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
12850d21680cSYann Gautier 
12860d21680cSYann Gautier 	if (digbyp) {
12870d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP);
12887839a050SYann Gautier 	}
12897839a050SYann Gautier 
12900d21680cSYann Gautier 	if (bypass || digbyp) {
12910d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP);
12920d21680cSYann Gautier 	}
12930d21680cSYann Gautier 
12940d21680cSYann Gautier 	stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON);
12950d21680cSYann Gautier 	if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) {
12967839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
12977839a050SYann Gautier 	}
12987839a050SYann Gautier 
12997839a050SYann Gautier 	if (css) {
13000d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON);
13017839a050SYann Gautier 	}
13027839a050SYann Gautier }
13037839a050SYann Gautier 
13040d21680cSYann Gautier static void stm32mp1_csi_set(bool enable)
13057839a050SYann Gautier {
13060d21680cSYann Gautier 	stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION);
13070d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) {
13087839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
13097839a050SYann Gautier 	}
13107839a050SYann Gautier }
13117839a050SYann Gautier 
13120d21680cSYann Gautier static void stm32mp1_hsi_set(bool enable)
13137839a050SYann Gautier {
13140d21680cSYann Gautier 	stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION);
13150d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) {
13167839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
13177839a050SYann Gautier 	}
13187839a050SYann Gautier }
13197839a050SYann Gautier 
13200d21680cSYann Gautier static int stm32mp1_set_hsidiv(uint8_t hsidiv)
13217839a050SYann Gautier {
1322dfdb057aSYann Gautier 	uint64_t timeout;
13230d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13240d21680cSYann Gautier 	uintptr_t address = rcc_base + RCC_OCRDYR;
13257839a050SYann Gautier 
13260d21680cSYann Gautier 	mmio_clrsetbits_32(rcc_base + RCC_HSICFGR,
13277839a050SYann Gautier 			   RCC_HSICFGR_HSIDIV_MASK,
13287839a050SYann Gautier 			   RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv);
13297839a050SYann Gautier 
1330dfdb057aSYann Gautier 	timeout = timeout_init_us(HSIDIV_TIMEOUT);
13317839a050SYann Gautier 	while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) {
1332dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
13330d21680cSYann Gautier 			ERROR("HSIDIV failed @ 0x%lx: 0x%x\n",
13347839a050SYann Gautier 			      address, mmio_read_32(address));
13357839a050SYann Gautier 			return -ETIMEDOUT;
13367839a050SYann Gautier 		}
13377839a050SYann Gautier 	}
13387839a050SYann Gautier 
13397839a050SYann Gautier 	return 0;
13407839a050SYann Gautier }
13417839a050SYann Gautier 
13420d21680cSYann Gautier static int stm32mp1_hsidiv(unsigned long hsifreq)
13437839a050SYann Gautier {
13447839a050SYann Gautier 	uint8_t hsidiv;
13457839a050SYann Gautier 	uint32_t hsidivfreq = MAX_HSI_HZ;
13467839a050SYann Gautier 
13477839a050SYann Gautier 	for (hsidiv = 0; hsidiv < 4U; hsidiv++) {
13487839a050SYann Gautier 		if (hsidivfreq == hsifreq) {
13497839a050SYann Gautier 			break;
13507839a050SYann Gautier 		}
13517839a050SYann Gautier 
13527839a050SYann Gautier 		hsidivfreq /= 2U;
13537839a050SYann Gautier 	}
13547839a050SYann Gautier 
13557839a050SYann Gautier 	if (hsidiv == 4U) {
13567839a050SYann Gautier 		ERROR("Invalid clk-hsi frequency\n");
13577839a050SYann Gautier 		return -1;
13587839a050SYann Gautier 	}
13597839a050SYann Gautier 
13607839a050SYann Gautier 	if (hsidiv != 0U) {
13610d21680cSYann Gautier 		return stm32mp1_set_hsidiv(hsidiv);
13627839a050SYann Gautier 	}
13637839a050SYann Gautier 
13647839a050SYann Gautier 	return 0;
13657839a050SYann Gautier }
13667839a050SYann Gautier 
13670d21680cSYann Gautier static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id,
13680d21680cSYann Gautier 				    unsigned int clksrc,
13690d21680cSYann Gautier 				    uint32_t *pllcfg, int plloff)
13707839a050SYann Gautier {
13710d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
13720d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13730d21680cSYann Gautier 	uintptr_t pllxcr = rcc_base + pll->pllxcr;
13740d21680cSYann Gautier 	enum stm32mp1_plltype type = pll->plltype;
13750d21680cSYann Gautier 	uintptr_t clksrc_address = rcc_base + (clksrc >> 4);
13760d21680cSYann Gautier 	unsigned long refclk;
13770d21680cSYann Gautier 	uint32_t ifrge = 0U;
1378be858cffSAndre Przywara 	uint32_t src, value, fracv = 0;
1379be858cffSAndre Przywara 	void *fdt;
13807839a050SYann Gautier 
13810d21680cSYann Gautier 	/* Check PLL output */
13820d21680cSYann Gautier 	if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) {
13830d21680cSYann Gautier 		return false;
13847839a050SYann Gautier 	}
13857839a050SYann Gautier 
13860d21680cSYann Gautier 	/* Check current clksrc */
13870d21680cSYann Gautier 	src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK;
13880d21680cSYann Gautier 	if (src != (clksrc & RCC_SELR_SRC_MASK)) {
13890d21680cSYann Gautier 		return false;
13900d21680cSYann Gautier 	}
13910d21680cSYann Gautier 
13920d21680cSYann Gautier 	/* Check Div */
13930d21680cSYann Gautier 	src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK;
13940d21680cSYann Gautier 
13950d21680cSYann Gautier 	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
13960d21680cSYann Gautier 		 (pllcfg[PLLCFG_M] + 1U);
13970d21680cSYann Gautier 
13980d21680cSYann Gautier 	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
13990d21680cSYann Gautier 	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
14000d21680cSYann Gautier 		return false;
14010d21680cSYann Gautier 	}
14020d21680cSYann Gautier 
14030d21680cSYann Gautier 	if ((type == PLL_800) && (refclk >= 8000000U)) {
14040d21680cSYann Gautier 		ifrge = 1U;
14050d21680cSYann Gautier 	}
14060d21680cSYann Gautier 
14070d21680cSYann Gautier 	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
14080d21680cSYann Gautier 		RCC_PLLNCFGR1_DIVN_MASK;
14090d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
14100d21680cSYann Gautier 		 RCC_PLLNCFGR1_DIVM_MASK;
14110d21680cSYann Gautier 	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
14120d21680cSYann Gautier 		 RCC_PLLNCFGR1_IFRGE_MASK;
14130d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) {
14140d21680cSYann Gautier 		return false;
14150d21680cSYann Gautier 	}
14160d21680cSYann Gautier 
14170d21680cSYann Gautier 	/* Fractional configuration */
1418be858cffSAndre Przywara 	if (fdt_get_address(&fdt) == 1) {
1419be858cffSAndre Przywara 		fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0);
1420be858cffSAndre Przywara 	}
14210d21680cSYann Gautier 
14220d21680cSYann Gautier 	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
14230d21680cSYann Gautier 	value |= RCC_PLLNFRACR_FRACLE;
14240d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxfracr) != value) {
14250d21680cSYann Gautier 		return false;
14260d21680cSYann Gautier 	}
14270d21680cSYann Gautier 
14280d21680cSYann Gautier 	/* Output config */
14290d21680cSYann Gautier 	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
14300d21680cSYann Gautier 		RCC_PLLNCFGR2_DIVP_MASK;
14310d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
14320d21680cSYann Gautier 		 RCC_PLLNCFGR2_DIVQ_MASK;
14330d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
14340d21680cSYann Gautier 		 RCC_PLLNCFGR2_DIVR_MASK;
14350d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) {
14360d21680cSYann Gautier 		return false;
14370d21680cSYann Gautier 	}
14380d21680cSYann Gautier 
14390d21680cSYann Gautier 	return true;
14400d21680cSYann Gautier }
14410d21680cSYann Gautier 
14420d21680cSYann Gautier static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id)
14437839a050SYann Gautier {
14440d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
14450d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
14460d21680cSYann Gautier 
1447dd98aec8SYann Gautier 	/* Preserve RCC_PLLNCR_SSCG_CTRL value */
1448dd98aec8SYann Gautier 	mmio_clrsetbits_32(pllxcr,
1449dd98aec8SYann Gautier 			   RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
1450dd98aec8SYann Gautier 			   RCC_PLLNCR_DIVREN,
1451dd98aec8SYann Gautier 			   RCC_PLLNCR_PLLON);
14520d21680cSYann Gautier }
14530d21680cSYann Gautier 
14540d21680cSYann Gautier static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output)
14550d21680cSYann Gautier {
14560d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
14570d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
1458dfdb057aSYann Gautier 	uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT);
14597839a050SYann Gautier 
14607839a050SYann Gautier 	/* Wait PLL lock */
14617839a050SYann Gautier 	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) {
1462dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
14630d21680cSYann Gautier 			ERROR("PLL%d start failed @ 0x%lx: 0x%x\n",
14647839a050SYann Gautier 			      pll_id, pllxcr, mmio_read_32(pllxcr));
14657839a050SYann Gautier 			return -ETIMEDOUT;
14667839a050SYann Gautier 		}
14677839a050SYann Gautier 	}
14687839a050SYann Gautier 
14697839a050SYann Gautier 	/* Start the requested output */
14707839a050SYann Gautier 	mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT);
14717839a050SYann Gautier 
14727839a050SYann Gautier 	return 0;
14737839a050SYann Gautier }
14747839a050SYann Gautier 
14750d21680cSYann Gautier static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id)
14767839a050SYann Gautier {
14770d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
14780d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
1479dfdb057aSYann Gautier 	uint64_t timeout;
14807839a050SYann Gautier 
14817839a050SYann Gautier 	/* Stop all output */
14827839a050SYann Gautier 	mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
14837839a050SYann Gautier 			RCC_PLLNCR_DIVREN);
14847839a050SYann Gautier 
14857839a050SYann Gautier 	/* Stop PLL */
14867839a050SYann Gautier 	mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON);
14877839a050SYann Gautier 
1488dfdb057aSYann Gautier 	timeout = timeout_init_us(PLLRDY_TIMEOUT);
14897839a050SYann Gautier 	/* Wait PLL stopped */
14907839a050SYann Gautier 	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) {
1491dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
14920d21680cSYann Gautier 			ERROR("PLL%d stop failed @ 0x%lx: 0x%x\n",
14937839a050SYann Gautier 			      pll_id, pllxcr, mmio_read_32(pllxcr));
14947839a050SYann Gautier 			return -ETIMEDOUT;
14957839a050SYann Gautier 		}
14967839a050SYann Gautier 	}
14977839a050SYann Gautier 
14987839a050SYann Gautier 	return 0;
14997839a050SYann Gautier }
15007839a050SYann Gautier 
15010d21680cSYann Gautier static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id,
15027839a050SYann Gautier 				       uint32_t *pllcfg)
15037839a050SYann Gautier {
15040d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
15050d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
15067839a050SYann Gautier 	uint32_t value;
15077839a050SYann Gautier 
15087839a050SYann Gautier 	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
15097839a050SYann Gautier 		RCC_PLLNCFGR2_DIVP_MASK;
15107839a050SYann Gautier 	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
15117839a050SYann Gautier 		 RCC_PLLNCFGR2_DIVQ_MASK;
15127839a050SYann Gautier 	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
15137839a050SYann Gautier 		 RCC_PLLNCFGR2_DIVR_MASK;
15140d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxcfgr2, value);
15157839a050SYann Gautier }
15167839a050SYann Gautier 
15170d21680cSYann Gautier static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id,
15187839a050SYann Gautier 			       uint32_t *pllcfg, uint32_t fracv)
15197839a050SYann Gautier {
15200d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
15210d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
15220d21680cSYann Gautier 	enum stm32mp1_plltype type = pll->plltype;
15237839a050SYann Gautier 	unsigned long refclk;
15247839a050SYann Gautier 	uint32_t ifrge = 0;
15257839a050SYann Gautier 	uint32_t src, value;
15267839a050SYann Gautier 
15270d21680cSYann Gautier 	src = mmio_read_32(rcc_base + pll->rckxselr) &
15287839a050SYann Gautier 		RCC_SELR_REFCLK_SRC_MASK;
15297839a050SYann Gautier 
15300d21680cSYann Gautier 	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
15317839a050SYann Gautier 		 (pllcfg[PLLCFG_M] + 1U);
15327839a050SYann Gautier 
15337839a050SYann Gautier 	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
15347839a050SYann Gautier 	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
15357839a050SYann Gautier 		return -EINVAL;
15367839a050SYann Gautier 	}
15377839a050SYann Gautier 
15387839a050SYann Gautier 	if ((type == PLL_800) && (refclk >= 8000000U)) {
15397839a050SYann Gautier 		ifrge = 1U;
15407839a050SYann Gautier 	}
15417839a050SYann Gautier 
15427839a050SYann Gautier 	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
15437839a050SYann Gautier 		RCC_PLLNCFGR1_DIVN_MASK;
15447839a050SYann Gautier 	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
15457839a050SYann Gautier 		 RCC_PLLNCFGR1_DIVM_MASK;
15467839a050SYann Gautier 	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
15477839a050SYann Gautier 		 RCC_PLLNCFGR1_IFRGE_MASK;
15480d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxcfgr1, value);
15497839a050SYann Gautier 
15507839a050SYann Gautier 	/* Fractional configuration */
15517839a050SYann Gautier 	value = 0;
15520d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
15537839a050SYann Gautier 
15547839a050SYann Gautier 	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
15550d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
15567839a050SYann Gautier 
15577839a050SYann Gautier 	value |= RCC_PLLNFRACR_FRACLE;
15580d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
15597839a050SYann Gautier 
15600d21680cSYann Gautier 	stm32mp1_pll_config_output(pll_id, pllcfg);
15617839a050SYann Gautier 
15627839a050SYann Gautier 	return 0;
15637839a050SYann Gautier }
15647839a050SYann Gautier 
15650d21680cSYann Gautier static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg)
15667839a050SYann Gautier {
15670d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
15687839a050SYann Gautier 	uint32_t pllxcsg = 0;
15697839a050SYann Gautier 
15707839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) &
15717839a050SYann Gautier 		    RCC_PLLNCSGR_MOD_PER_MASK;
15727839a050SYann Gautier 
15737839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) &
15747839a050SYann Gautier 		    RCC_PLLNCSGR_INC_STEP_MASK;
15757839a050SYann Gautier 
15767839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) &
15777839a050SYann Gautier 		    RCC_PLLNCSGR_SSCG_MODE_MASK;
15787839a050SYann Gautier 
15790d21680cSYann Gautier 	mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg);
1580dd98aec8SYann Gautier 
1581dd98aec8SYann Gautier 	mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr,
1582dd98aec8SYann Gautier 			RCC_PLLNCR_SSCG_CTRL);
15837839a050SYann Gautier }
15847839a050SYann Gautier 
15850d21680cSYann Gautier static int stm32mp1_set_clksrc(unsigned int clksrc)
15867839a050SYann Gautier {
15870d21680cSYann Gautier 	uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4);
1588dfdb057aSYann Gautier 	uint64_t timeout;
15897839a050SYann Gautier 
15900d21680cSYann Gautier 	mmio_clrsetbits_32(clksrc_address, RCC_SELR_SRC_MASK,
15917839a050SYann Gautier 			   clksrc & RCC_SELR_SRC_MASK);
15927839a050SYann Gautier 
1593dfdb057aSYann Gautier 	timeout = timeout_init_us(CLKSRC_TIMEOUT);
15940d21680cSYann Gautier 	while ((mmio_read_32(clksrc_address) & RCC_SELR_SRCRDY) == 0U) {
1595dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
15960d21680cSYann Gautier 			ERROR("CLKSRC %x start failed @ 0x%lx: 0x%x\n", clksrc,
15970d21680cSYann Gautier 			      clksrc_address, mmio_read_32(clksrc_address));
15987839a050SYann Gautier 			return -ETIMEDOUT;
15997839a050SYann Gautier 		}
16007839a050SYann Gautier 	}
16017839a050SYann Gautier 
16027839a050SYann Gautier 	return 0;
16037839a050SYann Gautier }
16047839a050SYann Gautier 
16050d21680cSYann Gautier static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address)
16067839a050SYann Gautier {
1607dfdb057aSYann Gautier 	uint64_t timeout;
16087839a050SYann Gautier 
16097839a050SYann Gautier 	mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK,
16107839a050SYann Gautier 			   clkdiv & RCC_DIVR_DIV_MASK);
16117839a050SYann Gautier 
1612dfdb057aSYann Gautier 	timeout = timeout_init_us(CLKDIV_TIMEOUT);
16137839a050SYann Gautier 	while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) {
1614dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
16150d21680cSYann Gautier 			ERROR("CLKDIV %x start failed @ 0x%lx: 0x%x\n",
16167839a050SYann Gautier 			      clkdiv, address, mmio_read_32(address));
16177839a050SYann Gautier 			return -ETIMEDOUT;
16187839a050SYann Gautier 		}
16197839a050SYann Gautier 	}
16207839a050SYann Gautier 
16217839a050SYann Gautier 	return 0;
16227839a050SYann Gautier }
16237839a050SYann Gautier 
16240d21680cSYann Gautier static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv)
16257839a050SYann Gautier {
16260d21680cSYann Gautier 	uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4);
16277839a050SYann Gautier 
16287839a050SYann Gautier 	/*
16297839a050SYann Gautier 	 * Binding clksrc :
16307839a050SYann Gautier 	 *      bit15-4 offset
16317839a050SYann Gautier 	 *      bit3:   disable
16327839a050SYann Gautier 	 *      bit2-0: MCOSEL[2:0]
16337839a050SYann Gautier 	 */
16347839a050SYann Gautier 	if ((clksrc & 0x8U) != 0U) {
16350d21680cSYann Gautier 		mmio_clrbits_32(clksrc_address, RCC_MCOCFG_MCOON);
16367839a050SYann Gautier 	} else {
16370d21680cSYann Gautier 		mmio_clrsetbits_32(clksrc_address,
16387839a050SYann Gautier 				   RCC_MCOCFG_MCOSRC_MASK,
16397839a050SYann Gautier 				   clksrc & RCC_MCOCFG_MCOSRC_MASK);
16400d21680cSYann Gautier 		mmio_clrsetbits_32(clksrc_address,
16417839a050SYann Gautier 				   RCC_MCOCFG_MCODIV_MASK,
16427839a050SYann Gautier 				   clkdiv << RCC_MCOCFG_MCODIV_SHIFT);
16430d21680cSYann Gautier 		mmio_setbits_32(clksrc_address, RCC_MCOCFG_MCOON);
16447839a050SYann Gautier 	}
16457839a050SYann Gautier }
16467839a050SYann Gautier 
16470d21680cSYann Gautier static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css)
16487839a050SYann Gautier {
16490d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + RCC_BDCR;
16507839a050SYann Gautier 
16517839a050SYann Gautier 	if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) ||
16527839a050SYann Gautier 	    (clksrc != (uint32_t)CLK_RTC_DISABLED)) {
16537839a050SYann Gautier 		mmio_clrsetbits_32(address,
16547839a050SYann Gautier 				   RCC_BDCR_RTCSRC_MASK,
1655*15509093SYann Gautier 				   (clksrc & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT);
16567839a050SYann Gautier 
16577839a050SYann Gautier 		mmio_setbits_32(address, RCC_BDCR_RTCCKEN);
16587839a050SYann Gautier 	}
16597839a050SYann Gautier 
16607839a050SYann Gautier 	if (lse_css) {
16617839a050SYann Gautier 		mmio_setbits_32(address, RCC_BDCR_LSECSSON);
16627839a050SYann Gautier 	}
16637839a050SYann Gautier }
16647839a050SYann Gautier 
16650d21680cSYann Gautier static void stm32mp1_stgen_config(void)
16667839a050SYann Gautier {
16677839a050SYann Gautier 	uint32_t cntfid0;
16687839a050SYann Gautier 	unsigned long rate;
16697839a050SYann Gautier 	unsigned long long counter;
16707839a050SYann Gautier 
1671ade9ce03SYann Gautier 	cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF);
16720d21680cSYann Gautier 	rate = get_clock_rate(stm32mp1_clk_get_parent(STGEN_K));
16730d21680cSYann Gautier 
16740d21680cSYann Gautier 	if (cntfid0 == rate) {
16750d21680cSYann Gautier 		return;
16760d21680cSYann Gautier 	}
16770d21680cSYann Gautier 
1678ade9ce03SYann Gautier 	mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
1679ade9ce03SYann Gautier 	counter = (unsigned long long)mmio_read_32(STGEN_BASE + CNTCVL_OFF);
1680ade9ce03SYann Gautier 	counter |= ((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF)) << 32;
16817839a050SYann Gautier 	counter = (counter * rate / cntfid0);
16820d21680cSYann Gautier 
1683ade9ce03SYann Gautier 	mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter);
1684ade9ce03SYann Gautier 	mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32));
1685ade9ce03SYann Gautier 	mmio_write_32(STGEN_BASE + CNTFID_OFF, rate);
1686ade9ce03SYann Gautier 	mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
16877839a050SYann Gautier 
16887839a050SYann Gautier 	write_cntfrq((u_register_t)rate);
16897839a050SYann Gautier 
16907839a050SYann Gautier 	/* Need to update timer with new frequency */
16917839a050SYann Gautier 	generic_delay_timer_init();
16927839a050SYann Gautier }
16937839a050SYann Gautier 
16947839a050SYann Gautier void stm32mp1_stgen_increment(unsigned long long offset_in_ms)
16957839a050SYann Gautier {
16967839a050SYann Gautier 	unsigned long long cnt;
16977839a050SYann Gautier 
1698ade9ce03SYann Gautier 	cnt = ((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) |
1699ade9ce03SYann Gautier 		mmio_read_32(STGEN_BASE + CNTCVL_OFF);
17007839a050SYann Gautier 
1701ade9ce03SYann Gautier 	cnt += (offset_in_ms * mmio_read_32(STGEN_BASE + CNTFID_OFF)) / 1000U;
17027839a050SYann Gautier 
1703ade9ce03SYann Gautier 	mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
1704ade9ce03SYann Gautier 	mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)cnt);
1705ade9ce03SYann Gautier 	mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(cnt >> 32));
1706ade9ce03SYann Gautier 	mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
17077839a050SYann Gautier }
17087839a050SYann Gautier 
17090d21680cSYann Gautier static void stm32mp1_pkcs_config(uint32_t pkcs)
17107839a050SYann Gautier {
17110d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU);
17127839a050SYann Gautier 	uint32_t value = pkcs & 0xFU;
17137839a050SYann Gautier 	uint32_t mask = 0xFU;
17147839a050SYann Gautier 
17157839a050SYann Gautier 	if ((pkcs & BIT(31)) != 0U) {
17167839a050SYann Gautier 		mask <<= 4;
17177839a050SYann Gautier 		value <<= 4;
17187839a050SYann Gautier 	}
17197839a050SYann Gautier 
17207839a050SYann Gautier 	mmio_clrsetbits_32(address, mask, value);
17217839a050SYann Gautier }
17227839a050SYann Gautier 
17237839a050SYann Gautier int stm32mp1_clk_init(void)
17247839a050SYann Gautier {
17250d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
17267839a050SYann Gautier 	unsigned int clksrc[CLKSRC_NB];
17277839a050SYann Gautier 	unsigned int clkdiv[CLKDIV_NB];
17287839a050SYann Gautier 	unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
17297839a050SYann Gautier 	int plloff[_PLL_NB];
17307839a050SYann Gautier 	int ret, len;
17317839a050SYann Gautier 	enum stm32mp1_pll_id i;
17327839a050SYann Gautier 	bool lse_css = false;
17330d21680cSYann Gautier 	bool pll3_preserve = false;
17340d21680cSYann Gautier 	bool pll4_preserve = false;
17350d21680cSYann Gautier 	bool pll4_bootrom = false;
17363e6fab43SYann Gautier 	const fdt32_t *pkcs_cell;
173752a616b4SAndre Przywara 	void *fdt;
173852a616b4SAndre Przywara 
173952a616b4SAndre Przywara 	if (fdt_get_address(&fdt) == 0) {
17408f97c4faSYann Gautier 		return -FDT_ERR_NOTFOUND;
174152a616b4SAndre Przywara 	}
17427839a050SYann Gautier 
17437839a050SYann Gautier 	/* Check status field to disable security */
17447839a050SYann Gautier 	if (!fdt_get_rcc_secure_status()) {
17450d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_TZCR, 0);
17467839a050SYann Gautier 	}
17477839a050SYann Gautier 
174852a616b4SAndre Przywara 	ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB,
174952a616b4SAndre Przywara 					clksrc);
17507839a050SYann Gautier 	if (ret < 0) {
17517839a050SYann Gautier 		return -FDT_ERR_NOTFOUND;
17527839a050SYann Gautier 	}
17537839a050SYann Gautier 
175452a616b4SAndre Przywara 	ret = fdt_rcc_read_uint32_array("st,clkdiv", (uint32_t)CLKDIV_NB,
175552a616b4SAndre Przywara 					clkdiv);
17567839a050SYann Gautier 	if (ret < 0) {
17577839a050SYann Gautier 		return -FDT_ERR_NOTFOUND;
17587839a050SYann Gautier 	}
17597839a050SYann Gautier 
17607839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
17617839a050SYann Gautier 		char name[12];
17627839a050SYann Gautier 
176339b6cc66SAntonio Nino Diaz 		snprintf(name, sizeof(name), "st,pll@%d", i);
17647839a050SYann Gautier 		plloff[i] = fdt_rcc_subnode_offset(name);
17657839a050SYann Gautier 
17667839a050SYann Gautier 		if (!fdt_check_node(plloff[i])) {
17677839a050SYann Gautier 			continue;
17687839a050SYann Gautier 		}
17697839a050SYann Gautier 
177052a616b4SAndre Przywara 		ret = fdt_read_uint32_array(fdt, plloff[i], "cfg",
177152a616b4SAndre Przywara 					    (int)PLLCFG_NB, pllcfg[i]);
17727839a050SYann Gautier 		if (ret < 0) {
17737839a050SYann Gautier 			return -FDT_ERR_NOTFOUND;
17747839a050SYann Gautier 		}
17757839a050SYann Gautier 	}
17767839a050SYann Gautier 
17770d21680cSYann Gautier 	stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]);
17780d21680cSYann Gautier 	stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]);
17797839a050SYann Gautier 
17807839a050SYann Gautier 	/*
17817839a050SYann Gautier 	 * Switch ON oscillator found in device-tree.
17827839a050SYann Gautier 	 * Note: HSI already ON after BootROM stage.
17837839a050SYann Gautier 	 */
17840d21680cSYann Gautier 	if (stm32mp1_osc[_LSI] != 0U) {
17850d21680cSYann Gautier 		stm32mp1_lsi_set(true);
17867839a050SYann Gautier 	}
17870d21680cSYann Gautier 	if (stm32mp1_osc[_LSE] != 0U) {
17880d21680cSYann Gautier 		bool bypass, digbyp;
17897839a050SYann Gautier 		uint32_t lsedrv;
17907839a050SYann Gautier 
17917839a050SYann Gautier 		bypass = fdt_osc_read_bool(_LSE, "st,bypass");
17920d21680cSYann Gautier 		digbyp = fdt_osc_read_bool(_LSE, "st,digbypass");
17937839a050SYann Gautier 		lse_css = fdt_osc_read_bool(_LSE, "st,css");
17947839a050SYann Gautier 		lsedrv = fdt_osc_read_uint32_default(_LSE, "st,drive",
17957839a050SYann Gautier 						     LSEDRV_MEDIUM_HIGH);
17960d21680cSYann Gautier 		stm32mp1_lse_enable(bypass, digbyp, lsedrv);
17977839a050SYann Gautier 	}
17980d21680cSYann Gautier 	if (stm32mp1_osc[_HSE] != 0U) {
17990d21680cSYann Gautier 		bool bypass, digbyp, css;
18007839a050SYann Gautier 
18010d21680cSYann Gautier 		bypass = fdt_osc_read_bool(_HSE, "st,bypass");
18020d21680cSYann Gautier 		digbyp = fdt_osc_read_bool(_HSE, "st,digbypass");
18030d21680cSYann Gautier 		css = fdt_osc_read_bool(_HSE, "st,css");
18040d21680cSYann Gautier 		stm32mp1_hse_enable(bypass, digbyp, css);
18057839a050SYann Gautier 	}
18067839a050SYann Gautier 	/*
18077839a050SYann Gautier 	 * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR)
18087839a050SYann Gautier 	 * => switch on CSI even if node is not present in device tree
18097839a050SYann Gautier 	 */
18100d21680cSYann Gautier 	stm32mp1_csi_set(true);
18117839a050SYann Gautier 
18127839a050SYann Gautier 	/* Come back to HSI */
18130d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(CLK_MPU_HSI);
18147839a050SYann Gautier 	if (ret != 0) {
18157839a050SYann Gautier 		return ret;
18167839a050SYann Gautier 	}
18170d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(CLK_AXI_HSI);
18187839a050SYann Gautier 	if (ret != 0) {
18197839a050SYann Gautier 		return ret;
18207839a050SYann Gautier 	}
1821b053a22eSYann Gautier 	ret = stm32mp1_set_clksrc(CLK_MCU_HSI);
1822b053a22eSYann Gautier 	if (ret != 0) {
1823b053a22eSYann Gautier 		return ret;
1824b053a22eSYann Gautier 	}
18257839a050SYann Gautier 
18260d21680cSYann Gautier 	if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) &
18270d21680cSYann Gautier 	     RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) {
18280d21680cSYann Gautier 		pll3_preserve = stm32mp1_check_pll_conf(_PLL3,
18290d21680cSYann Gautier 							clksrc[CLKSRC_PLL3],
18300d21680cSYann Gautier 							pllcfg[_PLL3],
18310d21680cSYann Gautier 							plloff[_PLL3]);
18320d21680cSYann Gautier 		pll4_preserve = stm32mp1_check_pll_conf(_PLL4,
18330d21680cSYann Gautier 							clksrc[CLKSRC_PLL4],
18340d21680cSYann Gautier 							pllcfg[_PLL4],
18350d21680cSYann Gautier 							plloff[_PLL4]);
18360d21680cSYann Gautier 	}
18370d21680cSYann Gautier 
18387839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
18390d21680cSYann Gautier 		if (((i == _PLL3) && pll3_preserve) ||
18400d21680cSYann Gautier 		    ((i == _PLL4) && pll4_preserve)) {
18417839a050SYann Gautier 			continue;
18420d21680cSYann Gautier 		}
18430d21680cSYann Gautier 
18440d21680cSYann Gautier 		ret = stm32mp1_pll_stop(i);
18457839a050SYann Gautier 		if (ret != 0) {
18467839a050SYann Gautier 			return ret;
18477839a050SYann Gautier 		}
18487839a050SYann Gautier 	}
18497839a050SYann Gautier 
18507839a050SYann Gautier 	/* Configure HSIDIV */
18510d21680cSYann Gautier 	if (stm32mp1_osc[_HSI] != 0U) {
18520d21680cSYann Gautier 		ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]);
18537839a050SYann Gautier 		if (ret != 0) {
18547839a050SYann Gautier 			return ret;
18557839a050SYann Gautier 		}
18560d21680cSYann Gautier 		stm32mp1_stgen_config();
18577839a050SYann Gautier 	}
18587839a050SYann Gautier 
18597839a050SYann Gautier 	/* Select DIV */
18607839a050SYann Gautier 	/* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */
18610d21680cSYann Gautier 	mmio_write_32(rcc_base + RCC_MPCKDIVR,
18627839a050SYann Gautier 		      clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK);
18630d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR);
18647839a050SYann Gautier 	if (ret != 0) {
18657839a050SYann Gautier 		return ret;
18667839a050SYann Gautier 	}
18670d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR);
18687839a050SYann Gautier 	if (ret != 0) {
18697839a050SYann Gautier 		return ret;
18707839a050SYann Gautier 	}
18710d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR);
18727839a050SYann Gautier 	if (ret != 0) {
18737839a050SYann Gautier 		return ret;
18747839a050SYann Gautier 	}
1875b053a22eSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR);
1876b053a22eSYann Gautier 	if (ret != 0) {
1877b053a22eSYann Gautier 		return ret;
1878b053a22eSYann Gautier 	}
18790d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR);
18807839a050SYann Gautier 	if (ret != 0) {
18817839a050SYann Gautier 		return ret;
18827839a050SYann Gautier 	}
18830d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR);
18847839a050SYann Gautier 	if (ret != 0) {
18857839a050SYann Gautier 		return ret;
18867839a050SYann Gautier 	}
18870d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR);
18887839a050SYann Gautier 	if (ret != 0) {
18897839a050SYann Gautier 		return ret;
18907839a050SYann Gautier 	}
18917839a050SYann Gautier 
18927839a050SYann Gautier 	/* No ready bit for RTC */
18930d21680cSYann Gautier 	mmio_write_32(rcc_base + RCC_RTCDIVR,
18947839a050SYann Gautier 		      clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK);
18957839a050SYann Gautier 
18967839a050SYann Gautier 	/* Configure PLLs source */
18970d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]);
18987839a050SYann Gautier 	if (ret != 0) {
18997839a050SYann Gautier 		return ret;
19007839a050SYann Gautier 	}
19017839a050SYann Gautier 
19020d21680cSYann Gautier 	if (!pll3_preserve) {
19030d21680cSYann Gautier 		ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]);
19047839a050SYann Gautier 		if (ret != 0) {
19057839a050SYann Gautier 			return ret;
19067839a050SYann Gautier 		}
19070d21680cSYann Gautier 	}
19080d21680cSYann Gautier 
19090d21680cSYann Gautier 	if (!pll4_preserve) {
19100d21680cSYann Gautier 		ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]);
19110d21680cSYann Gautier 		if (ret != 0) {
19120d21680cSYann Gautier 			return ret;
19130d21680cSYann Gautier 		}
19140d21680cSYann Gautier 	}
19157839a050SYann Gautier 
19167839a050SYann Gautier 	/* Configure and start PLLs */
19177839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
19187839a050SYann Gautier 		uint32_t fracv;
19197839a050SYann Gautier 		uint32_t csg[PLLCSG_NB];
19207839a050SYann Gautier 
19210d21680cSYann Gautier 		if (((i == _PLL3) && pll3_preserve) ||
19220d21680cSYann Gautier 		    ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) {
19230d21680cSYann Gautier 			continue;
19240d21680cSYann Gautier 		}
19250d21680cSYann Gautier 
19267839a050SYann Gautier 		if (!fdt_check_node(plloff[i])) {
19277839a050SYann Gautier 			continue;
19287839a050SYann Gautier 		}
19297839a050SYann Gautier 
19300d21680cSYann Gautier 		if ((i == _PLL4) && pll4_bootrom) {
19310d21680cSYann Gautier 			/* Set output divider if not done by the Bootrom */
19320d21680cSYann Gautier 			stm32mp1_pll_config_output(i, pllcfg[i]);
19330d21680cSYann Gautier 			continue;
19340d21680cSYann Gautier 		}
19350d21680cSYann Gautier 
1936be858cffSAndre Przywara 		fracv = fdt_read_uint32_default(fdt, plloff[i], "frac", 0);
19377839a050SYann Gautier 
19380d21680cSYann Gautier 		ret = stm32mp1_pll_config(i, pllcfg[i], fracv);
19397839a050SYann Gautier 		if (ret != 0) {
19407839a050SYann Gautier 			return ret;
19417839a050SYann Gautier 		}
194252a616b4SAndre Przywara 		ret = fdt_read_uint32_array(fdt, plloff[i], "csg",
194352a616b4SAndre Przywara 					    (uint32_t)PLLCSG_NB, csg);
19447839a050SYann Gautier 		if (ret == 0) {
19450d21680cSYann Gautier 			stm32mp1_pll_csg(i, csg);
19467839a050SYann Gautier 		} else if (ret != -FDT_ERR_NOTFOUND) {
19477839a050SYann Gautier 			return ret;
19487839a050SYann Gautier 		}
19497839a050SYann Gautier 
19500d21680cSYann Gautier 		stm32mp1_pll_start(i);
19517839a050SYann Gautier 	}
19527839a050SYann Gautier 	/* Wait and start PLLs ouptut when ready */
19537839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
19547839a050SYann Gautier 		if (!fdt_check_node(plloff[i])) {
19557839a050SYann Gautier 			continue;
19567839a050SYann Gautier 		}
19577839a050SYann Gautier 
19580d21680cSYann Gautier 		ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]);
19597839a050SYann Gautier 		if (ret != 0) {
19607839a050SYann Gautier 			return ret;
19617839a050SYann Gautier 		}
19627839a050SYann Gautier 	}
19637839a050SYann Gautier 	/* Wait LSE ready before to use it */
19640d21680cSYann Gautier 	if (stm32mp1_osc[_LSE] != 0U) {
19650d21680cSYann Gautier 		stm32mp1_lse_wait();
19667839a050SYann Gautier 	}
19677839a050SYann Gautier 
19687839a050SYann Gautier 	/* Configure with expected clock source */
19690d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]);
19707839a050SYann Gautier 	if (ret != 0) {
19717839a050SYann Gautier 		return ret;
19727839a050SYann Gautier 	}
19730d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]);
19747839a050SYann Gautier 	if (ret != 0) {
19757839a050SYann Gautier 		return ret;
19767839a050SYann Gautier 	}
1977b053a22eSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]);
1978b053a22eSYann Gautier 	if (ret != 0) {
1979b053a22eSYann Gautier 		return ret;
1980b053a22eSYann Gautier 	}
19810d21680cSYann Gautier 	stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css);
19827839a050SYann Gautier 
19837839a050SYann Gautier 	/* Configure PKCK */
19847839a050SYann Gautier 	pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len);
19857839a050SYann Gautier 	if (pkcs_cell != NULL) {
19867839a050SYann Gautier 		bool ckper_disabled = false;
19877839a050SYann Gautier 		uint32_t j;
19887839a050SYann Gautier 
19897839a050SYann Gautier 		for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) {
19903e6fab43SYann Gautier 			uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]);
19917839a050SYann Gautier 
19927839a050SYann Gautier 			if (pkcs == (uint32_t)CLK_CKPER_DISABLED) {
19937839a050SYann Gautier 				ckper_disabled = true;
19947839a050SYann Gautier 				continue;
19957839a050SYann Gautier 			}
19960d21680cSYann Gautier 			stm32mp1_pkcs_config(pkcs);
19977839a050SYann Gautier 		}
19987839a050SYann Gautier 
19997839a050SYann Gautier 		/*
20007839a050SYann Gautier 		 * CKPER is source for some peripheral clocks
20017839a050SYann Gautier 		 * (FMC-NAND / QPSI-NOR) and switching source is allowed
20027839a050SYann Gautier 		 * only if previous clock is still ON
20037839a050SYann Gautier 		 * => deactivated CKPER only after switching clock
20047839a050SYann Gautier 		 */
20057839a050SYann Gautier 		if (ckper_disabled) {
20060d21680cSYann Gautier 			stm32mp1_pkcs_config(CLK_CKPER_DISABLED);
20077839a050SYann Gautier 		}
20087839a050SYann Gautier 	}
20097839a050SYann Gautier 
20107839a050SYann Gautier 	/* Switch OFF HSI if not found in device-tree */
20110d21680cSYann Gautier 	if (stm32mp1_osc[_HSI] == 0U) {
20120d21680cSYann Gautier 		stm32mp1_hsi_set(false);
20137839a050SYann Gautier 	}
20140d21680cSYann Gautier 	stm32mp1_stgen_config();
20157839a050SYann Gautier 
20167839a050SYann Gautier 	/* Software Self-Refresh mode (SSR) during DDR initilialization */
20170d21680cSYann Gautier 	mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR,
20187839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_MASK,
20197839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_SSR <<
20207839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_SHIFT);
20217839a050SYann Gautier 
20227839a050SYann Gautier 	return 0;
20237839a050SYann Gautier }
20247839a050SYann Gautier 
20257839a050SYann Gautier static void stm32mp1_osc_clk_init(const char *name,
20267839a050SYann Gautier 				  enum stm32mp_osc_id index)
20277839a050SYann Gautier {
20287839a050SYann Gautier 	uint32_t frequency;
20297839a050SYann Gautier 
20300d21680cSYann Gautier 	if (fdt_osc_read_freq(name, &frequency) == 0) {
20310d21680cSYann Gautier 		stm32mp1_osc[index] = frequency;
20327839a050SYann Gautier 	}
20337839a050SYann Gautier }
20347839a050SYann Gautier 
20357839a050SYann Gautier static void stm32mp1_osc_init(void)
20367839a050SYann Gautier {
20377839a050SYann Gautier 	enum stm32mp_osc_id i;
20387839a050SYann Gautier 
20397839a050SYann Gautier 	for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) {
20400d21680cSYann Gautier 		stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i);
20417839a050SYann Gautier 	}
20427839a050SYann Gautier }
20437839a050SYann Gautier 
204437e8295aSEtienne Carriere #ifdef STM32MP_SHARED_RESOURCES
204537e8295aSEtienne Carriere /*
204637e8295aSEtienne Carriere  * Get the parent ID of the target parent clock, for tagging as secure
204737e8295aSEtienne Carriere  * shared clock dependencies.
204837e8295aSEtienne Carriere  */
204937e8295aSEtienne Carriere static int get_parent_id_parent(unsigned int parent_id)
205037e8295aSEtienne Carriere {
205137e8295aSEtienne Carriere 	enum stm32mp1_parent_sel s = _UNKNOWN_SEL;
205237e8295aSEtienne Carriere 	enum stm32mp1_pll_id pll_id;
205337e8295aSEtienne Carriere 	uint32_t p_sel;
205437e8295aSEtienne Carriere 	uintptr_t rcc_base = stm32mp_rcc_base();
205537e8295aSEtienne Carriere 
205637e8295aSEtienne Carriere 	switch (parent_id) {
205737e8295aSEtienne Carriere 	case _ACLK:
205837e8295aSEtienne Carriere 	case _PCLK4:
205937e8295aSEtienne Carriere 	case _PCLK5:
206037e8295aSEtienne Carriere 		s = _AXIS_SEL;
206137e8295aSEtienne Carriere 		break;
206237e8295aSEtienne Carriere 	case _PLL1_P:
206337e8295aSEtienne Carriere 	case _PLL1_Q:
206437e8295aSEtienne Carriere 	case _PLL1_R:
206537e8295aSEtienne Carriere 		pll_id = _PLL1;
206637e8295aSEtienne Carriere 		break;
206737e8295aSEtienne Carriere 	case _PLL2_P:
206837e8295aSEtienne Carriere 	case _PLL2_Q:
206937e8295aSEtienne Carriere 	case _PLL2_R:
207037e8295aSEtienne Carriere 		pll_id = _PLL2;
207137e8295aSEtienne Carriere 		break;
207237e8295aSEtienne Carriere 	case _PLL3_P:
207337e8295aSEtienne Carriere 	case _PLL3_Q:
207437e8295aSEtienne Carriere 	case _PLL3_R:
207537e8295aSEtienne Carriere 		pll_id = _PLL3;
207637e8295aSEtienne Carriere 		break;
207737e8295aSEtienne Carriere 	case _PLL4_P:
207837e8295aSEtienne Carriere 	case _PLL4_Q:
207937e8295aSEtienne Carriere 	case _PLL4_R:
208037e8295aSEtienne Carriere 		pll_id = _PLL4;
208137e8295aSEtienne Carriere 		break;
208237e8295aSEtienne Carriere 	case _PCLK1:
208337e8295aSEtienne Carriere 	case _PCLK2:
208437e8295aSEtienne Carriere 	case _HCLK2:
208537e8295aSEtienne Carriere 	case _HCLK6:
208637e8295aSEtienne Carriere 	case _CK_PER:
208737e8295aSEtienne Carriere 	case _CK_MPU:
208837e8295aSEtienne Carriere 	case _CK_MCU:
208937e8295aSEtienne Carriere 	case _USB_PHY_48:
209037e8295aSEtienne Carriere 		/* We do not expect to access these */
209137e8295aSEtienne Carriere 		panic();
209237e8295aSEtienne Carriere 		break;
209337e8295aSEtienne Carriere 	default:
209437e8295aSEtienne Carriere 		/* Other parents have no parent */
209537e8295aSEtienne Carriere 		return -1;
209637e8295aSEtienne Carriere 	}
209737e8295aSEtienne Carriere 
209837e8295aSEtienne Carriere 	if (s != _UNKNOWN_SEL) {
209937e8295aSEtienne Carriere 		const struct stm32mp1_clk_sel *sel = clk_sel_ref(s);
210037e8295aSEtienne Carriere 
210137e8295aSEtienne Carriere 		p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) &
210237e8295aSEtienne Carriere 			sel->msk;
210337e8295aSEtienne Carriere 
210437e8295aSEtienne Carriere 		if (p_sel < sel->nb_parent) {
210537e8295aSEtienne Carriere 			return (int)sel->parent[p_sel];
210637e8295aSEtienne Carriere 		}
210737e8295aSEtienne Carriere 	} else {
210837e8295aSEtienne Carriere 		const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
210937e8295aSEtienne Carriere 
211037e8295aSEtienne Carriere 		p_sel = mmio_read_32(rcc_base + pll->rckxselr) &
211137e8295aSEtienne Carriere 			RCC_SELR_REFCLK_SRC_MASK;
211237e8295aSEtienne Carriere 
211337e8295aSEtienne Carriere 		if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) {
211437e8295aSEtienne Carriere 			return (int)pll->refclk[p_sel];
211537e8295aSEtienne Carriere 		}
211637e8295aSEtienne Carriere 	}
211737e8295aSEtienne Carriere 
211837e8295aSEtienne Carriere 	VERBOSE("No parent selected for %s\n",
211937e8295aSEtienne Carriere 		stm32mp1_clk_parent_name[parent_id]);
212037e8295aSEtienne Carriere 
212137e8295aSEtienne Carriere 	return -1;
212237e8295aSEtienne Carriere }
212337e8295aSEtienne Carriere 
212437e8295aSEtienne Carriere static void secure_parent_clocks(unsigned long parent_id)
212537e8295aSEtienne Carriere {
212637e8295aSEtienne Carriere 	int grandparent_id;
212737e8295aSEtienne Carriere 
212837e8295aSEtienne Carriere 	switch (parent_id) {
212937e8295aSEtienne Carriere 	case _PLL3_P:
213037e8295aSEtienne Carriere 	case _PLL3_Q:
213137e8295aSEtienne Carriere 	case _PLL3_R:
213237e8295aSEtienne Carriere 		stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
213337e8295aSEtienne Carriere 		break;
213437e8295aSEtienne Carriere 
213537e8295aSEtienne Carriere 	/* These clocks are always secure when RCC is secure */
213637e8295aSEtienne Carriere 	case _ACLK:
213737e8295aSEtienne Carriere 	case _HCLK2:
213837e8295aSEtienne Carriere 	case _HCLK6:
213937e8295aSEtienne Carriere 	case _PCLK4:
214037e8295aSEtienne Carriere 	case _PCLK5:
214137e8295aSEtienne Carriere 	case _PLL1_P:
214237e8295aSEtienne Carriere 	case _PLL1_Q:
214337e8295aSEtienne Carriere 	case _PLL1_R:
214437e8295aSEtienne Carriere 	case _PLL2_P:
214537e8295aSEtienne Carriere 	case _PLL2_Q:
214637e8295aSEtienne Carriere 	case _PLL2_R:
214737e8295aSEtienne Carriere 	case _HSI:
214837e8295aSEtienne Carriere 	case _HSI_KER:
214937e8295aSEtienne Carriere 	case _LSI:
215037e8295aSEtienne Carriere 	case _CSI:
215137e8295aSEtienne Carriere 	case _CSI_KER:
215237e8295aSEtienne Carriere 	case _HSE:
215337e8295aSEtienne Carriere 	case _HSE_KER:
215437e8295aSEtienne Carriere 	case _HSE_KER_DIV2:
215537e8295aSEtienne Carriere 	case _LSE:
215637e8295aSEtienne Carriere 		break;
215737e8295aSEtienne Carriere 
215837e8295aSEtienne Carriere 	default:
215937e8295aSEtienne Carriere 		VERBOSE("Cannot secure parent clock %s\n",
216037e8295aSEtienne Carriere 			stm32mp1_clk_parent_name[parent_id]);
216137e8295aSEtienne Carriere 		panic();
216237e8295aSEtienne Carriere 	}
216337e8295aSEtienne Carriere 
216437e8295aSEtienne Carriere 	grandparent_id = get_parent_id_parent(parent_id);
216537e8295aSEtienne Carriere 	if (grandparent_id >= 0) {
216637e8295aSEtienne Carriere 		secure_parent_clocks(grandparent_id);
216737e8295aSEtienne Carriere 	}
216837e8295aSEtienne Carriere }
216937e8295aSEtienne Carriere 
217037e8295aSEtienne Carriere void stm32mp1_register_clock_parents_secure(unsigned long clock_id)
217137e8295aSEtienne Carriere {
217237e8295aSEtienne Carriere 	int parent_id;
217337e8295aSEtienne Carriere 
217437e8295aSEtienne Carriere 	if (!stm32mp1_rcc_is_secure()) {
217537e8295aSEtienne Carriere 		return;
217637e8295aSEtienne Carriere 	}
217737e8295aSEtienne Carriere 
217837e8295aSEtienne Carriere 	switch (clock_id) {
217937e8295aSEtienne Carriere 	case PLL1:
218037e8295aSEtienne Carriere 	case PLL2:
218137e8295aSEtienne Carriere 		/* PLL1/PLL2 are always secure: nothing to do */
218237e8295aSEtienne Carriere 		break;
218337e8295aSEtienne Carriere 	case PLL3:
218437e8295aSEtienne Carriere 		stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
218537e8295aSEtienne Carriere 		break;
218637e8295aSEtienne Carriere 	case PLL4:
218737e8295aSEtienne Carriere 		ERROR("PLL4 cannot be secured\n");
218837e8295aSEtienne Carriere 		panic();
218937e8295aSEtienne Carriere 		break;
219037e8295aSEtienne Carriere 	default:
219137e8295aSEtienne Carriere 		/* Others are expected gateable clock */
219237e8295aSEtienne Carriere 		parent_id = stm32mp1_clk_get_parent(clock_id);
219337e8295aSEtienne Carriere 		if (parent_id < 0) {
219437e8295aSEtienne Carriere 			INFO("No parent found for clock %lu\n", clock_id);
219537e8295aSEtienne Carriere 		} else {
219637e8295aSEtienne Carriere 			secure_parent_clocks(parent_id);
219737e8295aSEtienne Carriere 		}
219837e8295aSEtienne Carriere 		break;
219937e8295aSEtienne Carriere 	}
220037e8295aSEtienne Carriere }
220137e8295aSEtienne Carriere #endif /* STM32MP_SHARED_RESOURCES */
220237e8295aSEtienne Carriere 
22036cb45f89SYann Gautier static void sync_earlyboot_clocks_state(void)
22046cb45f89SYann Gautier {
2205033b6c3aSEtienne Carriere 	unsigned int idx;
2206033b6c3aSEtienne Carriere 	const unsigned long secure_enable[] = {
2207033b6c3aSEtienne Carriere 		AXIDCG,
2208033b6c3aSEtienne Carriere 		BSEC,
2209033b6c3aSEtienne Carriere 		DDRC1, DDRC1LP,
2210033b6c3aSEtienne Carriere 		DDRC2, DDRC2LP,
2211033b6c3aSEtienne Carriere 		DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP,
2212033b6c3aSEtienne Carriere 		DDRPHYC, DDRPHYCLP,
2213033b6c3aSEtienne Carriere 		TZC1, TZC2,
2214033b6c3aSEtienne Carriere 		TZPC,
2215033b6c3aSEtienne Carriere 		STGEN_K,
2216033b6c3aSEtienne Carriere 	};
2217033b6c3aSEtienne Carriere 
2218033b6c3aSEtienne Carriere 	for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) {
2219033b6c3aSEtienne Carriere 		stm32mp_clk_enable(secure_enable[idx]);
2220033b6c3aSEtienne Carriere 	}
2221033b6c3aSEtienne Carriere 
22226cb45f89SYann Gautier 	if (!stm32mp_is_single_core()) {
22236cb45f89SYann Gautier 		stm32mp1_clk_enable_secure(RTCAPB);
22246cb45f89SYann Gautier 	}
22256cb45f89SYann Gautier }
22266cb45f89SYann Gautier 
22277839a050SYann Gautier int stm32mp1_clk_probe(void)
22287839a050SYann Gautier {
22297839a050SYann Gautier 	stm32mp1_osc_init();
22307839a050SYann Gautier 
22316cb45f89SYann Gautier 	sync_earlyboot_clocks_state();
22326cb45f89SYann Gautier 
22337839a050SYann Gautier 	return 0;
22347839a050SYann Gautier }
2235