xref: /optee_os/core/drivers/clk/clk-stm32mp15.c (revision 11bee8b0dfc82c966bb6e13dafcec0f182bbcf41)
16b651796SEtienne Carriere // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0+)
26b651796SEtienne Carriere /*
36b651796SEtienne Carriere  * Copyright (C) 2018-2019, STMicroelectronics
46b651796SEtienne Carriere  */
56b651796SEtienne Carriere 
66b651796SEtienne Carriere #include <assert.h>
76b651796SEtienne Carriere #include <config.h>
86b651796SEtienne Carriere #include <drivers/stm32mp1_rcc.h>
96b651796SEtienne Carriere #include <drivers/clk.h>
106b651796SEtienne Carriere #include <drivers/clk_dt.h>
116b651796SEtienne Carriere #include <dt-bindings/clock/stm32mp1-clks.h>
126b651796SEtienne Carriere #include <initcall.h>
136b651796SEtienne Carriere #include <io.h>
146b651796SEtienne Carriere #include <keep.h>
156b651796SEtienne Carriere #include <kernel/dt.h>
166b651796SEtienne Carriere #include <kernel/boot.h>
176b651796SEtienne Carriere #include <kernel/panic.h>
186b651796SEtienne Carriere #include <kernel/spinlock.h>
196b651796SEtienne Carriere #include <libfdt.h>
206b651796SEtienne Carriere #include <platform_config.h>
216b651796SEtienne Carriere #include <stdio.h>
226b651796SEtienne Carriere #include <stm32_util.h>
236b651796SEtienne Carriere #include <trace.h>
246b651796SEtienne Carriere #include <util.h>
256b651796SEtienne Carriere 
266b651796SEtienne Carriere /* Identifiers for root oscillators */
276b651796SEtienne Carriere enum stm32mp_osc_id {
28bb73802dSEtienne Carriere 	OSC_HSI,
29bb73802dSEtienne Carriere 	OSC_HSE,
30bb73802dSEtienne Carriere 	OSC_CSI,
31bb73802dSEtienne Carriere 	OSC_LSI,
32bb73802dSEtienne Carriere 	OSC_LSE,
33bb73802dSEtienne Carriere 	OSC_I2S_CKIN,
34bb73802dSEtienne Carriere 	OSC_USB_PHY_48,
356b651796SEtienne Carriere 	NB_OSC,
366b651796SEtienne Carriere 	_UNKNOWN_OSC_ID = 0xffU
376b651796SEtienne Carriere };
386b651796SEtienne Carriere 
396b651796SEtienne Carriere /* Identifiers for parent clocks */
406b651796SEtienne Carriere enum stm32mp1_parent_id {
41bb73802dSEtienne Carriere 	_HSI,
42bb73802dSEtienne Carriere 	_HSE,
43bb73802dSEtienne Carriere 	_CSI,
44bb73802dSEtienne Carriere 	_LSI,
45bb73802dSEtienne Carriere 	_LSE,
46bb73802dSEtienne Carriere 	_I2S_CKIN,
47bb73802dSEtienne Carriere 	_USB_PHY_48,
48bb73802dSEtienne Carriere 	_HSI_KER,
496b651796SEtienne Carriere 	_HSE_KER,
506b651796SEtienne Carriere 	_HSE_KER_DIV2,
5162bb2715SEtienne Carriere 	_HSE_RTC,
526b651796SEtienne Carriere 	_CSI_KER,
536b651796SEtienne Carriere 	_PLL1_P,
546b651796SEtienne Carriere 	_PLL1_Q,
556b651796SEtienne Carriere 	_PLL1_R,
566b651796SEtienne Carriere 	_PLL2_P,
576b651796SEtienne Carriere 	_PLL2_Q,
586b651796SEtienne Carriere 	_PLL2_R,
596b651796SEtienne Carriere 	_PLL3_P,
606b651796SEtienne Carriere 	_PLL3_Q,
616b651796SEtienne Carriere 	_PLL3_R,
626b651796SEtienne Carriere 	_PLL4_P,
636b651796SEtienne Carriere 	_PLL4_Q,
646b651796SEtienne Carriere 	_PLL4_R,
656b651796SEtienne Carriere 	_ACLK,
666b651796SEtienne Carriere 	_PCLK1,
676b651796SEtienne Carriere 	_PCLK2,
686b651796SEtienne Carriere 	_PCLK3,
696b651796SEtienne Carriere 	_PCLK4,
706b651796SEtienne Carriere 	_PCLK5,
716b651796SEtienne Carriere 	_HCLK5,
726b651796SEtienne Carriere 	_HCLK6,
736b651796SEtienne Carriere 	_HCLK2,
746b651796SEtienne Carriere 	_CK_PER,
756b651796SEtienne Carriere 	_CK_MPU,
766b651796SEtienne Carriere 	_CK_MCU,
776b651796SEtienne Carriere 	_PARENT_NB,
786b651796SEtienne Carriere 	_UNKNOWN_ID = 0xff,
796b651796SEtienne Carriere };
806b651796SEtienne Carriere 
816b651796SEtienne Carriere /*
826b651796SEtienne Carriere  * Identifiers for parent clock selectors.
836b651796SEtienne Carriere  * This enum lists only the parent clocks we are interested in.
846b651796SEtienne Carriere  */
856b651796SEtienne Carriere enum stm32mp1_parent_sel {
866b651796SEtienne Carriere 	_STGEN_SEL,
876b651796SEtienne Carriere 	_I2C46_SEL,
886b651796SEtienne Carriere 	_SPI6_SEL,
896b651796SEtienne Carriere 	_USART1_SEL,
906b651796SEtienne Carriere 	_RNG1_SEL,
916b651796SEtienne Carriere 	_UART6_SEL,
926b651796SEtienne Carriere 	_UART24_SEL,
936b651796SEtienne Carriere 	_UART35_SEL,
946b651796SEtienne Carriere 	_UART78_SEL,
956b651796SEtienne Carriere 	_AXISS_SEL,
966b651796SEtienne Carriere 	_MCUSS_SEL,
976b651796SEtienne Carriere 	_USBPHY_SEL,
986b651796SEtienne Carriere 	_USBO_SEL,
996b651796SEtienne Carriere 	_RTC_SEL,
10062bb2715SEtienne Carriere 	_MPU_SEL,
1016b651796SEtienne Carriere 	_PARENT_SEL_NB,
1026b651796SEtienne Carriere 	_UNKNOWN_SEL = 0xff,
1036b651796SEtienne Carriere };
1046b651796SEtienne Carriere 
1056b651796SEtienne Carriere static const uint8_t parent_id_clock_id[_PARENT_NB] = {
1066b651796SEtienne Carriere 	[_HSE] = CK_HSE,
1076b651796SEtienne Carriere 	[_HSI] = CK_HSI,
1086b651796SEtienne Carriere 	[_CSI] = CK_CSI,
1096b651796SEtienne Carriere 	[_LSE] = CK_LSE,
1106b651796SEtienne Carriere 	[_LSI] = CK_LSI,
1116b651796SEtienne Carriere 	[_I2S_CKIN] = _UNKNOWN_ID,
1126b651796SEtienne Carriere 	[_USB_PHY_48] = _UNKNOWN_ID,
1136b651796SEtienne Carriere 	[_HSI_KER] = CK_HSI,
1146b651796SEtienne Carriere 	[_HSE_KER] = CK_HSE,
1156b651796SEtienne Carriere 	[_HSE_KER_DIV2] = CK_HSE_DIV2,
11662bb2715SEtienne Carriere 	[_HSE_RTC] = _UNKNOWN_ID,
1176b651796SEtienne Carriere 	[_CSI_KER] = CK_CSI,
1186b651796SEtienne Carriere 	[_PLL1_P] = PLL1_P,
1196b651796SEtienne Carriere 	[_PLL1_Q] = PLL1_Q,
1206b651796SEtienne Carriere 	[_PLL1_R] = PLL1_R,
1216b651796SEtienne Carriere 	[_PLL2_P] = PLL2_P,
1226b651796SEtienne Carriere 	[_PLL2_Q] = PLL2_Q,
1236b651796SEtienne Carriere 	[_PLL2_R] = PLL2_R,
1246b651796SEtienne Carriere 	[_PLL3_P] = PLL3_P,
1256b651796SEtienne Carriere 	[_PLL3_Q] = PLL3_Q,
1266b651796SEtienne Carriere 	[_PLL3_R] = PLL3_R,
1276b651796SEtienne Carriere 	[_PLL4_P] = PLL4_P,
1286b651796SEtienne Carriere 	[_PLL4_Q] = PLL4_Q,
1296b651796SEtienne Carriere 	[_PLL4_R] = PLL4_R,
1306b651796SEtienne Carriere 	[_ACLK] = CK_AXI,
1316b651796SEtienne Carriere 	[_PCLK1] = CK_AXI,
1326b651796SEtienne Carriere 	[_PCLK2] = CK_AXI,
1336b651796SEtienne Carriere 	[_PCLK3] = CK_AXI,
1346b651796SEtienne Carriere 	[_PCLK4] = CK_AXI,
1356b651796SEtienne Carriere 	[_PCLK5] = CK_AXI,
1366b651796SEtienne Carriere 	[_HCLK5] = CK_AXI,
1376b651796SEtienne Carriere 	[_HCLK6] = CK_AXI,
1386b651796SEtienne Carriere 	[_HCLK2] = CK_AXI,
1396b651796SEtienne Carriere 	[_CK_PER] = CK_PER,
1406b651796SEtienne Carriere 	[_CK_MPU] = CK_MPU,
1416b651796SEtienne Carriere 	[_CK_MCU] = CK_MCU,
1426b651796SEtienne Carriere };
1436b651796SEtienne Carriere 
144bb73802dSEtienne Carriere static enum stm32mp1_parent_id osc_id2parent_id(enum stm32mp_osc_id osc_id)
145bb73802dSEtienne Carriere {
146bb73802dSEtienne Carriere 	assert(osc_id >= OSC_HSI && osc_id < NB_OSC);
147bb73802dSEtienne Carriere 	COMPILE_TIME_ASSERT((int)OSC_HSI == (int)_HSI &&
148bb73802dSEtienne Carriere 			    (int)OSC_HSE == (int)_HSE &&
149bb73802dSEtienne Carriere 			    (int)OSC_CSI == (int)_CSI &&
150bb73802dSEtienne Carriere 			    (int)OSC_LSI == (int)_LSI &&
151bb73802dSEtienne Carriere 			    (int)OSC_LSE == (int)_LSE &&
152bb73802dSEtienne Carriere 			    (int)OSC_I2S_CKIN == (int)_I2S_CKIN &&
153bb73802dSEtienne Carriere 			    (int)OSC_USB_PHY_48 == (int)_USB_PHY_48);
154bb73802dSEtienne Carriere 
155bb73802dSEtienne Carriere 	return (enum stm32mp1_parent_id)osc_id;
156bb73802dSEtienne Carriere }
157bb73802dSEtienne Carriere 
1586b651796SEtienne Carriere static enum stm32mp1_parent_id clock_id2parent_id(unsigned long id)
1596b651796SEtienne Carriere {
1606b651796SEtienne Carriere 	size_t n = 0;
1616b651796SEtienne Carriere 
1626b651796SEtienne Carriere 	COMPILE_TIME_ASSERT(STM32MP1_LAST_CLK < _UNKNOWN_ID);
1636b651796SEtienne Carriere 
1646b651796SEtienne Carriere 	for (n = 0; n < ARRAY_SIZE(parent_id_clock_id); n++)
1656b651796SEtienne Carriere 		if (parent_id_clock_id[n] == id)
1666b651796SEtienne Carriere 			return (enum stm32mp1_parent_id)n;
1676b651796SEtienne Carriere 
1686b651796SEtienne Carriere 	return _UNKNOWN_ID;
1696b651796SEtienne Carriere }
1706b651796SEtienne Carriere 
1716b651796SEtienne Carriere /* Identifiers for PLLs and their configuration resources */
1726b651796SEtienne Carriere enum stm32mp1_pll_id {
1736b651796SEtienne Carriere 	_PLL1,
1746b651796SEtienne Carriere 	_PLL2,
1756b651796SEtienne Carriere 	_PLL3,
1766b651796SEtienne Carriere 	_PLL4,
1776b651796SEtienne Carriere 	_PLL_NB
1786b651796SEtienne Carriere };
1796b651796SEtienne Carriere 
1806b651796SEtienne Carriere enum stm32mp1_div_id {
1816b651796SEtienne Carriere 	_DIV_P,
1826b651796SEtienne Carriere 	_DIV_Q,
1836b651796SEtienne Carriere 	_DIV_R,
1846b651796SEtienne Carriere 	_DIV_NB,
1856b651796SEtienne Carriere };
1866b651796SEtienne Carriere 
1876b651796SEtienne Carriere enum stm32mp1_plltype {
1886b651796SEtienne Carriere 	PLL_800,
1896b651796SEtienne Carriere 	PLL_1600,
1906b651796SEtienne Carriere 	PLL_TYPE_NB
1916b651796SEtienne Carriere };
1926b651796SEtienne Carriere 
1936b651796SEtienne Carriere /*
1946b651796SEtienne Carriere  * Clock generic gates clocks which state is controlled by a single RCC bit
1956b651796SEtienne Carriere  *
1966b651796SEtienne Carriere  * @offset: RCC register byte offset from RCC base where clock is controlled
1976b651796SEtienne Carriere  * @bit: Bit position in the RCC 32bit register
1986b651796SEtienne Carriere  * @clock_id: Identifier used for the clock in the clock driver API
1996b651796SEtienne Carriere  * @set_clr: Non-null if and only-if RCC register is a CLEAR/SET register
2006b651796SEtienne Carriere  *	(CLEAR register is at offset RCC_MP_ENCLRR_OFFSET from SET register)
2016b651796SEtienne Carriere  * @secure: One of N_S or SEC, defined below
2026b651796SEtienne Carriere  * @sel: _UNKNOWN_ID (fixed parent) or reference to parent clock selector
2036b651796SEtienne Carriere  *	(8bit storage of ID from enum stm32mp1_parent_sel)
2046b651796SEtienne Carriere  * @fixed: _UNKNOWN_ID (selectable paranet) or reference to parent clock
2056b651796SEtienne Carriere  *	(8bit storage of ID from enum stm32mp1_parent_id)
2066b651796SEtienne Carriere  */
2076b651796SEtienne Carriere struct stm32mp1_clk_gate {
2086b651796SEtienne Carriere 	uint16_t offset;
2096b651796SEtienne Carriere 	uint8_t bit;
2106b651796SEtienne Carriere 	uint8_t clock_id;
2116b651796SEtienne Carriere 	uint8_t set_clr;
2126b651796SEtienne Carriere 	uint8_t secure;
2136b651796SEtienne Carriere 	uint8_t sel; /* Relates to enum stm32mp1_parent_sel */
2146b651796SEtienne Carriere 	uint8_t fixed; /* Relates to enum stm32mp1_parent_id */
2156b651796SEtienne Carriere };
2166b651796SEtienne Carriere 
2176b651796SEtienne Carriere /* Parent clock selection: select register info, parent clocks references */
2186b651796SEtienne Carriere struct stm32mp1_clk_sel {
2196b651796SEtienne Carriere 	uint16_t offset;
2206b651796SEtienne Carriere 	uint8_t src;
2216b651796SEtienne Carriere 	uint8_t msk;
2226b651796SEtienne Carriere 	uint8_t nb_parent;
2236b651796SEtienne Carriere 	const uint8_t *parent;
2246b651796SEtienne Carriere };
2256b651796SEtienne Carriere 
2266b651796SEtienne Carriere #define REFCLK_SIZE 4
2276b651796SEtienne Carriere /* PLL control: type, control register offsets, up-to-4 selectable parent */
2286b651796SEtienne Carriere struct stm32mp1_clk_pll {
2296b651796SEtienne Carriere 	enum stm32mp1_plltype plltype;
2306b651796SEtienne Carriere 	uint16_t rckxselr;
2316b651796SEtienne Carriere 	uint16_t pllxcfgr1;
2326b651796SEtienne Carriere 	uint16_t pllxcfgr2;
2336b651796SEtienne Carriere 	uint16_t pllxfracr;
2346b651796SEtienne Carriere 	uint16_t pllxcr;
2356b651796SEtienne Carriere 	uint16_t pllxcsgr;
2366b651796SEtienne Carriere 	enum stm32mp_osc_id refclk[REFCLK_SIZE];
2376b651796SEtienne Carriere };
2386b651796SEtienne Carriere 
2396b651796SEtienne Carriere #define N_S	0	/* Non-secure can access RCC interface */
2406b651796SEtienne Carriere #define SEC	1	/* RCC[TZEN] protects RCC interface */
2416b651796SEtienne Carriere 
2426b651796SEtienne Carriere /* Clocks with selectable source and not set/clr register access */
2436b651796SEtienne Carriere #define _CLK_SELEC(_sec, _offset, _bit, _clock_id, _parent_sel)	\
2446b651796SEtienne Carriere 	{							\
2456b651796SEtienne Carriere 		.offset = (_offset),				\
2466b651796SEtienne Carriere 		.bit = (_bit),					\
2476b651796SEtienne Carriere 		.clock_id = (_clock_id),			\
2486b651796SEtienne Carriere 		.set_clr = 0,					\
2496b651796SEtienne Carriere 		.secure = (_sec),				\
2506b651796SEtienne Carriere 		.sel = (_parent_sel),				\
2516b651796SEtienne Carriere 		.fixed = _UNKNOWN_ID,				\
2526b651796SEtienne Carriere 	}
2536b651796SEtienne Carriere 
2546b651796SEtienne Carriere /* Clocks with fixed source and not set/clr register access */
2556b651796SEtienne Carriere #define _CLK_FIXED(_sec, _offset, _bit, _clock_id, _parent)		\
2566b651796SEtienne Carriere 	{							\
2576b651796SEtienne Carriere 		.offset = (_offset),				\
2586b651796SEtienne Carriere 		.bit = (_bit),					\
2596b651796SEtienne Carriere 		.clock_id = (_clock_id),			\
2606b651796SEtienne Carriere 		.set_clr = 0,					\
2616b651796SEtienne Carriere 		.secure = (_sec),				\
2626b651796SEtienne Carriere 		.sel = _UNKNOWN_SEL,				\
2636b651796SEtienne Carriere 		.fixed = (_parent),				\
2646b651796SEtienne Carriere 	}
2656b651796SEtienne Carriere 
2666b651796SEtienne Carriere /* Clocks with selectable source and set/clr register access */
2676b651796SEtienne Carriere #define _CLK_SC_SELEC(_sec, _offset, _bit, _clock_id, _parent_sel)	\
2686b651796SEtienne Carriere 	{							\
2696b651796SEtienne Carriere 		.offset = (_offset),				\
2706b651796SEtienne Carriere 		.bit = (_bit),					\
2716b651796SEtienne Carriere 		.clock_id = (_clock_id),			\
2726b651796SEtienne Carriere 		.set_clr = 1,					\
2736b651796SEtienne Carriere 		.secure = (_sec),				\
2746b651796SEtienne Carriere 		.sel = (_parent_sel),				\
2756b651796SEtienne Carriere 		.fixed = _UNKNOWN_ID,				\
2766b651796SEtienne Carriere 	}
2776b651796SEtienne Carriere 
2786b651796SEtienne Carriere /* Clocks with fixed source and set/clr register access */
2796b651796SEtienne Carriere #define _CLK_SC_FIXED(_sec, _offset, _bit, _clock_id, _parent)	\
2806b651796SEtienne Carriere 	{							\
2816b651796SEtienne Carriere 		.offset = (_offset),				\
2826b651796SEtienne Carriere 		.bit = (_bit),					\
2836b651796SEtienne Carriere 		.clock_id = (_clock_id),			\
2846b651796SEtienne Carriere 		.set_clr = 1,					\
2856b651796SEtienne Carriere 		.secure = (_sec),				\
2866b651796SEtienne Carriere 		.sel = _UNKNOWN_SEL,				\
2876b651796SEtienne Carriere 		.fixed = (_parent),				\
2886b651796SEtienne Carriere 	}
2896b651796SEtienne Carriere 
2906b651796SEtienne Carriere /*
2916b651796SEtienne Carriere  * Clocks with selectable source and set/clr register access
2926b651796SEtienne Carriere  * and enable bit position defined by a label (argument _bit)
2936b651796SEtienne Carriere  */
2946b651796SEtienne Carriere #define _CLK_SC2_SELEC(_sec, _offset, _bit, _clock_id, _parent_sel)	\
2956b651796SEtienne Carriere 	{							\
2966b651796SEtienne Carriere 		.offset = (_offset),				\
2976b651796SEtienne Carriere 		.clock_id = (_clock_id),			\
2986b651796SEtienne Carriere 		.bit = _offset ## _ ## _bit ## _POS,		\
2996b651796SEtienne Carriere 		.set_clr = 1,					\
3006b651796SEtienne Carriere 		.secure = (_sec),				\
3016b651796SEtienne Carriere 		.sel = (_parent_sel),				\
3026b651796SEtienne Carriere 		.fixed = _UNKNOWN_ID,				\
3036b651796SEtienne Carriere 	}
3046b651796SEtienne Carriere #define _CLK_SC2_FIXED(_sec, _offset, _bit, _clock_id, _parent)	\
3056b651796SEtienne Carriere 	{							\
3066b651796SEtienne Carriere 		.offset = (_offset),				\
3076b651796SEtienne Carriere 		.clock_id = (_clock_id),			\
3086b651796SEtienne Carriere 		.bit = _offset ## _ ## _bit ## _POS,		\
3096b651796SEtienne Carriere 		.set_clr = 1,					\
3106b651796SEtienne Carriere 		.secure = (_sec),				\
3116b651796SEtienne Carriere 		.sel = _UNKNOWN_SEL,				\
3126b651796SEtienne Carriere 		.fixed = (_parent),				\
3136b651796SEtienne Carriere 	}
3146b651796SEtienne Carriere 
3156b651796SEtienne Carriere #define _CLK_PARENT(idx, _offset, _src, _mask, _parent)		\
3166b651796SEtienne Carriere 	[(idx)] = {						\
3176b651796SEtienne Carriere 		.offset = (_offset),				\
3186b651796SEtienne Carriere 		.src = (_src),					\
3196b651796SEtienne Carriere 		.msk = (_mask),					\
3206b651796SEtienne Carriere 		.parent = (_parent),				\
3216b651796SEtienne Carriere 		.nb_parent = ARRAY_SIZE(_parent)		\
3226b651796SEtienne Carriere 	}
3236b651796SEtienne Carriere 
3246b651796SEtienne Carriere #define _CLK_PLL(_idx, _type, _off1, _off2, _off3, _off4,	\
3256b651796SEtienne Carriere 		 _off5, _off6, _p1, _p2, _p3, _p4)		\
3266b651796SEtienne Carriere 	[(_idx)] = {						\
3276b651796SEtienne Carriere 		.plltype = (_type),				\
3286b651796SEtienne Carriere 		.rckxselr = (_off1),				\
3296b651796SEtienne Carriere 		.pllxcfgr1 = (_off2),				\
3306b651796SEtienne Carriere 		.pllxcfgr2 = (_off3),				\
3316b651796SEtienne Carriere 		.pllxfracr = (_off4),				\
3326b651796SEtienne Carriere 		.pllxcr = (_off5),				\
3336b651796SEtienne Carriere 		.pllxcsgr = (_off6),				\
3346b651796SEtienne Carriere 		.refclk[0] = (_p1),				\
3356b651796SEtienne Carriere 		.refclk[1] = (_p2),				\
3366b651796SEtienne Carriere 		.refclk[2] = (_p3),				\
3376b651796SEtienne Carriere 		.refclk[3] = (_p4),				\
3386b651796SEtienne Carriere 	}
3396b651796SEtienne Carriere 
3406b651796SEtienne Carriere #define NB_GATES	ARRAY_SIZE(stm32mp1_clk_gate)
3416b651796SEtienne Carriere 
3426b651796SEtienne Carriere static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
3436b651796SEtienne Carriere 	_CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK),
3446b651796SEtienne Carriere 	_CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
3456b651796SEtienne Carriere 	_CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK),
3466b651796SEtienne Carriere 	_CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
3476b651796SEtienne Carriere 	_CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
3486b651796SEtienne Carriere 	_CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
3496b651796SEtienne Carriere 	_CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
3506b651796SEtienne Carriere 	_CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
3516b651796SEtienne Carriere 	_CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK),
3526b651796SEtienne Carriere 	_CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
3536b651796SEtienne Carriere 	_CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
3546b651796SEtienne Carriere 
3556b651796SEtienne Carriere 	_CLK_SC2_SELEC(SEC, RCC_MP_APB5ENSETR, SPI6EN, SPI6_K, _SPI6_SEL),
3566b651796SEtienne Carriere 	_CLK_SC2_SELEC(SEC, RCC_MP_APB5ENSETR, I2C4EN, I2C4_K, _I2C46_SEL),
3576b651796SEtienne Carriere 	_CLK_SC2_SELEC(SEC, RCC_MP_APB5ENSETR, I2C6EN, I2C6_K, _I2C46_SEL),
3586b651796SEtienne Carriere 	_CLK_SC2_SELEC(SEC, RCC_MP_APB5ENSETR, USART1EN, USART1_K, _USART1_SEL),
3596b651796SEtienne Carriere 	_CLK_SC2_FIXED(SEC, RCC_MP_APB5ENSETR, RTCAPBEN, RTCAPB, _PCLK5),
3606b651796SEtienne Carriere 	_CLK_SC2_FIXED(SEC, RCC_MP_APB5ENSETR, TZC1EN, TZC1, _PCLK5),
3616b651796SEtienne Carriere 	_CLK_SC2_FIXED(SEC, RCC_MP_APB5ENSETR, TZC2EN, TZC2, _PCLK5),
3626b651796SEtienne Carriere 	_CLK_SC2_FIXED(SEC, RCC_MP_APB5ENSETR, TZPCEN, TZPC, _PCLK5),
3636b651796SEtienne Carriere 	_CLK_SC2_FIXED(SEC, RCC_MP_APB5ENSETR, IWDG1APBEN, IWDG1, _PCLK5),
3646b651796SEtienne Carriere 	_CLK_SC2_FIXED(SEC, RCC_MP_APB5ENSETR, BSECEN, BSEC, _PCLK5),
3656b651796SEtienne Carriere 	_CLK_SC2_SELEC(SEC, RCC_MP_APB5ENSETR, STGENEN, STGEN_K, _STGEN_SEL),
3666b651796SEtienne Carriere 
3676b651796SEtienne Carriere 	_CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, GPIOZEN, GPIOZ, _HCLK5),
3686b651796SEtienne Carriere 	_CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, CRYP1EN, CRYP1, _HCLK5),
3696b651796SEtienne Carriere 	_CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, HASH1EN, HASH1, _HCLK5),
3706b651796SEtienne Carriere 	_CLK_SC2_SELEC(SEC, RCC_MP_AHB5ENSETR, RNG1EN, RNG1_K, _RNG1_SEL),
3713e3bea3dSEtienne Carriere 	_CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, BKPSRAMEN, BKPSRAM, _HCLK5),
3726b651796SEtienne Carriere 
3736b651796SEtienne Carriere 	_CLK_SC2_FIXED(SEC, RCC_MP_TZAHB6ENSETR, MDMA, MDMA, _HCLK6),
3746b651796SEtienne Carriere 
3756b651796SEtienne Carriere 	_CLK_SELEC(SEC, RCC_BDCR, RCC_BDCR_RTCCKEN_POS, RTC, _RTC_SEL),
3766b651796SEtienne Carriere 
3776b651796SEtienne Carriere 	/* Non-secure clocks */
3786b651796SEtienne Carriere #ifdef CFG_WITH_NSEC_GPIOS
3796b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_ID),
3806b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_ID),
3816b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_ID),
3826b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_ID),
3836b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_ID),
3846b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_ID),
3856b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_ID),
3866b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_ID),
3876b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_ID),
3886b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_ID),
3896b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_ID),
3906b651796SEtienne Carriere #endif
3916b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
3926b651796SEtienne Carriere #ifdef CFG_WITH_NSEC_UARTS
3936b651796SEtienne Carriere 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
3946b651796SEtienne Carriere 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
3956b651796SEtienne Carriere 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
3966b651796SEtienne Carriere 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
3976b651796SEtienne Carriere 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
3986b651796SEtienne Carriere 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
3996b651796SEtienne Carriere #endif
4006b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
4016b651796SEtienne Carriere #ifdef CFG_WITH_NSEC_UARTS
4026b651796SEtienne Carriere 	_CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
4036b651796SEtienne Carriere #endif
4046b651796SEtienne Carriere 	_CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID),
4056b651796SEtienne Carriere 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
4066b651796SEtienne Carriere 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
4076b651796SEtienne Carriere 
4086b651796SEtienne Carriere 	_CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
4096b651796SEtienne Carriere };
4106b651796SEtienne Carriere DECLARE_KEEP_PAGER(stm32mp1_clk_gate);
4116b651796SEtienne Carriere 
4126b651796SEtienne Carriere const uint8_t stm32mp1_clk_on[] = {
4136b651796SEtienne Carriere 	CK_HSE, CK_CSI, CK_LSI, CK_LSE, CK_HSI, CK_HSE_DIV2,
4146b651796SEtienne Carriere 	PLL1_P, PLL1_Q, PLL1_R, PLL2_P, PLL2_Q, PLL2_R, PLL3_P, PLL3_Q, PLL3_R,
4156b651796SEtienne Carriere 	CK_AXI, CK_MPU, CK_MCU,
4166b651796SEtienne Carriere };
4176b651796SEtienne Carriere 
4186b651796SEtienne Carriere /* Parents for secure aware clocks in the xxxSELR value ordering */
4196b651796SEtienne Carriere static const uint8_t stgen_parents[] = {
4206b651796SEtienne Carriere 	_HSI_KER, _HSE_KER
4216b651796SEtienne Carriere };
4226b651796SEtienne Carriere 
4236b651796SEtienne Carriere static const uint8_t i2c46_parents[] = {
4246b651796SEtienne Carriere 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER
4256b651796SEtienne Carriere };
4266b651796SEtienne Carriere 
4276b651796SEtienne Carriere static const uint8_t spi6_parents[] = {
4286b651796SEtienne Carriere 	_PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q
4296b651796SEtienne Carriere };
4306b651796SEtienne Carriere 
4316b651796SEtienne Carriere static const uint8_t usart1_parents[] = {
4326b651796SEtienne Carriere 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER
4336b651796SEtienne Carriere };
4346b651796SEtienne Carriere 
4356b651796SEtienne Carriere static const uint8_t rng1_parents[] = {
4366b651796SEtienne Carriere 	_CSI, _PLL4_R, _LSE, _LSI
4376b651796SEtienne Carriere };
4386b651796SEtienne Carriere 
43962bb2715SEtienne Carriere static const uint8_t mpu_parents[] = {
44062bb2715SEtienne Carriere 	_HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */
44162bb2715SEtienne Carriere };
44262bb2715SEtienne Carriere 
4436b651796SEtienne Carriere /* Parents for (some) non-secure clocks */
4446b651796SEtienne Carriere #ifdef CFG_WITH_NSEC_UARTS
4456b651796SEtienne Carriere static const uint8_t uart6_parents[] = {
4466b651796SEtienne Carriere 	_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
4476b651796SEtienne Carriere };
4486b651796SEtienne Carriere 
4496b651796SEtienne Carriere static const uint8_t uart234578_parents[] = {
4506b651796SEtienne Carriere 	_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
4516b651796SEtienne Carriere };
4526b651796SEtienne Carriere #endif
4536b651796SEtienne Carriere 
4546b651796SEtienne Carriere static const uint8_t axiss_parents[] = {
4556b651796SEtienne Carriere 	_HSI, _HSE, _PLL2_P
4566b651796SEtienne Carriere };
4576b651796SEtienne Carriere 
4586b651796SEtienne Carriere static const uint8_t mcuss_parents[] = {
4596b651796SEtienne Carriere 	_HSI, _HSE, _CSI, _PLL3_P
4606b651796SEtienne Carriere };
4616b651796SEtienne Carriere 
4626b651796SEtienne Carriere static const uint8_t rtc_parents[] = {
46362bb2715SEtienne Carriere 	_UNKNOWN_ID, _LSE, _LSI, _HSE_RTC
4646b651796SEtienne Carriere };
4656b651796SEtienne Carriere 
4666b651796SEtienne Carriere static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
4676b651796SEtienne Carriere 	/* Secure aware clocks */
4686b651796SEtienne Carriere 	_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents),
4696b651796SEtienne Carriere 	_CLK_PARENT(_I2C46_SEL, RCC_I2C46CKSELR, 0, 0x7, i2c46_parents),
4706b651796SEtienne Carriere 	_CLK_PARENT(_SPI6_SEL, RCC_SPI6CKSELR, 0, 0x7, spi6_parents),
4716b651796SEtienne Carriere 	_CLK_PARENT(_USART1_SEL, RCC_UART1CKSELR, 0, 0x7, usart1_parents),
4726b651796SEtienne Carriere 	_CLK_PARENT(_RNG1_SEL, RCC_RNG1CKSELR, 0, 0x3, rng1_parents),
47362bb2715SEtienne Carriere 	_CLK_PARENT(_RTC_SEL, RCC_BDCR, 16, 0x3, rtc_parents),
47462bb2715SEtienne Carriere 	_CLK_PARENT(_MPU_SEL, RCC_MPCKSELR, 0, 0x3, mpu_parents),
4756b651796SEtienne Carriere 	/* Always non-secure clocks (maybe used in some way in secure world) */
4766b651796SEtienne Carriere #ifdef CFG_WITH_NSEC_UARTS
4776b651796SEtienne Carriere 	_CLK_PARENT(_UART6_SEL, RCC_UART6CKSELR, 0, 0x7, uart6_parents),
4786b651796SEtienne Carriere 	_CLK_PARENT(_UART24_SEL, RCC_UART24CKSELR, 0, 0x7, uart234578_parents),
4796b651796SEtienne Carriere 	_CLK_PARENT(_UART35_SEL, RCC_UART35CKSELR, 0, 0x7, uart234578_parents),
4806b651796SEtienne Carriere 	_CLK_PARENT(_UART78_SEL, RCC_UART78CKSELR, 0, 0x7, uart234578_parents),
4816b651796SEtienne Carriere #endif
4826b651796SEtienne Carriere 	_CLK_PARENT(_AXISS_SEL, RCC_ASSCKSELR, 0, 0x3, axiss_parents),
4836b651796SEtienne Carriere 	_CLK_PARENT(_MCUSS_SEL, RCC_MSSCKSELR, 0, 0x3, mcuss_parents),
4846b651796SEtienne Carriere };
4856b651796SEtienne Carriere 
4866b651796SEtienne Carriere /* PLLNCFGR2 register divider by output */
4876b651796SEtienne Carriere static const uint8_t pllncfgr2[_DIV_NB] = {
4886b651796SEtienne Carriere 	[_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT,
4896b651796SEtienne Carriere 	[_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT,
4906b651796SEtienne Carriere 	[_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT,
4916b651796SEtienne Carriere };
4926b651796SEtienne Carriere 
4936b651796SEtienne Carriere static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = {
4946b651796SEtienne Carriere 	_CLK_PLL(_PLL1, PLL_1600,
4956b651796SEtienne Carriere 		 RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2,
4966b651796SEtienne Carriere 		 RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR,
497bb73802dSEtienne Carriere 		 OSC_HSI, OSC_HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
4986b651796SEtienne Carriere 	_CLK_PLL(_PLL2, PLL_1600,
4996b651796SEtienne Carriere 		 RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2,
5006b651796SEtienne Carriere 		 RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR,
501bb73802dSEtienne Carriere 		 OSC_HSI, OSC_HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
5026b651796SEtienne Carriere 	_CLK_PLL(_PLL3, PLL_800,
5036b651796SEtienne Carriere 		 RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2,
5046b651796SEtienne Carriere 		 RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR,
505bb73802dSEtienne Carriere 		 OSC_HSI, OSC_HSE, OSC_CSI, _UNKNOWN_OSC_ID),
5066b651796SEtienne Carriere 	_CLK_PLL(_PLL4, PLL_800,
5076b651796SEtienne Carriere 		 RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2,
5086b651796SEtienne Carriere 		 RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR,
509bb73802dSEtienne Carriere 		 OSC_HSI, OSC_HSE, OSC_CSI, OSC_I2S_CKIN),
5106b651796SEtienne Carriere };
5116b651796SEtienne Carriere 
5126b651796SEtienne Carriere /* Prescaler table lookups for clock computation */
5136b651796SEtienne Carriere /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */
5146b651796SEtienne Carriere static const uint8_t stm32mp1_mcu_div[16] = {
5156b651796SEtienne Carriere 	0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9
5166b651796SEtienne Carriere };
5176b651796SEtienne Carriere 
5186b651796SEtienne Carriere /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */
5196b651796SEtienne Carriere #define stm32mp1_mpu_div	stm32mp1_mpu_apbx_div
5206b651796SEtienne Carriere #define stm32mp1_apbx_div	stm32mp1_mpu_apbx_div
5216b651796SEtienne Carriere static const uint8_t stm32mp1_mpu_apbx_div[8] = {
5226b651796SEtienne Carriere 	0, 1, 2, 3, 4, 4, 4, 4
5236b651796SEtienne Carriere };
5246b651796SEtienne Carriere 
5256b651796SEtienne Carriere /* div = /1 /2 /3 /4 */
5266b651796SEtienne Carriere static const uint8_t stm32mp1_axi_div[8] = {
5276b651796SEtienne Carriere 	1, 2, 3, 4, 4, 4, 4, 4
5286b651796SEtienne Carriere };
5296b651796SEtienne Carriere 
5306b651796SEtienne Carriere static const char __maybe_unused *const stm32mp1_clk_parent_name[_PARENT_NB] = {
5316b651796SEtienne Carriere 	[_HSI] = "HSI",
5326b651796SEtienne Carriere 	[_HSE] = "HSE",
5336b651796SEtienne Carriere 	[_CSI] = "CSI",
5346b651796SEtienne Carriere 	[_LSI] = "LSI",
5356b651796SEtienne Carriere 	[_LSE] = "LSE",
5366b651796SEtienne Carriere 	[_I2S_CKIN] = "I2S_CKIN",
5376b651796SEtienne Carriere 	[_HSI_KER] = "HSI_KER",
5386b651796SEtienne Carriere 	[_HSE_KER] = "HSE_KER",
5396b651796SEtienne Carriere 	[_HSE_KER_DIV2] = "HSE_KER_DIV2",
54062bb2715SEtienne Carriere 	[_HSE_RTC] = "HSE_RTC",
5416b651796SEtienne Carriere 	[_CSI_KER] = "CSI_KER",
5426b651796SEtienne Carriere 	[_PLL1_P] = "PLL1_P",
5436b651796SEtienne Carriere 	[_PLL1_Q] = "PLL1_Q",
5446b651796SEtienne Carriere 	[_PLL1_R] = "PLL1_R",
5456b651796SEtienne Carriere 	[_PLL2_P] = "PLL2_P",
5466b651796SEtienne Carriere 	[_PLL2_Q] = "PLL2_Q",
5476b651796SEtienne Carriere 	[_PLL2_R] = "PLL2_R",
5486b651796SEtienne Carriere 	[_PLL3_P] = "PLL3_P",
5496b651796SEtienne Carriere 	[_PLL3_Q] = "PLL3_Q",
5506b651796SEtienne Carriere 	[_PLL3_R] = "PLL3_R",
5516b651796SEtienne Carriere 	[_PLL4_P] = "PLL4_P",
5526b651796SEtienne Carriere 	[_PLL4_Q] = "PLL4_Q",
5536b651796SEtienne Carriere 	[_PLL4_R] = "PLL4_R",
5546b651796SEtienne Carriere 	[_ACLK] = "ACLK",
5556b651796SEtienne Carriere 	[_PCLK1] = "PCLK1",
5566b651796SEtienne Carriere 	[_PCLK2] = "PCLK2",
5576b651796SEtienne Carriere 	[_PCLK3] = "PCLK3",
5586b651796SEtienne Carriere 	[_PCLK4] = "PCLK4",
5596b651796SEtienne Carriere 	[_PCLK5] = "PCLK5",
5606b651796SEtienne Carriere 	[_HCLK5] = "HCLK5",
5616b651796SEtienne Carriere 	[_HCLK6] = "HCLK6",
5626b651796SEtienne Carriere 	[_HCLK2] = "HCLK2",
5636b651796SEtienne Carriere 	[_CK_PER] = "CK_PER",
5646b651796SEtienne Carriere 	[_CK_MPU] = "CK_MPU",
5656b651796SEtienne Carriere 	[_CK_MCU] = "CK_MCU",
5666b651796SEtienne Carriere 	[_USB_PHY_48] = "USB_PHY_48",
5676b651796SEtienne Carriere };
5686b651796SEtienne Carriere 
5696b651796SEtienne Carriere /*
5706b651796SEtienne Carriere  * Oscillator frequency in Hz. This array shall be initialized
5716b651796SEtienne Carriere  * according to platform.
5726b651796SEtienne Carriere  */
5736b651796SEtienne Carriere static unsigned long stm32mp1_osc[NB_OSC];
5746b651796SEtienne Carriere 
5756b651796SEtienne Carriere static unsigned long osc_frequency(enum stm32mp_osc_id idx)
5766b651796SEtienne Carriere {
5776b651796SEtienne Carriere 	if (idx >= ARRAY_SIZE(stm32mp1_osc)) {
5786b651796SEtienne Carriere 		DMSG("clk id %d not found", idx);
5796b651796SEtienne Carriere 		return 0;
5806b651796SEtienne Carriere 	}
5816b651796SEtienne Carriere 
5826b651796SEtienne Carriere 	return stm32mp1_osc[idx];
5836b651796SEtienne Carriere }
5846b651796SEtienne Carriere 
5856b651796SEtienne Carriere static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx)
5866b651796SEtienne Carriere {
5876b651796SEtienne Carriere 	return &stm32mp1_clk_gate[idx];
5886b651796SEtienne Carriere }
5896b651796SEtienne Carriere 
5906b651796SEtienne Carriere static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx)
5916b651796SEtienne Carriere {
5926b651796SEtienne Carriere 	return &stm32mp1_clk_sel[idx];
5936b651796SEtienne Carriere }
5946b651796SEtienne Carriere 
5956b651796SEtienne Carriere static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx)
5966b651796SEtienne Carriere {
5976b651796SEtienne Carriere 	return &stm32mp1_clk_pll[idx];
5986b651796SEtienne Carriere }
5996b651796SEtienne Carriere 
6006b651796SEtienne Carriere static int stm32mp1_clk_get_gated_id(unsigned long id)
6016b651796SEtienne Carriere {
6026b651796SEtienne Carriere 	unsigned int i = 0;
6036b651796SEtienne Carriere 
6046b651796SEtienne Carriere 	for (i = 0; i < NB_GATES; i++)
6056b651796SEtienne Carriere 		if (gate_ref(i)->clock_id == id)
6066b651796SEtienne Carriere 			return i;
6076b651796SEtienne Carriere 
6086b651796SEtienne Carriere 	DMSG("clk id %lu not found", id);
6096b651796SEtienne Carriere 	return -1;
6106b651796SEtienne Carriere }
6116b651796SEtienne Carriere 
6126b651796SEtienne Carriere static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i)
6136b651796SEtienne Carriere {
6146b651796SEtienne Carriere 	return (enum stm32mp1_parent_sel)gate_ref(i)->sel;
6156b651796SEtienne Carriere }
6166b651796SEtienne Carriere 
6176b651796SEtienne Carriere static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i)
6186b651796SEtienne Carriere {
6196b651796SEtienne Carriere 	return (enum stm32mp1_parent_id)gate_ref(i)->fixed;
6206b651796SEtienne Carriere }
6216b651796SEtienne Carriere 
6226b651796SEtienne Carriere static int stm32mp1_clk_get_parent(unsigned long id)
6236b651796SEtienne Carriere {
6246b651796SEtienne Carriere 	const struct stm32mp1_clk_sel *sel = NULL;
6256b651796SEtienne Carriere 	enum stm32mp1_parent_id parent_id = 0;
6266b651796SEtienne Carriere 	uint32_t p_sel = 0;
6276b651796SEtienne Carriere 	int i = 0;
6286b651796SEtienne Carriere 	enum stm32mp1_parent_id p = _UNKNOWN_ID;
6296b651796SEtienne Carriere 	enum stm32mp1_parent_sel s = _UNKNOWN_SEL;
6306b651796SEtienne Carriere 	vaddr_t rcc_base = stm32_rcc_base();
6316b651796SEtienne Carriere 
6326b651796SEtienne Carriere 	parent_id = clock_id2parent_id(id);
6336b651796SEtienne Carriere 	if (parent_id != _UNKNOWN_ID)
6346b651796SEtienne Carriere 		return (int)parent_id;
6356b651796SEtienne Carriere 
6366b651796SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
6376b651796SEtienne Carriere 	if (i < 0)
6386b651796SEtienne Carriere 		panic();
6396b651796SEtienne Carriere 
6406b651796SEtienne Carriere 	p = stm32mp1_clk_get_fixed_parent(i);
6416b651796SEtienne Carriere 	if (p < _PARENT_NB)
6426b651796SEtienne Carriere 		return (int)p;
6436b651796SEtienne Carriere 
6446b651796SEtienne Carriere 	s = stm32mp1_clk_get_sel(i);
6456b651796SEtienne Carriere 	if (s == _UNKNOWN_SEL)
6466b651796SEtienne Carriere 		return -1;
6476b651796SEtienne Carriere 	if (s >= _PARENT_SEL_NB)
6486b651796SEtienne Carriere 		panic();
6496b651796SEtienne Carriere 
6506b651796SEtienne Carriere 	sel = clk_sel_ref(s);
6516b651796SEtienne Carriere 	p_sel = (io_read32(rcc_base + sel->offset) >> sel->src) & sel->msk;
6526b651796SEtienne Carriere 	if (p_sel < sel->nb_parent)
6536b651796SEtienne Carriere 		return (int)sel->parent[p_sel];
6546b651796SEtienne Carriere 
6556b651796SEtienne Carriere 	DMSG("No parent selected for clk %lu", id);
6566b651796SEtienne Carriere 	return -1;
6576b651796SEtienne Carriere }
6586b651796SEtienne Carriere 
6596b651796SEtienne Carriere static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll)
6606b651796SEtienne Carriere {
6616b651796SEtienne Carriere 	uint32_t selr = io_read32(stm32_rcc_base() + pll->rckxselr);
6626b651796SEtienne Carriere 	uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK;
6636b651796SEtienne Carriere 
6646b651796SEtienne Carriere 	return osc_frequency(pll->refclk[src]);
6656b651796SEtienne Carriere }
6666b651796SEtienne Carriere 
6676b651796SEtienne Carriere /*
6686b651796SEtienne Carriere  * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL
6696b651796SEtienne Carriere  * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1)
6706b651796SEtienne Carriere  * - PLL3 & PLL4 => return VCO     with Fpll_y_ck = FVCO / (DIVy + 1)
6716b651796SEtienne Carriere  * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1)
6726b651796SEtienne Carriere  */
6736b651796SEtienne Carriere static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll)
6746b651796SEtienne Carriere {
6756b651796SEtienne Carriere 	unsigned long refclk = 0;
6766b651796SEtienne Carriere 	unsigned long fvco = 0;
6776b651796SEtienne Carriere 	uint32_t cfgr1 = 0;
6786b651796SEtienne Carriere 	uint32_t fracr = 0;
6796b651796SEtienne Carriere 	uint32_t divm = 0;
6806b651796SEtienne Carriere 	uint32_t divn = 0;
6816b651796SEtienne Carriere 
6826b651796SEtienne Carriere 	cfgr1 = io_read32(stm32_rcc_base() + pll->pllxcfgr1);
6836b651796SEtienne Carriere 	fracr = io_read32(stm32_rcc_base() + pll->pllxfracr);
6846b651796SEtienne Carriere 
6856b651796SEtienne Carriere 	divm = (cfgr1 & RCC_PLLNCFGR1_DIVM_MASK) >> RCC_PLLNCFGR1_DIVM_SHIFT;
6866b651796SEtienne Carriere 	divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK;
6876b651796SEtienne Carriere 
6886b651796SEtienne Carriere 	refclk = stm32mp1_pll_get_fref(pll);
6896b651796SEtienne Carriere 
6906b651796SEtienne Carriere 	/*
6916b651796SEtienne Carriere 	 * With FRACV :
6926b651796SEtienne Carriere 	 *   Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1)
6936b651796SEtienne Carriere 	 * Without FRACV
6946b651796SEtienne Carriere 	 *   Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1)
6956b651796SEtienne Carriere 	 */
6966b651796SEtienne Carriere 	if (fracr & RCC_PLLNFRACR_FRACLE) {
6976b651796SEtienne Carriere 		unsigned long long numerator = 0;
6986b651796SEtienne Carriere 		unsigned long long denominator = 0;
6996b651796SEtienne Carriere 		uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >>
7006b651796SEtienne Carriere 				 RCC_PLLNFRACR_FRACV_SHIFT;
7016b651796SEtienne Carriere 
7026b651796SEtienne Carriere 		numerator = (((unsigned long long)divn + 1U) << 13) + fracv;
7036b651796SEtienne Carriere 		numerator = refclk * numerator;
7046b651796SEtienne Carriere 		denominator = ((unsigned long long)divm + 1U) << 13;
7056b651796SEtienne Carriere 		fvco = (unsigned long)(numerator / denominator);
7066b651796SEtienne Carriere 	} else {
7076b651796SEtienne Carriere 		fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U));
7086b651796SEtienne Carriere 	}
7096b651796SEtienne Carriere 
7106b651796SEtienne Carriere 	return fvco;
7116b651796SEtienne Carriere }
7126b651796SEtienne Carriere 
7136b651796SEtienne Carriere static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id,
7146b651796SEtienne Carriere 					    enum stm32mp1_div_id div_id)
7156b651796SEtienne Carriere {
7166b651796SEtienne Carriere 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
7176b651796SEtienne Carriere 	unsigned long dfout = 0;
7186b651796SEtienne Carriere 	uint32_t cfgr2 = 0;
7196b651796SEtienne Carriere 	uint32_t divy = 0;
7206b651796SEtienne Carriere 
7216b651796SEtienne Carriere 	if (div_id >= _DIV_NB)
7226b651796SEtienne Carriere 		return 0;
7236b651796SEtienne Carriere 
7246b651796SEtienne Carriere 	cfgr2 = io_read32(stm32_rcc_base() + pll->pllxcfgr2);
7256b651796SEtienne Carriere 	divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK;
7266b651796SEtienne Carriere 
7276b651796SEtienne Carriere 	dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U);
7286b651796SEtienne Carriere 
7296b651796SEtienne Carriere 	return dfout;
7306b651796SEtienne Carriere }
7316b651796SEtienne Carriere 
732bb73802dSEtienne Carriere static unsigned long get_clock_rate(enum stm32mp1_parent_id p)
7336b651796SEtienne Carriere {
7346b651796SEtienne Carriere 	uint32_t reg = 0;
7356b651796SEtienne Carriere 	unsigned long clock = 0;
7366b651796SEtienne Carriere 	vaddr_t rcc_base = stm32_rcc_base();
7376b651796SEtienne Carriere 
7386b651796SEtienne Carriere 	switch (p) {
7396b651796SEtienne Carriere 	case _CK_MPU:
7406b651796SEtienne Carriere 	/* MPU sub system */
7416b651796SEtienne Carriere 		reg = io_read32(rcc_base + RCC_MPCKSELR);
7426b651796SEtienne Carriere 		switch (reg & RCC_SELR_SRC_MASK) {
7436b651796SEtienne Carriere 		case RCC_MPCKSELR_HSI:
744bb73802dSEtienne Carriere 			clock = osc_frequency(OSC_HSI);
7456b651796SEtienne Carriere 			break;
7466b651796SEtienne Carriere 		case RCC_MPCKSELR_HSE:
747bb73802dSEtienne Carriere 			clock = osc_frequency(OSC_HSE);
7486b651796SEtienne Carriere 			break;
7496b651796SEtienne Carriere 		case RCC_MPCKSELR_PLL:
7506b651796SEtienne Carriere 			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
7516b651796SEtienne Carriere 			break;
7526b651796SEtienne Carriere 		case RCC_MPCKSELR_PLL_MPUDIV:
7536b651796SEtienne Carriere 			reg = io_read32(rcc_base + RCC_MPCKDIVR);
7546b651796SEtienne Carriere 			if (reg & RCC_MPUDIV_MASK)
7556b651796SEtienne Carriere 				clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P) >>
7566b651796SEtienne Carriere 					stm32mp1_mpu_div[reg & RCC_MPUDIV_MASK];
7576b651796SEtienne Carriere 			else
7586b651796SEtienne Carriere 				clock = 0;
7596b651796SEtienne Carriere 			break;
7606b651796SEtienne Carriere 		default:
7616b651796SEtienne Carriere 			break;
7626b651796SEtienne Carriere 		}
7636b651796SEtienne Carriere 		break;
7646b651796SEtienne Carriere 	/* AXI sub system */
7656b651796SEtienne Carriere 	case _ACLK:
7666b651796SEtienne Carriere 	case _HCLK2:
7676b651796SEtienne Carriere 	case _HCLK5:
7686b651796SEtienne Carriere 	case _HCLK6:
7696b651796SEtienne Carriere 	case _PCLK4:
7706b651796SEtienne Carriere 	case _PCLK5:
7716b651796SEtienne Carriere 		reg = io_read32(rcc_base + RCC_ASSCKSELR);
7726b651796SEtienne Carriere 		switch (reg & RCC_SELR_SRC_MASK) {
7736b651796SEtienne Carriere 		case RCC_ASSCKSELR_HSI:
774bb73802dSEtienne Carriere 			clock = osc_frequency(OSC_HSI);
7756b651796SEtienne Carriere 			break;
7766b651796SEtienne Carriere 		case RCC_ASSCKSELR_HSE:
777bb73802dSEtienne Carriere 			clock = osc_frequency(OSC_HSE);
7786b651796SEtienne Carriere 			break;
7796b651796SEtienne Carriere 		case RCC_ASSCKSELR_PLL:
7806b651796SEtienne Carriere 			clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
7816b651796SEtienne Carriere 			break;
7826b651796SEtienne Carriere 		default:
7836b651796SEtienne Carriere 			break;
7846b651796SEtienne Carriere 		}
7856b651796SEtienne Carriere 
7866b651796SEtienne Carriere 		/* System clock divider */
7876b651796SEtienne Carriere 		reg = io_read32(rcc_base + RCC_AXIDIVR);
7886b651796SEtienne Carriere 		clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK];
7896b651796SEtienne Carriere 
7906b651796SEtienne Carriere 		switch (p) {
7916b651796SEtienne Carriere 		case _PCLK4:
7926b651796SEtienne Carriere 			reg = io_read32(rcc_base + RCC_APB4DIVR);
7936b651796SEtienne Carriere 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
7946b651796SEtienne Carriere 			break;
7956b651796SEtienne Carriere 		case _PCLK5:
7966b651796SEtienne Carriere 			reg = io_read32(rcc_base + RCC_APB5DIVR);
7976b651796SEtienne Carriere 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
7986b651796SEtienne Carriere 			break;
7996b651796SEtienne Carriere 		default:
8006b651796SEtienne Carriere 			break;
8016b651796SEtienne Carriere 		}
8026b651796SEtienne Carriere 		break;
8036b651796SEtienne Carriere 	/* MCU sub system */
8046b651796SEtienne Carriere 	case _CK_MCU:
8056b651796SEtienne Carriere 	case _PCLK1:
8066b651796SEtienne Carriere 	case _PCLK2:
8076b651796SEtienne Carriere 	case _PCLK3:
8086b651796SEtienne Carriere 		reg = io_read32(rcc_base + RCC_MSSCKSELR);
8096b651796SEtienne Carriere 		switch (reg & RCC_SELR_SRC_MASK) {
8106b651796SEtienne Carriere 		case RCC_MSSCKSELR_HSI:
811bb73802dSEtienne Carriere 			clock = osc_frequency(OSC_HSI);
8126b651796SEtienne Carriere 			break;
8136b651796SEtienne Carriere 		case RCC_MSSCKSELR_HSE:
814bb73802dSEtienne Carriere 			clock = osc_frequency(OSC_HSE);
8156b651796SEtienne Carriere 			break;
8166b651796SEtienne Carriere 		case RCC_MSSCKSELR_CSI:
817bb73802dSEtienne Carriere 			clock = osc_frequency(OSC_CSI);
8186b651796SEtienne Carriere 			break;
8196b651796SEtienne Carriere 		case RCC_MSSCKSELR_PLL:
8206b651796SEtienne Carriere 			clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
8216b651796SEtienne Carriere 			break;
8226b651796SEtienne Carriere 		default:
8236b651796SEtienne Carriere 			break;
8246b651796SEtienne Carriere 		}
8256b651796SEtienne Carriere 
8266b651796SEtienne Carriere 		/* MCU clock divider */
8276b651796SEtienne Carriere 		reg = io_read32(rcc_base + RCC_MCUDIVR);
8286b651796SEtienne Carriere 		clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK];
8296b651796SEtienne Carriere 
8306b651796SEtienne Carriere 		switch (p) {
8316b651796SEtienne Carriere 		case _PCLK1:
8326b651796SEtienne Carriere 			reg = io_read32(rcc_base + RCC_APB1DIVR);
8336b651796SEtienne Carriere 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
8346b651796SEtienne Carriere 			break;
8356b651796SEtienne Carriere 		case _PCLK2:
8366b651796SEtienne Carriere 			reg = io_read32(rcc_base + RCC_APB2DIVR);
8376b651796SEtienne Carriere 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
8386b651796SEtienne Carriere 			break;
8396b651796SEtienne Carriere 		case _PCLK3:
8406b651796SEtienne Carriere 			reg = io_read32(rcc_base + RCC_APB3DIVR);
8416b651796SEtienne Carriere 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
8426b651796SEtienne Carriere 			break;
8436b651796SEtienne Carriere 		case _CK_MCU:
8446b651796SEtienne Carriere 		default:
8456b651796SEtienne Carriere 			break;
8466b651796SEtienne Carriere 		}
8476b651796SEtienne Carriere 		break;
8486b651796SEtienne Carriere 	case _CK_PER:
8496b651796SEtienne Carriere 		reg = io_read32(rcc_base + RCC_CPERCKSELR);
8506b651796SEtienne Carriere 		switch (reg & RCC_SELR_SRC_MASK) {
8516b651796SEtienne Carriere 		case RCC_CPERCKSELR_HSI:
852bb73802dSEtienne Carriere 			clock = osc_frequency(OSC_HSI);
8536b651796SEtienne Carriere 			break;
8546b651796SEtienne Carriere 		case RCC_CPERCKSELR_HSE:
855bb73802dSEtienne Carriere 			clock = osc_frequency(OSC_HSE);
8566b651796SEtienne Carriere 			break;
8576b651796SEtienne Carriere 		case RCC_CPERCKSELR_CSI:
858bb73802dSEtienne Carriere 			clock = osc_frequency(OSC_CSI);
8596b651796SEtienne Carriere 			break;
8606b651796SEtienne Carriere 		default:
8616b651796SEtienne Carriere 			break;
8626b651796SEtienne Carriere 		}
8636b651796SEtienne Carriere 		break;
8646b651796SEtienne Carriere 	case _HSI:
8656b651796SEtienne Carriere 	case _HSI_KER:
866bb73802dSEtienne Carriere 		clock = osc_frequency(OSC_HSI);
8676b651796SEtienne Carriere 		break;
8686b651796SEtienne Carriere 	case _CSI:
8696b651796SEtienne Carriere 	case _CSI_KER:
870bb73802dSEtienne Carriere 		clock = osc_frequency(OSC_CSI);
8716b651796SEtienne Carriere 		break;
8726b651796SEtienne Carriere 	case _HSE:
8736b651796SEtienne Carriere 	case _HSE_KER:
874bb73802dSEtienne Carriere 		clock = osc_frequency(OSC_HSE);
8756b651796SEtienne Carriere 		break;
8766b651796SEtienne Carriere 	case _HSE_KER_DIV2:
877bb73802dSEtienne Carriere 		clock = osc_frequency(OSC_HSE) >> 1;
878bb73802dSEtienne Carriere 		break;
87962bb2715SEtienne Carriere 	case _HSE_RTC:
88062bb2715SEtienne Carriere 		clock = osc_frequency(OSC_HSE);
88162bb2715SEtienne Carriere 		clock /= (io_read32(rcc_base + RCC_RTCDIVR) &
88262bb2715SEtienne Carriere 			  RCC_DIVR_DIV_MASK) + 1;
8836b651796SEtienne Carriere 		break;
8846b651796SEtienne Carriere 	case _LSI:
885bb73802dSEtienne Carriere 		clock = osc_frequency(OSC_LSI);
8866b651796SEtienne Carriere 		break;
8876b651796SEtienne Carriere 	case _LSE:
888bb73802dSEtienne Carriere 		clock = osc_frequency(OSC_LSE);
8896b651796SEtienne Carriere 		break;
8906b651796SEtienne Carriere 	/* PLL */
8916b651796SEtienne Carriere 	case _PLL1_P:
8926b651796SEtienne Carriere 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
8936b651796SEtienne Carriere 		break;
8946b651796SEtienne Carriere 	case _PLL1_Q:
8956b651796SEtienne Carriere 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q);
8966b651796SEtienne Carriere 		break;
8976b651796SEtienne Carriere 	case _PLL1_R:
8986b651796SEtienne Carriere 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R);
8996b651796SEtienne Carriere 		break;
9006b651796SEtienne Carriere 	case _PLL2_P:
9016b651796SEtienne Carriere 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
9026b651796SEtienne Carriere 		break;
9036b651796SEtienne Carriere 	case _PLL2_Q:
9046b651796SEtienne Carriere 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q);
9056b651796SEtienne Carriere 		break;
9066b651796SEtienne Carriere 	case _PLL2_R:
9076b651796SEtienne Carriere 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R);
9086b651796SEtienne Carriere 		break;
9096b651796SEtienne Carriere 	case _PLL3_P:
9106b651796SEtienne Carriere 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
9116b651796SEtienne Carriere 		break;
9126b651796SEtienne Carriere 	case _PLL3_Q:
9136b651796SEtienne Carriere 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q);
9146b651796SEtienne Carriere 		break;
9156b651796SEtienne Carriere 	case _PLL3_R:
9166b651796SEtienne Carriere 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R);
9176b651796SEtienne Carriere 		break;
9186b651796SEtienne Carriere 	case _PLL4_P:
9196b651796SEtienne Carriere 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P);
9206b651796SEtienne Carriere 		break;
9216b651796SEtienne Carriere 	case _PLL4_Q:
9226b651796SEtienne Carriere 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q);
9236b651796SEtienne Carriere 		break;
9246b651796SEtienne Carriere 	case _PLL4_R:
9256b651796SEtienne Carriere 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R);
9266b651796SEtienne Carriere 		break;
9276b651796SEtienne Carriere 	/* Other */
9286b651796SEtienne Carriere 	case _USB_PHY_48:
929bb73802dSEtienne Carriere 		clock = osc_frequency(OSC_USB_PHY_48);
9306b651796SEtienne Carriere 		break;
9316b651796SEtienne Carriere 	default:
9326b651796SEtienne Carriere 		break;
9336b651796SEtienne Carriere 	}
9346b651796SEtienne Carriere 
9356b651796SEtienne Carriere 	return clock;
9366b651796SEtienne Carriere }
9376b651796SEtienne Carriere 
9386b651796SEtienne Carriere static void __clk_enable(const struct stm32mp1_clk_gate *gate)
9396b651796SEtienne Carriere {
9406b651796SEtienne Carriere 	vaddr_t base = stm32_rcc_base();
9416b651796SEtienne Carriere 	uint32_t bit = BIT(gate->bit);
9426b651796SEtienne Carriere 
9436b651796SEtienne Carriere 	if (gate->set_clr)
9446b651796SEtienne Carriere 		io_write32(base + gate->offset, bit);
9456b651796SEtienne Carriere 	else
9466b651796SEtienne Carriere 		io_setbits32_stm32shregs(base + gate->offset, bit);
9476b651796SEtienne Carriere 
9486b651796SEtienne Carriere 	FMSG("Clock %u has been enabled", gate->clock_id);
9496b651796SEtienne Carriere }
9506b651796SEtienne Carriere 
9516b651796SEtienne Carriere static void __clk_disable(const struct stm32mp1_clk_gate *gate)
9526b651796SEtienne Carriere {
9536b651796SEtienne Carriere 	vaddr_t base = stm32_rcc_base();
9546b651796SEtienne Carriere 	uint32_t bit = BIT(gate->bit);
9556b651796SEtienne Carriere 
9566b651796SEtienne Carriere 	if (gate->set_clr)
9576b651796SEtienne Carriere 		io_write32(base + gate->offset + RCC_MP_ENCLRR_OFFSET, bit);
9586b651796SEtienne Carriere 	else
9596b651796SEtienne Carriere 		io_clrbits32_stm32shregs(base + gate->offset, bit);
9606b651796SEtienne Carriere 
9616b651796SEtienne Carriere 	FMSG("Clock %u has been disabled", gate->clock_id);
9626b651796SEtienne Carriere }
9636b651796SEtienne Carriere 
9646b651796SEtienne Carriere static long get_timer_rate(long parent_rate, unsigned int apb_bus)
9656b651796SEtienne Carriere {
9666b651796SEtienne Carriere 	uint32_t timgxpre = 0;
9676b651796SEtienne Carriere 	uint32_t apbxdiv = 0;
9686b651796SEtienne Carriere 	vaddr_t rcc_base = stm32_rcc_base();
9696b651796SEtienne Carriere 
9706b651796SEtienne Carriere 	switch (apb_bus) {
9716b651796SEtienne Carriere 	case 1:
9726b651796SEtienne Carriere 		apbxdiv = io_read32(rcc_base + RCC_APB1DIVR) &
9736b651796SEtienne Carriere 			  RCC_APBXDIV_MASK;
9746b651796SEtienne Carriere 		timgxpre = io_read32(rcc_base + RCC_TIMG1PRER) &
9756b651796SEtienne Carriere 			   RCC_TIMGXPRER_TIMGXPRE;
9766b651796SEtienne Carriere 		break;
9776b651796SEtienne Carriere 	case 2:
9786b651796SEtienne Carriere 		apbxdiv = io_read32(rcc_base + RCC_APB2DIVR) &
9796b651796SEtienne Carriere 			  RCC_APBXDIV_MASK;
9806b651796SEtienne Carriere 		timgxpre = io_read32(rcc_base + RCC_TIMG2PRER) &
9816b651796SEtienne Carriere 			   RCC_TIMGXPRER_TIMGXPRE;
9826b651796SEtienne Carriere 		break;
9836b651796SEtienne Carriere 	default:
9846b651796SEtienne Carriere 		panic();
9856b651796SEtienne Carriere 		break;
9866b651796SEtienne Carriere 	}
9876b651796SEtienne Carriere 
9886b651796SEtienne Carriere 	if (apbxdiv == 0)
9896b651796SEtienne Carriere 		return parent_rate;
9906b651796SEtienne Carriere 
9916b651796SEtienne Carriere 	return parent_rate * (timgxpre + 1) * 2;
9926b651796SEtienne Carriere }
9936b651796SEtienne Carriere 
9946b651796SEtienne Carriere static unsigned long _stm32_clock_get_rate(unsigned long id)
9956b651796SEtienne Carriere {
996bb73802dSEtienne Carriere 	enum stm32mp1_parent_id p = _UNKNOWN_ID;
9976b651796SEtienne Carriere 	unsigned long rate = 0;
9986b651796SEtienne Carriere 
9996b651796SEtienne Carriere 	p = stm32mp1_clk_get_parent(id);
10006b651796SEtienne Carriere 	if (p < 0)
10016b651796SEtienne Carriere 		return 0;
10026b651796SEtienne Carriere 
10036b651796SEtienne Carriere 	rate = get_clock_rate(p);
10046b651796SEtienne Carriere 
10056b651796SEtienne Carriere 	if ((id >= TIM2_K) && (id <= TIM14_K))
10066b651796SEtienne Carriere 		rate = get_timer_rate(rate, 1);
10076b651796SEtienne Carriere 
10086b651796SEtienne Carriere 	if ((id >= TIM1_K) && (id <= TIM17_K))
10096b651796SEtienne Carriere 		rate = get_timer_rate(rate, 2);
10106b651796SEtienne Carriere 
10116b651796SEtienne Carriere 	return rate;
10126b651796SEtienne Carriere }
10136b651796SEtienne Carriere 
10146b651796SEtienne Carriere /*
10156b651796SEtienne Carriere  * Get the parent ID of the target parent clock, or -1 if no parent found.
10166b651796SEtienne Carriere  */
1017bb73802dSEtienne Carriere static enum stm32mp1_parent_id get_parent_id_parent(enum stm32mp1_parent_id id)
10186b651796SEtienne Carriere {
10196b651796SEtienne Carriere 	enum stm32mp1_parent_sel s = _UNKNOWN_SEL;
10206b651796SEtienne Carriere 	enum stm32mp1_pll_id pll_id = _PLL_NB;
10216b651796SEtienne Carriere 	uint32_t p_sel = 0;
10226b651796SEtienne Carriere 
1023bb73802dSEtienne Carriere 	switch (id) {
10246b651796SEtienne Carriere 	case _ACLK:
10253e3bea3dSEtienne Carriere 	case _HCLK5:
1026*11bee8b0SEtienne Carriere 	case _HCLK6:
10276b651796SEtienne Carriere 	case _PCLK4:
10286b651796SEtienne Carriere 	case _PCLK5:
10296b651796SEtienne Carriere 		s = _AXISS_SEL;
10306b651796SEtienne Carriere 		break;
10316b651796SEtienne Carriere 	case _PLL1_P:
10326b651796SEtienne Carriere 	case _PLL1_Q:
10336b651796SEtienne Carriere 	case _PLL1_R:
10346b651796SEtienne Carriere 		pll_id = _PLL1;
10356b651796SEtienne Carriere 		break;
10366b651796SEtienne Carriere 	case _PLL2_P:
10376b651796SEtienne Carriere 	case _PLL2_Q:
10386b651796SEtienne Carriere 	case _PLL2_R:
10396b651796SEtienne Carriere 		pll_id = _PLL2;
10406b651796SEtienne Carriere 		break;
10416b651796SEtienne Carriere 	case _PLL3_P:
10426b651796SEtienne Carriere 	case _PLL3_Q:
10436b651796SEtienne Carriere 	case _PLL3_R:
10446b651796SEtienne Carriere 		pll_id = _PLL3;
10456b651796SEtienne Carriere 		break;
10466b651796SEtienne Carriere 	case _PLL4_P:
10476b651796SEtienne Carriere 	case _PLL4_Q:
10486b651796SEtienne Carriere 	case _PLL4_R:
10496b651796SEtienne Carriere 		pll_id = _PLL4;
10506b651796SEtienne Carriere 		break;
10516b651796SEtienne Carriere 	case _PCLK1:
10526b651796SEtienne Carriere 	case _PCLK2:
10536b651796SEtienne Carriere 	case _HCLK2:
10546b651796SEtienne Carriere 	case _CK_PER:
10556b651796SEtienne Carriere 	case _CK_MPU:
10566b651796SEtienne Carriere 	case _CK_MCU:
10576b651796SEtienne Carriere 	case _USB_PHY_48:
10586b651796SEtienne Carriere 		/* We do not expected to access these */
10596b651796SEtienne Carriere 		panic();
10606b651796SEtienne Carriere 		break;
10616b651796SEtienne Carriere 	default:
10626b651796SEtienne Carriere 		/* Other parents have no parent */
10636b651796SEtienne Carriere 		return -1;
10646b651796SEtienne Carriere 	}
10656b651796SEtienne Carriere 
10666b651796SEtienne Carriere 	if (s != _UNKNOWN_SEL) {
10676b651796SEtienne Carriere 		const struct stm32mp1_clk_sel *sel = clk_sel_ref(s);
10686b651796SEtienne Carriere 		vaddr_t rcc_base = stm32_rcc_base();
10696b651796SEtienne Carriere 
10706b651796SEtienne Carriere 		p_sel = (io_read32(rcc_base + sel->offset) >> sel->src) &
10716b651796SEtienne Carriere 			sel->msk;
10726b651796SEtienne Carriere 
10736b651796SEtienne Carriere 		if (p_sel < sel->nb_parent)
10746b651796SEtienne Carriere 			return sel->parent[p_sel];
10756b651796SEtienne Carriere 	} else {
10766b651796SEtienne Carriere 		const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
10776b651796SEtienne Carriere 
10786b651796SEtienne Carriere 		p_sel = io_read32(stm32_rcc_base() + pll->rckxselr) &
10796b651796SEtienne Carriere 			RCC_SELR_REFCLK_SRC_MASK;
10806b651796SEtienne Carriere 
10816b651796SEtienne Carriere 		if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID)
1082bb73802dSEtienne Carriere 			return osc_id2parent_id(pll->refclk[p_sel]);
10836b651796SEtienne Carriere 	}
10846b651796SEtienne Carriere 
1085bb73802dSEtienne Carriere 	FMSG("No parent found for %s", stm32mp1_clk_parent_name[id]);
10866b651796SEtienne Carriere 	return -1;
10876b651796SEtienne Carriere }
10886b651796SEtienne Carriere 
10896b651796SEtienne Carriere /* We are only interested in knowing if PLL3 shall be secure or not */
1090bb73802dSEtienne Carriere static void secure_parent_clocks(enum stm32mp1_parent_id parent_id)
10916b651796SEtienne Carriere {
1092bb73802dSEtienne Carriere 	enum stm32mp1_parent_id grandparent_id = _UNKNOWN_ID;
10936b651796SEtienne Carriere 
10946b651796SEtienne Carriere 	switch (parent_id) {
10956b651796SEtienne Carriere 	case _ACLK:
10966b651796SEtienne Carriere 	case _HCLK2:
10976b651796SEtienne Carriere 	case _HCLK5:
10986b651796SEtienne Carriere 	case _HCLK6:
10996b651796SEtienne Carriere 	case _PCLK4:
11006b651796SEtienne Carriere 	case _PCLK5:
11016b651796SEtienne Carriere 		/* Intermediate clock mux or clock, go deeper in clock tree */
11026b651796SEtienne Carriere 		break;
11036b651796SEtienne Carriere 	case _HSI:
11046b651796SEtienne Carriere 	case _HSI_KER:
11056b651796SEtienne Carriere 	case _LSI:
11066b651796SEtienne Carriere 	case _CSI:
11076b651796SEtienne Carriere 	case _CSI_KER:
11086b651796SEtienne Carriere 	case _HSE:
11096b651796SEtienne Carriere 	case _HSE_KER:
11106b651796SEtienne Carriere 	case _HSE_KER_DIV2:
111162bb2715SEtienne Carriere 	case _HSE_RTC:
11126b651796SEtienne Carriere 	case _LSE:
11136b651796SEtienne Carriere 	case _PLL1_P:
11146b651796SEtienne Carriere 	case _PLL1_Q:
11156b651796SEtienne Carriere 	case _PLL1_R:
11166b651796SEtienne Carriere 	case _PLL2_P:
11176b651796SEtienne Carriere 	case _PLL2_Q:
11186b651796SEtienne Carriere 	case _PLL2_R:
11196b651796SEtienne Carriere 		/* Always secure clocks, no need to go further */
11206b651796SEtienne Carriere 		return;
11216b651796SEtienne Carriere 	case _PLL3_P:
11226b651796SEtienne Carriere 	case _PLL3_Q:
11236b651796SEtienne Carriere 	case _PLL3_R:
11246b651796SEtienne Carriere 		/* PLL3 is a shared resource, registered and don't go further */
11256b651796SEtienne Carriere 		stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
11266b651796SEtienne Carriere 		return;
11276b651796SEtienne Carriere 	default:
11286b651796SEtienne Carriere 		DMSG("Cannot lookup parent clock %s",
11296b651796SEtienne Carriere 		     stm32mp1_clk_parent_name[parent_id]);
11306b651796SEtienne Carriere 		panic();
11316b651796SEtienne Carriere 	}
11326b651796SEtienne Carriere 
11336b651796SEtienne Carriere 	grandparent_id = get_parent_id_parent(parent_id);
11346b651796SEtienne Carriere 	if (grandparent_id >= 0)
11356b651796SEtienne Carriere 		secure_parent_clocks(grandparent_id);
11366b651796SEtienne Carriere }
11376b651796SEtienne Carriere 
11386b651796SEtienne Carriere void stm32mp_register_clock_parents_secure(unsigned long clock_id)
11396b651796SEtienne Carriere {
1140bb73802dSEtienne Carriere 	enum stm32mp1_parent_id parent_id = stm32mp1_clk_get_parent(clock_id);
11416b651796SEtienne Carriere 
11426b651796SEtienne Carriere 	if (parent_id < 0) {
11436b651796SEtienne Carriere 		DMSG("No parent for clock %lu", clock_id);
11446b651796SEtienne Carriere 		return;
11456b651796SEtienne Carriere 	}
11466b651796SEtienne Carriere 
11476b651796SEtienne Carriere 	secure_parent_clocks(parent_id);
11486b651796SEtienne Carriere }
11496b651796SEtienne Carriere 
11506b651796SEtienne Carriere #ifdef CFG_EMBED_DTB
11516b651796SEtienne Carriere static const char *stm32mp_osc_node_label[NB_OSC] = {
1152bb73802dSEtienne Carriere 	[OSC_LSI] = "clk-lsi",
1153bb73802dSEtienne Carriere 	[OSC_LSE] = "clk-lse",
1154bb73802dSEtienne Carriere 	[OSC_HSI] = "clk-hsi",
1155bb73802dSEtienne Carriere 	[OSC_HSE] = "clk-hse",
1156bb73802dSEtienne Carriere 	[OSC_CSI] = "clk-csi",
1157bb73802dSEtienne Carriere 	[OSC_I2S_CKIN] = "i2s_ckin",
1158bb73802dSEtienne Carriere 	[OSC_USB_PHY_48] = "ck_usbo_48m"
11596b651796SEtienne Carriere };
11606b651796SEtienne Carriere 
11616b651796SEtienne Carriere static unsigned int clk_freq_prop(const void *fdt, int node)
11626b651796SEtienne Carriere {
11636b651796SEtienne Carriere 	const fdt32_t *cuint = NULL;
11646b651796SEtienne Carriere 	int ret = 0;
11656b651796SEtienne Carriere 
11666b651796SEtienne Carriere 	/* Disabled clocks report null rate */
11676b651796SEtienne Carriere 	if (_fdt_get_status(fdt, node) == DT_STATUS_DISABLED)
11686b651796SEtienne Carriere 		return 0;
11696b651796SEtienne Carriere 
11706b651796SEtienne Carriere 	cuint = fdt_getprop(fdt, node, "clock-frequency", &ret);
11716b651796SEtienne Carriere 	if (!cuint)
11726b651796SEtienne Carriere 		panic();
11736b651796SEtienne Carriere 
11746b651796SEtienne Carriere 	return fdt32_to_cpu(*cuint);
11756b651796SEtienne Carriere }
11766b651796SEtienne Carriere 
11776b651796SEtienne Carriere static void get_osc_freq_from_dt(const void *fdt)
11786b651796SEtienne Carriere {
11796b651796SEtienne Carriere 	enum stm32mp_osc_id idx = _UNKNOWN_OSC_ID;
11806b651796SEtienne Carriere 	int clk_node = fdt_path_offset(fdt, "/clocks");
11816b651796SEtienne Carriere 
11826b651796SEtienne Carriere 	if (clk_node < 0)
11836b651796SEtienne Carriere 		panic();
11846b651796SEtienne Carriere 
1185bb73802dSEtienne Carriere 	COMPILE_TIME_ASSERT((int)OSC_HSI == 0);
1186bb73802dSEtienne Carriere 	for (idx = OSC_HSI; idx < NB_OSC; idx++) {
11876b651796SEtienne Carriere 		const char *name = stm32mp_osc_node_label[idx];
11886b651796SEtienne Carriere 		int subnode = 0;
11896b651796SEtienne Carriere 
11906b651796SEtienne Carriere 		fdt_for_each_subnode(subnode, fdt, clk_node) {
11916b651796SEtienne Carriere 			const char *cchar = NULL;
11926b651796SEtienne Carriere 			int ret = 0;
11936b651796SEtienne Carriere 
11946b651796SEtienne Carriere 			cchar = fdt_get_name(fdt, subnode, &ret);
11956b651796SEtienne Carriere 			if (!cchar)
11966b651796SEtienne Carriere 				panic();
11976b651796SEtienne Carriere 
11986b651796SEtienne Carriere 			if (strncmp(cchar, name, (size_t)ret) == 0) {
11996b651796SEtienne Carriere 				stm32mp1_osc[idx] = clk_freq_prop(fdt, subnode);
12006b651796SEtienne Carriere 
12016b651796SEtienne Carriere 				DMSG("Osc %s: %lu Hz", name, stm32mp1_osc[idx]);
12026b651796SEtienne Carriere 				break;
12036b651796SEtienne Carriere 			}
12046b651796SEtienne Carriere 		}
12056b651796SEtienne Carriere 
12066b651796SEtienne Carriere 		if (!stm32mp1_osc[idx])
12076b651796SEtienne Carriere 			DMSG("Osc %s: no frequency info", name);
12086b651796SEtienne Carriere 	}
12096b651796SEtienne Carriere }
12106b651796SEtienne Carriere #endif /*CFG_EMBED_DTB*/
12116b651796SEtienne Carriere 
12126b651796SEtienne Carriere static void enable_static_secure_clocks(void)
12136b651796SEtienne Carriere {
12146b651796SEtienne Carriere 	unsigned int idx = 0;
12156b651796SEtienne Carriere 	const unsigned long secure_enable[] = {
12166b651796SEtienne Carriere 		DDRC1, DDRC1LP, DDRC2, DDRC2LP, DDRPHYC, DDRPHYCLP, DDRCAPB,
12176b651796SEtienne Carriere 		AXIDCG, DDRPHYCAPB, DDRPHYCAPBLP, TZPC, TZC1, TZC2, STGEN_K,
12186b651796SEtienne Carriere 		BSEC,
12196b651796SEtienne Carriere 	};
12206b651796SEtienne Carriere 
12216b651796SEtienne Carriere 	for (idx = 0; idx < ARRAY_SIZE(secure_enable); idx++) {
12226b651796SEtienne Carriere 		stm32_clock_enable(secure_enable[idx]);
12236b651796SEtienne Carriere 		stm32mp_register_clock_parents_secure(secure_enable[idx]);
12246b651796SEtienne Carriere 	}
12256b651796SEtienne Carriere 
12266b651796SEtienne Carriere 	if (CFG_TEE_CORE_NB_CORE > 1)
12276b651796SEtienne Carriere 		stm32_clock_enable(RTCAPB);
12286b651796SEtienne Carriere }
12296b651796SEtienne Carriere 
12306b651796SEtienne Carriere static void __maybe_unused enable_rcc_tzen(void)
12316b651796SEtienne Carriere {
12326b651796SEtienne Carriere 	io_setbits32(stm32_rcc_base() + RCC_TZCR, RCC_TZCR_TZEN);
12336b651796SEtienne Carriere }
12346b651796SEtienne Carriere 
12356b651796SEtienne Carriere static void __maybe_unused disable_rcc_tzen(void)
12366b651796SEtienne Carriere {
12376b651796SEtienne Carriere 	IMSG("RCC is non-secure");
12386b651796SEtienne Carriere 	io_clrbits32(stm32_rcc_base() + RCC_TZCR, RCC_TZCR_TZEN);
12396b651796SEtienne Carriere }
12406b651796SEtienne Carriere 
12416b651796SEtienne Carriere #ifdef CFG_EMBED_DTB
12426b651796SEtienne Carriere static TEE_Result stm32mp1_clk_fdt_init(const void *fdt, int node)
12436b651796SEtienne Carriere {
12446b651796SEtienne Carriere 	unsigned int i = 0;
12456b651796SEtienne Carriere 	int len = 0;
12466b651796SEtienne Carriere 	int ignored = 0;
12476b651796SEtienne Carriere 
12486b651796SEtienne Carriere 	get_osc_freq_from_dt(fdt);
12496b651796SEtienne Carriere 
12506b651796SEtienne Carriere 	/*
12516b651796SEtienne Carriere 	 * OP-TEE core is not in charge of configuring clock parenthood.
12526b651796SEtienne Carriere 	 * This is expected from an earlier boot stage. Modifying the clock
12536b651796SEtienne Carriere 	 * tree parenthood here may jeopardize already configured clocks.
12546b651796SEtienne Carriere 	 * The sequence below ignores such DT directives with a friendly
12556b651796SEtienne Carriere 	 * debug trace.
12566b651796SEtienne Carriere 	 */
12576b651796SEtienne Carriere 	if (fdt_getprop(fdt, node, "st,clksrc", &len)) {
12586b651796SEtienne Carriere 		DMSG("Ignore source clocks configuration from DT");
12596b651796SEtienne Carriere 		ignored++;
12606b651796SEtienne Carriere 	}
12616b651796SEtienne Carriere 	if (fdt_getprop(fdt, node, "st,clkdiv", &len)) {
12626b651796SEtienne Carriere 		DMSG("Ignore clock divisors configuration from DT");
12636b651796SEtienne Carriere 		ignored++;
12646b651796SEtienne Carriere 	}
12656b651796SEtienne Carriere 	if (fdt_getprop(fdt, node, "st,pkcs", &len)) {
12666b651796SEtienne Carriere 		DMSG("Ignore peripheral clocks tree configuration from DT");
12676b651796SEtienne Carriere 		ignored++;
12686b651796SEtienne Carriere 	}
12696b651796SEtienne Carriere 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
12706b651796SEtienne Carriere 		char name[] = "st,pll@X";
12716b651796SEtienne Carriere 
12726b651796SEtienne Carriere 		snprintf(name, sizeof(name), "st,pll@%d", i);
12736b651796SEtienne Carriere 		node = fdt_subnode_offset(fdt, node, name);
12746b651796SEtienne Carriere 		if (node < 0)
12756b651796SEtienne Carriere 			continue;
12766b651796SEtienne Carriere 
12776b651796SEtienne Carriere 		if (fdt_getprop(fdt, node, "cfg", &len) ||
12786b651796SEtienne Carriere 		    fdt_getprop(fdt, node, "frac", &len)) {
12796b651796SEtienne Carriere 			DMSG("Ignore PLL%u configurations from DT", i);
12806b651796SEtienne Carriere 			ignored++;
12816b651796SEtienne Carriere 		}
12826b651796SEtienne Carriere 	}
12836b651796SEtienne Carriere 
12846b651796SEtienne Carriere 	if (ignored != 0)
12856b651796SEtienne Carriere 		IMSG("DT clock tree configurations were ignored");
12866b651796SEtienne Carriere 
12876b651796SEtienne Carriere 	return TEE_SUCCESS;
12886b651796SEtienne Carriere }
12896b651796SEtienne Carriere #endif /*CFG_EMBED_DTB*/
12906b651796SEtienne Carriere 
12916b651796SEtienne Carriere /*
12926b651796SEtienne Carriere  * Conversion between clk references and clock gates and clock on internals
12936b651796SEtienne Carriere  *
12946b651796SEtienne Carriere  * stm32mp1_clk first cells follow stm32mp1_clk_gate[] ordering.
12956b651796SEtienne Carriere  * stm32mp1_clk last cells follow stm32mp1_clk_on[] ordering.
12966b651796SEtienne Carriere  */
12976b651796SEtienne Carriere static struct clk stm32mp1_clk[ARRAY_SIZE(stm32mp1_clk_gate) +
12986b651796SEtienne Carriere 			       ARRAY_SIZE(stm32mp1_clk_on)];
12996b651796SEtienne Carriere 
13006b651796SEtienne Carriere #define CLK_ON_INDEX_OFFSET	((int)ARRAY_SIZE(stm32mp1_clk_gate))
13016b651796SEtienne Carriere 
13026b651796SEtienne Carriere static bool clk_is_gate(struct clk *clk)
13036b651796SEtienne Carriere {
13046b651796SEtienne Carriere 	int clk_index = clk - stm32mp1_clk;
13056b651796SEtienne Carriere 
13066b651796SEtienne Carriere 	assert(clk_index >= 0 && clk_index < (int)ARRAY_SIZE(stm32mp1_clk));
13076b651796SEtienne Carriere 	return clk_index < CLK_ON_INDEX_OFFSET;
13086b651796SEtienne Carriere }
13096b651796SEtienne Carriere 
13106b651796SEtienne Carriere static unsigned long clk_to_clock_id(struct clk *clk)
13116b651796SEtienne Carriere {
13126b651796SEtienne Carriere 	int gate_index = clk - stm32mp1_clk;
13136b651796SEtienne Carriere 	int on_index = gate_index - CLK_ON_INDEX_OFFSET;
13146b651796SEtienne Carriere 
13156b651796SEtienne Carriere 	if (clk_is_gate(clk))
13166b651796SEtienne Carriere 		return stm32mp1_clk_gate[gate_index].clock_id;
13176b651796SEtienne Carriere 
13186b651796SEtienne Carriere 	return stm32mp1_clk_on[on_index];
13196b651796SEtienne Carriere }
13206b651796SEtienne Carriere 
13216b651796SEtienne Carriere static const struct stm32mp1_clk_gate *clk_to_gate_ref(struct clk *clk)
13226b651796SEtienne Carriere {
13236b651796SEtienne Carriere 	int gate_index = clk - stm32mp1_clk;
13246b651796SEtienne Carriere 
13256b651796SEtienne Carriere 	assert(clk_is_gate(clk));
13266b651796SEtienne Carriere 
13276b651796SEtienne Carriere 	return stm32mp1_clk_gate + gate_index;
13286b651796SEtienne Carriere }
13296b651796SEtienne Carriere 
13306b651796SEtienne Carriere static int clock_id_to_gate_index(unsigned long clock_id)
13316b651796SEtienne Carriere {
13326b651796SEtienne Carriere 	size_t n = 0;
13336b651796SEtienne Carriere 
13346b651796SEtienne Carriere 	for (n = 0; n < ARRAY_SIZE(stm32mp1_clk_gate); n++)
13356b651796SEtienne Carriere 		if (stm32mp1_clk_gate[n].clock_id == clock_id)
13366b651796SEtienne Carriere 			return n;
13376b651796SEtienne Carriere 
13386b651796SEtienne Carriere 	return -1;
13396b651796SEtienne Carriere }
13406b651796SEtienne Carriere 
13416b651796SEtienne Carriere static int clock_id_to_always_on_index(unsigned long clock_id)
13426b651796SEtienne Carriere {
13436b651796SEtienne Carriere 	size_t n = 0;
13446b651796SEtienne Carriere 
13456b651796SEtienne Carriere 	for (n = 0; n < ARRAY_SIZE(stm32mp1_clk_on); n++)
13466b651796SEtienne Carriere 		if (stm32mp1_clk_on[n] == clock_id)
13476b651796SEtienne Carriere 			return n;
13486b651796SEtienne Carriere 
13496b651796SEtienne Carriere 	return -1;
13506b651796SEtienne Carriere }
13516b651796SEtienne Carriere 
13526b651796SEtienne Carriere static struct clk *clock_id_to_clk(unsigned long clock_id)
13536b651796SEtienne Carriere {
13546b651796SEtienne Carriere 	int gate_index = clock_id_to_gate_index(clock_id);
13556b651796SEtienne Carriere 	int on_index = clock_id_to_always_on_index(clock_id);
13566b651796SEtienne Carriere 
13576b651796SEtienne Carriere 	if (gate_index >= 0)
13586b651796SEtienne Carriere 		return stm32mp1_clk + gate_index;
13596b651796SEtienne Carriere 
13606b651796SEtienne Carriere 	if (on_index >= 0)
13616b651796SEtienne Carriere 		return stm32mp1_clk + CLK_ON_INDEX_OFFSET + on_index;
13626b651796SEtienne Carriere 
13636b651796SEtienne Carriere 	return NULL;
13646b651796SEtienne Carriere }
13656b651796SEtienne Carriere 
13666b651796SEtienne Carriere #if CFG_TEE_CORE_LOG_LEVEL >= TRACE_DEBUG
13676b651796SEtienne Carriere struct clk_name {
13686b651796SEtienne Carriere 	unsigned int clock_id;
13696b651796SEtienne Carriere 	const char *name;
13706b651796SEtienne Carriere };
13716b651796SEtienne Carriere 
13726b651796SEtienne Carriere #define CLOCK_NAME(_binding, _name) \
13736b651796SEtienne Carriere 	{ .clock_id = (_binding), .name = (_name) }
13746b651796SEtienne Carriere 
13756b651796SEtienne Carriere /* Store names only for some clocks */
13766b651796SEtienne Carriere const struct clk_name exposed_clk_name[] = {
13776b651796SEtienne Carriere 	/* Clocks used by platform drivers not yet probed from DT */
13786b651796SEtienne Carriere 	CLOCK_NAME(CK_DBG, "dbg"),
13796b651796SEtienne Carriere 	CLOCK_NAME(CK_MCU, "mcu"),
13806b651796SEtienne Carriere 	CLOCK_NAME(RTCAPB, "rtcapb"),
13816b651796SEtienne Carriere 	CLOCK_NAME(BKPSRAM, "bkpsram"),
13826b651796SEtienne Carriere 	CLOCK_NAME(RTC, "rtc"),
13836b651796SEtienne Carriere 	CLOCK_NAME(CRYP1, "crpy1"),
13846b651796SEtienne Carriere 	CLOCK_NAME(SYSCFG, "syscfg"),
13856b651796SEtienne Carriere 	CLOCK_NAME(GPIOA, "gpioa"),
13866b651796SEtienne Carriere 	CLOCK_NAME(GPIOB, "gpiob"),
13876b651796SEtienne Carriere 	CLOCK_NAME(GPIOC, "gpioc"),
13886b651796SEtienne Carriere 	CLOCK_NAME(GPIOD, "gpiod"),
13896b651796SEtienne Carriere 	CLOCK_NAME(GPIOE, "gpioe"),
13906b651796SEtienne Carriere 	CLOCK_NAME(GPIOF, "gpiof"),
13916b651796SEtienne Carriere 	CLOCK_NAME(GPIOG, "gpiog"),
13926b651796SEtienne Carriere 	CLOCK_NAME(GPIOH, "gpioh"),
13936b651796SEtienne Carriere 	CLOCK_NAME(GPIOI, "gpioi"),
13946b651796SEtienne Carriere 	CLOCK_NAME(GPIOJ, "gpioj"),
13956b651796SEtienne Carriere 	CLOCK_NAME(GPIOK, "gpiok"),
13966b651796SEtienne Carriere 	CLOCK_NAME(GPIOZ, "gpioz"),
13976b651796SEtienne Carriere 	/* Clock exposed by SCMI. SCMI clock fmro DT bindings to come... */
13986b651796SEtienne Carriere 	CLOCK_NAME(CK_HSE, "hse"),
13996b651796SEtienne Carriere 	CLOCK_NAME(CK_HSI, "hsi"),
14006b651796SEtienne Carriere 	CLOCK_NAME(CK_CSI, "csi"),
14016b651796SEtienne Carriere 	CLOCK_NAME(CK_LSE, "lse"),
14026b651796SEtienne Carriere 	CLOCK_NAME(CK_LSI, "lsi"),
14036b651796SEtienne Carriere 	CLOCK_NAME(PLL2_Q, "pll2q"),
14046b651796SEtienne Carriere 	CLOCK_NAME(PLL2_R, "pll2r"),
14056b651796SEtienne Carriere 	CLOCK_NAME(PLL3_Q, "pll3q"),
14066b651796SEtienne Carriere 	CLOCK_NAME(PLL3_R, "pll3r"),
14076b651796SEtienne Carriere 	CLOCK_NAME(CRYP1, "cryp1"),
14086b651796SEtienne Carriere 	CLOCK_NAME(HASH1, "hash1"),
14096b651796SEtienne Carriere 	CLOCK_NAME(I2C4_K, "i2c4"),
14106b651796SEtienne Carriere 	CLOCK_NAME(I2C6_K, "i2c6"),
14116b651796SEtienne Carriere 	CLOCK_NAME(IWDG1, "iwdg"),
14126b651796SEtienne Carriere 	CLOCK_NAME(RNG1_K, "rng1"),
14136b651796SEtienne Carriere 	CLOCK_NAME(SPI6_K, "spi6"),
14146b651796SEtienne Carriere 	CLOCK_NAME(USART1_K, "usart1"),
14156b651796SEtienne Carriere 	CLOCK_NAME(CK_MCU, "mcu"),
14166b651796SEtienne Carriere };
14176b651796SEtienne Carriere DECLARE_KEEP_PAGER(exposed_clk_name);
14186b651796SEtienne Carriere 
14196b651796SEtienne Carriere static const char *clk_op_get_name(struct clk *clk)
14206b651796SEtienne Carriere {
14216b651796SEtienne Carriere 	unsigned long clock_id = clk_to_clock_id(clk);
14226b651796SEtienne Carriere 	size_t n = 0;
14236b651796SEtienne Carriere 
14246b651796SEtienne Carriere 	for (n = 0; n < ARRAY_SIZE(exposed_clk_name); n++)
14256b651796SEtienne Carriere 		if (exposed_clk_name[n].clock_id == clock_id)
14266b651796SEtienne Carriere 			return exposed_clk_name[n].name;
14276b651796SEtienne Carriere 
14286b651796SEtienne Carriere 	return NULL;
14296b651796SEtienne Carriere }
14306b651796SEtienne Carriere #else
14316b651796SEtienne Carriere static const char *clk_op_get_name(struct clk *clk __unused)
14326b651796SEtienne Carriere {
14336b651796SEtienne Carriere 	return NULL;
14346b651796SEtienne Carriere }
14356b651796SEtienne Carriere #endif /*CFG_TEE_CORE_LOG_LEVEL*/
14366b651796SEtienne Carriere 
14376b651796SEtienne Carriere static unsigned long clk_op_compute_rate(struct clk *clk,
14386b651796SEtienne Carriere 					 unsigned long parent_rate __unused)
14396b651796SEtienne Carriere {
14406b651796SEtienne Carriere 	return _stm32_clock_get_rate(clk_to_clock_id(clk));
14416b651796SEtienne Carriere }
14426b651796SEtienne Carriere 
14436b651796SEtienne Carriere static TEE_Result clk_op_enable(struct clk *clk)
14446b651796SEtienne Carriere {
14456b651796SEtienne Carriere 	if (clk_is_gate(clk))
14466b651796SEtienne Carriere 		__clk_enable(clk_to_gate_ref(clk));
14476b651796SEtienne Carriere 
14486b651796SEtienne Carriere 	return TEE_SUCCESS;
14496b651796SEtienne Carriere }
14506b651796SEtienne Carriere DECLARE_KEEP_PAGER(clk_op_enable);
14516b651796SEtienne Carriere 
14526b651796SEtienne Carriere static void clk_op_disable(struct clk *clk)
14536b651796SEtienne Carriere {
14546b651796SEtienne Carriere 	if (clk_is_gate(clk))
14556b651796SEtienne Carriere 		__clk_disable(clk_to_gate_ref(clk));
14566b651796SEtienne Carriere }
14576b651796SEtienne Carriere DECLARE_KEEP_PAGER(clk_op_disable);
14586b651796SEtienne Carriere 
14596b651796SEtienne Carriere /* This variable is weak to break its dependency chain when linked as unpaged */
14606b651796SEtienne Carriere const struct clk_ops stm32mp1_clk_ops
14616b651796SEtienne Carriere __weak __rodata_unpaged("stm32mp1_clk_ops") = {
14626b651796SEtienne Carriere 	.enable = clk_op_enable,
14636b651796SEtienne Carriere 	.disable = clk_op_disable,
14646b651796SEtienne Carriere 	.get_rate = clk_op_compute_rate,
14656b651796SEtienne Carriere };
14666b651796SEtienne Carriere 
14676b651796SEtienne Carriere static TEE_Result register_stm32mp1_clocks(void)
14686b651796SEtienne Carriere {
14696b651796SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
14706b651796SEtienne Carriere 	size_t n = 0;
14716b651796SEtienne Carriere 
14726b651796SEtienne Carriere 	for (n = 0; n < ARRAY_SIZE(stm32mp1_clk); n++) {
14736b651796SEtienne Carriere 		stm32mp1_clk[n].ops = &stm32mp1_clk_ops;
14746b651796SEtienne Carriere 		stm32mp1_clk[n].name = clk_op_get_name(stm32mp1_clk + n);
14756b651796SEtienne Carriere 		refcount_set(&stm32mp1_clk[n].enabled_count, 0);
14766b651796SEtienne Carriere 
14776b651796SEtienne Carriere 		res = clk_register(stm32mp1_clk + n);
14786b651796SEtienne Carriere 		if (res)
14796b651796SEtienne Carriere 			return res;
14806b651796SEtienne Carriere 	}
14816b651796SEtienne Carriere 
14826b651796SEtienne Carriere 	return TEE_SUCCESS;
14836b651796SEtienne Carriere }
14846b651796SEtienne Carriere 
14856b651796SEtienne Carriere /* Route platform legacy clock functions to clk driver functions */
14866b651796SEtienne Carriere bool stm32_clock_is_enabled(unsigned long clock_id)
14876b651796SEtienne Carriere {
14886b651796SEtienne Carriere 	struct clk *clk = clock_id_to_clk(clock_id);
14896b651796SEtienne Carriere 
14906b651796SEtienne Carriere 	assert(clk);
14916b651796SEtienne Carriere 	return clk_is_enabled(clk);
14926b651796SEtienne Carriere }
14936b651796SEtienne Carriere 
14946b651796SEtienne Carriere void stm32_clock_enable(unsigned long clock_id)
14956b651796SEtienne Carriere {
14966b651796SEtienne Carriere 	struct clk *clk = clock_id_to_clk(clock_id);
14976b651796SEtienne Carriere 	TEE_Result __maybe_unused res = TEE_ERROR_GENERIC;
14986b651796SEtienne Carriere 
14996b651796SEtienne Carriere 	assert(clk);
15006b651796SEtienne Carriere 	res = clk_enable(clk);
15016b651796SEtienne Carriere 	assert(!res);
15026b651796SEtienne Carriere }
15036b651796SEtienne Carriere 
15046b651796SEtienne Carriere void stm32_clock_disable(unsigned long clock_id)
15056b651796SEtienne Carriere {
15066b651796SEtienne Carriere 	struct clk *clk = clock_id_to_clk(clock_id);
15076b651796SEtienne Carriere 
15086b651796SEtienne Carriere 	assert(clk);
15096b651796SEtienne Carriere 	clk_disable(clk);
15106b651796SEtienne Carriere }
15116b651796SEtienne Carriere 
15126b651796SEtienne Carriere unsigned long stm32_clock_get_rate(unsigned long clock_id)
15136b651796SEtienne Carriere {
15146b651796SEtienne Carriere 	struct clk *clk = clock_id_to_clk(clock_id);
15156b651796SEtienne Carriere 
15166b651796SEtienne Carriere 	assert(clk);
15176b651796SEtienne Carriere 	return clk_get_rate(clk);
15186b651796SEtienne Carriere }
15196b651796SEtienne Carriere 
15206b651796SEtienne Carriere #ifdef CFG_DRIVERS_CLK_DT
15216b651796SEtienne Carriere static struct clk *stm32mp1_clk_dt_get_clk(struct dt_driver_phandle_args *pargs,
15226b651796SEtienne Carriere 					   void *data __unused, TEE_Result *res)
15236b651796SEtienne Carriere {
15246b651796SEtienne Carriere 	unsigned long clock_id = pargs->args[0];
15256b651796SEtienne Carriere 	struct clk *clk = NULL;
15266b651796SEtienne Carriere 
15276b651796SEtienne Carriere 	*res = TEE_ERROR_BAD_PARAMETERS;
15286b651796SEtienne Carriere 
15296b651796SEtienne Carriere 	if (pargs->args_count != 1)
15306b651796SEtienne Carriere 		return NULL;
15316b651796SEtienne Carriere 
15326b651796SEtienne Carriere 	clk = clock_id_to_clk(clock_id);
15336b651796SEtienne Carriere 	if (!clk)
15346b651796SEtienne Carriere 		return NULL;
15356b651796SEtienne Carriere 
15366b651796SEtienne Carriere 	*res = TEE_SUCCESS;
15376b651796SEtienne Carriere 	return clk;
15386b651796SEtienne Carriere }
15396b651796SEtienne Carriere 
15406b651796SEtienne Carriere /* Non-null reference for compat data */
15416b651796SEtienne Carriere static const uint8_t non_secure_rcc;
15426b651796SEtienne Carriere 
15436b651796SEtienne Carriere static TEE_Result stm32mp1_clock_provider_probe(const void *fdt, int offs,
15446b651796SEtienne Carriere 						const void *compat_data)
15456b651796SEtienne Carriere {
15466b651796SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
15476b651796SEtienne Carriere 
15486b651796SEtienne Carriere 	if (compat_data == &non_secure_rcc)
15496b651796SEtienne Carriere 		disable_rcc_tzen();
15506b651796SEtienne Carriere 	else
15516b651796SEtienne Carriere 		enable_rcc_tzen();
15526b651796SEtienne Carriere 
15536b651796SEtienne Carriere 	res = stm32mp1_clk_fdt_init(fdt, offs);
15546b651796SEtienne Carriere 	if (res) {
15556b651796SEtienne Carriere 		EMSG("Failed to initialize clocks from DT: %#"PRIx32, res);
15566b651796SEtienne Carriere 		panic();
15576b651796SEtienne Carriere 	}
15586b651796SEtienne Carriere 
15596b651796SEtienne Carriere 	res = register_stm32mp1_clocks();
15606b651796SEtienne Carriere 	if (res) {
15616b651796SEtienne Carriere 		EMSG("Failed to register clocks: %#"PRIx32, res);
15626b651796SEtienne Carriere 		panic();
15636b651796SEtienne Carriere 	}
15646b651796SEtienne Carriere 
15656b651796SEtienne Carriere 	res = clk_dt_register_clk_provider(fdt, offs, stm32mp1_clk_dt_get_clk,
15666b651796SEtienne Carriere 					   NULL);
15676b651796SEtienne Carriere 	if (res) {
15686b651796SEtienne Carriere 		EMSG("Failed to register clock provider: %#"PRIx32, res);
15696b651796SEtienne Carriere 		panic();
15706b651796SEtienne Carriere 	}
15716b651796SEtienne Carriere 
15726b651796SEtienne Carriere 	enable_static_secure_clocks();
15736b651796SEtienne Carriere 
15746b651796SEtienne Carriere 	return TEE_SUCCESS;
15756b651796SEtienne Carriere }
15766b651796SEtienne Carriere 
15776b651796SEtienne Carriere static const struct dt_device_match stm32mp1_clock_match_table[] = {
15786b651796SEtienne Carriere 	{  .compatible = "st,stm32mp1-rcc", .compat_data = &non_secure_rcc, },
15796b651796SEtienne Carriere 	{  .compatible = "st,stm32mp1-rcc-secure", },
15806b651796SEtienne Carriere 	{ }
15816b651796SEtienne Carriere };
15826b651796SEtienne Carriere 
15836b651796SEtienne Carriere DEFINE_DT_DRIVER(stm32mp1_clock_dt_driver) = {
15846b651796SEtienne Carriere 	.name = "stm32mp1_clock",
15856b651796SEtienne Carriere 	.type = DT_DRIVER_CLK,
15866b651796SEtienne Carriere 	.match_table = stm32mp1_clock_match_table,
15876b651796SEtienne Carriere 	.probe = stm32mp1_clock_provider_probe,
15886b651796SEtienne Carriere };
15896b651796SEtienne Carriere #else /*CFG_DRIVERS_CLK_DT*/
15906b651796SEtienne Carriere static TEE_Result stm32mp1_clk_early_init(void)
15916b651796SEtienne Carriere {
15926b651796SEtienne Carriere 	TEE_Result __maybe_unused res = TEE_ERROR_GENERIC;
15936b651796SEtienne Carriere 
15946b651796SEtienne Carriere 	res = register_stm32mp1_clocks();
15956b651796SEtienne Carriere 	if (res) {
15966b651796SEtienne Carriere 		EMSG("Failed to register clocks: %#"PRIx32, res);
15976b651796SEtienne Carriere 		panic();
15986b651796SEtienne Carriere 	}
15996b651796SEtienne Carriere 
16006b651796SEtienne Carriere 	enable_static_secure_clocks();
16016b651796SEtienne Carriere 
16026b651796SEtienne Carriere 	return TEE_SUCCESS;
16036b651796SEtienne Carriere }
16046b651796SEtienne Carriere 
16056b651796SEtienne Carriere service_init(stm32mp1_clk_early_init);
16066b651796SEtienne Carriere #endif /*CFG_DRIVERS_CLK_DT*/
1607