xref: /rk3399_ARM-atf/drivers/st/clk/stm32mp1_clk.c (revision f4a2bb986b43fcb1c0c8c45b5d9a93798f655453)
17839a050SYann Gautier /*
277b4ca0bSLionel Debieve  * Copyright (C) 2018-2024, STMicroelectronics - All Rights Reserved
37839a050SYann Gautier  *
47839a050SYann Gautier  * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
57839a050SYann Gautier  */
67839a050SYann Gautier 
77839a050SYann Gautier #include <assert.h>
87839a050SYann Gautier #include <errno.h>
97839a050SYann Gautier #include <stdint.h>
1039b6cc66SAntonio Nino Diaz #include <stdio.h>
1109d40e0eSAntonio Nino Diaz 
1209d40e0eSAntonio Nino Diaz #include <arch.h>
1309d40e0eSAntonio Nino Diaz #include <arch_helpers.h>
1409d40e0eSAntonio Nino Diaz #include <common/debug.h>
1552a616b4SAndre Przywara #include <common/fdt_wrappers.h>
1633667d29SYann Gautier #include <drivers/clk.h>
1709d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h>
18447b2b13SYann Gautier #include <drivers/st/stm32mp_clkfunc.h>
1909d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_clk.h>
2009d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_rcc.h>
2109d40e0eSAntonio Nino Diaz #include <dt-bindings/clock/stm32mp1-clksrc.h>
2209d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
230d21680cSYann Gautier #include <lib/spinlock.h>
2409d40e0eSAntonio Nino Diaz #include <lib/utils_def.h>
25964e5ff1SNicolas Le Bayon #include <libfdt.h>
2609d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
2709d40e0eSAntonio Nino Diaz 
28964e5ff1SNicolas Le Bayon #include <platform_def.h>
29964e5ff1SNicolas Le Bayon 
307839a050SYann Gautier #define MAX_HSI_HZ		64000000
310d21680cSYann Gautier #define USB_PHY_48_MHZ		48000000
327839a050SYann Gautier 
33dfdb057aSYann Gautier #define TIMEOUT_US_200MS	U(200000)
34dfdb057aSYann Gautier #define TIMEOUT_US_1S		U(1000000)
357839a050SYann Gautier 
36dfdb057aSYann Gautier #define PLLRDY_TIMEOUT		TIMEOUT_US_200MS
37dfdb057aSYann Gautier #define CLKSRC_TIMEOUT		TIMEOUT_US_200MS
38dfdb057aSYann Gautier #define CLKDIV_TIMEOUT		TIMEOUT_US_200MS
39dfdb057aSYann Gautier #define HSIDIV_TIMEOUT		TIMEOUT_US_200MS
40dfdb057aSYann Gautier #define OSCRDY_TIMEOUT		TIMEOUT_US_1S
417839a050SYann Gautier 
42f66358afSYann Gautier const char *stm32mp_osc_node_label[NB_OSC] = {
43f66358afSYann Gautier 	[_LSI] = "clk-lsi",
44f66358afSYann Gautier 	[_LSE] = "clk-lse",
45f66358afSYann Gautier 	[_HSI] = "clk-hsi",
46f66358afSYann Gautier 	[_HSE] = "clk-hse",
47f66358afSYann Gautier 	[_CSI] = "clk-csi",
48f66358afSYann Gautier 	[_I2S_CKIN] = "i2s_ckin",
49f66358afSYann Gautier };
50f66358afSYann Gautier 
517839a050SYann Gautier enum stm32mp1_parent_id {
527839a050SYann Gautier /* Oscillators are defined in enum stm32mp_osc_id */
537839a050SYann Gautier 
547839a050SYann Gautier /* Other parent source */
557839a050SYann Gautier 	_HSI_KER = NB_OSC,
567839a050SYann Gautier 	_HSE_KER,
577839a050SYann Gautier 	_HSE_KER_DIV2,
58cbd2e8a6SGabriel Fernandez 	_HSE_RTC,
597839a050SYann Gautier 	_CSI_KER,
607839a050SYann Gautier 	_PLL1_P,
617839a050SYann Gautier 	_PLL1_Q,
627839a050SYann Gautier 	_PLL1_R,
637839a050SYann Gautier 	_PLL2_P,
647839a050SYann Gautier 	_PLL2_Q,
657839a050SYann Gautier 	_PLL2_R,
667839a050SYann Gautier 	_PLL3_P,
677839a050SYann Gautier 	_PLL3_Q,
687839a050SYann Gautier 	_PLL3_R,
697839a050SYann Gautier 	_PLL4_P,
707839a050SYann Gautier 	_PLL4_Q,
717839a050SYann Gautier 	_PLL4_R,
727839a050SYann Gautier 	_ACLK,
737839a050SYann Gautier 	_PCLK1,
747839a050SYann Gautier 	_PCLK2,
757839a050SYann Gautier 	_PCLK3,
767839a050SYann Gautier 	_PCLK4,
777839a050SYann Gautier 	_PCLK5,
787839a050SYann Gautier 	_HCLK6,
797839a050SYann Gautier 	_HCLK2,
807839a050SYann Gautier 	_CK_PER,
817839a050SYann Gautier 	_CK_MPU,
82b053a22eSYann Gautier 	_CK_MCU,
830d21680cSYann Gautier 	_USB_PHY_48,
847839a050SYann Gautier 	_PARENT_NB,
857839a050SYann Gautier 	_UNKNOWN_ID = 0xff,
867839a050SYann Gautier };
877839a050SYann Gautier 
880d21680cSYann Gautier /* Lists only the parent clock we are interested in */
897839a050SYann Gautier enum stm32mp1_parent_sel {
900d21680cSYann Gautier 	_I2C12_SEL,
910d21680cSYann Gautier 	_I2C35_SEL,
920d21680cSYann Gautier 	_STGEN_SEL,
937839a050SYann Gautier 	_I2C46_SEL,
940d21680cSYann Gautier 	_SPI6_SEL,
95d4151d2fSYann Gautier 	_UART1_SEL,
960d21680cSYann Gautier 	_RNG1_SEL,
977839a050SYann Gautier 	_UART6_SEL,
987839a050SYann Gautier 	_UART24_SEL,
997839a050SYann Gautier 	_UART35_SEL,
1007839a050SYann Gautier 	_UART78_SEL,
1017839a050SYann Gautier 	_SDMMC12_SEL,
1027839a050SYann Gautier 	_SDMMC3_SEL,
1037839a050SYann Gautier 	_QSPI_SEL,
1047839a050SYann Gautier 	_FMC_SEL,
105d4151d2fSYann Gautier 	_AXIS_SEL,
106d4151d2fSYann Gautier 	_MCUS_SEL,
1077839a050SYann Gautier 	_USBPHY_SEL,
1087839a050SYann Gautier 	_USBO_SEL,
1098fbcd9e4SEtienne Carriere 	_MPU_SEL,
110288f5cf2SYann Gautier 	_CKPER_SEL,
111016af006SEtienne Carriere 	_RTC_SEL,
1127839a050SYann Gautier 	_PARENT_SEL_NB,
1137839a050SYann Gautier 	_UNKNOWN_SEL = 0xff,
1147839a050SYann Gautier };
1157839a050SYann Gautier 
1168fbcd9e4SEtienne Carriere /* State the parent clock ID straight related to a clock */
1178fbcd9e4SEtienne Carriere static const uint8_t parent_id_clock_id[_PARENT_NB] = {
1188fbcd9e4SEtienne Carriere 	[_HSE] = CK_HSE,
1198fbcd9e4SEtienne Carriere 	[_HSI] = CK_HSI,
1208fbcd9e4SEtienne Carriere 	[_CSI] = CK_CSI,
1218fbcd9e4SEtienne Carriere 	[_LSE] = CK_LSE,
1228fbcd9e4SEtienne Carriere 	[_LSI] = CK_LSI,
1238fbcd9e4SEtienne Carriere 	[_I2S_CKIN] = _UNKNOWN_ID,
1248fbcd9e4SEtienne Carriere 	[_USB_PHY_48] = _UNKNOWN_ID,
1258fbcd9e4SEtienne Carriere 	[_HSI_KER] = CK_HSI,
1268fbcd9e4SEtienne Carriere 	[_HSE_KER] = CK_HSE,
1278fbcd9e4SEtienne Carriere 	[_HSE_KER_DIV2] = CK_HSE_DIV2,
128cbd2e8a6SGabriel Fernandez 	[_HSE_RTC] = _UNKNOWN_ID,
1298fbcd9e4SEtienne Carriere 	[_CSI_KER] = CK_CSI,
1308fbcd9e4SEtienne Carriere 	[_PLL1_P] = PLL1_P,
1318fbcd9e4SEtienne Carriere 	[_PLL1_Q] = PLL1_Q,
1328fbcd9e4SEtienne Carriere 	[_PLL1_R] = PLL1_R,
1338fbcd9e4SEtienne Carriere 	[_PLL2_P] = PLL2_P,
1348fbcd9e4SEtienne Carriere 	[_PLL2_Q] = PLL2_Q,
1358fbcd9e4SEtienne Carriere 	[_PLL2_R] = PLL2_R,
1368fbcd9e4SEtienne Carriere 	[_PLL3_P] = PLL3_P,
1378fbcd9e4SEtienne Carriere 	[_PLL3_Q] = PLL3_Q,
1388fbcd9e4SEtienne Carriere 	[_PLL3_R] = PLL3_R,
1398fbcd9e4SEtienne Carriere 	[_PLL4_P] = PLL4_P,
1408fbcd9e4SEtienne Carriere 	[_PLL4_Q] = PLL4_Q,
1418fbcd9e4SEtienne Carriere 	[_PLL4_R] = PLL4_R,
1428fbcd9e4SEtienne Carriere 	[_ACLK] = CK_AXI,
1438fbcd9e4SEtienne Carriere 	[_PCLK1] = CK_AXI,
1448fbcd9e4SEtienne Carriere 	[_PCLK2] = CK_AXI,
1458fbcd9e4SEtienne Carriere 	[_PCLK3] = CK_AXI,
1468fbcd9e4SEtienne Carriere 	[_PCLK4] = CK_AXI,
1478fbcd9e4SEtienne Carriere 	[_PCLK5] = CK_AXI,
1488fbcd9e4SEtienne Carriere 	[_CK_PER] = CK_PER,
1498fbcd9e4SEtienne Carriere 	[_CK_MPU] = CK_MPU,
1508fbcd9e4SEtienne Carriere 	[_CK_MCU] = CK_MCU,
1518fbcd9e4SEtienne Carriere };
1528fbcd9e4SEtienne Carriere 
1538fbcd9e4SEtienne Carriere static unsigned int clock_id2parent_id(unsigned long id)
1548fbcd9e4SEtienne Carriere {
1558fbcd9e4SEtienne Carriere 	unsigned int n;
1568fbcd9e4SEtienne Carriere 
1578fbcd9e4SEtienne Carriere 	for (n = 0U; n < ARRAY_SIZE(parent_id_clock_id); n++) {
1588fbcd9e4SEtienne Carriere 		if (parent_id_clock_id[n] == id) {
1598fbcd9e4SEtienne Carriere 			return n;
1608fbcd9e4SEtienne Carriere 		}
1618fbcd9e4SEtienne Carriere 	}
1628fbcd9e4SEtienne Carriere 
1638fbcd9e4SEtienne Carriere 	return _UNKNOWN_ID;
1648fbcd9e4SEtienne Carriere }
1658fbcd9e4SEtienne Carriere 
1667839a050SYann Gautier enum stm32mp1_pll_id {
1677839a050SYann Gautier 	_PLL1,
1687839a050SYann Gautier 	_PLL2,
1697839a050SYann Gautier 	_PLL3,
1707839a050SYann Gautier 	_PLL4,
1717839a050SYann Gautier 	_PLL_NB
1727839a050SYann Gautier };
1737839a050SYann Gautier 
1747839a050SYann Gautier enum stm32mp1_div_id {
1757839a050SYann Gautier 	_DIV_P,
1767839a050SYann Gautier 	_DIV_Q,
1777839a050SYann Gautier 	_DIV_R,
1787839a050SYann Gautier 	_DIV_NB,
1797839a050SYann Gautier };
1807839a050SYann Gautier 
1817839a050SYann Gautier enum stm32mp1_clksrc_id {
1827839a050SYann Gautier 	CLKSRC_MPU,
1837839a050SYann Gautier 	CLKSRC_AXI,
184b053a22eSYann Gautier 	CLKSRC_MCU,
1857839a050SYann Gautier 	CLKSRC_PLL12,
1867839a050SYann Gautier 	CLKSRC_PLL3,
1877839a050SYann Gautier 	CLKSRC_PLL4,
1887839a050SYann Gautier 	CLKSRC_RTC,
1897839a050SYann Gautier 	CLKSRC_MCO1,
1907839a050SYann Gautier 	CLKSRC_MCO2,
1917839a050SYann Gautier 	CLKSRC_NB
1927839a050SYann Gautier };
1937839a050SYann Gautier 
1947839a050SYann Gautier enum stm32mp1_clkdiv_id {
1957839a050SYann Gautier 	CLKDIV_MPU,
1967839a050SYann Gautier 	CLKDIV_AXI,
197b053a22eSYann Gautier 	CLKDIV_MCU,
1987839a050SYann Gautier 	CLKDIV_APB1,
1997839a050SYann Gautier 	CLKDIV_APB2,
2007839a050SYann Gautier 	CLKDIV_APB3,
2017839a050SYann Gautier 	CLKDIV_APB4,
2027839a050SYann Gautier 	CLKDIV_APB5,
2037839a050SYann Gautier 	CLKDIV_RTC,
2047839a050SYann Gautier 	CLKDIV_MCO1,
2057839a050SYann Gautier 	CLKDIV_MCO2,
2067839a050SYann Gautier 	CLKDIV_NB
2077839a050SYann Gautier };
2087839a050SYann Gautier 
2097839a050SYann Gautier enum stm32mp1_pllcfg {
2107839a050SYann Gautier 	PLLCFG_M,
2117839a050SYann Gautier 	PLLCFG_N,
2127839a050SYann Gautier 	PLLCFG_P,
2137839a050SYann Gautier 	PLLCFG_Q,
2147839a050SYann Gautier 	PLLCFG_R,
2157839a050SYann Gautier 	PLLCFG_O,
2167839a050SYann Gautier 	PLLCFG_NB
2177839a050SYann Gautier };
2187839a050SYann Gautier 
2197839a050SYann Gautier enum stm32mp1_pllcsg {
2207839a050SYann Gautier 	PLLCSG_MOD_PER,
2217839a050SYann Gautier 	PLLCSG_INC_STEP,
2227839a050SYann Gautier 	PLLCSG_SSCG_MODE,
2237839a050SYann Gautier 	PLLCSG_NB
2247839a050SYann Gautier };
2257839a050SYann Gautier 
2267839a050SYann Gautier enum stm32mp1_plltype {
2277839a050SYann Gautier 	PLL_800,
2287839a050SYann Gautier 	PLL_1600,
2297839a050SYann Gautier 	PLL_TYPE_NB
2307839a050SYann Gautier };
2317839a050SYann Gautier 
2327839a050SYann Gautier struct stm32mp1_pll {
2337839a050SYann Gautier 	uint8_t refclk_min;
2347839a050SYann Gautier 	uint8_t refclk_max;
2357839a050SYann Gautier };
2367839a050SYann Gautier 
2377839a050SYann Gautier struct stm32mp1_clk_gate {
2387839a050SYann Gautier 	uint16_t offset;
2397839a050SYann Gautier 	uint8_t bit;
2407839a050SYann Gautier 	uint8_t index;
2417839a050SYann Gautier 	uint8_t set_clr;
242aaa09b71SYann Gautier 	uint8_t secure;
2430d21680cSYann Gautier 	uint8_t sel; /* Relates to enum stm32mp1_parent_sel */
2440d21680cSYann Gautier 	uint8_t fixed; /* Relates to enum stm32mp1_parent_id */
2457839a050SYann Gautier };
2467839a050SYann Gautier 
2477839a050SYann Gautier struct stm32mp1_clk_sel {
2487839a050SYann Gautier 	uint16_t offset;
2497839a050SYann Gautier 	uint8_t src;
2507839a050SYann Gautier 	uint8_t msk;
2517839a050SYann Gautier 	uint8_t nb_parent;
2527839a050SYann Gautier 	const uint8_t *parent;
2537839a050SYann Gautier };
2547839a050SYann Gautier 
2557839a050SYann Gautier #define REFCLK_SIZE 4
2567839a050SYann Gautier struct stm32mp1_clk_pll {
2577839a050SYann Gautier 	enum stm32mp1_plltype plltype;
2587839a050SYann Gautier 	uint16_t rckxselr;
2597839a050SYann Gautier 	uint16_t pllxcfgr1;
2607839a050SYann Gautier 	uint16_t pllxcfgr2;
2617839a050SYann Gautier 	uint16_t pllxfracr;
2627839a050SYann Gautier 	uint16_t pllxcr;
2637839a050SYann Gautier 	uint16_t pllxcsgr;
2647839a050SYann Gautier 	enum stm32mp_osc_id refclk[REFCLK_SIZE];
2657839a050SYann Gautier };
2667839a050SYann Gautier 
2670d21680cSYann Gautier /* Clocks with selectable source and non set/clr register access */
268aaa09b71SYann Gautier #define _CLK_SELEC(sec, off, b, idx, s)			\
2697839a050SYann Gautier 	{						\
2707839a050SYann Gautier 		.offset = (off),			\
2717839a050SYann Gautier 		.bit = (b),				\
2727839a050SYann Gautier 		.index = (idx),				\
2737839a050SYann Gautier 		.set_clr = 0,				\
274aaa09b71SYann Gautier 		.secure = (sec),			\
2757839a050SYann Gautier 		.sel = (s),				\
2767839a050SYann Gautier 		.fixed = _UNKNOWN_ID,			\
2777839a050SYann Gautier 	}
2787839a050SYann Gautier 
2790d21680cSYann Gautier /* Clocks with fixed source and non set/clr register access */
280aaa09b71SYann Gautier #define _CLK_FIXED(sec, off, b, idx, f)			\
2817839a050SYann Gautier 	{						\
2827839a050SYann Gautier 		.offset = (off),			\
2837839a050SYann Gautier 		.bit = (b),				\
2847839a050SYann Gautier 		.index = (idx),				\
2857839a050SYann Gautier 		.set_clr = 0,				\
286aaa09b71SYann Gautier 		.secure = (sec),			\
2877839a050SYann Gautier 		.sel = _UNKNOWN_SEL,			\
2887839a050SYann Gautier 		.fixed = (f),				\
2897839a050SYann Gautier 	}
2907839a050SYann Gautier 
2910d21680cSYann Gautier /* Clocks with selectable source and set/clr register access */
292aaa09b71SYann Gautier #define _CLK_SC_SELEC(sec, off, b, idx, s)			\
2937839a050SYann Gautier 	{						\
2947839a050SYann Gautier 		.offset = (off),			\
2957839a050SYann Gautier 		.bit = (b),				\
2967839a050SYann Gautier 		.index = (idx),				\
2977839a050SYann Gautier 		.set_clr = 1,				\
298aaa09b71SYann Gautier 		.secure = (sec),			\
2997839a050SYann Gautier 		.sel = (s),				\
3007839a050SYann Gautier 		.fixed = _UNKNOWN_ID,			\
3017839a050SYann Gautier 	}
3027839a050SYann Gautier 
3030d21680cSYann Gautier /* Clocks with fixed source and set/clr register access */
304aaa09b71SYann Gautier #define _CLK_SC_FIXED(sec, off, b, idx, f)			\
3057839a050SYann Gautier 	{						\
3067839a050SYann Gautier 		.offset = (off),			\
3077839a050SYann Gautier 		.bit = (b),				\
3087839a050SYann Gautier 		.index = (idx),				\
3097839a050SYann Gautier 		.set_clr = 1,				\
310aaa09b71SYann Gautier 		.secure = (sec),			\
3117839a050SYann Gautier 		.sel = _UNKNOWN_SEL,			\
3127839a050SYann Gautier 		.fixed = (f),				\
3137839a050SYann Gautier 	}
3147839a050SYann Gautier 
315d4151d2fSYann Gautier #define _CLK_PARENT_SEL(_label, _rcc_selr, _parents)		\
316d4151d2fSYann Gautier 	[_ ## _label ## _SEL] = {				\
317d4151d2fSYann Gautier 		.offset = _rcc_selr,				\
318d4151d2fSYann Gautier 		.src = _rcc_selr ## _ ## _label ## SRC_SHIFT,	\
3198ae08dcdSEtienne Carriere 		.msk = (_rcc_selr ## _ ## _label ## SRC_MASK) >> \
3208ae08dcdSEtienne Carriere 		       (_rcc_selr ## _ ## _label ## SRC_SHIFT), \
321d4151d2fSYann Gautier 		.parent = (_parents),				\
322d4151d2fSYann Gautier 		.nb_parent = ARRAY_SIZE(_parents)		\
3237839a050SYann Gautier 	}
3247839a050SYann Gautier 
3250d21680cSYann Gautier #define _CLK_PLL(idx, type, off1, off2, off3,		\
3267839a050SYann Gautier 		 off4, off5, off6,			\
3277839a050SYann Gautier 		 p1, p2, p3, p4)			\
3287839a050SYann Gautier 	[(idx)] = {					\
3297839a050SYann Gautier 		.plltype = (type),			\
3307839a050SYann Gautier 		.rckxselr = (off1),			\
3317839a050SYann Gautier 		.pllxcfgr1 = (off2),			\
3327839a050SYann Gautier 		.pllxcfgr2 = (off3),			\
3337839a050SYann Gautier 		.pllxfracr = (off4),			\
3347839a050SYann Gautier 		.pllxcr = (off5),			\
3357839a050SYann Gautier 		.pllxcsgr = (off6),			\
3367839a050SYann Gautier 		.refclk[0] = (p1),			\
3377839a050SYann Gautier 		.refclk[1] = (p2),			\
3387839a050SYann Gautier 		.refclk[2] = (p3),			\
3397839a050SYann Gautier 		.refclk[3] = (p4),			\
3407839a050SYann Gautier 	}
3417839a050SYann Gautier 
3420d21680cSYann Gautier #define NB_GATES	ARRAY_SIZE(stm32mp1_clk_gate)
3430d21680cSYann Gautier 
344aaa09b71SYann Gautier #define SEC		1
345aaa09b71SYann Gautier #define N_S		0
346aaa09b71SYann Gautier 
3477839a050SYann Gautier static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
348aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK),
349aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
350aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK),
351aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
352aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
353aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
354aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
355aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
356aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK),
357aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
358aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
3597839a050SYann Gautier 
3607418cf39SYann Gautier #if defined(IMAGE_BL32)
361aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
3627418cf39SYann Gautier #endif
363aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
364aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
365aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
366aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
367aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
368aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
369aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL),
370aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL),
371aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL),
372aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL),
3737839a050SYann Gautier 
3747418cf39SYann Gautier #if defined(IMAGE_BL32)
375aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
3767418cf39SYann Gautier #endif
377aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
3787839a050SYann Gautier 
379aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID),
380f33b2433SYann Gautier 
381aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
382aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
383aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
3847839a050SYann Gautier 
385aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL),
386aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
387aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL),
388aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL),
389aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
390aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5),
391aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5),
392aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5),
393aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5),
394aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5),
395aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
3967839a050SYann Gautier 
3977418cf39SYann Gautier #if defined(IMAGE_BL32)
398aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
399aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
4007418cf39SYann Gautier #endif
4017839a050SYann Gautier 
402aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
403aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
404aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
405aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
406aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
407aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
408aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
409aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
410aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
411aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
412aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
4137839a050SYann Gautier 
414aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5),
415aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5),
416aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5),
417aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL),
418aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5),
4197839a050SYann Gautier 
4207418cf39SYann Gautier #if defined(IMAGE_BL2)
421aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
422aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
4237418cf39SYann Gautier #endif
424aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
425aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
4267418cf39SYann Gautier #if defined(IMAGE_BL32)
427aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
4287418cf39SYann Gautier #endif
4297839a050SYann Gautier 
430aaa09b71SYann Gautier 	_CLK_SELEC(SEC, RCC_BDCR, 20, RTC, _RTC_SEL),
431aaa09b71SYann Gautier 	_CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
4327839a050SYann Gautier };
4337839a050SYann Gautier 
4340d21680cSYann Gautier static const uint8_t i2c12_parents[] = {
4350d21680cSYann Gautier 	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
4360d21680cSYann Gautier };
4370d21680cSYann Gautier 
4380d21680cSYann Gautier static const uint8_t i2c35_parents[] = {
4390d21680cSYann Gautier 	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
4400d21680cSYann Gautier };
4410d21680cSYann Gautier 
4420d21680cSYann Gautier static const uint8_t stgen_parents[] = {
4430d21680cSYann Gautier 	_HSI_KER, _HSE_KER
4440d21680cSYann Gautier };
4450d21680cSYann Gautier 
4460d21680cSYann Gautier static const uint8_t i2c46_parents[] = {
4470d21680cSYann Gautier 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER
4480d21680cSYann Gautier };
4490d21680cSYann Gautier 
4500d21680cSYann Gautier static const uint8_t spi6_parents[] = {
4510d21680cSYann Gautier 	_PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q
4520d21680cSYann Gautier };
4530d21680cSYann Gautier 
4540d21680cSYann Gautier static const uint8_t usart1_parents[] = {
4550d21680cSYann Gautier 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER
4560d21680cSYann Gautier };
4570d21680cSYann Gautier 
4580d21680cSYann Gautier static const uint8_t rng1_parents[] = {
4590d21680cSYann Gautier 	_CSI, _PLL4_R, _LSE, _LSI
4600d21680cSYann Gautier };
4610d21680cSYann Gautier 
4620d21680cSYann Gautier static const uint8_t uart6_parents[] = {
4630d21680cSYann Gautier 	_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
4640d21680cSYann Gautier };
4650d21680cSYann Gautier 
4660d21680cSYann Gautier static const uint8_t uart234578_parents[] = {
4670d21680cSYann Gautier 	_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
4680d21680cSYann Gautier };
4690d21680cSYann Gautier 
4700d21680cSYann Gautier static const uint8_t sdmmc12_parents[] = {
4710d21680cSYann Gautier 	_HCLK6, _PLL3_R, _PLL4_P, _HSI_KER
4720d21680cSYann Gautier };
4730d21680cSYann Gautier 
4740d21680cSYann Gautier static const uint8_t sdmmc3_parents[] = {
4750d21680cSYann Gautier 	_HCLK2, _PLL3_R, _PLL4_P, _HSI_KER
4760d21680cSYann Gautier };
4770d21680cSYann Gautier 
4780d21680cSYann Gautier static const uint8_t qspi_parents[] = {
4790d21680cSYann Gautier 	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
4800d21680cSYann Gautier };
4810d21680cSYann Gautier 
4820d21680cSYann Gautier static const uint8_t fmc_parents[] = {
4830d21680cSYann Gautier 	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
4840d21680cSYann Gautier };
4850d21680cSYann Gautier 
486b8fe48b6SEtienne Carriere static const uint8_t axiss_parents[] = {
487b8fe48b6SEtienne Carriere 	_HSI, _HSE, _PLL2_P
4880d21680cSYann Gautier };
4890d21680cSYann Gautier 
490b8fe48b6SEtienne Carriere static const uint8_t mcuss_parents[] = {
491b8fe48b6SEtienne Carriere 	_HSI, _HSE, _CSI, _PLL3_P
492b053a22eSYann Gautier };
493b053a22eSYann Gautier 
4940d21680cSYann Gautier static const uint8_t usbphy_parents[] = {
4950d21680cSYann Gautier 	_HSE_KER, _PLL4_R, _HSE_KER_DIV2
4960d21680cSYann Gautier };
4970d21680cSYann Gautier 
4980d21680cSYann Gautier static const uint8_t usbo_parents[] = {
4990d21680cSYann Gautier 	_PLL4_R, _USB_PHY_48
5000d21680cSYann Gautier };
5017839a050SYann Gautier 
5028fbcd9e4SEtienne Carriere static const uint8_t mpu_parents[] = {
5038fbcd9e4SEtienne Carriere 	_HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */
5048fbcd9e4SEtienne Carriere };
5058fbcd9e4SEtienne Carriere 
5068fbcd9e4SEtienne Carriere static const uint8_t per_parents[] = {
5078fbcd9e4SEtienne Carriere 	_HSI, _HSE, _CSI,
5088fbcd9e4SEtienne Carriere };
5098fbcd9e4SEtienne Carriere 
510016af006SEtienne Carriere static const uint8_t rtc_parents[] = {
511cbd2e8a6SGabriel Fernandez 	_UNKNOWN_ID, _LSE, _LSI, _HSE_RTC
512016af006SEtienne Carriere };
513016af006SEtienne Carriere 
5147839a050SYann Gautier static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
515d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents),
516d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents),
517d4151d2fSYann Gautier 	_CLK_PARENT_SEL(STGEN, RCC_STGENCKSELR, stgen_parents),
518d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C46, RCC_I2C46CKSELR, i2c46_parents),
519d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents),
520d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents),
521d4151d2fSYann Gautier 	_CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents),
5228fbcd9e4SEtienne Carriere 	_CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents),
523288f5cf2SYann Gautier 	_CLK_PARENT_SEL(CKPER, RCC_CPERCKSELR, per_parents),
524016af006SEtienne Carriere 	_CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents),
525d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents),
526d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents),
527d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents),
528d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART78, RCC_UART78CKSELR, uart234578_parents),
529d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SDMMC12, RCC_SDMMC12CKSELR, sdmmc12_parents),
530d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents),
531d4151d2fSYann Gautier 	_CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents),
532d4151d2fSYann Gautier 	_CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents),
533b8fe48b6SEtienne Carriere 	_CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, axiss_parents),
534b8fe48b6SEtienne Carriere 	_CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mcuss_parents),
535d4151d2fSYann Gautier 	_CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents),
536d4151d2fSYann Gautier 	_CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents),
5377839a050SYann Gautier };
5387839a050SYann Gautier 
5397839a050SYann Gautier /* Define characteristic of PLL according type */
5407839a050SYann Gautier #define DIVN_MIN	24
5417839a050SYann Gautier static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
5427839a050SYann Gautier 	[PLL_800] = {
5437839a050SYann Gautier 		.refclk_min = 4,
5447839a050SYann Gautier 		.refclk_max = 16,
5457839a050SYann Gautier 	},
5467839a050SYann Gautier 	[PLL_1600] = {
5477839a050SYann Gautier 		.refclk_min = 8,
5487839a050SYann Gautier 		.refclk_max = 16,
5497839a050SYann Gautier 	},
5507839a050SYann Gautier };
5517839a050SYann Gautier 
5527839a050SYann Gautier /* PLLNCFGR2 register divider by output */
5537839a050SYann Gautier static const uint8_t pllncfgr2[_DIV_NB] = {
5547839a050SYann Gautier 	[_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT,
5557839a050SYann Gautier 	[_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT,
5560d21680cSYann Gautier 	[_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT,
5577839a050SYann Gautier };
5587839a050SYann Gautier 
5597839a050SYann Gautier static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = {
5600d21680cSYann Gautier 	_CLK_PLL(_PLL1, PLL_1600,
5617839a050SYann Gautier 		 RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2,
5627839a050SYann Gautier 		 RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR,
5637839a050SYann Gautier 		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
5640d21680cSYann Gautier 	_CLK_PLL(_PLL2, PLL_1600,
5657839a050SYann Gautier 		 RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2,
5667839a050SYann Gautier 		 RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR,
5677839a050SYann Gautier 		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
5680d21680cSYann Gautier 	_CLK_PLL(_PLL3, PLL_800,
5697839a050SYann Gautier 		 RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2,
5707839a050SYann Gautier 		 RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR,
5717839a050SYann Gautier 		 _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID),
5720d21680cSYann Gautier 	_CLK_PLL(_PLL4, PLL_800,
5737839a050SYann Gautier 		 RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2,
5747839a050SYann Gautier 		 RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR,
5757839a050SYann Gautier 		 _HSI, _HSE, _CSI, _I2S_CKIN),
5767839a050SYann Gautier };
5777839a050SYann Gautier 
5787839a050SYann Gautier /* Prescaler table lookups for clock computation */
579b053a22eSYann Gautier /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */
580b053a22eSYann Gautier static const uint8_t stm32mp1_mcu_div[16] = {
581b053a22eSYann Gautier 	0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9
582b053a22eSYann Gautier };
5837839a050SYann Gautier 
5847839a050SYann Gautier /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */
5857839a050SYann Gautier #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div
5867839a050SYann Gautier #define stm32mp1_apbx_div stm32mp1_mpu_apbx_div
5877839a050SYann Gautier static const uint8_t stm32mp1_mpu_apbx_div[8] = {
5887839a050SYann Gautier 	0, 1, 2, 3, 4, 4, 4, 4
5897839a050SYann Gautier };
5907839a050SYann Gautier 
5917839a050SYann Gautier /* div = /1 /2 /3 /4 */
5927839a050SYann Gautier static const uint8_t stm32mp1_axi_div[8] = {
5937839a050SYann Gautier 	1, 2, 3, 4, 4, 4, 4, 4
5947839a050SYann Gautier };
5957839a050SYann Gautier 
59637e8295aSEtienne Carriere static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = {
59737e8295aSEtienne Carriere 	[_HSI] = "HSI",
59837e8295aSEtienne Carriere 	[_HSE] = "HSE",
59937e8295aSEtienne Carriere 	[_CSI] = "CSI",
60037e8295aSEtienne Carriere 	[_LSI] = "LSI",
60137e8295aSEtienne Carriere 	[_LSE] = "LSE",
60237e8295aSEtienne Carriere 	[_I2S_CKIN] = "I2S_CKIN",
60337e8295aSEtienne Carriere 	[_HSI_KER] = "HSI_KER",
60437e8295aSEtienne Carriere 	[_HSE_KER] = "HSE_KER",
60537e8295aSEtienne Carriere 	[_HSE_KER_DIV2] = "HSE_KER_DIV2",
606cbd2e8a6SGabriel Fernandez 	[_HSE_RTC] = "HSE_RTC",
60737e8295aSEtienne Carriere 	[_CSI_KER] = "CSI_KER",
60837e8295aSEtienne Carriere 	[_PLL1_P] = "PLL1_P",
60937e8295aSEtienne Carriere 	[_PLL1_Q] = "PLL1_Q",
61037e8295aSEtienne Carriere 	[_PLL1_R] = "PLL1_R",
61137e8295aSEtienne Carriere 	[_PLL2_P] = "PLL2_P",
61237e8295aSEtienne Carriere 	[_PLL2_Q] = "PLL2_Q",
61337e8295aSEtienne Carriere 	[_PLL2_R] = "PLL2_R",
61437e8295aSEtienne Carriere 	[_PLL3_P] = "PLL3_P",
61537e8295aSEtienne Carriere 	[_PLL3_Q] = "PLL3_Q",
61637e8295aSEtienne Carriere 	[_PLL3_R] = "PLL3_R",
61737e8295aSEtienne Carriere 	[_PLL4_P] = "PLL4_P",
61837e8295aSEtienne Carriere 	[_PLL4_Q] = "PLL4_Q",
61937e8295aSEtienne Carriere 	[_PLL4_R] = "PLL4_R",
62037e8295aSEtienne Carriere 	[_ACLK] = "ACLK",
62137e8295aSEtienne Carriere 	[_PCLK1] = "PCLK1",
62237e8295aSEtienne Carriere 	[_PCLK2] = "PCLK2",
62337e8295aSEtienne Carriere 	[_PCLK3] = "PCLK3",
62437e8295aSEtienne Carriere 	[_PCLK4] = "PCLK4",
62537e8295aSEtienne Carriere 	[_PCLK5] = "PCLK5",
62637e8295aSEtienne Carriere 	[_HCLK6] = "KCLK6",
62737e8295aSEtienne Carriere 	[_HCLK2] = "HCLK2",
62837e8295aSEtienne Carriere 	[_CK_PER] = "CK_PER",
62937e8295aSEtienne Carriere 	[_CK_MPU] = "CK_MPU",
63037e8295aSEtienne Carriere 	[_CK_MCU] = "CK_MCU",
63137e8295aSEtienne Carriere 	[_USB_PHY_48] = "USB_PHY_48",
63237e8295aSEtienne Carriere };
63337e8295aSEtienne Carriere 
6340d21680cSYann Gautier /* RCC clock device driver private */
6350d21680cSYann Gautier static unsigned long stm32mp1_osc[NB_OSC];
6360d21680cSYann Gautier static struct spinlock reg_lock;
6370d21680cSYann Gautier static unsigned int gate_refcounts[NB_GATES];
6380d21680cSYann Gautier static struct spinlock refcount_lock;
6397839a050SYann Gautier 
6400d21680cSYann Gautier static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx)
6410d21680cSYann Gautier {
6420d21680cSYann Gautier 	return &stm32mp1_clk_gate[idx];
6430d21680cSYann Gautier }
6447839a050SYann Gautier 
6453d69149aSYann Gautier #if defined(IMAGE_BL32)
6463d69149aSYann Gautier static bool gate_is_non_secure(const struct stm32mp1_clk_gate *gate)
6473d69149aSYann Gautier {
6483d69149aSYann Gautier 	return gate->secure == N_S;
6493d69149aSYann Gautier }
6503d69149aSYann Gautier #endif
6513d69149aSYann Gautier 
6520d21680cSYann Gautier static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx)
6530d21680cSYann Gautier {
6540d21680cSYann Gautier 	return &stm32mp1_clk_sel[idx];
6550d21680cSYann Gautier }
6560d21680cSYann Gautier 
6570d21680cSYann Gautier static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx)
6580d21680cSYann Gautier {
6590d21680cSYann Gautier 	return &stm32mp1_clk_pll[idx];
6600d21680cSYann Gautier }
6610d21680cSYann Gautier 
6620d21680cSYann Gautier static void stm32mp1_clk_lock(struct spinlock *lock)
6630d21680cSYann Gautier {
664e463d3f4SYann Gautier 	if (stm32mp_lock_available()) {
6650d21680cSYann Gautier 		/* Assume interrupts are masked */
6660d21680cSYann Gautier 		spin_lock(lock);
6670d21680cSYann Gautier 	}
668e463d3f4SYann Gautier }
6690d21680cSYann Gautier 
6700d21680cSYann Gautier static void stm32mp1_clk_unlock(struct spinlock *lock)
6710d21680cSYann Gautier {
672e463d3f4SYann Gautier 	if (stm32mp_lock_available()) {
6730d21680cSYann Gautier 		spin_unlock(lock);
6740d21680cSYann Gautier 	}
675e463d3f4SYann Gautier }
6760d21680cSYann Gautier 
6770d21680cSYann Gautier bool stm32mp1_rcc_is_secure(void)
6780d21680cSYann Gautier {
6790d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
6801bb9072aSEtienne Carriere 	uint32_t mask = RCC_TZCR_TZEN;
6810d21680cSYann Gautier 
6821bb9072aSEtienne Carriere 	return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
6830d21680cSYann Gautier }
6840d21680cSYann Gautier 
685b053a22eSYann Gautier bool stm32mp1_rcc_is_mckprot(void)
686b053a22eSYann Gautier {
687b053a22eSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
6881bb9072aSEtienne Carriere 	uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT;
689b053a22eSYann Gautier 
6901bb9072aSEtienne Carriere 	return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
691b053a22eSYann Gautier }
692b053a22eSYann Gautier 
6930d21680cSYann Gautier void stm32mp1_clk_rcc_regs_lock(void)
6940d21680cSYann Gautier {
6950d21680cSYann Gautier 	stm32mp1_clk_lock(&reg_lock);
6960d21680cSYann Gautier }
6970d21680cSYann Gautier 
6980d21680cSYann Gautier void stm32mp1_clk_rcc_regs_unlock(void)
6990d21680cSYann Gautier {
7000d21680cSYann Gautier 	stm32mp1_clk_unlock(&reg_lock);
7010d21680cSYann Gautier }
7020d21680cSYann Gautier 
7030d21680cSYann Gautier static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx)
7047839a050SYann Gautier {
7057839a050SYann Gautier 	if (idx >= NB_OSC) {
7067839a050SYann Gautier 		return 0;
7077839a050SYann Gautier 	}
7087839a050SYann Gautier 
7090d21680cSYann Gautier 	return stm32mp1_osc[idx];
7107839a050SYann Gautier }
7117839a050SYann Gautier 
7120d21680cSYann Gautier static int stm32mp1_clk_get_gated_id(unsigned long id)
7137839a050SYann Gautier {
7140d21680cSYann Gautier 	unsigned int i;
7157839a050SYann Gautier 
7160d21680cSYann Gautier 	for (i = 0U; i < NB_GATES; i++) {
7170d21680cSYann Gautier 		if (gate_ref(i)->index == id) {
7187839a050SYann Gautier 			return i;
7197839a050SYann Gautier 		}
7207839a050SYann Gautier 	}
7217839a050SYann Gautier 
72244fb470bSYann Gautier 	ERROR("%s: clk id %lu not found\n", __func__, id);
7237839a050SYann Gautier 
7247839a050SYann Gautier 	return -EINVAL;
7257839a050SYann Gautier }
7267839a050SYann Gautier 
7270d21680cSYann Gautier static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i)
7287839a050SYann Gautier {
7290d21680cSYann Gautier 	return (enum stm32mp1_parent_sel)(gate_ref(i)->sel);
7307839a050SYann Gautier }
7317839a050SYann Gautier 
7320d21680cSYann Gautier static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i)
7337839a050SYann Gautier {
7340d21680cSYann Gautier 	return (enum stm32mp1_parent_id)(gate_ref(i)->fixed);
7357839a050SYann Gautier }
7367839a050SYann Gautier 
7370d21680cSYann Gautier static int stm32mp1_clk_get_parent(unsigned long id)
7387839a050SYann Gautier {
7390d21680cSYann Gautier 	const struct stm32mp1_clk_sel *sel;
7408fbcd9e4SEtienne Carriere 	uint32_t p_sel;
7417839a050SYann Gautier 	int i;
7427839a050SYann Gautier 	enum stm32mp1_parent_id p;
7437839a050SYann Gautier 	enum stm32mp1_parent_sel s;
7440d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
7457839a050SYann Gautier 
7468fbcd9e4SEtienne Carriere 	/* Few non gateable clock have a static parent ID, find them */
7478fbcd9e4SEtienne Carriere 	i = (int)clock_id2parent_id(id);
7488fbcd9e4SEtienne Carriere 	if (i != _UNKNOWN_ID) {
7498fbcd9e4SEtienne Carriere 		return i;
7507839a050SYann Gautier 	}
7517839a050SYann Gautier 
7520d21680cSYann Gautier 	i = stm32mp1_clk_get_gated_id(id);
7537839a050SYann Gautier 	if (i < 0) {
7540d21680cSYann Gautier 		panic();
7557839a050SYann Gautier 	}
7567839a050SYann Gautier 
7570d21680cSYann Gautier 	p = stm32mp1_clk_get_fixed_parent(i);
7587839a050SYann Gautier 	if (p < _PARENT_NB) {
7597839a050SYann Gautier 		return (int)p;
7607839a050SYann Gautier 	}
7617839a050SYann Gautier 
7620d21680cSYann Gautier 	s = stm32mp1_clk_get_sel(i);
7630d21680cSYann Gautier 	if (s == _UNKNOWN_SEL) {
7640d21680cSYann Gautier 		return -EINVAL;
7650d21680cSYann Gautier 	}
7667839a050SYann Gautier 	if (s >= _PARENT_SEL_NB) {
7670d21680cSYann Gautier 		panic();
7687839a050SYann Gautier 	}
7697839a050SYann Gautier 
7700d21680cSYann Gautier 	sel = clk_sel_ref(s);
7718ae08dcdSEtienne Carriere 	p_sel = (mmio_read_32(rcc_base + sel->offset) &
7728ae08dcdSEtienne Carriere 		 (sel->msk << sel->src)) >> sel->src;
7730d21680cSYann Gautier 	if (p_sel < sel->nb_parent) {
7740d21680cSYann Gautier 		return (int)sel->parent[p_sel];
7757839a050SYann Gautier 	}
7767839a050SYann Gautier 
7777839a050SYann Gautier 	return -EINVAL;
7787839a050SYann Gautier }
7797839a050SYann Gautier 
7800d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll)
7817839a050SYann Gautier {
7820d21680cSYann Gautier 	uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr);
7830d21680cSYann Gautier 	uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK;
7847839a050SYann Gautier 
7850d21680cSYann Gautier 	return stm32mp1_clk_get_fixed(pll->refclk[src]);
7867839a050SYann Gautier }
7877839a050SYann Gautier 
7887839a050SYann Gautier /*
7897839a050SYann Gautier  * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL
7907839a050SYann Gautier  * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1)
7917839a050SYann Gautier  * - PLL3 & PLL4 => return VCO     with Fpll_y_ck = FVCO / (DIVy + 1)
7927839a050SYann Gautier  * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1)
7937839a050SYann Gautier  */
7940d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll)
7957839a050SYann Gautier {
7967839a050SYann Gautier 	unsigned long refclk, fvco;
7977839a050SYann Gautier 	uint32_t cfgr1, fracr, divm, divn;
7980d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
7997839a050SYann Gautier 
8000d21680cSYann Gautier 	cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1);
8010d21680cSYann Gautier 	fracr = mmio_read_32(rcc_base + pll->pllxfracr);
8027839a050SYann Gautier 
8037839a050SYann Gautier 	divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT;
8047839a050SYann Gautier 	divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK;
8057839a050SYann Gautier 
8060d21680cSYann Gautier 	refclk = stm32mp1_pll_get_fref(pll);
8077839a050SYann Gautier 
8087839a050SYann Gautier 	/*
8097839a050SYann Gautier 	 * With FRACV :
8107839a050SYann Gautier 	 *   Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1)
8117839a050SYann Gautier 	 * Without FRACV
8127839a050SYann Gautier 	 *   Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1)
8137839a050SYann Gautier 	 */
8147839a050SYann Gautier 	if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) {
8150d21680cSYann Gautier 		uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >>
8160d21680cSYann Gautier 				 RCC_PLLNFRACR_FRACV_SHIFT;
8177839a050SYann Gautier 		unsigned long long numerator, denominator;
8187839a050SYann Gautier 
8190d21680cSYann Gautier 		numerator = (((unsigned long long)divn + 1U) << 13) + fracv;
8200d21680cSYann Gautier 		numerator = refclk * numerator;
8217839a050SYann Gautier 		denominator = ((unsigned long long)divm + 1U) << 13;
8227839a050SYann Gautier 		fvco = (unsigned long)(numerator / denominator);
8237839a050SYann Gautier 	} else {
8247839a050SYann Gautier 		fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U));
8257839a050SYann Gautier 	}
8267839a050SYann Gautier 
8277839a050SYann Gautier 	return fvco;
8287839a050SYann Gautier }
8297839a050SYann Gautier 
8300d21680cSYann Gautier static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id,
8317839a050SYann Gautier 					    enum stm32mp1_div_id div_id)
8327839a050SYann Gautier {
8330d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
8347839a050SYann Gautier 	unsigned long dfout;
8357839a050SYann Gautier 	uint32_t cfgr2, divy;
8367839a050SYann Gautier 
8377839a050SYann Gautier 	if (div_id >= _DIV_NB) {
8387839a050SYann Gautier 		return 0;
8397839a050SYann Gautier 	}
8407839a050SYann Gautier 
8410d21680cSYann Gautier 	cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2);
8427839a050SYann Gautier 	divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK;
8437839a050SYann Gautier 
8440d21680cSYann Gautier 	dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U);
8457839a050SYann Gautier 
8467839a050SYann Gautier 	return dfout;
8477839a050SYann Gautier }
8487839a050SYann Gautier 
8490d21680cSYann Gautier static unsigned long get_clock_rate(int p)
8507839a050SYann Gautier {
8517839a050SYann Gautier 	uint32_t reg, clkdiv;
8527839a050SYann Gautier 	unsigned long clock = 0;
8530d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
8547839a050SYann Gautier 
8557839a050SYann Gautier 	switch (p) {
8567839a050SYann Gautier 	case _CK_MPU:
8577839a050SYann Gautier 	/* MPU sub system */
8580d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MPCKSELR);
8597839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
8607839a050SYann Gautier 		case RCC_MPCKSELR_HSI:
8610d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
8627839a050SYann Gautier 			break;
8637839a050SYann Gautier 		case RCC_MPCKSELR_HSE:
8640d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
8657839a050SYann Gautier 			break;
8667839a050SYann Gautier 		case RCC_MPCKSELR_PLL:
8670d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
8687839a050SYann Gautier 			break;
8697839a050SYann Gautier 		case RCC_MPCKSELR_PLL_MPUDIV:
8700d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
8717839a050SYann Gautier 
8720d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_MPCKDIVR);
8737839a050SYann Gautier 			clkdiv = reg & RCC_MPUDIV_MASK;
874602ae2f2SGabriel Fernandez 			clock >>= stm32mp1_mpu_div[clkdiv];
8757839a050SYann Gautier 			break;
8767839a050SYann Gautier 		default:
8777839a050SYann Gautier 			break;
8787839a050SYann Gautier 		}
8797839a050SYann Gautier 		break;
8807839a050SYann Gautier 	/* AXI sub system */
8817839a050SYann Gautier 	case _ACLK:
8827839a050SYann Gautier 	case _HCLK2:
8837839a050SYann Gautier 	case _HCLK6:
8847839a050SYann Gautier 	case _PCLK4:
8857839a050SYann Gautier 	case _PCLK5:
8860d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_ASSCKSELR);
8877839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
8887839a050SYann Gautier 		case RCC_ASSCKSELR_HSI:
8890d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
8907839a050SYann Gautier 			break;
8917839a050SYann Gautier 		case RCC_ASSCKSELR_HSE:
8920d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
8937839a050SYann Gautier 			break;
8947839a050SYann Gautier 		case RCC_ASSCKSELR_PLL:
8950d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
8967839a050SYann Gautier 			break;
8977839a050SYann Gautier 		default:
8987839a050SYann Gautier 			break;
8997839a050SYann Gautier 		}
9007839a050SYann Gautier 
9017839a050SYann Gautier 		/* System clock divider */
9020d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_AXIDIVR);
9037839a050SYann Gautier 		clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK];
9047839a050SYann Gautier 
9057839a050SYann Gautier 		switch (p) {
9067839a050SYann Gautier 		case _PCLK4:
9070d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB4DIVR);
9087839a050SYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
9097839a050SYann Gautier 			break;
9107839a050SYann Gautier 		case _PCLK5:
9110d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB5DIVR);
9127839a050SYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
9137839a050SYann Gautier 			break;
9147839a050SYann Gautier 		default:
9157839a050SYann Gautier 			break;
9167839a050SYann Gautier 		}
9177839a050SYann Gautier 		break;
918b053a22eSYann Gautier 	/* MCU sub system */
919b053a22eSYann Gautier 	case _CK_MCU:
920b053a22eSYann Gautier 	case _PCLK1:
921b053a22eSYann Gautier 	case _PCLK2:
922b053a22eSYann Gautier 	case _PCLK3:
923b053a22eSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MSSCKSELR);
924b053a22eSYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
925b053a22eSYann Gautier 		case RCC_MSSCKSELR_HSI:
926b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
927b053a22eSYann Gautier 			break;
928b053a22eSYann Gautier 		case RCC_MSSCKSELR_HSE:
929b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
930b053a22eSYann Gautier 			break;
931b053a22eSYann Gautier 		case RCC_MSSCKSELR_CSI:
932b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_CSI);
933b053a22eSYann Gautier 			break;
934b053a22eSYann Gautier 		case RCC_MSSCKSELR_PLL:
935b053a22eSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
936b053a22eSYann Gautier 			break;
937b053a22eSYann Gautier 		default:
938b053a22eSYann Gautier 			break;
939b053a22eSYann Gautier 		}
940b053a22eSYann Gautier 
941b053a22eSYann Gautier 		/* MCU clock divider */
942b053a22eSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MCUDIVR);
943b053a22eSYann Gautier 		clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK];
944b053a22eSYann Gautier 
945b053a22eSYann Gautier 		switch (p) {
946b053a22eSYann Gautier 		case _PCLK1:
947b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB1DIVR);
948b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
949b053a22eSYann Gautier 			break;
950b053a22eSYann Gautier 		case _PCLK2:
951b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB2DIVR);
952b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
953b053a22eSYann Gautier 			break;
954b053a22eSYann Gautier 		case _PCLK3:
955b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB3DIVR);
956b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
957b053a22eSYann Gautier 			break;
958b053a22eSYann Gautier 		case _CK_MCU:
959b053a22eSYann Gautier 		default:
960b053a22eSYann Gautier 			break;
961b053a22eSYann Gautier 		}
962b053a22eSYann Gautier 		break;
9637839a050SYann Gautier 	case _CK_PER:
9640d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_CPERCKSELR);
9657839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
9667839a050SYann Gautier 		case RCC_CPERCKSELR_HSI:
9670d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
9687839a050SYann Gautier 			break;
9697839a050SYann Gautier 		case RCC_CPERCKSELR_HSE:
9700d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
9717839a050SYann Gautier 			break;
9727839a050SYann Gautier 		case RCC_CPERCKSELR_CSI:
9730d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_CSI);
9747839a050SYann Gautier 			break;
9757839a050SYann Gautier 		default:
9767839a050SYann Gautier 			break;
9777839a050SYann Gautier 		}
9787839a050SYann Gautier 		break;
9797839a050SYann Gautier 	case _HSI:
9807839a050SYann Gautier 	case _HSI_KER:
9810d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSI);
9827839a050SYann Gautier 		break;
9837839a050SYann Gautier 	case _CSI:
9847839a050SYann Gautier 	case _CSI_KER:
9850d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_CSI);
9867839a050SYann Gautier 		break;
9877839a050SYann Gautier 	case _HSE:
9887839a050SYann Gautier 	case _HSE_KER:
9890d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSE);
9907839a050SYann Gautier 		break;
9917839a050SYann Gautier 	case _HSE_KER_DIV2:
9920d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSE) >> 1;
9937839a050SYann Gautier 		break;
994cbd2e8a6SGabriel Fernandez 	case _HSE_RTC:
995cbd2e8a6SGabriel Fernandez 		clock = stm32mp1_clk_get_fixed(_HSE);
996cbd2e8a6SGabriel Fernandez 		clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U;
997cbd2e8a6SGabriel Fernandez 		break;
9987839a050SYann Gautier 	case _LSI:
9990d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_LSI);
10007839a050SYann Gautier 		break;
10017839a050SYann Gautier 	case _LSE:
10020d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_LSE);
10037839a050SYann Gautier 		break;
10047839a050SYann Gautier 	/* PLL */
10057839a050SYann Gautier 	case _PLL1_P:
10060d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
10077839a050SYann Gautier 		break;
10087839a050SYann Gautier 	case _PLL1_Q:
10090d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q);
10107839a050SYann Gautier 		break;
10117839a050SYann Gautier 	case _PLL1_R:
10120d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R);
10137839a050SYann Gautier 		break;
10147839a050SYann Gautier 	case _PLL2_P:
10150d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
10167839a050SYann Gautier 		break;
10177839a050SYann Gautier 	case _PLL2_Q:
10180d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q);
10197839a050SYann Gautier 		break;
10207839a050SYann Gautier 	case _PLL2_R:
10210d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R);
10227839a050SYann Gautier 		break;
10237839a050SYann Gautier 	case _PLL3_P:
10240d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
10257839a050SYann Gautier 		break;
10267839a050SYann Gautier 	case _PLL3_Q:
10270d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q);
10287839a050SYann Gautier 		break;
10297839a050SYann Gautier 	case _PLL3_R:
10300d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R);
10317839a050SYann Gautier 		break;
10327839a050SYann Gautier 	case _PLL4_P:
10330d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P);
10347839a050SYann Gautier 		break;
10357839a050SYann Gautier 	case _PLL4_Q:
10360d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q);
10377839a050SYann Gautier 		break;
10387839a050SYann Gautier 	case _PLL4_R:
10390d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R);
10407839a050SYann Gautier 		break;
10417839a050SYann Gautier 	/* Other */
10427839a050SYann Gautier 	case _USB_PHY_48:
10430d21680cSYann Gautier 		clock = USB_PHY_48_MHZ;
10447839a050SYann Gautier 		break;
10457839a050SYann Gautier 	default:
10467839a050SYann Gautier 		break;
10477839a050SYann Gautier 	}
10487839a050SYann Gautier 
10497839a050SYann Gautier 	return clock;
10507839a050SYann Gautier }
10517839a050SYann Gautier 
10520d21680cSYann Gautier static void __clk_enable(struct stm32mp1_clk_gate const *gate)
10530d21680cSYann Gautier {
10540d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10550d21680cSYann Gautier 
105625be845eSEtienne Carriere 	VERBOSE("Enable clock %u\n", gate->index);
105725be845eSEtienne Carriere 
10580d21680cSYann Gautier 	if (gate->set_clr != 0U) {
10590d21680cSYann Gautier 		mmio_write_32(rcc_base + gate->offset, BIT(gate->bit));
10600d21680cSYann Gautier 	} else {
10610d21680cSYann Gautier 		mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit));
10620d21680cSYann Gautier 	}
10630d21680cSYann Gautier }
10640d21680cSYann Gautier 
10650d21680cSYann Gautier static void __clk_disable(struct stm32mp1_clk_gate const *gate)
10660d21680cSYann Gautier {
10670d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10680d21680cSYann Gautier 
106925be845eSEtienne Carriere 	VERBOSE("Disable clock %u\n", gate->index);
107025be845eSEtienne Carriere 
10710d21680cSYann Gautier 	if (gate->set_clr != 0U) {
10720d21680cSYann Gautier 		mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET,
10730d21680cSYann Gautier 			      BIT(gate->bit));
10740d21680cSYann Gautier 	} else {
10750d21680cSYann Gautier 		mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit));
10760d21680cSYann Gautier 	}
10770d21680cSYann Gautier }
10780d21680cSYann Gautier 
10790d21680cSYann Gautier static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate)
10800d21680cSYann Gautier {
10810d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10820d21680cSYann Gautier 
10830d21680cSYann Gautier 	return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit);
10840d21680cSYann Gautier }
10850d21680cSYann Gautier 
108635848200SEtienne Carriere /* Oscillators and PLLs are not gated at runtime */
108735848200SEtienne Carriere static bool clock_is_always_on(unsigned long id)
108835848200SEtienne Carriere {
108935848200SEtienne Carriere 	switch (id) {
109035848200SEtienne Carriere 	case CK_HSE:
109135848200SEtienne Carriere 	case CK_CSI:
109235848200SEtienne Carriere 	case CK_LSI:
109335848200SEtienne Carriere 	case CK_LSE:
109435848200SEtienne Carriere 	case CK_HSI:
109535848200SEtienne Carriere 	case CK_HSE_DIV2:
109635848200SEtienne Carriere 	case PLL1_Q:
109735848200SEtienne Carriere 	case PLL1_R:
109835848200SEtienne Carriere 	case PLL2_P:
109935848200SEtienne Carriere 	case PLL2_Q:
110035848200SEtienne Carriere 	case PLL2_R:
110135848200SEtienne Carriere 	case PLL3_P:
110235848200SEtienne Carriere 	case PLL3_Q:
110335848200SEtienne Carriere 	case PLL3_R:
1104bf39318dSYann Gautier 	case CK_AXI:
1105bf39318dSYann Gautier 	case CK_MPU:
1106bf39318dSYann Gautier 	case CK_MCU:
11075b111c74SHE Shushan 	case RTC:
110835848200SEtienne Carriere 		return true;
110935848200SEtienne Carriere 	default:
111035848200SEtienne Carriere 		return false;
111135848200SEtienne Carriere 	}
111235848200SEtienne Carriere }
111335848200SEtienne Carriere 
11142444d231SYann Gautier static void __stm32mp1_clk_enable(unsigned long id, bool with_refcnt)
11150d21680cSYann Gautier {
11160d21680cSYann Gautier 	const struct stm32mp1_clk_gate *gate;
111735848200SEtienne Carriere 	int i;
11180d21680cSYann Gautier 
111935848200SEtienne Carriere 	if (clock_is_always_on(id)) {
112035848200SEtienne Carriere 		return;
112135848200SEtienne Carriere 	}
112235848200SEtienne Carriere 
112335848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
11240d21680cSYann Gautier 	if (i < 0) {
112544fb470bSYann Gautier 		ERROR("Clock %lu can't be enabled\n", id);
11260d21680cSYann Gautier 		panic();
11270d21680cSYann Gautier 	}
11280d21680cSYann Gautier 
11290d21680cSYann Gautier 	gate = gate_ref(i);
11302444d231SYann Gautier 
11312444d231SYann Gautier 	if (!with_refcnt) {
11322444d231SYann Gautier 		__clk_enable(gate);
11332444d231SYann Gautier 		return;
11342444d231SYann Gautier 	}
11350d21680cSYann Gautier 
11363d69149aSYann Gautier #if defined(IMAGE_BL32)
11373d69149aSYann Gautier 	if (gate_is_non_secure(gate)) {
11383d69149aSYann Gautier 		/* Enable non-secure clock w/o any refcounting */
11393d69149aSYann Gautier 		__clk_enable(gate);
11403d69149aSYann Gautier 		return;
11413d69149aSYann Gautier 	}
11423d69149aSYann Gautier #endif
11433d69149aSYann Gautier 
11440d21680cSYann Gautier 	stm32mp1_clk_lock(&refcount_lock);
11450d21680cSYann Gautier 
11462444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
11470d21680cSYann Gautier 		__clk_enable(gate);
11480d21680cSYann Gautier 	}
11490d21680cSYann Gautier 
11502444d231SYann Gautier 	gate_refcounts[i]++;
11512444d231SYann Gautier 	if (gate_refcounts[i] == UINT_MAX) {
11522444d231SYann Gautier 		ERROR("Clock %lu refcount reached max value\n", id);
11532444d231SYann Gautier 		panic();
11542444d231SYann Gautier 	}
11552444d231SYann Gautier 
11560d21680cSYann Gautier 	stm32mp1_clk_unlock(&refcount_lock);
11570d21680cSYann Gautier }
11580d21680cSYann Gautier 
11592444d231SYann Gautier static void __stm32mp1_clk_disable(unsigned long id, bool with_refcnt)
11600d21680cSYann Gautier {
11610d21680cSYann Gautier 	const struct stm32mp1_clk_gate *gate;
116235848200SEtienne Carriere 	int i;
11630d21680cSYann Gautier 
116435848200SEtienne Carriere 	if (clock_is_always_on(id)) {
116535848200SEtienne Carriere 		return;
116635848200SEtienne Carriere 	}
116735848200SEtienne Carriere 
116835848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
11690d21680cSYann Gautier 	if (i < 0) {
117044fb470bSYann Gautier 		ERROR("Clock %lu can't be disabled\n", id);
11710d21680cSYann Gautier 		panic();
11720d21680cSYann Gautier 	}
11730d21680cSYann Gautier 
11740d21680cSYann Gautier 	gate = gate_ref(i);
11752444d231SYann Gautier 
11762444d231SYann Gautier 	if (!with_refcnt) {
11772444d231SYann Gautier 		__clk_disable(gate);
11782444d231SYann Gautier 		return;
11792444d231SYann Gautier 	}
11800d21680cSYann Gautier 
11813d69149aSYann Gautier #if defined(IMAGE_BL32)
11823d69149aSYann Gautier 	if (gate_is_non_secure(gate)) {
11833d69149aSYann Gautier 		/* Don't disable non-secure clocks */
11843d69149aSYann Gautier 		return;
11853d69149aSYann Gautier 	}
11863d69149aSYann Gautier #endif
11873d69149aSYann Gautier 
11880d21680cSYann Gautier 	stm32mp1_clk_lock(&refcount_lock);
11890d21680cSYann Gautier 
11902444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
11912444d231SYann Gautier 		ERROR("Clock %lu refcount reached 0\n", id);
11922444d231SYann Gautier 		panic();
11932444d231SYann Gautier 	}
11942444d231SYann Gautier 	gate_refcounts[i]--;
11952444d231SYann Gautier 
11962444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
11970d21680cSYann Gautier 		__clk_disable(gate);
11980d21680cSYann Gautier 	}
11990d21680cSYann Gautier 
12000d21680cSYann Gautier 	stm32mp1_clk_unlock(&refcount_lock);
12010d21680cSYann Gautier }
12020d21680cSYann Gautier 
120333667d29SYann Gautier static int stm32mp_clk_enable(unsigned long id)
12040d21680cSYann Gautier {
12050d21680cSYann Gautier 	__stm32mp1_clk_enable(id, true);
120633667d29SYann Gautier 
120733667d29SYann Gautier 	return 0;
12080d21680cSYann Gautier }
12090d21680cSYann Gautier 
121033667d29SYann Gautier static void stm32mp_clk_disable(unsigned long id)
12110d21680cSYann Gautier {
12120d21680cSYann Gautier 	__stm32mp1_clk_disable(id, true);
12130d21680cSYann Gautier }
12140d21680cSYann Gautier 
121533667d29SYann Gautier static bool stm32mp_clk_is_enabled(unsigned long id)
12167839a050SYann Gautier {
121735848200SEtienne Carriere 	int i;
12187839a050SYann Gautier 
121935848200SEtienne Carriere 	if (clock_is_always_on(id)) {
122035848200SEtienne Carriere 		return true;
122135848200SEtienne Carriere 	}
122235848200SEtienne Carriere 
122335848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
12247839a050SYann Gautier 	if (i < 0) {
12250d21680cSYann Gautier 		panic();
12267839a050SYann Gautier 	}
12277839a050SYann Gautier 
12280d21680cSYann Gautier 	return __clk_is_enabled(gate_ref(i));
12297839a050SYann Gautier }
12307839a050SYann Gautier 
123133667d29SYann Gautier static unsigned long stm32mp_clk_get_rate(unsigned long id)
12327839a050SYann Gautier {
123333667d29SYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
12340d21680cSYann Gautier 	int p = stm32mp1_clk_get_parent(id);
123533667d29SYann Gautier 	uint32_t prescaler, timpre;
123633667d29SYann Gautier 	unsigned long parent_rate;
12377839a050SYann Gautier 
12387839a050SYann Gautier 	if (p < 0) {
12397839a050SYann Gautier 		return 0;
12407839a050SYann Gautier 	}
12417839a050SYann Gautier 
124233667d29SYann Gautier 	parent_rate = get_clock_rate(p);
124333667d29SYann Gautier 
124433667d29SYann Gautier 	switch (id) {
124533667d29SYann Gautier 	case TIM2_K:
124633667d29SYann Gautier 	case TIM3_K:
124733667d29SYann Gautier 	case TIM4_K:
124833667d29SYann Gautier 	case TIM5_K:
124933667d29SYann Gautier 	case TIM6_K:
125033667d29SYann Gautier 	case TIM7_K:
125133667d29SYann Gautier 	case TIM12_K:
125233667d29SYann Gautier 	case TIM13_K:
125333667d29SYann Gautier 	case TIM14_K:
125433667d29SYann Gautier 		prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) &
125533667d29SYann Gautier 			    RCC_APBXDIV_MASK;
125633667d29SYann Gautier 		timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) &
125733667d29SYann Gautier 			 RCC_TIMGXPRER_TIMGXPRE;
125833667d29SYann Gautier 		break;
125933667d29SYann Gautier 
126033667d29SYann Gautier 	case TIM1_K:
126133667d29SYann Gautier 	case TIM8_K:
126233667d29SYann Gautier 	case TIM15_K:
126333667d29SYann Gautier 	case TIM16_K:
126433667d29SYann Gautier 	case TIM17_K:
126533667d29SYann Gautier 		prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) &
126633667d29SYann Gautier 			    RCC_APBXDIV_MASK;
126733667d29SYann Gautier 		timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) &
126833667d29SYann Gautier 			 RCC_TIMGXPRER_TIMGXPRE;
126933667d29SYann Gautier 		break;
127033667d29SYann Gautier 
127133667d29SYann Gautier 	default:
127233667d29SYann Gautier 		return parent_rate;
127333667d29SYann Gautier 	}
127433667d29SYann Gautier 
127533667d29SYann Gautier 	if (prescaler == 0U) {
127633667d29SYann Gautier 		return parent_rate;
127733667d29SYann Gautier 	}
127833667d29SYann Gautier 
127933667d29SYann Gautier 	return parent_rate * (timpre + 1U) * 2U;
12807839a050SYann Gautier }
12817839a050SYann Gautier 
12820d21680cSYann Gautier static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on)
12837839a050SYann Gautier {
12840d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
12857839a050SYann Gautier 
12860d21680cSYann Gautier 	if (enable) {
12877839a050SYann Gautier 		mmio_setbits_32(address, mask_on);
12887839a050SYann Gautier 	} else {
12897839a050SYann Gautier 		mmio_clrbits_32(address, mask_on);
12907839a050SYann Gautier 	}
12917839a050SYann Gautier }
12927839a050SYann Gautier 
12930d21680cSYann Gautier static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on)
12947839a050SYann Gautier {
12950d21680cSYann Gautier 	uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR;
12960d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
12970d21680cSYann Gautier 
12980d21680cSYann Gautier 	mmio_write_32(address, mask_on);
12997839a050SYann Gautier }
13007839a050SYann Gautier 
13010d21680cSYann Gautier static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy)
13027839a050SYann Gautier {
1303dfdb057aSYann Gautier 	uint64_t timeout;
13047839a050SYann Gautier 	uint32_t mask_test;
13050d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
13067839a050SYann Gautier 
13070d21680cSYann Gautier 	if (enable) {
13087839a050SYann Gautier 		mask_test = mask_rdy;
13097839a050SYann Gautier 	} else {
13107839a050SYann Gautier 		mask_test = 0;
13117839a050SYann Gautier 	}
13127839a050SYann Gautier 
1313dfdb057aSYann Gautier 	timeout = timeout_init_us(OSCRDY_TIMEOUT);
13147839a050SYann Gautier 	while ((mmio_read_32(address) & mask_rdy) != mask_test) {
1315dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
13160d21680cSYann Gautier 			ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n",
13177839a050SYann Gautier 			      mask_rdy, address, enable, mmio_read_32(address));
13187839a050SYann Gautier 			return -ETIMEDOUT;
13197839a050SYann Gautier 		}
13207839a050SYann Gautier 	}
13217839a050SYann Gautier 
13227839a050SYann Gautier 	return 0;
13237839a050SYann Gautier }
13247839a050SYann Gautier 
13250d21680cSYann Gautier static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv)
13267839a050SYann Gautier {
13277839a050SYann Gautier 	uint32_t value;
13280d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13297839a050SYann Gautier 
1330*f4a2bb98SYann Gautier 	/* Do not reconfigure LSE if it is already ON */
1331*f4a2bb98SYann Gautier 	if ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEON) == RCC_BDCR_LSEON) {
1332*f4a2bb98SYann Gautier 		return;
1333*f4a2bb98SYann Gautier 	}
1334*f4a2bb98SYann Gautier 
13350d21680cSYann Gautier 	if (digbyp) {
13360d21680cSYann Gautier 		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP);
13370d21680cSYann Gautier 	}
13380d21680cSYann Gautier 
13390d21680cSYann Gautier 	if (bypass || digbyp) {
13400d21680cSYann Gautier 		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP);
13417839a050SYann Gautier 	}
13427839a050SYann Gautier 
13437839a050SYann Gautier 	/*
13447839a050SYann Gautier 	 * Warning: not recommended to switch directly from "high drive"
13457839a050SYann Gautier 	 * to "medium low drive", and vice-versa.
13467839a050SYann Gautier 	 */
13470d21680cSYann Gautier 	value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >>
13487839a050SYann Gautier 		RCC_BDCR_LSEDRV_SHIFT;
13497839a050SYann Gautier 
13507839a050SYann Gautier 	while (value != lsedrv) {
13517839a050SYann Gautier 		if (value > lsedrv) {
13527839a050SYann Gautier 			value--;
13537839a050SYann Gautier 		} else {
13547839a050SYann Gautier 			value++;
13557839a050SYann Gautier 		}
13567839a050SYann Gautier 
13570d21680cSYann Gautier 		mmio_clrsetbits_32(rcc_base + RCC_BDCR,
13587839a050SYann Gautier 				   RCC_BDCR_LSEDRV_MASK,
13597839a050SYann Gautier 				   value << RCC_BDCR_LSEDRV_SHIFT);
13607839a050SYann Gautier 	}
13617839a050SYann Gautier 
13620d21680cSYann Gautier 	stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON);
13637839a050SYann Gautier }
13647839a050SYann Gautier 
13650d21680cSYann Gautier static void stm32mp1_lse_wait(void)
13667839a050SYann Gautier {
13670d21680cSYann Gautier 	if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) {
13687839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
13697839a050SYann Gautier 	}
13707839a050SYann Gautier }
13717839a050SYann Gautier 
13720d21680cSYann Gautier static void stm32mp1_lsi_set(bool enable)
13737839a050SYann Gautier {
13740d21680cSYann Gautier 	stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION);
13750d21680cSYann Gautier 
13760d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) {
13777839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
13787839a050SYann Gautier 	}
13797839a050SYann Gautier }
13807839a050SYann Gautier 
13810d21680cSYann Gautier static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css)
13827839a050SYann Gautier {
13830d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13840d21680cSYann Gautier 
13850d21680cSYann Gautier 	if (digbyp) {
13860d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP);
13877839a050SYann Gautier 	}
13887839a050SYann Gautier 
13890d21680cSYann Gautier 	if (bypass || digbyp) {
13900d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP);
13910d21680cSYann Gautier 	}
13920d21680cSYann Gautier 
13930d21680cSYann Gautier 	stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON);
13940d21680cSYann Gautier 	if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) {
13957839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
13967839a050SYann Gautier 	}
13977839a050SYann Gautier 
13987839a050SYann Gautier 	if (css) {
13990d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON);
14007839a050SYann Gautier 	}
140131e9750bSLionel Debieve 
140231e9750bSLionel Debieve #if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
140331e9750bSLionel Debieve 	if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) &&
140431e9750bSLionel Debieve 	    (!(digbyp || bypass))) {
140531e9750bSLionel Debieve 		panic();
140631e9750bSLionel Debieve 	}
140731e9750bSLionel Debieve #endif
14087839a050SYann Gautier }
14097839a050SYann Gautier 
14100d21680cSYann Gautier static void stm32mp1_csi_set(bool enable)
14117839a050SYann Gautier {
14120d21680cSYann Gautier 	stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION);
14130d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) {
14147839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
14157839a050SYann Gautier 	}
14167839a050SYann Gautier }
14177839a050SYann Gautier 
14180d21680cSYann Gautier static void stm32mp1_hsi_set(bool enable)
14197839a050SYann Gautier {
14200d21680cSYann Gautier 	stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION);
14210d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) {
14227839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
14237839a050SYann Gautier 	}
14247839a050SYann Gautier }
14257839a050SYann Gautier 
14260d21680cSYann Gautier static int stm32mp1_set_hsidiv(uint8_t hsidiv)
14277839a050SYann Gautier {
1428dfdb057aSYann Gautier 	uint64_t timeout;
14290d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
14300d21680cSYann Gautier 	uintptr_t address = rcc_base + RCC_OCRDYR;
14317839a050SYann Gautier 
14320d21680cSYann Gautier 	mmio_clrsetbits_32(rcc_base + RCC_HSICFGR,
14337839a050SYann Gautier 			   RCC_HSICFGR_HSIDIV_MASK,
14347839a050SYann Gautier 			   RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv);
14357839a050SYann Gautier 
1436dfdb057aSYann Gautier 	timeout = timeout_init_us(HSIDIV_TIMEOUT);
14377839a050SYann Gautier 	while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) {
1438dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
14390d21680cSYann Gautier 			ERROR("HSIDIV failed @ 0x%lx: 0x%x\n",
14407839a050SYann Gautier 			      address, mmio_read_32(address));
14417839a050SYann Gautier 			return -ETIMEDOUT;
14427839a050SYann Gautier 		}
14437839a050SYann Gautier 	}
14447839a050SYann Gautier 
14457839a050SYann Gautier 	return 0;
14467839a050SYann Gautier }
14477839a050SYann Gautier 
14480d21680cSYann Gautier static int stm32mp1_hsidiv(unsigned long hsifreq)
14497839a050SYann Gautier {
14507839a050SYann Gautier 	uint8_t hsidiv;
14517839a050SYann Gautier 	uint32_t hsidivfreq = MAX_HSI_HZ;
14527839a050SYann Gautier 
14537839a050SYann Gautier 	for (hsidiv = 0; hsidiv < 4U; hsidiv++) {
14547839a050SYann Gautier 		if (hsidivfreq == hsifreq) {
14557839a050SYann Gautier 			break;
14567839a050SYann Gautier 		}
14577839a050SYann Gautier 
14587839a050SYann Gautier 		hsidivfreq /= 2U;
14597839a050SYann Gautier 	}
14607839a050SYann Gautier 
14617839a050SYann Gautier 	if (hsidiv == 4U) {
14627839a050SYann Gautier 		ERROR("Invalid clk-hsi frequency\n");
14637839a050SYann Gautier 		return -1;
14647839a050SYann Gautier 	}
14657839a050SYann Gautier 
14667839a050SYann Gautier 	if (hsidiv != 0U) {
14670d21680cSYann Gautier 		return stm32mp1_set_hsidiv(hsidiv);
14687839a050SYann Gautier 	}
14697839a050SYann Gautier 
14707839a050SYann Gautier 	return 0;
14717839a050SYann Gautier }
14727839a050SYann Gautier 
14730d21680cSYann Gautier static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id,
14740d21680cSYann Gautier 				    unsigned int clksrc,
14750d21680cSYann Gautier 				    uint32_t *pllcfg, int plloff)
14767839a050SYann Gautier {
14770d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
14780d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
14790d21680cSYann Gautier 	uintptr_t pllxcr = rcc_base + pll->pllxcr;
14800d21680cSYann Gautier 	enum stm32mp1_plltype type = pll->plltype;
14810d21680cSYann Gautier 	uintptr_t clksrc_address = rcc_base + (clksrc >> 4);
14820d21680cSYann Gautier 	unsigned long refclk;
14830d21680cSYann Gautier 	uint32_t ifrge = 0U;
1484be858cffSAndre Przywara 	uint32_t src, value, fracv = 0;
1485be858cffSAndre Przywara 	void *fdt;
14867839a050SYann Gautier 
14870d21680cSYann Gautier 	/* Check PLL output */
14880d21680cSYann Gautier 	if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) {
14890d21680cSYann Gautier 		return false;
14907839a050SYann Gautier 	}
14917839a050SYann Gautier 
14920d21680cSYann Gautier 	/* Check current clksrc */
14930d21680cSYann Gautier 	src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK;
14940d21680cSYann Gautier 	if (src != (clksrc & RCC_SELR_SRC_MASK)) {
14950d21680cSYann Gautier 		return false;
14960d21680cSYann Gautier 	}
14970d21680cSYann Gautier 
14980d21680cSYann Gautier 	/* Check Div */
14990d21680cSYann Gautier 	src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK;
15000d21680cSYann Gautier 
15010d21680cSYann Gautier 	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
15020d21680cSYann Gautier 		 (pllcfg[PLLCFG_M] + 1U);
15030d21680cSYann Gautier 
15040d21680cSYann Gautier 	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
15050d21680cSYann Gautier 	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
15060d21680cSYann Gautier 		return false;
15070d21680cSYann Gautier 	}
15080d21680cSYann Gautier 
15090d21680cSYann Gautier 	if ((type == PLL_800) && (refclk >= 8000000U)) {
15100d21680cSYann Gautier 		ifrge = 1U;
15110d21680cSYann Gautier 	}
15120d21680cSYann Gautier 
15130d21680cSYann Gautier 	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
15140d21680cSYann Gautier 		RCC_PLLNCFGR1_DIVN_MASK;
15150d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
15160d21680cSYann Gautier 		 RCC_PLLNCFGR1_DIVM_MASK;
15170d21680cSYann Gautier 	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
15180d21680cSYann Gautier 		 RCC_PLLNCFGR1_IFRGE_MASK;
15190d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) {
15200d21680cSYann Gautier 		return false;
15210d21680cSYann Gautier 	}
15220d21680cSYann Gautier 
15230d21680cSYann Gautier 	/* Fractional configuration */
1524be858cffSAndre Przywara 	if (fdt_get_address(&fdt) == 1) {
1525be858cffSAndre Przywara 		fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0);
1526be858cffSAndre Przywara 	}
15270d21680cSYann Gautier 
15280d21680cSYann Gautier 	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
15290d21680cSYann Gautier 	value |= RCC_PLLNFRACR_FRACLE;
15300d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxfracr) != value) {
15310d21680cSYann Gautier 		return false;
15320d21680cSYann Gautier 	}
15330d21680cSYann Gautier 
15340d21680cSYann Gautier 	/* Output config */
15350d21680cSYann Gautier 	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
15360d21680cSYann Gautier 		RCC_PLLNCFGR2_DIVP_MASK;
15370d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
15380d21680cSYann Gautier 		 RCC_PLLNCFGR2_DIVQ_MASK;
15390d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
15400d21680cSYann Gautier 		 RCC_PLLNCFGR2_DIVR_MASK;
15410d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) {
15420d21680cSYann Gautier 		return false;
15430d21680cSYann Gautier 	}
15440d21680cSYann Gautier 
15450d21680cSYann Gautier 	return true;
15460d21680cSYann Gautier }
15470d21680cSYann Gautier 
15480d21680cSYann Gautier static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id)
15497839a050SYann Gautier {
15500d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
15510d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
15520d21680cSYann Gautier 
1553dd98aec8SYann Gautier 	/* Preserve RCC_PLLNCR_SSCG_CTRL value */
1554dd98aec8SYann Gautier 	mmio_clrsetbits_32(pllxcr,
1555dd98aec8SYann Gautier 			   RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
1556dd98aec8SYann Gautier 			   RCC_PLLNCR_DIVREN,
1557dd98aec8SYann Gautier 			   RCC_PLLNCR_PLLON);
15580d21680cSYann Gautier }
15590d21680cSYann Gautier 
15600d21680cSYann Gautier static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output)
15610d21680cSYann Gautier {
15620d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
15630d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
1564dfdb057aSYann Gautier 	uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT);
15657839a050SYann Gautier 
15667839a050SYann Gautier 	/* Wait PLL lock */
15677839a050SYann Gautier 	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) {
1568dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
15699fa9a0c5SYann Gautier 			ERROR("PLL%u start failed @ 0x%lx: 0x%x\n",
15707839a050SYann Gautier 			      pll_id, pllxcr, mmio_read_32(pllxcr));
15717839a050SYann Gautier 			return -ETIMEDOUT;
15727839a050SYann Gautier 		}
15737839a050SYann Gautier 	}
15747839a050SYann Gautier 
15757839a050SYann Gautier 	/* Start the requested output */
15767839a050SYann Gautier 	mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT);
15777839a050SYann Gautier 
15787839a050SYann Gautier 	return 0;
15797839a050SYann Gautier }
15807839a050SYann Gautier 
15810d21680cSYann Gautier static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id)
15827839a050SYann Gautier {
15830d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
15840d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
1585dfdb057aSYann Gautier 	uint64_t timeout;
15867839a050SYann Gautier 
15877839a050SYann Gautier 	/* Stop all output */
15887839a050SYann Gautier 	mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
15897839a050SYann Gautier 			RCC_PLLNCR_DIVREN);
15907839a050SYann Gautier 
15917839a050SYann Gautier 	/* Stop PLL */
15927839a050SYann Gautier 	mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON);
15937839a050SYann Gautier 
1594dfdb057aSYann Gautier 	timeout = timeout_init_us(PLLRDY_TIMEOUT);
15957839a050SYann Gautier 	/* Wait PLL stopped */
15967839a050SYann Gautier 	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) {
1597dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
15989fa9a0c5SYann Gautier 			ERROR("PLL%u stop failed @ 0x%lx: 0x%x\n",
15997839a050SYann Gautier 			      pll_id, pllxcr, mmio_read_32(pllxcr));
16007839a050SYann Gautier 			return -ETIMEDOUT;
16017839a050SYann Gautier 		}
16027839a050SYann Gautier 	}
16037839a050SYann Gautier 
16047839a050SYann Gautier 	return 0;
16057839a050SYann Gautier }
16067839a050SYann Gautier 
16070d21680cSYann Gautier static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id,
16087839a050SYann Gautier 				       uint32_t *pllcfg)
16097839a050SYann Gautier {
16100d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
16110d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
16127839a050SYann Gautier 	uint32_t value;
16137839a050SYann Gautier 
16147839a050SYann Gautier 	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
16157839a050SYann Gautier 		RCC_PLLNCFGR2_DIVP_MASK;
16167839a050SYann Gautier 	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
16177839a050SYann Gautier 		 RCC_PLLNCFGR2_DIVQ_MASK;
16187839a050SYann Gautier 	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
16197839a050SYann Gautier 		 RCC_PLLNCFGR2_DIVR_MASK;
16200d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxcfgr2, value);
16217839a050SYann Gautier }
16227839a050SYann Gautier 
16230d21680cSYann Gautier static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id,
16247839a050SYann Gautier 			       uint32_t *pllcfg, uint32_t fracv)
16257839a050SYann Gautier {
16260d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
16270d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
16280d21680cSYann Gautier 	enum stm32mp1_plltype type = pll->plltype;
16297839a050SYann Gautier 	unsigned long refclk;
16307839a050SYann Gautier 	uint32_t ifrge = 0;
16317839a050SYann Gautier 	uint32_t src, value;
16327839a050SYann Gautier 
16330d21680cSYann Gautier 	src = mmio_read_32(rcc_base + pll->rckxselr) &
16347839a050SYann Gautier 		RCC_SELR_REFCLK_SRC_MASK;
16357839a050SYann Gautier 
16360d21680cSYann Gautier 	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
16377839a050SYann Gautier 		 (pllcfg[PLLCFG_M] + 1U);
16387839a050SYann Gautier 
16397839a050SYann Gautier 	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
16407839a050SYann Gautier 	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
16417839a050SYann Gautier 		return -EINVAL;
16427839a050SYann Gautier 	}
16437839a050SYann Gautier 
16447839a050SYann Gautier 	if ((type == PLL_800) && (refclk >= 8000000U)) {
16457839a050SYann Gautier 		ifrge = 1U;
16467839a050SYann Gautier 	}
16477839a050SYann Gautier 
16487839a050SYann Gautier 	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
16497839a050SYann Gautier 		RCC_PLLNCFGR1_DIVN_MASK;
16507839a050SYann Gautier 	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
16517839a050SYann Gautier 		 RCC_PLLNCFGR1_DIVM_MASK;
16527839a050SYann Gautier 	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
16537839a050SYann Gautier 		 RCC_PLLNCFGR1_IFRGE_MASK;
16540d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxcfgr1, value);
16557839a050SYann Gautier 
16567839a050SYann Gautier 	/* Fractional configuration */
16577839a050SYann Gautier 	value = 0;
16580d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
16597839a050SYann Gautier 
16607839a050SYann Gautier 	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
16610d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
16627839a050SYann Gautier 
16637839a050SYann Gautier 	value |= RCC_PLLNFRACR_FRACLE;
16640d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
16657839a050SYann Gautier 
16660d21680cSYann Gautier 	stm32mp1_pll_config_output(pll_id, pllcfg);
16677839a050SYann Gautier 
16687839a050SYann Gautier 	return 0;
16697839a050SYann Gautier }
16707839a050SYann Gautier 
16710d21680cSYann Gautier static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg)
16727839a050SYann Gautier {
16730d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
16747839a050SYann Gautier 	uint32_t pllxcsg = 0;
16757839a050SYann Gautier 
16767839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) &
16777839a050SYann Gautier 		    RCC_PLLNCSGR_MOD_PER_MASK;
16787839a050SYann Gautier 
16797839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) &
16807839a050SYann Gautier 		    RCC_PLLNCSGR_INC_STEP_MASK;
16817839a050SYann Gautier 
16827839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) &
16837839a050SYann Gautier 		    RCC_PLLNCSGR_SSCG_MODE_MASK;
16847839a050SYann Gautier 
16850d21680cSYann Gautier 	mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg);
1686dd98aec8SYann Gautier 
1687dd98aec8SYann Gautier 	mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr,
1688dd98aec8SYann Gautier 			RCC_PLLNCR_SSCG_CTRL);
16897839a050SYann Gautier }
16907839a050SYann Gautier 
16910d21680cSYann Gautier static int stm32mp1_set_clksrc(unsigned int clksrc)
16927839a050SYann Gautier {
16930d21680cSYann Gautier 	uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4);
1694dfdb057aSYann Gautier 	uint64_t timeout;
16957839a050SYann Gautier 
16960d21680cSYann Gautier 	mmio_clrsetbits_32(clksrc_address, RCC_SELR_SRC_MASK,
16977839a050SYann Gautier 			   clksrc & RCC_SELR_SRC_MASK);
16987839a050SYann Gautier 
1699dfdb057aSYann Gautier 	timeout = timeout_init_us(CLKSRC_TIMEOUT);
17000d21680cSYann Gautier 	while ((mmio_read_32(clksrc_address) & RCC_SELR_SRCRDY) == 0U) {
1701dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
17020d21680cSYann Gautier 			ERROR("CLKSRC %x start failed @ 0x%lx: 0x%x\n", clksrc,
17030d21680cSYann Gautier 			      clksrc_address, mmio_read_32(clksrc_address));
17047839a050SYann Gautier 			return -ETIMEDOUT;
17057839a050SYann Gautier 		}
17067839a050SYann Gautier 	}
17077839a050SYann Gautier 
17087839a050SYann Gautier 	return 0;
17097839a050SYann Gautier }
17107839a050SYann Gautier 
17110d21680cSYann Gautier static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address)
17127839a050SYann Gautier {
1713dfdb057aSYann Gautier 	uint64_t timeout;
17147839a050SYann Gautier 
17157839a050SYann Gautier 	mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK,
17167839a050SYann Gautier 			   clkdiv & RCC_DIVR_DIV_MASK);
17177839a050SYann Gautier 
1718dfdb057aSYann Gautier 	timeout = timeout_init_us(CLKDIV_TIMEOUT);
17197839a050SYann Gautier 	while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) {
1720dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
17210d21680cSYann Gautier 			ERROR("CLKDIV %x start failed @ 0x%lx: 0x%x\n",
17227839a050SYann Gautier 			      clkdiv, address, mmio_read_32(address));
17237839a050SYann Gautier 			return -ETIMEDOUT;
17247839a050SYann Gautier 		}
17257839a050SYann Gautier 	}
17267839a050SYann Gautier 
17277839a050SYann Gautier 	return 0;
17287839a050SYann Gautier }
17297839a050SYann Gautier 
17300d21680cSYann Gautier static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv)
17317839a050SYann Gautier {
17320d21680cSYann Gautier 	uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4);
17337839a050SYann Gautier 
17347839a050SYann Gautier 	/*
17357839a050SYann Gautier 	 * Binding clksrc :
17367839a050SYann Gautier 	 *      bit15-4 offset
17377839a050SYann Gautier 	 *      bit3:   disable
17387839a050SYann Gautier 	 *      bit2-0: MCOSEL[2:0]
17397839a050SYann Gautier 	 */
17407839a050SYann Gautier 	if ((clksrc & 0x8U) != 0U) {
17410d21680cSYann Gautier 		mmio_clrbits_32(clksrc_address, RCC_MCOCFG_MCOON);
17427839a050SYann Gautier 	} else {
17430d21680cSYann Gautier 		mmio_clrsetbits_32(clksrc_address,
17447839a050SYann Gautier 				   RCC_MCOCFG_MCOSRC_MASK,
17457839a050SYann Gautier 				   clksrc & RCC_MCOCFG_MCOSRC_MASK);
17460d21680cSYann Gautier 		mmio_clrsetbits_32(clksrc_address,
17477839a050SYann Gautier 				   RCC_MCOCFG_MCODIV_MASK,
17487839a050SYann Gautier 				   clkdiv << RCC_MCOCFG_MCODIV_SHIFT);
17490d21680cSYann Gautier 		mmio_setbits_32(clksrc_address, RCC_MCOCFG_MCOON);
17507839a050SYann Gautier 	}
17517839a050SYann Gautier }
17527839a050SYann Gautier 
17530d21680cSYann Gautier static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css)
17547839a050SYann Gautier {
17550d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + RCC_BDCR;
17567839a050SYann Gautier 
17577839a050SYann Gautier 	if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) ||
17587839a050SYann Gautier 	    (clksrc != (uint32_t)CLK_RTC_DISABLED)) {
17597839a050SYann Gautier 		mmio_clrsetbits_32(address,
17607839a050SYann Gautier 				   RCC_BDCR_RTCSRC_MASK,
176115509093SYann Gautier 				   (clksrc & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT);
17627839a050SYann Gautier 
17637839a050SYann Gautier 		mmio_setbits_32(address, RCC_BDCR_RTCCKEN);
17647839a050SYann Gautier 	}
17657839a050SYann Gautier 
17667839a050SYann Gautier 	if (lse_css) {
17677839a050SYann Gautier 		mmio_setbits_32(address, RCC_BDCR_LSECSSON);
17687839a050SYann Gautier 	}
17697839a050SYann Gautier }
17707839a050SYann Gautier 
17710d21680cSYann Gautier static void stm32mp1_pkcs_config(uint32_t pkcs)
17727839a050SYann Gautier {
17730d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU);
17747839a050SYann Gautier 	uint32_t value = pkcs & 0xFU;
17757839a050SYann Gautier 	uint32_t mask = 0xFU;
17767839a050SYann Gautier 
17777839a050SYann Gautier 	if ((pkcs & BIT(31)) != 0U) {
17787839a050SYann Gautier 		mask <<= 4;
17797839a050SYann Gautier 		value <<= 4;
17807839a050SYann Gautier 	}
17817839a050SYann Gautier 
17827839a050SYann Gautier 	mmio_clrsetbits_32(address, mask, value);
17837839a050SYann Gautier }
17847839a050SYann Gautier 
1785964e5ff1SNicolas Le Bayon static int clk_get_pll_settings_from_dt(int plloff, unsigned int *pllcfg,
1786964e5ff1SNicolas Le Bayon 					uint32_t *fracv, uint32_t *csg,
1787964e5ff1SNicolas Le Bayon 					bool *csg_set)
1788964e5ff1SNicolas Le Bayon {
1789964e5ff1SNicolas Le Bayon 	void *fdt;
1790964e5ff1SNicolas Le Bayon 	int ret;
1791964e5ff1SNicolas Le Bayon 
1792964e5ff1SNicolas Le Bayon 	if (fdt_get_address(&fdt) == 0) {
1793964e5ff1SNicolas Le Bayon 		return -FDT_ERR_NOTFOUND;
1794964e5ff1SNicolas Le Bayon 	}
1795964e5ff1SNicolas Le Bayon 
1796964e5ff1SNicolas Le Bayon 	ret = fdt_read_uint32_array(fdt, plloff, "cfg", (uint32_t)PLLCFG_NB,
1797964e5ff1SNicolas Le Bayon 				    pllcfg);
1798964e5ff1SNicolas Le Bayon 	if (ret < 0) {
1799964e5ff1SNicolas Le Bayon 		return -FDT_ERR_NOTFOUND;
1800964e5ff1SNicolas Le Bayon 	}
1801964e5ff1SNicolas Le Bayon 
1802964e5ff1SNicolas Le Bayon 	*fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0);
1803964e5ff1SNicolas Le Bayon 
1804964e5ff1SNicolas Le Bayon 	ret = fdt_read_uint32_array(fdt, plloff, "csg", (uint32_t)PLLCSG_NB,
1805964e5ff1SNicolas Le Bayon 				    csg);
1806964e5ff1SNicolas Le Bayon 
1807964e5ff1SNicolas Le Bayon 	*csg_set = (ret == 0);
1808964e5ff1SNicolas Le Bayon 
1809964e5ff1SNicolas Le Bayon 	if (ret == -FDT_ERR_NOTFOUND) {
1810964e5ff1SNicolas Le Bayon 		ret = 0;
1811964e5ff1SNicolas Le Bayon 	}
1812964e5ff1SNicolas Le Bayon 
1813964e5ff1SNicolas Le Bayon 	return ret;
1814964e5ff1SNicolas Le Bayon }
1815964e5ff1SNicolas Le Bayon 
18167839a050SYann Gautier int stm32mp1_clk_init(void)
18177839a050SYann Gautier {
18180d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
1819964e5ff1SNicolas Le Bayon 	uint32_t pllfracv[_PLL_NB];
1820964e5ff1SNicolas Le Bayon 	uint32_t pllcsg[_PLL_NB][PLLCSG_NB];
18217839a050SYann Gautier 	unsigned int clksrc[CLKSRC_NB];
18227839a050SYann Gautier 	unsigned int clkdiv[CLKDIV_NB];
18237839a050SYann Gautier 	unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
18247839a050SYann Gautier 	int plloff[_PLL_NB];
18257839a050SYann Gautier 	int ret, len;
18267839a050SYann Gautier 	enum stm32mp1_pll_id i;
1827964e5ff1SNicolas Le Bayon 	bool pllcsg_set[_PLL_NB];
1828964e5ff1SNicolas Le Bayon 	bool pllcfg_valid[_PLL_NB];
18297839a050SYann Gautier 	bool lse_css = false;
18300d21680cSYann Gautier 	bool pll3_preserve = false;
18310d21680cSYann Gautier 	bool pll4_preserve = false;
18320d21680cSYann Gautier 	bool pll4_bootrom = false;
18333e6fab43SYann Gautier 	const fdt32_t *pkcs_cell;
183452a616b4SAndre Przywara 	void *fdt;
1835bf1af154SPatrick Delaunay 	int stgen_p = stm32mp1_clk_get_parent(STGEN_K);
1836bf1af154SPatrick Delaunay 	int usbphy_p = stm32mp1_clk_get_parent(USBPHY_K);
183752a616b4SAndre Przywara 
183852a616b4SAndre Przywara 	if (fdt_get_address(&fdt) == 0) {
18398f97c4faSYann Gautier 		return -FDT_ERR_NOTFOUND;
184052a616b4SAndre Przywara 	}
18417839a050SYann Gautier 
184252a616b4SAndre Przywara 	ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB,
184352a616b4SAndre Przywara 					clksrc);
18447839a050SYann Gautier 	if (ret < 0) {
18457839a050SYann Gautier 		return -FDT_ERR_NOTFOUND;
18467839a050SYann Gautier 	}
18477839a050SYann Gautier 
184852a616b4SAndre Przywara 	ret = fdt_rcc_read_uint32_array("st,clkdiv", (uint32_t)CLKDIV_NB,
184952a616b4SAndre Przywara 					clkdiv);
18507839a050SYann Gautier 	if (ret < 0) {
18517839a050SYann Gautier 		return -FDT_ERR_NOTFOUND;
18527839a050SYann Gautier 	}
18537839a050SYann Gautier 
18547839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
18557839a050SYann Gautier 		char name[12];
18567839a050SYann Gautier 
18579fa9a0c5SYann Gautier 		snprintf(name, sizeof(name), "st,pll@%u", i);
18587839a050SYann Gautier 		plloff[i] = fdt_rcc_subnode_offset(name);
18597839a050SYann Gautier 
1860964e5ff1SNicolas Le Bayon 		pllcfg_valid[i] = fdt_check_node(plloff[i]);
1861964e5ff1SNicolas Le Bayon 		if (!pllcfg_valid[i]) {
18627839a050SYann Gautier 			continue;
18637839a050SYann Gautier 		}
18647839a050SYann Gautier 
1865964e5ff1SNicolas Le Bayon 		ret = clk_get_pll_settings_from_dt(plloff[i], pllcfg[i],
1866964e5ff1SNicolas Le Bayon 						   &pllfracv[i], pllcsg[i],
1867964e5ff1SNicolas Le Bayon 						   &pllcsg_set[i]);
1868964e5ff1SNicolas Le Bayon 		if (ret != 0) {
1869964e5ff1SNicolas Le Bayon 			return ret;
18707839a050SYann Gautier 		}
18717839a050SYann Gautier 	}
18727839a050SYann Gautier 
18730d21680cSYann Gautier 	stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]);
18740d21680cSYann Gautier 	stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]);
18757839a050SYann Gautier 
18767839a050SYann Gautier 	/*
18777839a050SYann Gautier 	 * Switch ON oscillator found in device-tree.
18787839a050SYann Gautier 	 * Note: HSI already ON after BootROM stage.
18797839a050SYann Gautier 	 */
18800d21680cSYann Gautier 	if (stm32mp1_osc[_LSI] != 0U) {
18810d21680cSYann Gautier 		stm32mp1_lsi_set(true);
18827839a050SYann Gautier 	}
18830d21680cSYann Gautier 	if (stm32mp1_osc[_LSE] != 0U) {
1884b208e3daSGabriel Fernandez 		const char *name = stm32mp_osc_node_label[_LSE];
18850d21680cSYann Gautier 		bool bypass, digbyp;
18867839a050SYann Gautier 		uint32_t lsedrv;
18877839a050SYann Gautier 
1888b208e3daSGabriel Fernandez 		bypass = fdt_clk_read_bool(name, "st,bypass");
1889b208e3daSGabriel Fernandez 		digbyp = fdt_clk_read_bool(name, "st,digbypass");
1890b208e3daSGabriel Fernandez 		lse_css = fdt_clk_read_bool(name, "st,css");
1891b208e3daSGabriel Fernandez 		lsedrv = fdt_clk_read_uint32_default(name, "st,drive",
18927839a050SYann Gautier 						     LSEDRV_MEDIUM_HIGH);
18930d21680cSYann Gautier 		stm32mp1_lse_enable(bypass, digbyp, lsedrv);
18947839a050SYann Gautier 	}
18950d21680cSYann Gautier 	if (stm32mp1_osc[_HSE] != 0U) {
1896b208e3daSGabriel Fernandez 		const char *name = stm32mp_osc_node_label[_HSE];
18970d21680cSYann Gautier 		bool bypass, digbyp, css;
18987839a050SYann Gautier 
1899b208e3daSGabriel Fernandez 		bypass = fdt_clk_read_bool(name, "st,bypass");
1900b208e3daSGabriel Fernandez 		digbyp = fdt_clk_read_bool(name, "st,digbypass");
1901b208e3daSGabriel Fernandez 		css = fdt_clk_read_bool(name, "st,css");
19020d21680cSYann Gautier 		stm32mp1_hse_enable(bypass, digbyp, css);
19037839a050SYann Gautier 	}
19047839a050SYann Gautier 	/*
19057839a050SYann Gautier 	 * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR)
19067839a050SYann Gautier 	 * => switch on CSI even if node is not present in device tree
19077839a050SYann Gautier 	 */
19080d21680cSYann Gautier 	stm32mp1_csi_set(true);
19097839a050SYann Gautier 
19107839a050SYann Gautier 	/* Come back to HSI */
19110d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(CLK_MPU_HSI);
19127839a050SYann Gautier 	if (ret != 0) {
19137839a050SYann Gautier 		return ret;
19147839a050SYann Gautier 	}
19150d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(CLK_AXI_HSI);
19167839a050SYann Gautier 	if (ret != 0) {
19177839a050SYann Gautier 		return ret;
19187839a050SYann Gautier 	}
1919b053a22eSYann Gautier 	ret = stm32mp1_set_clksrc(CLK_MCU_HSI);
1920b053a22eSYann Gautier 	if (ret != 0) {
1921b053a22eSYann Gautier 		return ret;
1922b053a22eSYann Gautier 	}
19237839a050SYann Gautier 
19240d21680cSYann Gautier 	if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) &
19250d21680cSYann Gautier 	     RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) {
1926175758b2SYann Gautier 		if (pllcfg_valid[_PLL3]) {
1927175758b2SYann Gautier 			pll3_preserve =
1928175758b2SYann Gautier 				stm32mp1_check_pll_conf(_PLL3,
19290d21680cSYann Gautier 							clksrc[CLKSRC_PLL3],
19300d21680cSYann Gautier 							pllcfg[_PLL3],
19310d21680cSYann Gautier 							plloff[_PLL3]);
1932175758b2SYann Gautier 		}
1933175758b2SYann Gautier 
1934175758b2SYann Gautier 		if (pllcfg_valid[_PLL4]) {
1935175758b2SYann Gautier 			pll4_preserve =
1936175758b2SYann Gautier 				stm32mp1_check_pll_conf(_PLL4,
19370d21680cSYann Gautier 							clksrc[CLKSRC_PLL4],
19380d21680cSYann Gautier 							pllcfg[_PLL4],
19390d21680cSYann Gautier 							plloff[_PLL4]);
19400d21680cSYann Gautier 		}
1941175758b2SYann Gautier 	}
1942bf1af154SPatrick Delaunay 	/* Don't initialize PLL4, when used by BOOTROM */
1943bf1af154SPatrick Delaunay 	if ((stm32mp_get_boot_itf_selected() ==
1944bf1af154SPatrick Delaunay 	     BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) &&
1945bf1af154SPatrick Delaunay 	    ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) {
1946bf1af154SPatrick Delaunay 		pll4_bootrom = true;
1947bf1af154SPatrick Delaunay 		pll4_preserve = true;
1948bf1af154SPatrick Delaunay 	}
19490d21680cSYann Gautier 
19507839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
19510d21680cSYann Gautier 		if (((i == _PLL3) && pll3_preserve) ||
19520d21680cSYann Gautier 		    ((i == _PLL4) && pll4_preserve)) {
19537839a050SYann Gautier 			continue;
19540d21680cSYann Gautier 		}
19550d21680cSYann Gautier 
19560d21680cSYann Gautier 		ret = stm32mp1_pll_stop(i);
19577839a050SYann Gautier 		if (ret != 0) {
19587839a050SYann Gautier 			return ret;
19597839a050SYann Gautier 		}
19607839a050SYann Gautier 	}
19617839a050SYann Gautier 
19627839a050SYann Gautier 	/* Configure HSIDIV */
19630d21680cSYann Gautier 	if (stm32mp1_osc[_HSI] != 0U) {
19640d21680cSYann Gautier 		ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]);
19657839a050SYann Gautier 		if (ret != 0) {
19667839a050SYann Gautier 			return ret;
19677839a050SYann Gautier 		}
1968591d80c8SLionel Debieve 
1969591d80c8SLionel Debieve 		stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
19707839a050SYann Gautier 	}
19717839a050SYann Gautier 
19727839a050SYann Gautier 	/* Select DIV */
19737839a050SYann Gautier 	/* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */
19740d21680cSYann Gautier 	mmio_write_32(rcc_base + RCC_MPCKDIVR,
19757839a050SYann Gautier 		      clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK);
19760d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR);
19777839a050SYann Gautier 	if (ret != 0) {
19787839a050SYann Gautier 		return ret;
19797839a050SYann Gautier 	}
19800d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR);
19817839a050SYann Gautier 	if (ret != 0) {
19827839a050SYann Gautier 		return ret;
19837839a050SYann Gautier 	}
19840d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR);
19857839a050SYann Gautier 	if (ret != 0) {
19867839a050SYann Gautier 		return ret;
19877839a050SYann Gautier 	}
1988b053a22eSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR);
1989b053a22eSYann Gautier 	if (ret != 0) {
1990b053a22eSYann Gautier 		return ret;
1991b053a22eSYann Gautier 	}
19920d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR);
19937839a050SYann Gautier 	if (ret != 0) {
19947839a050SYann Gautier 		return ret;
19957839a050SYann Gautier 	}
19960d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR);
19977839a050SYann Gautier 	if (ret != 0) {
19987839a050SYann Gautier 		return ret;
19997839a050SYann Gautier 	}
20000d21680cSYann Gautier 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR);
20017839a050SYann Gautier 	if (ret != 0) {
20027839a050SYann Gautier 		return ret;
20037839a050SYann Gautier 	}
20047839a050SYann Gautier 
20057839a050SYann Gautier 	/* No ready bit for RTC */
20060d21680cSYann Gautier 	mmio_write_32(rcc_base + RCC_RTCDIVR,
20077839a050SYann Gautier 		      clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK);
20087839a050SYann Gautier 
20097839a050SYann Gautier 	/* Configure PLLs source */
20100d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]);
20117839a050SYann Gautier 	if (ret != 0) {
20127839a050SYann Gautier 		return ret;
20137839a050SYann Gautier 	}
20147839a050SYann Gautier 
20150d21680cSYann Gautier 	if (!pll3_preserve) {
20160d21680cSYann Gautier 		ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]);
20177839a050SYann Gautier 		if (ret != 0) {
20187839a050SYann Gautier 			return ret;
20197839a050SYann Gautier 		}
20200d21680cSYann Gautier 	}
20210d21680cSYann Gautier 
20220d21680cSYann Gautier 	if (!pll4_preserve) {
20230d21680cSYann Gautier 		ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]);
20240d21680cSYann Gautier 		if (ret != 0) {
20250d21680cSYann Gautier 			return ret;
20260d21680cSYann Gautier 		}
20270d21680cSYann Gautier 	}
20287839a050SYann Gautier 
20297839a050SYann Gautier 	/* Configure and start PLLs */
20307839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
20310d21680cSYann Gautier 		if (((i == _PLL3) && pll3_preserve) ||
20320d21680cSYann Gautier 		    ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) {
20330d21680cSYann Gautier 			continue;
20340d21680cSYann Gautier 		}
20350d21680cSYann Gautier 
2036964e5ff1SNicolas Le Bayon 		if (!pllcfg_valid[i]) {
20377839a050SYann Gautier 			continue;
20387839a050SYann Gautier 		}
20397839a050SYann Gautier 
20400d21680cSYann Gautier 		if ((i == _PLL4) && pll4_bootrom) {
20410d21680cSYann Gautier 			/* Set output divider if not done by the Bootrom */
20420d21680cSYann Gautier 			stm32mp1_pll_config_output(i, pllcfg[i]);
20430d21680cSYann Gautier 			continue;
20440d21680cSYann Gautier 		}
20450d21680cSYann Gautier 
2046964e5ff1SNicolas Le Bayon 		ret = stm32mp1_pll_config(i, pllcfg[i], pllfracv[i]);
20477839a050SYann Gautier 		if (ret != 0) {
20487839a050SYann Gautier 			return ret;
20497839a050SYann Gautier 		}
2050964e5ff1SNicolas Le Bayon 
2051964e5ff1SNicolas Le Bayon 		if (pllcsg_set[i]) {
2052964e5ff1SNicolas Le Bayon 			stm32mp1_pll_csg(i, pllcsg[i]);
20537839a050SYann Gautier 		}
20547839a050SYann Gautier 
20550d21680cSYann Gautier 		stm32mp1_pll_start(i);
20567839a050SYann Gautier 	}
20571b491eeaSElyes Haouas 	/* Wait and start PLLs output when ready */
20587839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
2059964e5ff1SNicolas Le Bayon 		if (!pllcfg_valid[i]) {
20607839a050SYann Gautier 			continue;
20617839a050SYann Gautier 		}
20627839a050SYann Gautier 
20630d21680cSYann Gautier 		ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]);
20647839a050SYann Gautier 		if (ret != 0) {
20657839a050SYann Gautier 			return ret;
20667839a050SYann Gautier 		}
20677839a050SYann Gautier 	}
20687839a050SYann Gautier 	/* Wait LSE ready before to use it */
20690d21680cSYann Gautier 	if (stm32mp1_osc[_LSE] != 0U) {
20700d21680cSYann Gautier 		stm32mp1_lse_wait();
20717839a050SYann Gautier 	}
20727839a050SYann Gautier 
20737839a050SYann Gautier 	/* Configure with expected clock source */
20740d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]);
20757839a050SYann Gautier 	if (ret != 0) {
20767839a050SYann Gautier 		return ret;
20777839a050SYann Gautier 	}
20780d21680cSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]);
20797839a050SYann Gautier 	if (ret != 0) {
20807839a050SYann Gautier 		return ret;
20817839a050SYann Gautier 	}
2082b053a22eSYann Gautier 	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]);
2083b053a22eSYann Gautier 	if (ret != 0) {
2084b053a22eSYann Gautier 		return ret;
2085b053a22eSYann Gautier 	}
20860d21680cSYann Gautier 	stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css);
20877839a050SYann Gautier 
20887839a050SYann Gautier 	/* Configure PKCK */
20897839a050SYann Gautier 	pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len);
20907839a050SYann Gautier 	if (pkcs_cell != NULL) {
20917839a050SYann Gautier 		bool ckper_disabled = false;
20927839a050SYann Gautier 		uint32_t j;
2093bf1af154SPatrick Delaunay 		uint32_t usbreg_bootrom = 0U;
2094bf1af154SPatrick Delaunay 
2095bf1af154SPatrick Delaunay 		if (pll4_bootrom) {
2096bf1af154SPatrick Delaunay 			usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR);
2097bf1af154SPatrick Delaunay 		}
20987839a050SYann Gautier 
20997839a050SYann Gautier 		for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) {
21003e6fab43SYann Gautier 			uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]);
21017839a050SYann Gautier 
21027839a050SYann Gautier 			if (pkcs == (uint32_t)CLK_CKPER_DISABLED) {
21037839a050SYann Gautier 				ckper_disabled = true;
21047839a050SYann Gautier 				continue;
21057839a050SYann Gautier 			}
21060d21680cSYann Gautier 			stm32mp1_pkcs_config(pkcs);
21077839a050SYann Gautier 		}
21087839a050SYann Gautier 
21097839a050SYann Gautier 		/*
21107839a050SYann Gautier 		 * CKPER is source for some peripheral clocks
21117839a050SYann Gautier 		 * (FMC-NAND / QPSI-NOR) and switching source is allowed
21127839a050SYann Gautier 		 * only if previous clock is still ON
21137839a050SYann Gautier 		 * => deactivated CKPER only after switching clock
21147839a050SYann Gautier 		 */
21157839a050SYann Gautier 		if (ckper_disabled) {
21160d21680cSYann Gautier 			stm32mp1_pkcs_config(CLK_CKPER_DISABLED);
21177839a050SYann Gautier 		}
2118bf1af154SPatrick Delaunay 
2119bf1af154SPatrick Delaunay 		if (pll4_bootrom) {
2120bf1af154SPatrick Delaunay 			uint32_t usbreg_value, usbreg_mask;
2121bf1af154SPatrick Delaunay 			const struct stm32mp1_clk_sel *sel;
2122bf1af154SPatrick Delaunay 
2123bf1af154SPatrick Delaunay 			sel = clk_sel_ref(_USBPHY_SEL);
2124bf1af154SPatrick Delaunay 			usbreg_mask = (uint32_t)sel->msk << sel->src;
2125bf1af154SPatrick Delaunay 			sel = clk_sel_ref(_USBO_SEL);
2126bf1af154SPatrick Delaunay 			usbreg_mask |= (uint32_t)sel->msk << sel->src;
2127bf1af154SPatrick Delaunay 
2128bf1af154SPatrick Delaunay 			usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) &
2129bf1af154SPatrick Delaunay 				       usbreg_mask;
2130bf1af154SPatrick Delaunay 			usbreg_bootrom &= usbreg_mask;
2131bf1af154SPatrick Delaunay 			if (usbreg_bootrom != usbreg_value) {
2132bf1af154SPatrick Delaunay 				VERBOSE("forbidden new USB clk path\n");
2133bf1af154SPatrick Delaunay 				VERBOSE("vs bootrom on USB boot\n");
2134bf1af154SPatrick Delaunay 				return -FDT_ERR_BADVALUE;
2135bf1af154SPatrick Delaunay 			}
2136bf1af154SPatrick Delaunay 		}
21377839a050SYann Gautier 	}
21387839a050SYann Gautier 
21397839a050SYann Gautier 	/* Switch OFF HSI if not found in device-tree */
21400d21680cSYann Gautier 	if (stm32mp1_osc[_HSI] == 0U) {
21410d21680cSYann Gautier 		stm32mp1_hsi_set(false);
21427839a050SYann Gautier 	}
2143591d80c8SLionel Debieve 
2144591d80c8SLionel Debieve 	stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
21457839a050SYann Gautier 
21467839a050SYann Gautier 	/* Software Self-Refresh mode (SSR) during DDR initilialization */
21470d21680cSYann Gautier 	mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR,
21487839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_MASK,
21497839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_SSR <<
21507839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_SHIFT);
21517839a050SYann Gautier 
21527839a050SYann Gautier 	return 0;
21537839a050SYann Gautier }
21547839a050SYann Gautier 
21557839a050SYann Gautier static void stm32mp1_osc_clk_init(const char *name,
21567839a050SYann Gautier 				  enum stm32mp_osc_id index)
21577839a050SYann Gautier {
21587839a050SYann Gautier 	uint32_t frequency;
21597839a050SYann Gautier 
21600d21680cSYann Gautier 	if (fdt_osc_read_freq(name, &frequency) == 0) {
21610d21680cSYann Gautier 		stm32mp1_osc[index] = frequency;
21627839a050SYann Gautier 	}
21637839a050SYann Gautier }
21647839a050SYann Gautier 
21657839a050SYann Gautier static void stm32mp1_osc_init(void)
21667839a050SYann Gautier {
21677839a050SYann Gautier 	enum stm32mp_osc_id i;
21687839a050SYann Gautier 
21697839a050SYann Gautier 	for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) {
21700d21680cSYann Gautier 		stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i);
21717839a050SYann Gautier 	}
21727839a050SYann Gautier }
21737839a050SYann Gautier 
217437e8295aSEtienne Carriere #ifdef STM32MP_SHARED_RESOURCES
217537e8295aSEtienne Carriere /*
217637e8295aSEtienne Carriere  * Get the parent ID of the target parent clock, for tagging as secure
217737e8295aSEtienne Carriere  * shared clock dependencies.
217837e8295aSEtienne Carriere  */
217937e8295aSEtienne Carriere static int get_parent_id_parent(unsigned int parent_id)
218037e8295aSEtienne Carriere {
218137e8295aSEtienne Carriere 	enum stm32mp1_parent_sel s = _UNKNOWN_SEL;
218237e8295aSEtienne Carriere 	enum stm32mp1_pll_id pll_id;
218337e8295aSEtienne Carriere 	uint32_t p_sel;
218437e8295aSEtienne Carriere 	uintptr_t rcc_base = stm32mp_rcc_base();
218537e8295aSEtienne Carriere 
218637e8295aSEtienne Carriere 	switch (parent_id) {
218737e8295aSEtienne Carriere 	case _ACLK:
218837e8295aSEtienne Carriere 	case _PCLK4:
218937e8295aSEtienne Carriere 	case _PCLK5:
219037e8295aSEtienne Carriere 		s = _AXIS_SEL;
219137e8295aSEtienne Carriere 		break;
219237e8295aSEtienne Carriere 	case _PLL1_P:
219337e8295aSEtienne Carriere 	case _PLL1_Q:
219437e8295aSEtienne Carriere 	case _PLL1_R:
219537e8295aSEtienne Carriere 		pll_id = _PLL1;
219637e8295aSEtienne Carriere 		break;
219737e8295aSEtienne Carriere 	case _PLL2_P:
219837e8295aSEtienne Carriere 	case _PLL2_Q:
219937e8295aSEtienne Carriere 	case _PLL2_R:
220037e8295aSEtienne Carriere 		pll_id = _PLL2;
220137e8295aSEtienne Carriere 		break;
220237e8295aSEtienne Carriere 	case _PLL3_P:
220337e8295aSEtienne Carriere 	case _PLL3_Q:
220437e8295aSEtienne Carriere 	case _PLL3_R:
220537e8295aSEtienne Carriere 		pll_id = _PLL3;
220637e8295aSEtienne Carriere 		break;
220737e8295aSEtienne Carriere 	case _PLL4_P:
220837e8295aSEtienne Carriere 	case _PLL4_Q:
220937e8295aSEtienne Carriere 	case _PLL4_R:
221037e8295aSEtienne Carriere 		pll_id = _PLL4;
221137e8295aSEtienne Carriere 		break;
221237e8295aSEtienne Carriere 	case _PCLK1:
221337e8295aSEtienne Carriere 	case _PCLK2:
221437e8295aSEtienne Carriere 	case _HCLK2:
221537e8295aSEtienne Carriere 	case _HCLK6:
221637e8295aSEtienne Carriere 	case _CK_PER:
221737e8295aSEtienne Carriere 	case _CK_MPU:
221837e8295aSEtienne Carriere 	case _CK_MCU:
221937e8295aSEtienne Carriere 	case _USB_PHY_48:
222037e8295aSEtienne Carriere 		/* We do not expect to access these */
222137e8295aSEtienne Carriere 		panic();
222237e8295aSEtienne Carriere 		break;
222337e8295aSEtienne Carriere 	default:
222437e8295aSEtienne Carriere 		/* Other parents have no parent */
222537e8295aSEtienne Carriere 		return -1;
222637e8295aSEtienne Carriere 	}
222737e8295aSEtienne Carriere 
222837e8295aSEtienne Carriere 	if (s != _UNKNOWN_SEL) {
222937e8295aSEtienne Carriere 		const struct stm32mp1_clk_sel *sel = clk_sel_ref(s);
223037e8295aSEtienne Carriere 
223137e8295aSEtienne Carriere 		p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) &
223237e8295aSEtienne Carriere 			sel->msk;
223337e8295aSEtienne Carriere 
223437e8295aSEtienne Carriere 		if (p_sel < sel->nb_parent) {
223537e8295aSEtienne Carriere 			return (int)sel->parent[p_sel];
223637e8295aSEtienne Carriere 		}
223737e8295aSEtienne Carriere 	} else {
223837e8295aSEtienne Carriere 		const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
223937e8295aSEtienne Carriere 
224037e8295aSEtienne Carriere 		p_sel = mmio_read_32(rcc_base + pll->rckxselr) &
224137e8295aSEtienne Carriere 			RCC_SELR_REFCLK_SRC_MASK;
224237e8295aSEtienne Carriere 
224337e8295aSEtienne Carriere 		if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) {
224437e8295aSEtienne Carriere 			return (int)pll->refclk[p_sel];
224537e8295aSEtienne Carriere 		}
224637e8295aSEtienne Carriere 	}
224737e8295aSEtienne Carriere 
224837e8295aSEtienne Carriere 	VERBOSE("No parent selected for %s\n",
224937e8295aSEtienne Carriere 		stm32mp1_clk_parent_name[parent_id]);
225037e8295aSEtienne Carriere 
225137e8295aSEtienne Carriere 	return -1;
225237e8295aSEtienne Carriere }
225337e8295aSEtienne Carriere 
225437e8295aSEtienne Carriere static void secure_parent_clocks(unsigned long parent_id)
225537e8295aSEtienne Carriere {
225637e8295aSEtienne Carriere 	int grandparent_id;
225737e8295aSEtienne Carriere 
225837e8295aSEtienne Carriere 	switch (parent_id) {
225937e8295aSEtienne Carriere 	case _PLL3_P:
226037e8295aSEtienne Carriere 	case _PLL3_Q:
226137e8295aSEtienne Carriere 	case _PLL3_R:
226237e8295aSEtienne Carriere 		stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
226337e8295aSEtienne Carriere 		break;
226437e8295aSEtienne Carriere 
226537e8295aSEtienne Carriere 	/* These clocks are always secure when RCC is secure */
226637e8295aSEtienne Carriere 	case _ACLK:
226737e8295aSEtienne Carriere 	case _HCLK2:
226837e8295aSEtienne Carriere 	case _HCLK6:
226937e8295aSEtienne Carriere 	case _PCLK4:
227037e8295aSEtienne Carriere 	case _PCLK5:
227137e8295aSEtienne Carriere 	case _PLL1_P:
227237e8295aSEtienne Carriere 	case _PLL1_Q:
227337e8295aSEtienne Carriere 	case _PLL1_R:
227437e8295aSEtienne Carriere 	case _PLL2_P:
227537e8295aSEtienne Carriere 	case _PLL2_Q:
227637e8295aSEtienne Carriere 	case _PLL2_R:
227737e8295aSEtienne Carriere 	case _HSI:
227837e8295aSEtienne Carriere 	case _HSI_KER:
227937e8295aSEtienne Carriere 	case _LSI:
228037e8295aSEtienne Carriere 	case _CSI:
228137e8295aSEtienne Carriere 	case _CSI_KER:
228237e8295aSEtienne Carriere 	case _HSE:
228337e8295aSEtienne Carriere 	case _HSE_KER:
228437e8295aSEtienne Carriere 	case _HSE_KER_DIV2:
2285cbd2e8a6SGabriel Fernandez 	case _HSE_RTC:
228637e8295aSEtienne Carriere 	case _LSE:
228737e8295aSEtienne Carriere 		break;
228837e8295aSEtienne Carriere 
228937e8295aSEtienne Carriere 	default:
229037e8295aSEtienne Carriere 		VERBOSE("Cannot secure parent clock %s\n",
229137e8295aSEtienne Carriere 			stm32mp1_clk_parent_name[parent_id]);
229237e8295aSEtienne Carriere 		panic();
229337e8295aSEtienne Carriere 	}
229437e8295aSEtienne Carriere 
229537e8295aSEtienne Carriere 	grandparent_id = get_parent_id_parent(parent_id);
229637e8295aSEtienne Carriere 	if (grandparent_id >= 0) {
229737e8295aSEtienne Carriere 		secure_parent_clocks(grandparent_id);
229837e8295aSEtienne Carriere 	}
229937e8295aSEtienne Carriere }
230037e8295aSEtienne Carriere 
230137e8295aSEtienne Carriere void stm32mp1_register_clock_parents_secure(unsigned long clock_id)
230237e8295aSEtienne Carriere {
230337e8295aSEtienne Carriere 	int parent_id;
230437e8295aSEtienne Carriere 
230537e8295aSEtienne Carriere 	if (!stm32mp1_rcc_is_secure()) {
230637e8295aSEtienne Carriere 		return;
230737e8295aSEtienne Carriere 	}
230837e8295aSEtienne Carriere 
230937e8295aSEtienne Carriere 	switch (clock_id) {
231037e8295aSEtienne Carriere 	case PLL1:
231137e8295aSEtienne Carriere 	case PLL2:
231237e8295aSEtienne Carriere 		/* PLL1/PLL2 are always secure: nothing to do */
231337e8295aSEtienne Carriere 		break;
231437e8295aSEtienne Carriere 	case PLL3:
231537e8295aSEtienne Carriere 		stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
231637e8295aSEtienne Carriere 		break;
231737e8295aSEtienne Carriere 	case PLL4:
231837e8295aSEtienne Carriere 		ERROR("PLL4 cannot be secured\n");
231937e8295aSEtienne Carriere 		panic();
232037e8295aSEtienne Carriere 		break;
232137e8295aSEtienne Carriere 	default:
232237e8295aSEtienne Carriere 		/* Others are expected gateable clock */
232337e8295aSEtienne Carriere 		parent_id = stm32mp1_clk_get_parent(clock_id);
232437e8295aSEtienne Carriere 		if (parent_id < 0) {
232537e8295aSEtienne Carriere 			INFO("No parent found for clock %lu\n", clock_id);
232637e8295aSEtienne Carriere 		} else {
232737e8295aSEtienne Carriere 			secure_parent_clocks(parent_id);
232837e8295aSEtienne Carriere 		}
232937e8295aSEtienne Carriere 		break;
233037e8295aSEtienne Carriere 	}
233137e8295aSEtienne Carriere }
233237e8295aSEtienne Carriere #endif /* STM32MP_SHARED_RESOURCES */
233337e8295aSEtienne Carriere 
233477b4ca0bSLionel Debieve void stm32mp1_clk_mcuss_protect(bool enable)
233577b4ca0bSLionel Debieve {
233677b4ca0bSLionel Debieve 	uintptr_t rcc_base = stm32mp_rcc_base();
233777b4ca0bSLionel Debieve 
233877b4ca0bSLionel Debieve 	if (enable) {
233977b4ca0bSLionel Debieve 		mmio_setbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
234077b4ca0bSLionel Debieve 	} else {
234177b4ca0bSLionel Debieve 		mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
234277b4ca0bSLionel Debieve 	}
234377b4ca0bSLionel Debieve }
234477b4ca0bSLionel Debieve 
23456cb45f89SYann Gautier static void sync_earlyboot_clocks_state(void)
23466cb45f89SYann Gautier {
2347033b6c3aSEtienne Carriere 	unsigned int idx;
2348033b6c3aSEtienne Carriere 	const unsigned long secure_enable[] = {
2349033b6c3aSEtienne Carriere 		AXIDCG,
2350033b6c3aSEtienne Carriere 		BSEC,
2351033b6c3aSEtienne Carriere 		DDRC1, DDRC1LP,
2352033b6c3aSEtienne Carriere 		DDRC2, DDRC2LP,
2353033b6c3aSEtienne Carriere 		DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP,
2354033b6c3aSEtienne Carriere 		DDRPHYC, DDRPHYCLP,
2355373f06beSLionel Debieve 		RTCAPB,
2356033b6c3aSEtienne Carriere 		TZC1, TZC2,
2357033b6c3aSEtienne Carriere 		TZPC,
2358033b6c3aSEtienne Carriere 		STGEN_K,
2359033b6c3aSEtienne Carriere 	};
2360033b6c3aSEtienne Carriere 
2361033b6c3aSEtienne Carriere 	for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) {
2362033b6c3aSEtienne Carriere 		stm32mp_clk_enable(secure_enable[idx]);
2363033b6c3aSEtienne Carriere 	}
23646cb45f89SYann Gautier }
23656cb45f89SYann Gautier 
236633667d29SYann Gautier static const struct clk_ops stm32mp_clk_ops = {
236733667d29SYann Gautier 	.enable		= stm32mp_clk_enable,
236833667d29SYann Gautier 	.disable	= stm32mp_clk_disable,
236933667d29SYann Gautier 	.is_enabled	= stm32mp_clk_is_enabled,
237033667d29SYann Gautier 	.get_rate	= stm32mp_clk_get_rate,
237133667d29SYann Gautier 	.get_parent	= stm32mp1_clk_get_parent,
237233667d29SYann Gautier };
237333667d29SYann Gautier 
23747839a050SYann Gautier int stm32mp1_clk_probe(void)
23757839a050SYann Gautier {
2376812daf91SLionel Debieve #if defined(IMAGE_BL32)
2377812daf91SLionel Debieve 	if (!fdt_get_rcc_secure_state()) {
2378812daf91SLionel Debieve 		mmio_write_32(stm32mp_rcc_base() + RCC_TZCR, 0U);
2379812daf91SLionel Debieve 	}
2380812daf91SLionel Debieve #endif
2381812daf91SLionel Debieve 
23827839a050SYann Gautier 	stm32mp1_osc_init();
23837839a050SYann Gautier 
23846cb45f89SYann Gautier 	sync_earlyboot_clocks_state();
23856cb45f89SYann Gautier 
238633667d29SYann Gautier 	clk_register(&stm32mp_clk_ops);
238733667d29SYann Gautier 
23887839a050SYann Gautier 	return 0;
23897839a050SYann Gautier }
2390