xref: /rk3399_ARM-atf/drivers/st/clk/stm32mp1_clk.c (revision 78ff36192f7dd4defa874d8f4387ec94cfcd20ee)
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 
30ae1e5037SGabriel Fernandez enum stm32mp1_pllcfg {
31ae1e5037SGabriel Fernandez 	PLLCFG_M,
32ae1e5037SGabriel Fernandez 	PLLCFG_N,
33ae1e5037SGabriel Fernandez 	PLL_DIV_MN_NB,
34ae1e5037SGabriel Fernandez 	PLLCFG_P = PLL_DIV_MN_NB,
35ae1e5037SGabriel Fernandez 	PLLCFG_Q,
36ae1e5037SGabriel Fernandez 	PLLCFG_R,
37ae1e5037SGabriel Fernandez 	PLLCFG_O,
38ae1e5037SGabriel Fernandez 	PLLCFG_NB
39ae1e5037SGabriel Fernandez };
40ae1e5037SGabriel Fernandez 
41ae1e5037SGabriel Fernandez #define PLL_DIV_MN_NB	2
42ae1e5037SGabriel Fernandez #define PLL_DIV_PQR_NB	3
43ae1e5037SGabriel Fernandez 
44ae1e5037SGabriel Fernandez enum stm32mp1_pllcsg {
45ae1e5037SGabriel Fernandez 	PLLCSG_MOD_PER,
46ae1e5037SGabriel Fernandez 	PLLCSG_INC_STEP,
47ae1e5037SGabriel Fernandez 	PLLCSG_SSCG_MODE,
48ae1e5037SGabriel Fernandez 	PLLCSG_NB
49ae1e5037SGabriel Fernandez };
50ae1e5037SGabriel Fernandez 
51ae1e5037SGabriel Fernandez struct stm32_pll_dt_cfg {
52ae1e5037SGabriel Fernandez 	bool status;
53ae1e5037SGabriel Fernandez 	uint32_t src;
54ae1e5037SGabriel Fernandez 	uint32_t cfg[PLLCFG_NB];
55ae1e5037SGabriel Fernandez 	uint32_t frac;
56ae1e5037SGabriel Fernandez 	bool csg_enabled;
57ae1e5037SGabriel Fernandez 	uint32_t csg[PLLCSG_NB];
58ae1e5037SGabriel Fernandez };
59ae1e5037SGabriel Fernandez 
60ae1e5037SGabriel Fernandez struct stm32_clk_platdata {
61ae1e5037SGabriel Fernandez 	uint32_t npll;
62ae1e5037SGabriel Fernandez 	struct stm32_pll_dt_cfg *pll;
63ae1e5037SGabriel Fernandez 	uint32_t nclksrc;
64ae1e5037SGabriel Fernandez 	uint32_t *clksrc;
65ae1e5037SGabriel Fernandez 	uint32_t nclkdiv;
66ae1e5037SGabriel Fernandez 	uint32_t *clkdiv;
67eca51034SChristoph Fritz 	bool lse_css;
68ae1e5037SGabriel Fernandez };
69ae1e5037SGabriel Fernandez 
70ae1e5037SGabriel Fernandez struct stm32_clk_priv {
71ae1e5037SGabriel Fernandez 	uintptr_t base;
72ae1e5037SGabriel Fernandez 	const struct mux_cfg *parents;
73ae1e5037SGabriel Fernandez 	const uint32_t nb_parents;
74ae1e5037SGabriel Fernandez 	const struct div_cfg *div;
75ae1e5037SGabriel Fernandez 	const uint32_t nb_div;
76ae1e5037SGabriel Fernandez 	void *pdata;
77ae1e5037SGabriel Fernandez };
78ae1e5037SGabriel Fernandez 
79ae1e5037SGabriel Fernandez static struct stm32_clk_priv *stm32_clock_data;
80ae1e5037SGabriel Fernandez 
clk_stm32_get_priv(void)81ae1e5037SGabriel Fernandez static struct stm32_clk_priv *clk_stm32_get_priv(void)
82ae1e5037SGabriel Fernandez {
83ae1e5037SGabriel Fernandez 	return stm32_clock_data;
84ae1e5037SGabriel Fernandez }
85ae1e5037SGabriel Fernandez 
clk_stm32_init(struct stm32_clk_priv * priv,uintptr_t base)86ae1e5037SGabriel Fernandez static int clk_stm32_init(struct stm32_clk_priv *priv, uintptr_t base)
87ae1e5037SGabriel Fernandez {
88ae1e5037SGabriel Fernandez 	stm32_clock_data = priv;
89ae1e5037SGabriel Fernandez 
90ae1e5037SGabriel Fernandez 	priv->base = base;
91ae1e5037SGabriel Fernandez 
92ae1e5037SGabriel Fernandez 	return 0;
93ae1e5037SGabriel Fernandez }
94ae1e5037SGabriel Fernandez 
957839a050SYann Gautier #define MAX_HSI_HZ		64000000
960d21680cSYann Gautier #define USB_PHY_48_MHZ		48000000
977839a050SYann Gautier 
98dfdb057aSYann Gautier #define TIMEOUT_US_200MS	U(200000)
99dfdb057aSYann Gautier #define TIMEOUT_US_1S		U(1000000)
1007839a050SYann Gautier 
101dfdb057aSYann Gautier #define PLLRDY_TIMEOUT		TIMEOUT_US_200MS
102dfdb057aSYann Gautier #define CLKSRC_TIMEOUT		TIMEOUT_US_200MS
103dfdb057aSYann Gautier #define CLKDIV_TIMEOUT		TIMEOUT_US_200MS
104dfdb057aSYann Gautier #define HSIDIV_TIMEOUT		TIMEOUT_US_200MS
105dfdb057aSYann Gautier #define OSCRDY_TIMEOUT		TIMEOUT_US_1S
1067839a050SYann Gautier 
107ae1e5037SGabriel Fernandez struct mux_cfg {
108ae1e5037SGabriel Fernandez 	uint16_t offset;
109ae1e5037SGabriel Fernandez 	uint8_t shift;
110ae1e5037SGabriel Fernandez 	uint8_t width;
111ae1e5037SGabriel Fernandez 	uint8_t bitrdy;
112ae1e5037SGabriel Fernandez };
113ae1e5037SGabriel Fernandez 
114ae1e5037SGabriel Fernandez struct div_cfg {
115ae1e5037SGabriel Fernandez 	uint16_t offset;
116ae1e5037SGabriel Fernandez 	uint8_t shift;
117ae1e5037SGabriel Fernandez 	uint8_t width;
118ae1e5037SGabriel Fernandez 	uint8_t bitrdy;
119ae1e5037SGabriel Fernandez };
120ae1e5037SGabriel Fernandez 
121ae1e5037SGabriel Fernandez #define DIV_NO_BIT_RDY UINT8_MAX
122ae1e5037SGabriel Fernandez 
123ae1e5037SGabriel Fernandez #define DIV_CFG(_id, _offset, _shift, _width,  _bitrdy)\
124ae1e5037SGabriel Fernandez 	[(_id)] = {\
125ae1e5037SGabriel Fernandez 		.offset	= (_offset),\
126ae1e5037SGabriel Fernandez 		.shift	= (_shift),\
127ae1e5037SGabriel Fernandez 		.width	= (_width),\
128ae1e5037SGabriel Fernandez 		.bitrdy	= (_bitrdy),\
129ae1e5037SGabriel Fernandez 	}
130ae1e5037SGabriel Fernandez 
131ae1e5037SGabriel Fernandez static const struct div_cfg dividers_mp15[] = {
132ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_MPU, RCC_MPCKDIVR, 0, 4, 31),
133ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_AXI, RCC_AXIDIVR, 0, 3, 31),
134ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_MCU, RCC_MCUDIVR, 0, 4, 31),
135ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_APB1, RCC_APB1DIVR, 0, 3, 31),
136ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_APB2, RCC_APB2DIVR, 0, 3, 31),
137ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_APB3, RCC_APB3DIVR, 0, 3, 31),
138ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_APB4, RCC_APB4DIVR, 0, 3, 31),
139ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_APB5, RCC_APB5DIVR, 0, 3, 31),
140ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_RTC, RCC_RTCDIVR, 0, 6, DIV_NO_BIT_RDY),
141ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_MCO1, RCC_MCO1CFGR, 4, 4, DIV_NO_BIT_RDY),
142ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_MCO2, RCC_MCO2CFGR, 4, 4, DIV_NO_BIT_RDY),
143ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_TRACE, RCC_DBGCFGR, 0, 3, DIV_NO_BIT_RDY),
144ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_ETHPTP, RCC_ETHCKSELR, 4, 4, DIV_NO_BIT_RDY),
145ae1e5037SGabriel Fernandez };
146ae1e5037SGabriel Fernandez 
147ae1e5037SGabriel Fernandez /*
148ae1e5037SGabriel Fernandez  * MUX CONFIG
149ae1e5037SGabriel Fernandez  */
150ae1e5037SGabriel Fernandez 
151ae1e5037SGabriel Fernandez #define MUX_NO_BIT_RDY		UINT8_MAX
152ae1e5037SGabriel Fernandez 
153ae1e5037SGabriel Fernandez #define MUXRDY_CFG(_id, _offset, _shift, _width,  _bitrdy)\
154ae1e5037SGabriel Fernandez 	[(_id)] = {\
155ae1e5037SGabriel Fernandez 		.offset	= (_offset),\
156ae1e5037SGabriel Fernandez 		.shift	= (_shift),\
157ae1e5037SGabriel Fernandez 		.width	= (_width),\
158ae1e5037SGabriel Fernandez 		.bitrdy = (_bitrdy),\
159ae1e5037SGabriel Fernandez 	}
160ae1e5037SGabriel Fernandez 
161ae1e5037SGabriel Fernandez #define MUX_CFG(_id, _offset, _shift, _width)\
162ae1e5037SGabriel Fernandez 	MUXRDY_CFG(_id, _offset, _shift, _width,  MUX_NO_BIT_RDY)
163ae1e5037SGabriel Fernandez 
164ae1e5037SGabriel Fernandez static const struct mux_cfg parent_mp15[MUX_NB] = {
165ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_PLL12,	RCC_RCK12SELR, 0, 2),
166ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_PLL3,	RCC_RCK3SELR, 0, 2),
167ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_PLL4,	RCC_RCK4SELR, 0, 2),
168ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_CKPER,	RCC_CPERCKSELR, 0, 2),
169ae1e5037SGabriel Fernandez 	MUXRDY_CFG(MUX_MPU,	RCC_MPCKSELR, 0, 2, 31),
170ae1e5037SGabriel Fernandez 	MUXRDY_CFG(MUX_AXI,	RCC_ASSCKSELR, 0, 3, 31),
171ae1e5037SGabriel Fernandez 	MUXRDY_CFG(MUX_MCU,	RCC_MSSCKSELR, 0, 2, 31),
172ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_RTC,	RCC_BDCR, 16, 2),
173ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SDMMC12,	RCC_SDMMC12CKSELR, 0, 3),
174ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SPI2S23,	RCC_SPI2S23CKSELR, 0, 3),
175ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SPI45,	RCC_SPI45CKSELR, 0, 3),
176ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_I2C12,	RCC_I2C12CKSELR, 0, 3),
177ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_I2C35,	RCC_I2C35CKSELR, 0, 3),
178ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_LPTIM23,	RCC_LPTIM23CKSELR, 0, 3),
179ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_LPTIM45,	RCC_LPTIM45CKSELR, 0, 3),
180ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_UART24,	RCC_UART24CKSELR, 0, 3),
181ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_UART35,	RCC_UART35CKSELR, 0, 3),
182ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_UART78,	RCC_UART78CKSELR, 0, 3),
183ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SAI1,	RCC_SAI1CKSELR, 0, 3),
184ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_ETH,	RCC_ETHCKSELR, 0, 2),
185ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_I2C46,	RCC_I2C46CKSELR, 0, 3),
186ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_RNG2,	RCC_RNG2CKSELR, 0, 2),
187ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SDMMC3,	RCC_SDMMC3CKSELR, 0, 3),
188ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_FMC,	RCC_FMCCKSELR, 0, 2),
189ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_QSPI,	RCC_QSPICKSELR, 0, 2),
190ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_USBPHY,	RCC_USBCKSELR, 0, 2),
191ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_USBO,	RCC_USBCKSELR, 4, 1),
192ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SPDIF,	RCC_SPDIFCKSELR, 0, 2),
193ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SPI2S1,	RCC_SPI2S1CKSELR, 0, 3),
194ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_CEC,	RCC_CECCKSELR, 0, 2),
195ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_LPTIM1,	RCC_LPTIM1CKSELR, 0, 3),
196ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_UART6,	RCC_UART6CKSELR, 0, 3),
197ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_FDCAN,	RCC_FDCANCKSELR, 0, 2),
198ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SAI2,	RCC_SAI2CKSELR, 0, 3),
199ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SAI3,	RCC_SAI3CKSELR, 0, 3),
200ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SAI4,	RCC_SAI4CKSELR, 0, 3),
201ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_ADC,	RCC_ADCCKSELR, 0, 2),
202ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_DSI,	RCC_DSICKSELR, 0, 1),
203ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_RNG1,	RCC_RNG1CKSELR, 0, 2),
204ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_STGEN,	RCC_STGENCKSELR, 0, 2),
205ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_UART1,	RCC_UART1CKSELR, 0, 3),
206ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SPI6,	RCC_SPI6CKSELR, 0, 3),
207ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_MCO1,	RCC_MCO1CFGR, 0, 3),
208ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_MCO2,	RCC_MCO2CFGR, 0, 3),
209ae1e5037SGabriel Fernandez };
210ae1e5037SGabriel Fernandez 
211ae1e5037SGabriel Fernandez #define MASK_WIDTH_SHIFT(_width, _shift) \
212ae1e5037SGabriel Fernandez 	GENMASK(((_width) + (_shift) - 1U), (_shift))
213ae1e5037SGabriel Fernandez 
clk_mux_get_parent(struct stm32_clk_priv * priv,uint32_t mux_id)214ae1e5037SGabriel Fernandez int clk_mux_get_parent(struct stm32_clk_priv *priv, uint32_t mux_id)
215ae1e5037SGabriel Fernandez {
216ae1e5037SGabriel Fernandez 	const struct mux_cfg *mux;
217ae1e5037SGabriel Fernandez 	uint32_t mask;
218ae1e5037SGabriel Fernandez 
219ae1e5037SGabriel Fernandez 	if (mux_id >= priv->nb_parents) {
220ae1e5037SGabriel Fernandez 		panic();
221ae1e5037SGabriel Fernandez 	}
222ae1e5037SGabriel Fernandez 
223ae1e5037SGabriel Fernandez 	mux = &priv->parents[mux_id];
224ae1e5037SGabriel Fernandez 
225ae1e5037SGabriel Fernandez 	mask = MASK_WIDTH_SHIFT(mux->width, mux->shift);
226ae1e5037SGabriel Fernandez 
227ae1e5037SGabriel Fernandez 	return (mmio_read_32(priv->base + mux->offset) & mask) >> mux->shift;
228ae1e5037SGabriel Fernandez }
229ae1e5037SGabriel Fernandez 
clk_mux_set_parent(struct stm32_clk_priv * priv,uint16_t pid,uint8_t sel)230ae1e5037SGabriel Fernandez static int clk_mux_set_parent(struct stm32_clk_priv *priv, uint16_t pid, uint8_t sel)
231ae1e5037SGabriel Fernandez {
232ae1e5037SGabriel Fernandez 	const struct mux_cfg *mux = &priv->parents[pid];
233ae1e5037SGabriel Fernandez 	uintptr_t address = priv->base + mux->offset;
234ae1e5037SGabriel Fernandez 	uint32_t mask;
235ae1e5037SGabriel Fernandez 	uint64_t timeout;
236ae1e5037SGabriel Fernandez 
237ae1e5037SGabriel Fernandez 	mask = MASK_WIDTH_SHIFT(mux->width, mux->shift);
238ae1e5037SGabriel Fernandez 
239ae1e5037SGabriel Fernandez 	mmio_clrsetbits_32(address, mask, (sel << mux->shift) & mask);
240ae1e5037SGabriel Fernandez 
241ae1e5037SGabriel Fernandez 	if (mux->bitrdy == MUX_NO_BIT_RDY) {
242ae1e5037SGabriel Fernandez 		return 0;
243ae1e5037SGabriel Fernandez 	}
244ae1e5037SGabriel Fernandez 
245ae1e5037SGabriel Fernandez 	timeout = timeout_init_us(CLKSRC_TIMEOUT);
246ae1e5037SGabriel Fernandez 
247ae1e5037SGabriel Fernandez 	mask = BIT(mux->bitrdy);
248ae1e5037SGabriel Fernandez 
249ae1e5037SGabriel Fernandez 	while ((mmio_read_32(address) & mask) == 0U) {
250ae1e5037SGabriel Fernandez 		if (timeout_elapsed(timeout)) {
251ae1e5037SGabriel Fernandez 			return -ETIMEDOUT;
252ae1e5037SGabriel Fernandez 		}
253ae1e5037SGabriel Fernandez 	}
254ae1e5037SGabriel Fernandez 
255ae1e5037SGabriel Fernandez 	return 0;
256ae1e5037SGabriel Fernandez }
257ae1e5037SGabriel Fernandez 
stm32_clk_configure_mux(struct stm32_clk_priv * priv,uint32_t val)258ae1e5037SGabriel Fernandez static int stm32_clk_configure_mux(struct stm32_clk_priv *priv, uint32_t val)
259ae1e5037SGabriel Fernandez {
260ae1e5037SGabriel Fernandez 	uint32_t data = val & CMD_DATA_MASK;
261ae1e5037SGabriel Fernandez 	int mux = (data & MUX_ID_MASK) >> MUX_ID_SHIFT;
262ae1e5037SGabriel Fernandez 	int sel = (data & MUX_SEL_MASK) >> MUX_SEL_SHIFT;
263ae1e5037SGabriel Fernandez 
264ae1e5037SGabriel Fernandez 	return clk_mux_set_parent(priv, mux, sel);
265ae1e5037SGabriel Fernandez }
266ae1e5037SGabriel Fernandez 
clk_stm32_set_div(struct stm32_clk_priv * priv,uint32_t div_id,uint32_t value)267ae1e5037SGabriel Fernandez int clk_stm32_set_div(struct stm32_clk_priv *priv, uint32_t div_id, uint32_t value)
268ae1e5037SGabriel Fernandez {
269ae1e5037SGabriel Fernandez 	const struct div_cfg *divider;
270ae1e5037SGabriel Fernandez 	uintptr_t address;
271ae1e5037SGabriel Fernandez 	uint64_t timeout;
272ae1e5037SGabriel Fernandez 	uint32_t mask;
273ae1e5037SGabriel Fernandez 
274ae1e5037SGabriel Fernandez 	if (div_id >= priv->nb_div) {
275ae1e5037SGabriel Fernandez 		panic();
276ae1e5037SGabriel Fernandez 	}
277ae1e5037SGabriel Fernandez 
278ae1e5037SGabriel Fernandez 	divider = &priv->div[div_id];
279ae1e5037SGabriel Fernandez 	address = priv->base + divider->offset;
280ae1e5037SGabriel Fernandez 
281ae1e5037SGabriel Fernandez 	mask = MASK_WIDTH_SHIFT(divider->width, divider->shift);
282ae1e5037SGabriel Fernandez 	mmio_clrsetbits_32(address, mask, (value << divider->shift) & mask);
283ae1e5037SGabriel Fernandez 
284ae1e5037SGabriel Fernandez 	if (divider->bitrdy == DIV_NO_BIT_RDY) {
285ae1e5037SGabriel Fernandez 		return 0;
286ae1e5037SGabriel Fernandez 	}
287ae1e5037SGabriel Fernandez 
288ae1e5037SGabriel Fernandez 	timeout = timeout_init_us(CLKSRC_TIMEOUT);
289ae1e5037SGabriel Fernandez 	mask = BIT(divider->bitrdy);
290ae1e5037SGabriel Fernandez 
291ae1e5037SGabriel Fernandez 	while ((mmio_read_32(address) & mask) == 0U) {
292ae1e5037SGabriel Fernandez 		if (timeout_elapsed(timeout)) {
293ae1e5037SGabriel Fernandez 			return -ETIMEDOUT;
294ae1e5037SGabriel Fernandez 		}
295ae1e5037SGabriel Fernandez 	}
296ae1e5037SGabriel Fernandez 
297ae1e5037SGabriel Fernandez 	return 0;
298ae1e5037SGabriel Fernandez }
299ae1e5037SGabriel Fernandez 
300f66358afSYann Gautier const char *stm32mp_osc_node_label[NB_OSC] = {
301f66358afSYann Gautier 	[_LSI] = "clk-lsi",
302f66358afSYann Gautier 	[_LSE] = "clk-lse",
303f66358afSYann Gautier 	[_HSI] = "clk-hsi",
304f66358afSYann Gautier 	[_HSE] = "clk-hse",
305f66358afSYann Gautier 	[_CSI] = "clk-csi",
306f66358afSYann Gautier 	[_I2S_CKIN] = "i2s_ckin",
307f66358afSYann Gautier };
308f66358afSYann Gautier 
3097839a050SYann Gautier enum stm32mp1_parent_id {
3107839a050SYann Gautier /* Oscillators are defined in enum stm32mp_osc_id */
3117839a050SYann Gautier 
3127839a050SYann Gautier /* Other parent source */
3137839a050SYann Gautier 	_HSI_KER = NB_OSC,
3147839a050SYann Gautier 	_HSE_KER,
3157839a050SYann Gautier 	_HSE_KER_DIV2,
316cbd2e8a6SGabriel Fernandez 	_HSE_RTC,
3177839a050SYann Gautier 	_CSI_KER,
3187839a050SYann Gautier 	_PLL1_P,
3197839a050SYann Gautier 	_PLL1_Q,
3207839a050SYann Gautier 	_PLL1_R,
3217839a050SYann Gautier 	_PLL2_P,
3227839a050SYann Gautier 	_PLL2_Q,
3237839a050SYann Gautier 	_PLL2_R,
3247839a050SYann Gautier 	_PLL3_P,
3257839a050SYann Gautier 	_PLL3_Q,
3267839a050SYann Gautier 	_PLL3_R,
3277839a050SYann Gautier 	_PLL4_P,
3287839a050SYann Gautier 	_PLL4_Q,
3297839a050SYann Gautier 	_PLL4_R,
3307839a050SYann Gautier 	_ACLK,
3317839a050SYann Gautier 	_PCLK1,
3327839a050SYann Gautier 	_PCLK2,
3337839a050SYann Gautier 	_PCLK3,
3347839a050SYann Gautier 	_PCLK4,
3357839a050SYann Gautier 	_PCLK5,
3367839a050SYann Gautier 	_HCLK6,
3377839a050SYann Gautier 	_HCLK2,
3387839a050SYann Gautier 	_CK_PER,
3397839a050SYann Gautier 	_CK_MPU,
340b053a22eSYann Gautier 	_CK_MCU,
3410d21680cSYann Gautier 	_USB_PHY_48,
3427839a050SYann Gautier 	_PARENT_NB,
3437839a050SYann Gautier 	_UNKNOWN_ID = 0xff,
3447839a050SYann Gautier };
3457839a050SYann Gautier 
3460d21680cSYann Gautier /* Lists only the parent clock we are interested in */
3477839a050SYann Gautier enum stm32mp1_parent_sel {
3480d21680cSYann Gautier 	_I2C12_SEL,
3490d21680cSYann Gautier 	_I2C35_SEL,
3500d21680cSYann Gautier 	_STGEN_SEL,
3517839a050SYann Gautier 	_I2C46_SEL,
3520d21680cSYann Gautier 	_SPI6_SEL,
353d4151d2fSYann Gautier 	_UART1_SEL,
3540d21680cSYann Gautier 	_RNG1_SEL,
3557839a050SYann Gautier 	_UART6_SEL,
3567839a050SYann Gautier 	_UART24_SEL,
3577839a050SYann Gautier 	_UART35_SEL,
3587839a050SYann Gautier 	_UART78_SEL,
3597839a050SYann Gautier 	_SDMMC12_SEL,
3607839a050SYann Gautier 	_SDMMC3_SEL,
3617839a050SYann Gautier 	_QSPI_SEL,
3627839a050SYann Gautier 	_FMC_SEL,
363d4151d2fSYann Gautier 	_AXIS_SEL,
364d4151d2fSYann Gautier 	_MCUS_SEL,
3657839a050SYann Gautier 	_USBPHY_SEL,
3667839a050SYann Gautier 	_USBO_SEL,
3678fbcd9e4SEtienne Carriere 	_MPU_SEL,
368288f5cf2SYann Gautier 	_CKPER_SEL,
369016af006SEtienne Carriere 	_RTC_SEL,
3707839a050SYann Gautier 	_PARENT_SEL_NB,
3717839a050SYann Gautier 	_UNKNOWN_SEL = 0xff,
3727839a050SYann Gautier };
3737839a050SYann Gautier 
3748fbcd9e4SEtienne Carriere /* State the parent clock ID straight related to a clock */
3758fbcd9e4SEtienne Carriere static const uint8_t parent_id_clock_id[_PARENT_NB] = {
3768fbcd9e4SEtienne Carriere 	[_HSE] = CK_HSE,
3778fbcd9e4SEtienne Carriere 	[_HSI] = CK_HSI,
3788fbcd9e4SEtienne Carriere 	[_CSI] = CK_CSI,
3798fbcd9e4SEtienne Carriere 	[_LSE] = CK_LSE,
3808fbcd9e4SEtienne Carriere 	[_LSI] = CK_LSI,
3818fbcd9e4SEtienne Carriere 	[_I2S_CKIN] = _UNKNOWN_ID,
3828fbcd9e4SEtienne Carriere 	[_USB_PHY_48] = _UNKNOWN_ID,
3838fbcd9e4SEtienne Carriere 	[_HSI_KER] = CK_HSI,
3848fbcd9e4SEtienne Carriere 	[_HSE_KER] = CK_HSE,
3858fbcd9e4SEtienne Carriere 	[_HSE_KER_DIV2] = CK_HSE_DIV2,
386cbd2e8a6SGabriel Fernandez 	[_HSE_RTC] = _UNKNOWN_ID,
3878fbcd9e4SEtienne Carriere 	[_CSI_KER] = CK_CSI,
3888fbcd9e4SEtienne Carriere 	[_PLL1_P] = PLL1_P,
3898fbcd9e4SEtienne Carriere 	[_PLL1_Q] = PLL1_Q,
3908fbcd9e4SEtienne Carriere 	[_PLL1_R] = PLL1_R,
3918fbcd9e4SEtienne Carriere 	[_PLL2_P] = PLL2_P,
3928fbcd9e4SEtienne Carriere 	[_PLL2_Q] = PLL2_Q,
3938fbcd9e4SEtienne Carriere 	[_PLL2_R] = PLL2_R,
3948fbcd9e4SEtienne Carriere 	[_PLL3_P] = PLL3_P,
3958fbcd9e4SEtienne Carriere 	[_PLL3_Q] = PLL3_Q,
3968fbcd9e4SEtienne Carriere 	[_PLL3_R] = PLL3_R,
3978fbcd9e4SEtienne Carriere 	[_PLL4_P] = PLL4_P,
3988fbcd9e4SEtienne Carriere 	[_PLL4_Q] = PLL4_Q,
3998fbcd9e4SEtienne Carriere 	[_PLL4_R] = PLL4_R,
4008fbcd9e4SEtienne Carriere 	[_ACLK] = CK_AXI,
4018fbcd9e4SEtienne Carriere 	[_PCLK1] = CK_AXI,
4028fbcd9e4SEtienne Carriere 	[_PCLK2] = CK_AXI,
4038fbcd9e4SEtienne Carriere 	[_PCLK3] = CK_AXI,
4048fbcd9e4SEtienne Carriere 	[_PCLK4] = CK_AXI,
4058fbcd9e4SEtienne Carriere 	[_PCLK5] = CK_AXI,
4068fbcd9e4SEtienne Carriere 	[_CK_PER] = CK_PER,
4078fbcd9e4SEtienne Carriere 	[_CK_MPU] = CK_MPU,
4088fbcd9e4SEtienne Carriere 	[_CK_MCU] = CK_MCU,
4098fbcd9e4SEtienne Carriere };
4108fbcd9e4SEtienne Carriere 
clock_id2parent_id(unsigned long id)4118fbcd9e4SEtienne Carriere static unsigned int clock_id2parent_id(unsigned long id)
4128fbcd9e4SEtienne Carriere {
4138fbcd9e4SEtienne Carriere 	unsigned int n;
4148fbcd9e4SEtienne Carriere 
4158fbcd9e4SEtienne Carriere 	for (n = 0U; n < ARRAY_SIZE(parent_id_clock_id); n++) {
4168fbcd9e4SEtienne Carriere 		if (parent_id_clock_id[n] == id) {
4178fbcd9e4SEtienne Carriere 			return n;
4188fbcd9e4SEtienne Carriere 		}
4198fbcd9e4SEtienne Carriere 	}
4208fbcd9e4SEtienne Carriere 
4218fbcd9e4SEtienne Carriere 	return _UNKNOWN_ID;
4228fbcd9e4SEtienne Carriere }
4238fbcd9e4SEtienne Carriere 
4247839a050SYann Gautier enum stm32mp1_pll_id {
4257839a050SYann Gautier 	_PLL1,
4267839a050SYann Gautier 	_PLL2,
4277839a050SYann Gautier 	_PLL3,
4287839a050SYann Gautier 	_PLL4,
4297839a050SYann Gautier 	_PLL_NB
4307839a050SYann Gautier };
4317839a050SYann Gautier 
4327839a050SYann Gautier enum stm32mp1_div_id {
4337839a050SYann Gautier 	_DIV_P,
4347839a050SYann Gautier 	_DIV_Q,
4357839a050SYann Gautier 	_DIV_R,
4367839a050SYann Gautier 	_DIV_NB,
4377839a050SYann Gautier };
4387839a050SYann Gautier 
4397839a050SYann Gautier enum stm32mp1_clksrc_id {
4407839a050SYann Gautier 	CLKSRC_MPU,
4417839a050SYann Gautier 	CLKSRC_AXI,
442b053a22eSYann Gautier 	CLKSRC_MCU,
4437839a050SYann Gautier 	CLKSRC_PLL12,
4447839a050SYann Gautier 	CLKSRC_PLL3,
4457839a050SYann Gautier 	CLKSRC_PLL4,
4467839a050SYann Gautier 	CLKSRC_RTC,
4477839a050SYann Gautier 	CLKSRC_MCO1,
4487839a050SYann Gautier 	CLKSRC_MCO2,
4497839a050SYann Gautier 	CLKSRC_NB
4507839a050SYann Gautier };
4517839a050SYann Gautier 
4527839a050SYann Gautier enum stm32mp1_clkdiv_id {
4537839a050SYann Gautier 	CLKDIV_MPU,
4547839a050SYann Gautier 	CLKDIV_AXI,
455b053a22eSYann Gautier 	CLKDIV_MCU,
4567839a050SYann Gautier 	CLKDIV_APB1,
4577839a050SYann Gautier 	CLKDIV_APB2,
4587839a050SYann Gautier 	CLKDIV_APB3,
4597839a050SYann Gautier 	CLKDIV_APB4,
4607839a050SYann Gautier 	CLKDIV_APB5,
4617839a050SYann Gautier 	CLKDIV_RTC,
4627839a050SYann Gautier 	CLKDIV_MCO1,
4637839a050SYann Gautier 	CLKDIV_MCO2,
4647839a050SYann Gautier 	CLKDIV_NB
4657839a050SYann Gautier };
4667839a050SYann Gautier 
4677839a050SYann Gautier enum stm32mp1_plltype {
4687839a050SYann Gautier 	PLL_800,
4697839a050SYann Gautier 	PLL_1600,
4707839a050SYann Gautier 	PLL_TYPE_NB
4717839a050SYann Gautier };
4727839a050SYann Gautier 
4737839a050SYann Gautier struct stm32mp1_pll {
4747839a050SYann Gautier 	uint8_t refclk_min;
4757839a050SYann Gautier 	uint8_t refclk_max;
4767839a050SYann Gautier };
4777839a050SYann Gautier 
4787839a050SYann Gautier struct stm32mp1_clk_gate {
4797839a050SYann Gautier 	uint16_t offset;
4807839a050SYann Gautier 	uint8_t bit;
4817839a050SYann Gautier 	uint8_t index;
4827839a050SYann Gautier 	uint8_t set_clr;
483aaa09b71SYann Gautier 	uint8_t secure;
4840d21680cSYann Gautier 	uint8_t sel; /* Relates to enum stm32mp1_parent_sel */
4850d21680cSYann Gautier 	uint8_t fixed; /* Relates to enum stm32mp1_parent_id */
4867839a050SYann Gautier };
4877839a050SYann Gautier 
4887839a050SYann Gautier struct stm32mp1_clk_sel {
4897839a050SYann Gautier 	uint16_t offset;
4907839a050SYann Gautier 	uint8_t src;
4917839a050SYann Gautier 	uint8_t msk;
4927839a050SYann Gautier 	uint8_t nb_parent;
4937839a050SYann Gautier 	const uint8_t *parent;
4947839a050SYann Gautier };
4957839a050SYann Gautier 
4967839a050SYann Gautier #define REFCLK_SIZE 4
4977839a050SYann Gautier struct stm32mp1_clk_pll {
4987839a050SYann Gautier 	enum stm32mp1_plltype plltype;
4997839a050SYann Gautier 	uint16_t rckxselr;
5007839a050SYann Gautier 	uint16_t pllxcfgr1;
5017839a050SYann Gautier 	uint16_t pllxcfgr2;
5027839a050SYann Gautier 	uint16_t pllxfracr;
5037839a050SYann Gautier 	uint16_t pllxcr;
5047839a050SYann Gautier 	uint16_t pllxcsgr;
5057839a050SYann Gautier 	enum stm32mp_osc_id refclk[REFCLK_SIZE];
5067839a050SYann Gautier };
5077839a050SYann Gautier 
5080d21680cSYann Gautier /* Clocks with selectable source and non set/clr register access */
509aaa09b71SYann Gautier #define _CLK_SELEC(sec, off, b, idx, s)			\
5107839a050SYann Gautier 	{						\
5117839a050SYann Gautier 		.offset = (off),			\
5127839a050SYann Gautier 		.bit = (b),				\
5137839a050SYann Gautier 		.index = (idx),				\
5147839a050SYann Gautier 		.set_clr = 0,				\
515aaa09b71SYann Gautier 		.secure = (sec),			\
5167839a050SYann Gautier 		.sel = (s),				\
5177839a050SYann Gautier 		.fixed = _UNKNOWN_ID,			\
5187839a050SYann Gautier 	}
5197839a050SYann Gautier 
5200d21680cSYann Gautier /* Clocks with fixed source and non set/clr register access */
521aaa09b71SYann Gautier #define _CLK_FIXED(sec, off, b, idx, f)			\
5227839a050SYann Gautier 	{						\
5237839a050SYann Gautier 		.offset = (off),			\
5247839a050SYann Gautier 		.bit = (b),				\
5257839a050SYann Gautier 		.index = (idx),				\
5267839a050SYann Gautier 		.set_clr = 0,				\
527aaa09b71SYann Gautier 		.secure = (sec),			\
5287839a050SYann Gautier 		.sel = _UNKNOWN_SEL,			\
5297839a050SYann Gautier 		.fixed = (f),				\
5307839a050SYann Gautier 	}
5317839a050SYann Gautier 
5320d21680cSYann Gautier /* Clocks with selectable source and set/clr register access */
533aaa09b71SYann Gautier #define _CLK_SC_SELEC(sec, off, b, idx, s)			\
5347839a050SYann Gautier 	{						\
5357839a050SYann Gautier 		.offset = (off),			\
5367839a050SYann Gautier 		.bit = (b),				\
5377839a050SYann Gautier 		.index = (idx),				\
5387839a050SYann Gautier 		.set_clr = 1,				\
539aaa09b71SYann Gautier 		.secure = (sec),			\
5407839a050SYann Gautier 		.sel = (s),				\
5417839a050SYann Gautier 		.fixed = _UNKNOWN_ID,			\
5427839a050SYann Gautier 	}
5437839a050SYann Gautier 
5440d21680cSYann Gautier /* Clocks with fixed source and set/clr register access */
545aaa09b71SYann Gautier #define _CLK_SC_FIXED(sec, off, b, idx, f)			\
5467839a050SYann Gautier 	{						\
5477839a050SYann Gautier 		.offset = (off),			\
5487839a050SYann Gautier 		.bit = (b),				\
5497839a050SYann Gautier 		.index = (idx),				\
5507839a050SYann Gautier 		.set_clr = 1,				\
551aaa09b71SYann Gautier 		.secure = (sec),			\
5527839a050SYann Gautier 		.sel = _UNKNOWN_SEL,			\
5537839a050SYann Gautier 		.fixed = (f),				\
5547839a050SYann Gautier 	}
5557839a050SYann Gautier 
556d4151d2fSYann Gautier #define _CLK_PARENT_SEL(_label, _rcc_selr, _parents)		\
557d4151d2fSYann Gautier 	[_ ## _label ## _SEL] = {				\
558d4151d2fSYann Gautier 		.offset = _rcc_selr,				\
559d4151d2fSYann Gautier 		.src = _rcc_selr ## _ ## _label ## SRC_SHIFT,	\
5608ae08dcdSEtienne Carriere 		.msk = (_rcc_selr ## _ ## _label ## SRC_MASK) >> \
5618ae08dcdSEtienne Carriere 		       (_rcc_selr ## _ ## _label ## SRC_SHIFT), \
562d4151d2fSYann Gautier 		.parent = (_parents),				\
563d4151d2fSYann Gautier 		.nb_parent = ARRAY_SIZE(_parents)		\
5647839a050SYann Gautier 	}
5657839a050SYann Gautier 
5660d21680cSYann Gautier #define _CLK_PLL(idx, type, off1, off2, off3,		\
5677839a050SYann Gautier 		 off4, off5, off6,			\
5687839a050SYann Gautier 		 p1, p2, p3, p4)			\
5697839a050SYann Gautier 	[(idx)] = {					\
5707839a050SYann Gautier 		.plltype = (type),			\
5717839a050SYann Gautier 		.rckxselr = (off1),			\
5727839a050SYann Gautier 		.pllxcfgr1 = (off2),			\
5737839a050SYann Gautier 		.pllxcfgr2 = (off3),			\
5747839a050SYann Gautier 		.pllxfracr = (off4),			\
5757839a050SYann Gautier 		.pllxcr = (off5),			\
5767839a050SYann Gautier 		.pllxcsgr = (off6),			\
5777839a050SYann Gautier 		.refclk[0] = (p1),			\
5787839a050SYann Gautier 		.refclk[1] = (p2),			\
5797839a050SYann Gautier 		.refclk[2] = (p3),			\
5807839a050SYann Gautier 		.refclk[3] = (p4),			\
5817839a050SYann Gautier 	}
5827839a050SYann Gautier 
5830d21680cSYann Gautier #define NB_GATES	ARRAY_SIZE(stm32mp1_clk_gate)
5840d21680cSYann Gautier 
585aaa09b71SYann Gautier #define SEC		1
586aaa09b71SYann Gautier #define N_S		0
587aaa09b71SYann Gautier 
5887839a050SYann Gautier static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
589aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK),
590aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
591aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK),
592aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
593aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
594aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
595aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
596aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
597aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK),
598aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
599aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
6007839a050SYann Gautier 
6017418cf39SYann Gautier #if defined(IMAGE_BL32)
602aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
6037418cf39SYann Gautier #endif
604aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
605aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
606aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
607aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
608aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
609aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
610aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL),
611aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL),
612aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL),
613aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL),
6147839a050SYann Gautier 
6157418cf39SYann Gautier #if defined(IMAGE_BL32)
616aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
6177418cf39SYann Gautier #endif
618aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
6197839a050SYann Gautier 
620aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID),
621f33b2433SYann Gautier 
622aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
623aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
624aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
6257839a050SYann Gautier 
626aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL),
627aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
628aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL),
629aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL),
630aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
631aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5),
632aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5),
633aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5),
634aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5),
635aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5),
636aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
6377839a050SYann Gautier 
6387418cf39SYann Gautier #if defined(IMAGE_BL32)
639aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
640aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
6417418cf39SYann Gautier #endif
6427839a050SYann Gautier 
643aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
644aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
645aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
646aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
647aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
648aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
649aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
650aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
651aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
652aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
653aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
6547839a050SYann Gautier 
655aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5),
656aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5),
657aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5),
658aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL),
659aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5),
6607839a050SYann Gautier 
6617418cf39SYann Gautier #if defined(IMAGE_BL2)
662aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
663aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
6647418cf39SYann Gautier #endif
665aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
666aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
6677418cf39SYann Gautier #if defined(IMAGE_BL32)
668aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
6697418cf39SYann Gautier #endif
6707839a050SYann Gautier 
671aaa09b71SYann Gautier 	_CLK_SELEC(SEC, RCC_BDCR, 20, RTC, _RTC_SEL),
672aaa09b71SYann Gautier 	_CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
6737839a050SYann Gautier };
6747839a050SYann Gautier 
6750d21680cSYann Gautier static const uint8_t i2c12_parents[] = {
6760d21680cSYann Gautier 	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
6770d21680cSYann Gautier };
6780d21680cSYann Gautier 
6790d21680cSYann Gautier static const uint8_t i2c35_parents[] = {
6800d21680cSYann Gautier 	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
6810d21680cSYann Gautier };
6820d21680cSYann Gautier 
6830d21680cSYann Gautier static const uint8_t stgen_parents[] = {
6840d21680cSYann Gautier 	_HSI_KER, _HSE_KER
6850d21680cSYann Gautier };
6860d21680cSYann Gautier 
6870d21680cSYann Gautier static const uint8_t i2c46_parents[] = {
6880d21680cSYann Gautier 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER
6890d21680cSYann Gautier };
6900d21680cSYann Gautier 
6910d21680cSYann Gautier static const uint8_t spi6_parents[] = {
6920d21680cSYann Gautier 	_PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q
6930d21680cSYann Gautier };
6940d21680cSYann Gautier 
6950d21680cSYann Gautier static const uint8_t usart1_parents[] = {
6960d21680cSYann Gautier 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER
6970d21680cSYann Gautier };
6980d21680cSYann Gautier 
6990d21680cSYann Gautier static const uint8_t rng1_parents[] = {
7000d21680cSYann Gautier 	_CSI, _PLL4_R, _LSE, _LSI
7010d21680cSYann Gautier };
7020d21680cSYann Gautier 
7030d21680cSYann Gautier static const uint8_t uart6_parents[] = {
7040d21680cSYann Gautier 	_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
7050d21680cSYann Gautier };
7060d21680cSYann Gautier 
7070d21680cSYann Gautier static const uint8_t uart234578_parents[] = {
7080d21680cSYann Gautier 	_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
7090d21680cSYann Gautier };
7100d21680cSYann Gautier 
7110d21680cSYann Gautier static const uint8_t sdmmc12_parents[] = {
7120d21680cSYann Gautier 	_HCLK6, _PLL3_R, _PLL4_P, _HSI_KER
7130d21680cSYann Gautier };
7140d21680cSYann Gautier 
7150d21680cSYann Gautier static const uint8_t sdmmc3_parents[] = {
7160d21680cSYann Gautier 	_HCLK2, _PLL3_R, _PLL4_P, _HSI_KER
7170d21680cSYann Gautier };
7180d21680cSYann Gautier 
7190d21680cSYann Gautier static const uint8_t qspi_parents[] = {
7200d21680cSYann Gautier 	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
7210d21680cSYann Gautier };
7220d21680cSYann Gautier 
7230d21680cSYann Gautier static const uint8_t fmc_parents[] = {
7240d21680cSYann Gautier 	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
7250d21680cSYann Gautier };
7260d21680cSYann Gautier 
727b8fe48b6SEtienne Carriere static const uint8_t axiss_parents[] = {
728b8fe48b6SEtienne Carriere 	_HSI, _HSE, _PLL2_P
7290d21680cSYann Gautier };
7300d21680cSYann Gautier 
731b8fe48b6SEtienne Carriere static const uint8_t mcuss_parents[] = {
732b8fe48b6SEtienne Carriere 	_HSI, _HSE, _CSI, _PLL3_P
733b053a22eSYann Gautier };
734b053a22eSYann Gautier 
7350d21680cSYann Gautier static const uint8_t usbphy_parents[] = {
7360d21680cSYann Gautier 	_HSE_KER, _PLL4_R, _HSE_KER_DIV2
7370d21680cSYann Gautier };
7380d21680cSYann Gautier 
7390d21680cSYann Gautier static const uint8_t usbo_parents[] = {
7400d21680cSYann Gautier 	_PLL4_R, _USB_PHY_48
7410d21680cSYann Gautier };
7427839a050SYann Gautier 
7438fbcd9e4SEtienne Carriere static const uint8_t mpu_parents[] = {
7448fbcd9e4SEtienne Carriere 	_HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */
7458fbcd9e4SEtienne Carriere };
7468fbcd9e4SEtienne Carriere 
7478fbcd9e4SEtienne Carriere static const uint8_t per_parents[] = {
7488fbcd9e4SEtienne Carriere 	_HSI, _HSE, _CSI,
7498fbcd9e4SEtienne Carriere };
7508fbcd9e4SEtienne Carriere 
751016af006SEtienne Carriere static const uint8_t rtc_parents[] = {
752cbd2e8a6SGabriel Fernandez 	_UNKNOWN_ID, _LSE, _LSI, _HSE_RTC
753016af006SEtienne Carriere };
754016af006SEtienne Carriere 
7557839a050SYann Gautier static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
756d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents),
757d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents),
758d4151d2fSYann Gautier 	_CLK_PARENT_SEL(STGEN, RCC_STGENCKSELR, stgen_parents),
759d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C46, RCC_I2C46CKSELR, i2c46_parents),
760d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents),
761d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents),
762d4151d2fSYann Gautier 	_CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents),
7638fbcd9e4SEtienne Carriere 	_CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents),
764288f5cf2SYann Gautier 	_CLK_PARENT_SEL(CKPER, RCC_CPERCKSELR, per_parents),
765016af006SEtienne Carriere 	_CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents),
766d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents),
767d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents),
768d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents),
769d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART78, RCC_UART78CKSELR, uart234578_parents),
770d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SDMMC12, RCC_SDMMC12CKSELR, sdmmc12_parents),
771d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents),
772d4151d2fSYann Gautier 	_CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents),
773d4151d2fSYann Gautier 	_CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents),
774b8fe48b6SEtienne Carriere 	_CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, axiss_parents),
775b8fe48b6SEtienne Carriere 	_CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mcuss_parents),
776d4151d2fSYann Gautier 	_CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents),
777d4151d2fSYann Gautier 	_CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents),
7787839a050SYann Gautier };
7797839a050SYann Gautier 
7807839a050SYann Gautier /* Define characteristic of PLL according type */
781f6559227SYann Gautier #define POST_DIVM_MIN	8000000U
782f6559227SYann Gautier #define POST_DIVM_MAX	16000000U
783f6559227SYann Gautier #define DIVM_MIN	0U
784f6559227SYann Gautier #define DIVM_MAX	63U
785f6559227SYann Gautier #define DIVN_MIN	24U
786f6559227SYann Gautier #define DIVN_MAX	99U
787f6559227SYann Gautier #define DIVP_MIN	0U
788f6559227SYann Gautier #define DIVP_MAX	127U
789f6559227SYann Gautier #define FRAC_MAX	8192U
790f6559227SYann Gautier #define VCO_MIN		800000000U
791f6559227SYann Gautier #define VCO_MAX		1600000000U
792f6559227SYann Gautier 
7937839a050SYann Gautier static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
7947839a050SYann Gautier 	[PLL_800] = {
7957839a050SYann Gautier 		.refclk_min = 4,
7967839a050SYann Gautier 		.refclk_max = 16,
7977839a050SYann Gautier 	},
7987839a050SYann Gautier 	[PLL_1600] = {
7997839a050SYann Gautier 		.refclk_min = 8,
8007839a050SYann Gautier 		.refclk_max = 16,
8017839a050SYann Gautier 	},
8027839a050SYann Gautier };
8037839a050SYann Gautier 
8047839a050SYann Gautier /* PLLNCFGR2 register divider by output */
8057839a050SYann Gautier static const uint8_t pllncfgr2[_DIV_NB] = {
8067839a050SYann Gautier 	[_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT,
8077839a050SYann Gautier 	[_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT,
8080d21680cSYann Gautier 	[_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT,
8097839a050SYann Gautier };
8107839a050SYann Gautier 
8117839a050SYann Gautier static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = {
8120d21680cSYann Gautier 	_CLK_PLL(_PLL1, PLL_1600,
8137839a050SYann Gautier 		 RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2,
8147839a050SYann Gautier 		 RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR,
8157839a050SYann Gautier 		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
8160d21680cSYann Gautier 	_CLK_PLL(_PLL2, PLL_1600,
8177839a050SYann Gautier 		 RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2,
8187839a050SYann Gautier 		 RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR,
8197839a050SYann Gautier 		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
8200d21680cSYann Gautier 	_CLK_PLL(_PLL3, PLL_800,
8217839a050SYann Gautier 		 RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2,
8227839a050SYann Gautier 		 RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR,
8237839a050SYann Gautier 		 _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID),
8240d21680cSYann Gautier 	_CLK_PLL(_PLL4, PLL_800,
8257839a050SYann Gautier 		 RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2,
8267839a050SYann Gautier 		 RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR,
8277839a050SYann Gautier 		 _HSI, _HSE, _CSI, _I2S_CKIN),
8287839a050SYann Gautier };
8297839a050SYann Gautier 
8307839a050SYann Gautier /* Prescaler table lookups for clock computation */
831b053a22eSYann Gautier /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */
832b053a22eSYann Gautier static const uint8_t stm32mp1_mcu_div[16] = {
833b053a22eSYann Gautier 	0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9
834b053a22eSYann Gautier };
8357839a050SYann Gautier 
8367839a050SYann Gautier /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */
8377839a050SYann Gautier #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div
8387839a050SYann Gautier #define stm32mp1_apbx_div stm32mp1_mpu_apbx_div
8397839a050SYann Gautier static const uint8_t stm32mp1_mpu_apbx_div[8] = {
8407839a050SYann Gautier 	0, 1, 2, 3, 4, 4, 4, 4
8417839a050SYann Gautier };
8427839a050SYann Gautier 
8437839a050SYann Gautier /* div = /1 /2 /3 /4 */
8447839a050SYann Gautier static const uint8_t stm32mp1_axi_div[8] = {
8457839a050SYann Gautier 	1, 2, 3, 4, 4, 4, 4, 4
8467839a050SYann Gautier };
8477839a050SYann Gautier 
84837e8295aSEtienne Carriere static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = {
84937e8295aSEtienne Carriere 	[_HSI] = "HSI",
85037e8295aSEtienne Carriere 	[_HSE] = "HSE",
85137e8295aSEtienne Carriere 	[_CSI] = "CSI",
85237e8295aSEtienne Carriere 	[_LSI] = "LSI",
85337e8295aSEtienne Carriere 	[_LSE] = "LSE",
85437e8295aSEtienne Carriere 	[_I2S_CKIN] = "I2S_CKIN",
85537e8295aSEtienne Carriere 	[_HSI_KER] = "HSI_KER",
85637e8295aSEtienne Carriere 	[_HSE_KER] = "HSE_KER",
85737e8295aSEtienne Carriere 	[_HSE_KER_DIV2] = "HSE_KER_DIV2",
858cbd2e8a6SGabriel Fernandez 	[_HSE_RTC] = "HSE_RTC",
85937e8295aSEtienne Carriere 	[_CSI_KER] = "CSI_KER",
86037e8295aSEtienne Carriere 	[_PLL1_P] = "PLL1_P",
86137e8295aSEtienne Carriere 	[_PLL1_Q] = "PLL1_Q",
86237e8295aSEtienne Carriere 	[_PLL1_R] = "PLL1_R",
86337e8295aSEtienne Carriere 	[_PLL2_P] = "PLL2_P",
86437e8295aSEtienne Carriere 	[_PLL2_Q] = "PLL2_Q",
86537e8295aSEtienne Carriere 	[_PLL2_R] = "PLL2_R",
86637e8295aSEtienne Carriere 	[_PLL3_P] = "PLL3_P",
86737e8295aSEtienne Carriere 	[_PLL3_Q] = "PLL3_Q",
86837e8295aSEtienne Carriere 	[_PLL3_R] = "PLL3_R",
86937e8295aSEtienne Carriere 	[_PLL4_P] = "PLL4_P",
87037e8295aSEtienne Carriere 	[_PLL4_Q] = "PLL4_Q",
87137e8295aSEtienne Carriere 	[_PLL4_R] = "PLL4_R",
87237e8295aSEtienne Carriere 	[_ACLK] = "ACLK",
87337e8295aSEtienne Carriere 	[_PCLK1] = "PCLK1",
87437e8295aSEtienne Carriere 	[_PCLK2] = "PCLK2",
87537e8295aSEtienne Carriere 	[_PCLK3] = "PCLK3",
87637e8295aSEtienne Carriere 	[_PCLK4] = "PCLK4",
87737e8295aSEtienne Carriere 	[_PCLK5] = "PCLK5",
87837e8295aSEtienne Carriere 	[_HCLK6] = "KCLK6",
87937e8295aSEtienne Carriere 	[_HCLK2] = "HCLK2",
88037e8295aSEtienne Carriere 	[_CK_PER] = "CK_PER",
88137e8295aSEtienne Carriere 	[_CK_MPU] = "CK_MPU",
88237e8295aSEtienne Carriere 	[_CK_MCU] = "CK_MCU",
88337e8295aSEtienne Carriere 	[_USB_PHY_48] = "USB_PHY_48",
88437e8295aSEtienne Carriere };
88537e8295aSEtienne Carriere 
8860d21680cSYann Gautier /* RCC clock device driver private */
8870d21680cSYann Gautier static unsigned long stm32mp1_osc[NB_OSC];
8880d21680cSYann Gautier static struct spinlock reg_lock;
8890d21680cSYann Gautier static unsigned int gate_refcounts[NB_GATES];
8900d21680cSYann Gautier static struct spinlock refcount_lock;
8917839a050SYann Gautier 
gate_ref(unsigned int idx)8920d21680cSYann Gautier static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx)
8930d21680cSYann Gautier {
8940d21680cSYann Gautier 	return &stm32mp1_clk_gate[idx];
8950d21680cSYann Gautier }
8967839a050SYann Gautier 
8973d69149aSYann Gautier #if defined(IMAGE_BL32)
gate_is_non_secure(const struct stm32mp1_clk_gate * gate)8983d69149aSYann Gautier static bool gate_is_non_secure(const struct stm32mp1_clk_gate *gate)
8993d69149aSYann Gautier {
9003d69149aSYann Gautier 	return gate->secure == N_S;
9013d69149aSYann Gautier }
9023d69149aSYann Gautier #endif
9033d69149aSYann Gautier 
clk_sel_ref(unsigned int idx)9040d21680cSYann Gautier static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx)
9050d21680cSYann Gautier {
9060d21680cSYann Gautier 	return &stm32mp1_clk_sel[idx];
9070d21680cSYann Gautier }
9080d21680cSYann Gautier 
pll_ref(unsigned int idx)9090d21680cSYann Gautier static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx)
9100d21680cSYann Gautier {
9110d21680cSYann Gautier 	return &stm32mp1_clk_pll[idx];
9120d21680cSYann Gautier }
9130d21680cSYann Gautier 
stm32mp1_clk_lock(struct spinlock * lock)9140d21680cSYann Gautier static void stm32mp1_clk_lock(struct spinlock *lock)
9150d21680cSYann Gautier {
916e463d3f4SYann Gautier 	if (stm32mp_lock_available()) {
9170d21680cSYann Gautier 		/* Assume interrupts are masked */
9180d21680cSYann Gautier 		spin_lock(lock);
9190d21680cSYann Gautier 	}
920e463d3f4SYann Gautier }
9210d21680cSYann Gautier 
stm32mp1_clk_unlock(struct spinlock * lock)9220d21680cSYann Gautier static void stm32mp1_clk_unlock(struct spinlock *lock)
9230d21680cSYann Gautier {
924e463d3f4SYann Gautier 	if (stm32mp_lock_available()) {
9250d21680cSYann Gautier 		spin_unlock(lock);
9260d21680cSYann Gautier 	}
927e463d3f4SYann Gautier }
9280d21680cSYann Gautier 
stm32mp1_rcc_is_secure(void)9290d21680cSYann Gautier bool stm32mp1_rcc_is_secure(void)
9300d21680cSYann Gautier {
9310d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
9321bb9072aSEtienne Carriere 	uint32_t mask = RCC_TZCR_TZEN;
9330d21680cSYann Gautier 
9341bb9072aSEtienne Carriere 	return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
9350d21680cSYann Gautier }
9360d21680cSYann Gautier 
stm32mp1_rcc_is_mckprot(void)937b053a22eSYann Gautier bool stm32mp1_rcc_is_mckprot(void)
938b053a22eSYann Gautier {
939b053a22eSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
9401bb9072aSEtienne Carriere 	uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT;
941b053a22eSYann Gautier 
9421bb9072aSEtienne Carriere 	return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
943b053a22eSYann Gautier }
944b053a22eSYann Gautier 
stm32mp1_clk_rcc_regs_lock(void)9450d21680cSYann Gautier void stm32mp1_clk_rcc_regs_lock(void)
9460d21680cSYann Gautier {
9470d21680cSYann Gautier 	stm32mp1_clk_lock(&reg_lock);
9480d21680cSYann Gautier }
9490d21680cSYann Gautier 
stm32mp1_clk_rcc_regs_unlock(void)9500d21680cSYann Gautier void stm32mp1_clk_rcc_regs_unlock(void)
9510d21680cSYann Gautier {
9520d21680cSYann Gautier 	stm32mp1_clk_unlock(&reg_lock);
9530d21680cSYann Gautier }
9540d21680cSYann Gautier 
stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx)9550d21680cSYann Gautier static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx)
9567839a050SYann Gautier {
9577839a050SYann Gautier 	if (idx >= NB_OSC) {
9587839a050SYann Gautier 		return 0;
9597839a050SYann Gautier 	}
9607839a050SYann Gautier 
9610d21680cSYann Gautier 	return stm32mp1_osc[idx];
9627839a050SYann Gautier }
9637839a050SYann Gautier 
stm32mp1_clk_get_gated_id(unsigned long id)9640d21680cSYann Gautier static int stm32mp1_clk_get_gated_id(unsigned long id)
9657839a050SYann Gautier {
9660d21680cSYann Gautier 	unsigned int i;
9677839a050SYann Gautier 
9680d21680cSYann Gautier 	for (i = 0U; i < NB_GATES; i++) {
9690d21680cSYann Gautier 		if (gate_ref(i)->index == id) {
9707839a050SYann Gautier 			return i;
9717839a050SYann Gautier 		}
9727839a050SYann Gautier 	}
9737839a050SYann Gautier 
97444fb470bSYann Gautier 	ERROR("%s: clk id %lu not found\n", __func__, id);
9757839a050SYann Gautier 
9767839a050SYann Gautier 	return -EINVAL;
9777839a050SYann Gautier }
9787839a050SYann Gautier 
stm32mp1_clk_get_sel(int i)9790d21680cSYann Gautier static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i)
9807839a050SYann Gautier {
9810d21680cSYann Gautier 	return (enum stm32mp1_parent_sel)(gate_ref(i)->sel);
9827839a050SYann Gautier }
9837839a050SYann Gautier 
stm32mp1_clk_get_fixed_parent(int i)9840d21680cSYann Gautier static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i)
9857839a050SYann Gautier {
9860d21680cSYann Gautier 	return (enum stm32mp1_parent_id)(gate_ref(i)->fixed);
9877839a050SYann Gautier }
9887839a050SYann Gautier 
stm32mp1_clk_get_parent(unsigned long id)9890d21680cSYann Gautier static int stm32mp1_clk_get_parent(unsigned long id)
9907839a050SYann Gautier {
9910d21680cSYann Gautier 	const struct stm32mp1_clk_sel *sel;
9928fbcd9e4SEtienne Carriere 	uint32_t p_sel;
9937839a050SYann Gautier 	int i;
9947839a050SYann Gautier 	enum stm32mp1_parent_id p;
9957839a050SYann Gautier 	enum stm32mp1_parent_sel s;
9960d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
9977839a050SYann Gautier 
9988fbcd9e4SEtienne Carriere 	/* Few non gateable clock have a static parent ID, find them */
9998fbcd9e4SEtienne Carriere 	i = (int)clock_id2parent_id(id);
10008fbcd9e4SEtienne Carriere 	if (i != _UNKNOWN_ID) {
10018fbcd9e4SEtienne Carriere 		return i;
10027839a050SYann Gautier 	}
10037839a050SYann Gautier 
10040d21680cSYann Gautier 	i = stm32mp1_clk_get_gated_id(id);
10057839a050SYann Gautier 	if (i < 0) {
10060d21680cSYann Gautier 		panic();
10077839a050SYann Gautier 	}
10087839a050SYann Gautier 
10090d21680cSYann Gautier 	p = stm32mp1_clk_get_fixed_parent(i);
10107839a050SYann Gautier 	if (p < _PARENT_NB) {
10117839a050SYann Gautier 		return (int)p;
10127839a050SYann Gautier 	}
10137839a050SYann Gautier 
10140d21680cSYann Gautier 	s = stm32mp1_clk_get_sel(i);
10150d21680cSYann Gautier 	if (s == _UNKNOWN_SEL) {
10160d21680cSYann Gautier 		return -EINVAL;
10170d21680cSYann Gautier 	}
10187839a050SYann Gautier 	if (s >= _PARENT_SEL_NB) {
10190d21680cSYann Gautier 		panic();
10207839a050SYann Gautier 	}
10217839a050SYann Gautier 
10220d21680cSYann Gautier 	sel = clk_sel_ref(s);
10238ae08dcdSEtienne Carriere 	p_sel = (mmio_read_32(rcc_base + sel->offset) &
10248ae08dcdSEtienne Carriere 		 (sel->msk << sel->src)) >> sel->src;
10250d21680cSYann Gautier 	if (p_sel < sel->nb_parent) {
10260d21680cSYann Gautier 		return (int)sel->parent[p_sel];
10277839a050SYann Gautier 	}
10287839a050SYann Gautier 
10297839a050SYann Gautier 	return -EINVAL;
10307839a050SYann Gautier }
10317839a050SYann Gautier 
stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll * pll)10320d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll)
10337839a050SYann Gautier {
10340d21680cSYann Gautier 	uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr);
10350d21680cSYann Gautier 	uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK;
10367839a050SYann Gautier 
10370d21680cSYann Gautier 	return stm32mp1_clk_get_fixed(pll->refclk[src]);
10387839a050SYann Gautier }
10397839a050SYann Gautier 
10407839a050SYann Gautier /*
10417839a050SYann Gautier  * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL
10427839a050SYann Gautier  * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1)
10437839a050SYann Gautier  * - PLL3 & PLL4 => return VCO     with Fpll_y_ck = FVCO / (DIVy + 1)
10447839a050SYann Gautier  * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1)
10457839a050SYann Gautier  */
stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll * pll)10460d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll)
10477839a050SYann Gautier {
10487839a050SYann Gautier 	unsigned long refclk, fvco;
10497839a050SYann Gautier 	uint32_t cfgr1, fracr, divm, divn;
10500d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10517839a050SYann Gautier 
10520d21680cSYann Gautier 	cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1);
10530d21680cSYann Gautier 	fracr = mmio_read_32(rcc_base + pll->pllxfracr);
10547839a050SYann Gautier 
10557839a050SYann Gautier 	divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT;
10567839a050SYann Gautier 	divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK;
10577839a050SYann Gautier 
10580d21680cSYann Gautier 	refclk = stm32mp1_pll_get_fref(pll);
10597839a050SYann Gautier 
10607839a050SYann Gautier 	/*
10617839a050SYann Gautier 	 * With FRACV :
10627839a050SYann Gautier 	 *   Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1)
10637839a050SYann Gautier 	 * Without FRACV
10647839a050SYann Gautier 	 *   Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1)
10657839a050SYann Gautier 	 */
10667839a050SYann Gautier 	if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) {
10670d21680cSYann Gautier 		uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >>
10680d21680cSYann Gautier 				 RCC_PLLNFRACR_FRACV_SHIFT;
10697839a050SYann Gautier 		unsigned long long numerator, denominator;
10707839a050SYann Gautier 
10710d21680cSYann Gautier 		numerator = (((unsigned long long)divn + 1U) << 13) + fracv;
10720d21680cSYann Gautier 		numerator = refclk * numerator;
10737839a050SYann Gautier 		denominator = ((unsigned long long)divm + 1U) << 13;
10747839a050SYann Gautier 		fvco = (unsigned long)(numerator / denominator);
10757839a050SYann Gautier 	} else {
10767839a050SYann Gautier 		fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U));
10777839a050SYann Gautier 	}
10787839a050SYann Gautier 
10797839a050SYann Gautier 	return fvco;
10807839a050SYann Gautier }
10817839a050SYann Gautier 
stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id,enum stm32mp1_div_id div_id)10820d21680cSYann Gautier static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id,
10837839a050SYann Gautier 					    enum stm32mp1_div_id div_id)
10847839a050SYann Gautier {
10850d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
10867839a050SYann Gautier 	unsigned long dfout;
10877839a050SYann Gautier 	uint32_t cfgr2, divy;
10887839a050SYann Gautier 
10897839a050SYann Gautier 	if (div_id >= _DIV_NB) {
10907839a050SYann Gautier 		return 0;
10917839a050SYann Gautier 	}
10927839a050SYann Gautier 
10930d21680cSYann Gautier 	cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2);
10947839a050SYann Gautier 	divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK;
10957839a050SYann Gautier 
10960d21680cSYann Gautier 	dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U);
10977839a050SYann Gautier 
10987839a050SYann Gautier 	return dfout;
10997839a050SYann Gautier }
11007839a050SYann Gautier 
get_clock_rate(int p)11010d21680cSYann Gautier static unsigned long get_clock_rate(int p)
11027839a050SYann Gautier {
11037839a050SYann Gautier 	uint32_t reg, clkdiv;
11047839a050SYann Gautier 	unsigned long clock = 0;
11050d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
11067839a050SYann Gautier 
11077839a050SYann Gautier 	switch (p) {
11087839a050SYann Gautier 	case _CK_MPU:
11097839a050SYann Gautier 	/* MPU sub system */
11100d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MPCKSELR);
11117839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
11127839a050SYann Gautier 		case RCC_MPCKSELR_HSI:
11130d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
11147839a050SYann Gautier 			break;
11157839a050SYann Gautier 		case RCC_MPCKSELR_HSE:
11160d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
11177839a050SYann Gautier 			break;
11187839a050SYann Gautier 		case RCC_MPCKSELR_PLL:
11190d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
11207839a050SYann Gautier 			break;
11217839a050SYann Gautier 		case RCC_MPCKSELR_PLL_MPUDIV:
11220d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
11237839a050SYann Gautier 
11240d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_MPCKDIVR);
11257839a050SYann Gautier 			clkdiv = reg & RCC_MPUDIV_MASK;
1126602ae2f2SGabriel Fernandez 			clock >>= stm32mp1_mpu_div[clkdiv];
11277839a050SYann Gautier 			break;
11287839a050SYann Gautier 		default:
11297839a050SYann Gautier 			break;
11307839a050SYann Gautier 		}
11317839a050SYann Gautier 		break;
11327839a050SYann Gautier 	/* AXI sub system */
11337839a050SYann Gautier 	case _ACLK:
11347839a050SYann Gautier 	case _HCLK2:
11357839a050SYann Gautier 	case _HCLK6:
11367839a050SYann Gautier 	case _PCLK4:
11377839a050SYann Gautier 	case _PCLK5:
11380d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_ASSCKSELR);
11397839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
11407839a050SYann Gautier 		case RCC_ASSCKSELR_HSI:
11410d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
11427839a050SYann Gautier 			break;
11437839a050SYann Gautier 		case RCC_ASSCKSELR_HSE:
11440d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
11457839a050SYann Gautier 			break;
11467839a050SYann Gautier 		case RCC_ASSCKSELR_PLL:
11470d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
11487839a050SYann Gautier 			break;
11497839a050SYann Gautier 		default:
11507839a050SYann Gautier 			break;
11517839a050SYann Gautier 		}
11527839a050SYann Gautier 
11537839a050SYann Gautier 		/* System clock divider */
11540d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_AXIDIVR);
11557839a050SYann Gautier 		clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK];
11567839a050SYann Gautier 
11577839a050SYann Gautier 		switch (p) {
11587839a050SYann Gautier 		case _PCLK4:
11590d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB4DIVR);
11607839a050SYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
11617839a050SYann Gautier 			break;
11627839a050SYann Gautier 		case _PCLK5:
11630d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB5DIVR);
11647839a050SYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
11657839a050SYann Gautier 			break;
11667839a050SYann Gautier 		default:
11677839a050SYann Gautier 			break;
11687839a050SYann Gautier 		}
11697839a050SYann Gautier 		break;
1170b053a22eSYann Gautier 	/* MCU sub system */
1171b053a22eSYann Gautier 	case _CK_MCU:
1172b053a22eSYann Gautier 	case _PCLK1:
1173b053a22eSYann Gautier 	case _PCLK2:
1174b053a22eSYann Gautier 	case _PCLK3:
1175b053a22eSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MSSCKSELR);
1176b053a22eSYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
1177b053a22eSYann Gautier 		case RCC_MSSCKSELR_HSI:
1178b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
1179b053a22eSYann Gautier 			break;
1180b053a22eSYann Gautier 		case RCC_MSSCKSELR_HSE:
1181b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
1182b053a22eSYann Gautier 			break;
1183b053a22eSYann Gautier 		case RCC_MSSCKSELR_CSI:
1184b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_CSI);
1185b053a22eSYann Gautier 			break;
1186b053a22eSYann Gautier 		case RCC_MSSCKSELR_PLL:
1187b053a22eSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
1188b053a22eSYann Gautier 			break;
1189b053a22eSYann Gautier 		default:
1190b053a22eSYann Gautier 			break;
1191b053a22eSYann Gautier 		}
1192b053a22eSYann Gautier 
1193b053a22eSYann Gautier 		/* MCU clock divider */
1194b053a22eSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MCUDIVR);
1195b053a22eSYann Gautier 		clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK];
1196b053a22eSYann Gautier 
1197b053a22eSYann Gautier 		switch (p) {
1198b053a22eSYann Gautier 		case _PCLK1:
1199b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB1DIVR);
1200b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
1201b053a22eSYann Gautier 			break;
1202b053a22eSYann Gautier 		case _PCLK2:
1203b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB2DIVR);
1204b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
1205b053a22eSYann Gautier 			break;
1206b053a22eSYann Gautier 		case _PCLK3:
1207b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB3DIVR);
1208b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
1209b053a22eSYann Gautier 			break;
1210b053a22eSYann Gautier 		case _CK_MCU:
1211b053a22eSYann Gautier 		default:
1212b053a22eSYann Gautier 			break;
1213b053a22eSYann Gautier 		}
1214b053a22eSYann Gautier 		break;
12157839a050SYann Gautier 	case _CK_PER:
12160d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_CPERCKSELR);
12177839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
12187839a050SYann Gautier 		case RCC_CPERCKSELR_HSI:
12190d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
12207839a050SYann Gautier 			break;
12217839a050SYann Gautier 		case RCC_CPERCKSELR_HSE:
12220d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
12237839a050SYann Gautier 			break;
12247839a050SYann Gautier 		case RCC_CPERCKSELR_CSI:
12250d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_CSI);
12267839a050SYann Gautier 			break;
12277839a050SYann Gautier 		default:
12287839a050SYann Gautier 			break;
12297839a050SYann Gautier 		}
12307839a050SYann Gautier 		break;
12317839a050SYann Gautier 	case _HSI:
12327839a050SYann Gautier 	case _HSI_KER:
12330d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSI);
12347839a050SYann Gautier 		break;
12357839a050SYann Gautier 	case _CSI:
12367839a050SYann Gautier 	case _CSI_KER:
12370d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_CSI);
12387839a050SYann Gautier 		break;
12397839a050SYann Gautier 	case _HSE:
12407839a050SYann Gautier 	case _HSE_KER:
12410d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSE);
12427839a050SYann Gautier 		break;
12437839a050SYann Gautier 	case _HSE_KER_DIV2:
12440d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSE) >> 1;
12457839a050SYann Gautier 		break;
1246cbd2e8a6SGabriel Fernandez 	case _HSE_RTC:
1247cbd2e8a6SGabriel Fernandez 		clock = stm32mp1_clk_get_fixed(_HSE);
1248cbd2e8a6SGabriel Fernandez 		clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U;
1249cbd2e8a6SGabriel Fernandez 		break;
12507839a050SYann Gautier 	case _LSI:
12510d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_LSI);
12527839a050SYann Gautier 		break;
12537839a050SYann Gautier 	case _LSE:
12540d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_LSE);
12557839a050SYann Gautier 		break;
12567839a050SYann Gautier 	/* PLL */
12577839a050SYann Gautier 	case _PLL1_P:
12580d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
12597839a050SYann Gautier 		break;
12607839a050SYann Gautier 	case _PLL1_Q:
12610d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q);
12627839a050SYann Gautier 		break;
12637839a050SYann Gautier 	case _PLL1_R:
12640d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R);
12657839a050SYann Gautier 		break;
12667839a050SYann Gautier 	case _PLL2_P:
12670d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
12687839a050SYann Gautier 		break;
12697839a050SYann Gautier 	case _PLL2_Q:
12700d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q);
12717839a050SYann Gautier 		break;
12727839a050SYann Gautier 	case _PLL2_R:
12730d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R);
12747839a050SYann Gautier 		break;
12757839a050SYann Gautier 	case _PLL3_P:
12760d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
12777839a050SYann Gautier 		break;
12787839a050SYann Gautier 	case _PLL3_Q:
12790d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q);
12807839a050SYann Gautier 		break;
12817839a050SYann Gautier 	case _PLL3_R:
12820d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R);
12837839a050SYann Gautier 		break;
12847839a050SYann Gautier 	case _PLL4_P:
12850d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P);
12867839a050SYann Gautier 		break;
12877839a050SYann Gautier 	case _PLL4_Q:
12880d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q);
12897839a050SYann Gautier 		break;
12907839a050SYann Gautier 	case _PLL4_R:
12910d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R);
12927839a050SYann Gautier 		break;
12937839a050SYann Gautier 	/* Other */
12947839a050SYann Gautier 	case _USB_PHY_48:
12950d21680cSYann Gautier 		clock = USB_PHY_48_MHZ;
12967839a050SYann Gautier 		break;
12977839a050SYann Gautier 	default:
12987839a050SYann Gautier 		break;
12997839a050SYann Gautier 	}
13007839a050SYann Gautier 
13017839a050SYann Gautier 	return clock;
13027839a050SYann Gautier }
13037839a050SYann Gautier 
__clk_enable(struct stm32mp1_clk_gate const * gate)13040d21680cSYann Gautier static void __clk_enable(struct stm32mp1_clk_gate const *gate)
13050d21680cSYann Gautier {
13060d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13070d21680cSYann Gautier 
130825be845eSEtienne Carriere 	VERBOSE("Enable clock %u\n", gate->index);
130925be845eSEtienne Carriere 
13100d21680cSYann Gautier 	if (gate->set_clr != 0U) {
13110d21680cSYann Gautier 		mmio_write_32(rcc_base + gate->offset, BIT(gate->bit));
13120d21680cSYann Gautier 	} else {
13130d21680cSYann Gautier 		mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit));
13140d21680cSYann Gautier 	}
13150d21680cSYann Gautier }
13160d21680cSYann Gautier 
__clk_disable(struct stm32mp1_clk_gate const * gate)13170d21680cSYann Gautier static void __clk_disable(struct stm32mp1_clk_gate const *gate)
13180d21680cSYann Gautier {
13190d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13200d21680cSYann Gautier 
132125be845eSEtienne Carriere 	VERBOSE("Disable clock %u\n", gate->index);
132225be845eSEtienne Carriere 
13230d21680cSYann Gautier 	if (gate->set_clr != 0U) {
13240d21680cSYann Gautier 		mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET,
13250d21680cSYann Gautier 			      BIT(gate->bit));
13260d21680cSYann Gautier 	} else {
13270d21680cSYann Gautier 		mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit));
13280d21680cSYann Gautier 	}
13290d21680cSYann Gautier }
13300d21680cSYann Gautier 
__clk_is_enabled(struct stm32mp1_clk_gate const * gate)13310d21680cSYann Gautier static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate)
13320d21680cSYann Gautier {
13330d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13340d21680cSYann Gautier 
13350d21680cSYann Gautier 	return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit);
13360d21680cSYann Gautier }
13370d21680cSYann Gautier 
133835848200SEtienne Carriere /* Oscillators and PLLs are not gated at runtime */
clock_is_always_on(unsigned long id)133935848200SEtienne Carriere static bool clock_is_always_on(unsigned long id)
134035848200SEtienne Carriere {
134135848200SEtienne Carriere 	switch (id) {
134235848200SEtienne Carriere 	case CK_HSE:
134335848200SEtienne Carriere 	case CK_CSI:
134435848200SEtienne Carriere 	case CK_LSI:
134535848200SEtienne Carriere 	case CK_LSE:
134635848200SEtienne Carriere 	case CK_HSI:
134735848200SEtienne Carriere 	case CK_HSE_DIV2:
134835848200SEtienne Carriere 	case PLL1_Q:
134935848200SEtienne Carriere 	case PLL1_R:
135035848200SEtienne Carriere 	case PLL2_P:
135135848200SEtienne Carriere 	case PLL2_Q:
135235848200SEtienne Carriere 	case PLL2_R:
135335848200SEtienne Carriere 	case PLL3_P:
135435848200SEtienne Carriere 	case PLL3_Q:
135535848200SEtienne Carriere 	case PLL3_R:
1356bf39318dSYann Gautier 	case CK_AXI:
1357bf39318dSYann Gautier 	case CK_MPU:
1358bf39318dSYann Gautier 	case CK_MCU:
13595b111c74SHE Shushan 	case RTC:
136035848200SEtienne Carriere 		return true;
136135848200SEtienne Carriere 	default:
136235848200SEtienne Carriere 		return false;
136335848200SEtienne Carriere 	}
136435848200SEtienne Carriere }
136535848200SEtienne Carriere 
__stm32mp1_clk_enable(unsigned long id,bool with_refcnt)13662444d231SYann Gautier static void __stm32mp1_clk_enable(unsigned long id, bool with_refcnt)
13670d21680cSYann Gautier {
13680d21680cSYann Gautier 	const struct stm32mp1_clk_gate *gate;
136935848200SEtienne Carriere 	int i;
13700d21680cSYann Gautier 
137135848200SEtienne Carriere 	if (clock_is_always_on(id)) {
137235848200SEtienne Carriere 		return;
137335848200SEtienne Carriere 	}
137435848200SEtienne Carriere 
137535848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
13760d21680cSYann Gautier 	if (i < 0) {
137744fb470bSYann Gautier 		ERROR("Clock %lu can't be enabled\n", id);
13780d21680cSYann Gautier 		panic();
13790d21680cSYann Gautier 	}
13800d21680cSYann Gautier 
13810d21680cSYann Gautier 	gate = gate_ref(i);
13822444d231SYann Gautier 
13832444d231SYann Gautier 	if (!with_refcnt) {
13842444d231SYann Gautier 		__clk_enable(gate);
13852444d231SYann Gautier 		return;
13862444d231SYann Gautier 	}
13870d21680cSYann Gautier 
13883d69149aSYann Gautier #if defined(IMAGE_BL32)
13893d69149aSYann Gautier 	if (gate_is_non_secure(gate)) {
13903d69149aSYann Gautier 		/* Enable non-secure clock w/o any refcounting */
13913d69149aSYann Gautier 		__clk_enable(gate);
13923d69149aSYann Gautier 		return;
13933d69149aSYann Gautier 	}
13943d69149aSYann Gautier #endif
13953d69149aSYann Gautier 
13960d21680cSYann Gautier 	stm32mp1_clk_lock(&refcount_lock);
13970d21680cSYann Gautier 
13982444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
13990d21680cSYann Gautier 		__clk_enable(gate);
14000d21680cSYann Gautier 	}
14010d21680cSYann Gautier 
14022444d231SYann Gautier 	gate_refcounts[i]++;
14032444d231SYann Gautier 	if (gate_refcounts[i] == UINT_MAX) {
14042444d231SYann Gautier 		ERROR("Clock %lu refcount reached max value\n", id);
14052444d231SYann Gautier 		panic();
14062444d231SYann Gautier 	}
14072444d231SYann Gautier 
14080d21680cSYann Gautier 	stm32mp1_clk_unlock(&refcount_lock);
14090d21680cSYann Gautier }
14100d21680cSYann Gautier 
__stm32mp1_clk_disable(unsigned long id,bool with_refcnt)14112444d231SYann Gautier static void __stm32mp1_clk_disable(unsigned long id, bool with_refcnt)
14120d21680cSYann Gautier {
14130d21680cSYann Gautier 	const struct stm32mp1_clk_gate *gate;
141435848200SEtienne Carriere 	int i;
14150d21680cSYann Gautier 
141635848200SEtienne Carriere 	if (clock_is_always_on(id)) {
141735848200SEtienne Carriere 		return;
141835848200SEtienne Carriere 	}
141935848200SEtienne Carriere 
142035848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
14210d21680cSYann Gautier 	if (i < 0) {
142244fb470bSYann Gautier 		ERROR("Clock %lu can't be disabled\n", id);
14230d21680cSYann Gautier 		panic();
14240d21680cSYann Gautier 	}
14250d21680cSYann Gautier 
14260d21680cSYann Gautier 	gate = gate_ref(i);
14272444d231SYann Gautier 
14282444d231SYann Gautier 	if (!with_refcnt) {
14292444d231SYann Gautier 		__clk_disable(gate);
14302444d231SYann Gautier 		return;
14312444d231SYann Gautier 	}
14320d21680cSYann Gautier 
14333d69149aSYann Gautier #if defined(IMAGE_BL32)
14343d69149aSYann Gautier 	if (gate_is_non_secure(gate)) {
14353d69149aSYann Gautier 		/* Don't disable non-secure clocks */
14363d69149aSYann Gautier 		return;
14373d69149aSYann Gautier 	}
14383d69149aSYann Gautier #endif
14393d69149aSYann Gautier 
14400d21680cSYann Gautier 	stm32mp1_clk_lock(&refcount_lock);
14410d21680cSYann Gautier 
14422444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
14432444d231SYann Gautier 		ERROR("Clock %lu refcount reached 0\n", id);
14442444d231SYann Gautier 		panic();
14452444d231SYann Gautier 	}
14462444d231SYann Gautier 	gate_refcounts[i]--;
14472444d231SYann Gautier 
14482444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
14490d21680cSYann Gautier 		__clk_disable(gate);
14500d21680cSYann Gautier 	}
14510d21680cSYann Gautier 
14520d21680cSYann Gautier 	stm32mp1_clk_unlock(&refcount_lock);
14530d21680cSYann Gautier }
14540d21680cSYann Gautier 
stm32mp_clk_enable(unsigned long id)145533667d29SYann Gautier static int stm32mp_clk_enable(unsigned long id)
14560d21680cSYann Gautier {
14570d21680cSYann Gautier 	__stm32mp1_clk_enable(id, true);
145833667d29SYann Gautier 
145933667d29SYann Gautier 	return 0;
14600d21680cSYann Gautier }
14610d21680cSYann Gautier 
stm32mp_clk_disable(unsigned long id)146233667d29SYann Gautier static void stm32mp_clk_disable(unsigned long id)
14630d21680cSYann Gautier {
14640d21680cSYann Gautier 	__stm32mp1_clk_disable(id, true);
14650d21680cSYann Gautier }
14660d21680cSYann Gautier 
stm32mp_clk_is_enabled(unsigned long id)146733667d29SYann Gautier static bool stm32mp_clk_is_enabled(unsigned long id)
14687839a050SYann Gautier {
146935848200SEtienne Carriere 	int i;
14707839a050SYann Gautier 
147135848200SEtienne Carriere 	if (clock_is_always_on(id)) {
147235848200SEtienne Carriere 		return true;
147335848200SEtienne Carriere 	}
147435848200SEtienne Carriere 
147535848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
14767839a050SYann Gautier 	if (i < 0) {
14770d21680cSYann Gautier 		panic();
14787839a050SYann Gautier 	}
14797839a050SYann Gautier 
14800d21680cSYann Gautier 	return __clk_is_enabled(gate_ref(i));
14817839a050SYann Gautier }
14827839a050SYann Gautier 
stm32mp_clk_get_rate(unsigned long id)148333667d29SYann Gautier static unsigned long stm32mp_clk_get_rate(unsigned long id)
14847839a050SYann Gautier {
148533667d29SYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
14860d21680cSYann Gautier 	int p = stm32mp1_clk_get_parent(id);
148733667d29SYann Gautier 	uint32_t prescaler, timpre;
148833667d29SYann Gautier 	unsigned long parent_rate;
14897839a050SYann Gautier 
14907839a050SYann Gautier 	if (p < 0) {
14917839a050SYann Gautier 		return 0;
14927839a050SYann Gautier 	}
14937839a050SYann Gautier 
149433667d29SYann Gautier 	parent_rate = get_clock_rate(p);
149533667d29SYann Gautier 
149633667d29SYann Gautier 	switch (id) {
149733667d29SYann Gautier 	case TIM2_K:
149833667d29SYann Gautier 	case TIM3_K:
149933667d29SYann Gautier 	case TIM4_K:
150033667d29SYann Gautier 	case TIM5_K:
150133667d29SYann Gautier 	case TIM6_K:
150233667d29SYann Gautier 	case TIM7_K:
150333667d29SYann Gautier 	case TIM12_K:
150433667d29SYann Gautier 	case TIM13_K:
150533667d29SYann Gautier 	case TIM14_K:
150633667d29SYann Gautier 		prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) &
150733667d29SYann Gautier 			    RCC_APBXDIV_MASK;
150833667d29SYann Gautier 		timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) &
150933667d29SYann Gautier 			 RCC_TIMGXPRER_TIMGXPRE;
151033667d29SYann Gautier 		break;
151133667d29SYann Gautier 
151233667d29SYann Gautier 	case TIM1_K:
151333667d29SYann Gautier 	case TIM8_K:
151433667d29SYann Gautier 	case TIM15_K:
151533667d29SYann Gautier 	case TIM16_K:
151633667d29SYann Gautier 	case TIM17_K:
151733667d29SYann Gautier 		prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) &
151833667d29SYann Gautier 			    RCC_APBXDIV_MASK;
151933667d29SYann Gautier 		timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) &
152033667d29SYann Gautier 			 RCC_TIMGXPRER_TIMGXPRE;
152133667d29SYann Gautier 		break;
152233667d29SYann Gautier 
152333667d29SYann Gautier 	default:
152433667d29SYann Gautier 		return parent_rate;
152533667d29SYann Gautier 	}
152633667d29SYann Gautier 
152733667d29SYann Gautier 	if (prescaler == 0U) {
152833667d29SYann Gautier 		return parent_rate;
152933667d29SYann Gautier 	}
153033667d29SYann Gautier 
153133667d29SYann Gautier 	return parent_rate * (timpre + 1U) * 2U;
15327839a050SYann Gautier }
15337839a050SYann Gautier 
stm32mp1_ls_osc_set(bool enable,uint32_t offset,uint32_t mask_on)15340d21680cSYann Gautier static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on)
15357839a050SYann Gautier {
15360d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
15377839a050SYann Gautier 
15380d21680cSYann Gautier 	if (enable) {
15397839a050SYann Gautier 		mmio_setbits_32(address, mask_on);
15407839a050SYann Gautier 	} else {
15417839a050SYann Gautier 		mmio_clrbits_32(address, mask_on);
15427839a050SYann Gautier 	}
15437839a050SYann Gautier }
15447839a050SYann Gautier 
stm32mp1_hs_ocs_set(bool enable,uint32_t mask_on)15450d21680cSYann Gautier static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on)
15467839a050SYann Gautier {
15470d21680cSYann Gautier 	uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR;
15480d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
15490d21680cSYann Gautier 
15500d21680cSYann Gautier 	mmio_write_32(address, mask_on);
15517839a050SYann Gautier }
15527839a050SYann Gautier 
stm32mp1_osc_wait(bool enable,uint32_t offset,uint32_t mask_rdy)15530d21680cSYann Gautier static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy)
15547839a050SYann Gautier {
1555dfdb057aSYann Gautier 	uint64_t timeout;
15567839a050SYann Gautier 	uint32_t mask_test;
15570d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
15587839a050SYann Gautier 
15590d21680cSYann Gautier 	if (enable) {
15607839a050SYann Gautier 		mask_test = mask_rdy;
15617839a050SYann Gautier 	} else {
15627839a050SYann Gautier 		mask_test = 0;
15637839a050SYann Gautier 	}
15647839a050SYann Gautier 
1565dfdb057aSYann Gautier 	timeout = timeout_init_us(OSCRDY_TIMEOUT);
15667839a050SYann Gautier 	while ((mmio_read_32(address) & mask_rdy) != mask_test) {
1567dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
15680d21680cSYann Gautier 			ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n",
15697839a050SYann Gautier 			      mask_rdy, address, enable, mmio_read_32(address));
15707839a050SYann Gautier 			return -ETIMEDOUT;
15717839a050SYann Gautier 		}
15727839a050SYann Gautier 	}
15737839a050SYann Gautier 
15747839a050SYann Gautier 	return 0;
15757839a050SYann Gautier }
15767839a050SYann Gautier 
stm32mp1_lse_enable(bool bypass,bool digbyp,uint32_t lsedrv)15770d21680cSYann Gautier static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv)
15787839a050SYann Gautier {
15797839a050SYann Gautier 	uint32_t value;
15800d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
15817839a050SYann Gautier 
1582f4a2bb98SYann Gautier 	/* Do not reconfigure LSE if it is already ON */
1583f4a2bb98SYann Gautier 	if ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEON) == RCC_BDCR_LSEON) {
1584f4a2bb98SYann Gautier 		return;
1585f4a2bb98SYann Gautier 	}
1586f4a2bb98SYann Gautier 
15870d21680cSYann Gautier 	if (digbyp) {
15880d21680cSYann Gautier 		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP);
15890d21680cSYann Gautier 	}
15900d21680cSYann Gautier 
15910d21680cSYann Gautier 	if (bypass || digbyp) {
15920d21680cSYann Gautier 		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP);
15937839a050SYann Gautier 	}
15947839a050SYann Gautier 
15957839a050SYann Gautier 	/*
15967839a050SYann Gautier 	 * Warning: not recommended to switch directly from "high drive"
15977839a050SYann Gautier 	 * to "medium low drive", and vice-versa.
15987839a050SYann Gautier 	 */
15990d21680cSYann Gautier 	value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >>
16007839a050SYann Gautier 		RCC_BDCR_LSEDRV_SHIFT;
16017839a050SYann Gautier 
16027839a050SYann Gautier 	while (value != lsedrv) {
16037839a050SYann Gautier 		if (value > lsedrv) {
16047839a050SYann Gautier 			value--;
16057839a050SYann Gautier 		} else {
16067839a050SYann Gautier 			value++;
16077839a050SYann Gautier 		}
16087839a050SYann Gautier 
16090d21680cSYann Gautier 		mmio_clrsetbits_32(rcc_base + RCC_BDCR,
16107839a050SYann Gautier 				   RCC_BDCR_LSEDRV_MASK,
16117839a050SYann Gautier 				   value << RCC_BDCR_LSEDRV_SHIFT);
16127839a050SYann Gautier 	}
16137839a050SYann Gautier 
16140d21680cSYann Gautier 	stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON);
16157839a050SYann Gautier }
16167839a050SYann Gautier 
stm32mp1_lse_wait(void)16170d21680cSYann Gautier static void stm32mp1_lse_wait(void)
16187839a050SYann Gautier {
16190d21680cSYann Gautier 	if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) {
1620*1a25db19SYann Gautier 		EARLY_ERROR("%s: failed\n", __func__);
16217839a050SYann Gautier 	}
16227839a050SYann Gautier }
16237839a050SYann Gautier 
stm32mp1_lsi_set(bool enable)16240d21680cSYann Gautier static void stm32mp1_lsi_set(bool enable)
16257839a050SYann Gautier {
16260d21680cSYann Gautier 	stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION);
16270d21680cSYann Gautier 
16280d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) {
1629*1a25db19SYann Gautier 		EARLY_ERROR("%s: failed\n", __func__);
16307839a050SYann Gautier 	}
16317839a050SYann Gautier }
16327839a050SYann Gautier 
stm32mp1_hse_enable(bool bypass,bool digbyp,bool css)16330d21680cSYann Gautier static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css)
16347839a050SYann Gautier {
16350d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
16360d21680cSYann Gautier 
16370d21680cSYann Gautier 	if (digbyp) {
16380d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP);
16397839a050SYann Gautier 	}
16407839a050SYann Gautier 
16410d21680cSYann Gautier 	if (bypass || digbyp) {
16420d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP);
16430d21680cSYann Gautier 	}
16440d21680cSYann Gautier 
16450d21680cSYann Gautier 	stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON);
16460d21680cSYann Gautier 	if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) {
1647*1a25db19SYann Gautier 		EARLY_ERROR("%s: failed\n", __func__);
16487839a050SYann Gautier 	}
16497839a050SYann Gautier 
16507839a050SYann Gautier 	if (css) {
16510d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON);
16527839a050SYann Gautier 	}
165331e9750bSLionel Debieve 
165431e9750bSLionel Debieve #if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
165531e9750bSLionel Debieve 	if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) &&
165631e9750bSLionel Debieve 	    (!(digbyp || bypass))) {
165731e9750bSLionel Debieve 		panic();
165831e9750bSLionel Debieve 	}
165931e9750bSLionel Debieve #endif
16607839a050SYann Gautier }
16617839a050SYann Gautier 
stm32mp1_csi_set(bool enable)16620d21680cSYann Gautier static void stm32mp1_csi_set(bool enable)
16637839a050SYann Gautier {
16640d21680cSYann Gautier 	stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION);
16650d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) {
1666*1a25db19SYann Gautier 		EARLY_ERROR("%s: failed\n", __func__);
16677839a050SYann Gautier 	}
16687839a050SYann Gautier }
16697839a050SYann Gautier 
stm32mp1_hsi_set(bool enable)16700d21680cSYann Gautier static void stm32mp1_hsi_set(bool enable)
16717839a050SYann Gautier {
16720d21680cSYann Gautier 	stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION);
16730d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) {
1674*1a25db19SYann Gautier 		EARLY_ERROR("%s: failed\n", __func__);
16757839a050SYann Gautier 	}
16767839a050SYann Gautier }
16777839a050SYann Gautier 
stm32mp1_set_hsidiv(uint8_t hsidiv)16780d21680cSYann Gautier static int stm32mp1_set_hsidiv(uint8_t hsidiv)
16797839a050SYann Gautier {
1680dfdb057aSYann Gautier 	uint64_t timeout;
16810d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
16820d21680cSYann Gautier 	uintptr_t address = rcc_base + RCC_OCRDYR;
16837839a050SYann Gautier 
16840d21680cSYann Gautier 	mmio_clrsetbits_32(rcc_base + RCC_HSICFGR,
16857839a050SYann Gautier 			   RCC_HSICFGR_HSIDIV_MASK,
16867839a050SYann Gautier 			   RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv);
16877839a050SYann Gautier 
1688dfdb057aSYann Gautier 	timeout = timeout_init_us(HSIDIV_TIMEOUT);
16897839a050SYann Gautier 	while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) {
1690dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
16910d21680cSYann Gautier 			ERROR("HSIDIV failed @ 0x%lx: 0x%x\n",
16927839a050SYann Gautier 			      address, mmio_read_32(address));
16937839a050SYann Gautier 			return -ETIMEDOUT;
16947839a050SYann Gautier 		}
16957839a050SYann Gautier 	}
16967839a050SYann Gautier 
16977839a050SYann Gautier 	return 0;
16987839a050SYann Gautier }
16997839a050SYann Gautier 
stm32mp1_hsidiv(unsigned long hsifreq)17000d21680cSYann Gautier static int stm32mp1_hsidiv(unsigned long hsifreq)
17017839a050SYann Gautier {
17027839a050SYann Gautier 	uint8_t hsidiv;
17037839a050SYann Gautier 	uint32_t hsidivfreq = MAX_HSI_HZ;
17047839a050SYann Gautier 
17057839a050SYann Gautier 	for (hsidiv = 0; hsidiv < 4U; hsidiv++) {
17067839a050SYann Gautier 		if (hsidivfreq == hsifreq) {
17077839a050SYann Gautier 			break;
17087839a050SYann Gautier 		}
17097839a050SYann Gautier 
17107839a050SYann Gautier 		hsidivfreq /= 2U;
17117839a050SYann Gautier 	}
17127839a050SYann Gautier 
17137839a050SYann Gautier 	if (hsidiv == 4U) {
1714*1a25db19SYann Gautier 		EARLY_ERROR("Invalid clk-hsi frequency\n");
17157839a050SYann Gautier 		return -1;
17167839a050SYann Gautier 	}
17177839a050SYann Gautier 
17187839a050SYann Gautier 	if (hsidiv != 0U) {
17190d21680cSYann Gautier 		return stm32mp1_set_hsidiv(hsidiv);
17207839a050SYann Gautier 	}
17217839a050SYann Gautier 
17227839a050SYann Gautier 	return 0;
17237839a050SYann Gautier }
17247839a050SYann Gautier 
stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id,unsigned int clksrc,uint32_t * pllcfg,uint32_t fracv)17250d21680cSYann Gautier static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id,
17260d21680cSYann Gautier 				    unsigned int clksrc,
1727ae1e5037SGabriel Fernandez 				    uint32_t *pllcfg, uint32_t fracv)
17287839a050SYann Gautier {
17290d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
17300d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
17310d21680cSYann Gautier 	uintptr_t pllxcr = rcc_base + pll->pllxcr;
17320d21680cSYann Gautier 	enum stm32mp1_plltype type = pll->plltype;
17330d21680cSYann Gautier 	uintptr_t clksrc_address = rcc_base + (clksrc >> 4);
17340d21680cSYann Gautier 	unsigned long refclk;
17350d21680cSYann Gautier 	uint32_t ifrge = 0U;
1736ae1e5037SGabriel Fernandez 	uint32_t src, value;
17377839a050SYann Gautier 
17380d21680cSYann Gautier 	/* Check PLL output */
17390d21680cSYann Gautier 	if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) {
17400d21680cSYann Gautier 		return false;
17417839a050SYann Gautier 	}
17427839a050SYann Gautier 
17430d21680cSYann Gautier 	/* Check current clksrc */
17440d21680cSYann Gautier 	src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK;
17450d21680cSYann Gautier 	if (src != (clksrc & RCC_SELR_SRC_MASK)) {
17460d21680cSYann Gautier 		return false;
17470d21680cSYann Gautier 	}
17480d21680cSYann Gautier 
17490d21680cSYann Gautier 	/* Check Div */
17500d21680cSYann Gautier 	src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK;
17510d21680cSYann Gautier 
17520d21680cSYann Gautier 	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
17530d21680cSYann Gautier 		 (pllcfg[PLLCFG_M] + 1U);
17540d21680cSYann Gautier 
17550d21680cSYann Gautier 	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
17560d21680cSYann Gautier 	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
17570d21680cSYann Gautier 		return false;
17580d21680cSYann Gautier 	}
17590d21680cSYann Gautier 
17600d21680cSYann Gautier 	if ((type == PLL_800) && (refclk >= 8000000U)) {
17610d21680cSYann Gautier 		ifrge = 1U;
17620d21680cSYann Gautier 	}
17630d21680cSYann Gautier 
17640d21680cSYann Gautier 	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
17650d21680cSYann Gautier 		RCC_PLLNCFGR1_DIVN_MASK;
17660d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
17670d21680cSYann Gautier 		 RCC_PLLNCFGR1_DIVM_MASK;
17680d21680cSYann Gautier 	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
17690d21680cSYann Gautier 		 RCC_PLLNCFGR1_IFRGE_MASK;
17700d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) {
17710d21680cSYann Gautier 		return false;
17720d21680cSYann Gautier 	}
17730d21680cSYann Gautier 
17740d21680cSYann Gautier 	/* Fractional configuration */
17750d21680cSYann Gautier 	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
17760d21680cSYann Gautier 	value |= RCC_PLLNFRACR_FRACLE;
17770d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxfracr) != value) {
17780d21680cSYann Gautier 		return false;
17790d21680cSYann Gautier 	}
17800d21680cSYann Gautier 
17810d21680cSYann Gautier 	/* Output config */
17820d21680cSYann Gautier 	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
17830d21680cSYann Gautier 		RCC_PLLNCFGR2_DIVP_MASK;
17840d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
17850d21680cSYann Gautier 		 RCC_PLLNCFGR2_DIVQ_MASK;
17860d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
17870d21680cSYann Gautier 		 RCC_PLLNCFGR2_DIVR_MASK;
17880d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) {
17890d21680cSYann Gautier 		return false;
17900d21680cSYann Gautier 	}
17910d21680cSYann Gautier 
17920d21680cSYann Gautier 	return true;
17930d21680cSYann Gautier }
17940d21680cSYann Gautier 
stm32mp1_pll_start(enum stm32mp1_pll_id pll_id)17950d21680cSYann Gautier static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id)
17967839a050SYann Gautier {
17970d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
17980d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
17990d21680cSYann Gautier 
1800dd98aec8SYann Gautier 	/* Preserve RCC_PLLNCR_SSCG_CTRL value */
1801dd98aec8SYann Gautier 	mmio_clrsetbits_32(pllxcr,
1802dd98aec8SYann Gautier 			   RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
1803dd98aec8SYann Gautier 			   RCC_PLLNCR_DIVREN,
1804dd98aec8SYann Gautier 			   RCC_PLLNCR_PLLON);
18050d21680cSYann Gautier }
18060d21680cSYann Gautier 
stm32mp1_pll_output(enum stm32mp1_pll_id pll_id,uint32_t output)18070d21680cSYann Gautier static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output)
18080d21680cSYann Gautier {
18090d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
18100d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
1811dfdb057aSYann Gautier 	uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT);
18127839a050SYann Gautier 
18137839a050SYann Gautier 	/* Wait PLL lock */
18147839a050SYann Gautier 	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) {
1815dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
1816*1a25db19SYann Gautier 			EARLY_ERROR("PLL%u start failed @ 0x%lx: 0x%x\n",
18177839a050SYann Gautier 				    pll_id, pllxcr, mmio_read_32(pllxcr));
18187839a050SYann Gautier 			return -ETIMEDOUT;
18197839a050SYann Gautier 		}
18207839a050SYann Gautier 	}
18217839a050SYann Gautier 
18227839a050SYann Gautier 	/* Start the requested output */
18237839a050SYann Gautier 	mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT);
18247839a050SYann Gautier 
18257839a050SYann Gautier 	return 0;
18267839a050SYann Gautier }
18277839a050SYann Gautier 
stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id)18280d21680cSYann Gautier static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id)
18297839a050SYann Gautier {
18300d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
18310d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
1832dfdb057aSYann Gautier 	uint64_t timeout;
18337839a050SYann Gautier 
18347839a050SYann Gautier 	/* Stop all output */
18357839a050SYann Gautier 	mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
18367839a050SYann Gautier 			RCC_PLLNCR_DIVREN);
18377839a050SYann Gautier 
18387839a050SYann Gautier 	/* Stop PLL */
18397839a050SYann Gautier 	mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON);
18407839a050SYann Gautier 
1841dfdb057aSYann Gautier 	timeout = timeout_init_us(PLLRDY_TIMEOUT);
18427839a050SYann Gautier 	/* Wait PLL stopped */
18437839a050SYann Gautier 	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) {
1844dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
1845*1a25db19SYann Gautier 			EARLY_ERROR("PLL%u stop failed @ 0x%lx: 0x%x\n",
18467839a050SYann Gautier 				    pll_id, pllxcr, mmio_read_32(pllxcr));
18477839a050SYann Gautier 			return -ETIMEDOUT;
18487839a050SYann Gautier 		}
18497839a050SYann Gautier 	}
18507839a050SYann Gautier 
18517839a050SYann Gautier 	return 0;
18527839a050SYann Gautier }
18537839a050SYann Gautier 
stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id,uint32_t * pllcfg)18540d21680cSYann Gautier static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id,
18557839a050SYann Gautier 				       uint32_t *pllcfg)
18567839a050SYann Gautier {
18570d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
18580d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
18597839a050SYann Gautier 	uint32_t value;
18607839a050SYann Gautier 
18617839a050SYann Gautier 	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
18627839a050SYann Gautier 		RCC_PLLNCFGR2_DIVP_MASK;
18637839a050SYann Gautier 	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
18647839a050SYann Gautier 		 RCC_PLLNCFGR2_DIVQ_MASK;
18657839a050SYann Gautier 	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
18667839a050SYann Gautier 		 RCC_PLLNCFGR2_DIVR_MASK;
18670d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxcfgr2, value);
18687839a050SYann Gautier }
18697839a050SYann Gautier 
stm32mp1_pll_config(enum stm32mp1_pll_id pll_id,uint32_t * pllcfg,uint32_t fracv)18700d21680cSYann Gautier static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id,
18717839a050SYann Gautier 			       uint32_t *pllcfg, uint32_t fracv)
18727839a050SYann Gautier {
18730d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
18740d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
18750d21680cSYann Gautier 	enum stm32mp1_plltype type = pll->plltype;
18767839a050SYann Gautier 	unsigned long refclk;
18777839a050SYann Gautier 	uint32_t ifrge = 0;
18787839a050SYann Gautier 	uint32_t src, value;
18797839a050SYann Gautier 
18800d21680cSYann Gautier 	src = mmio_read_32(rcc_base + pll->rckxselr) &
18817839a050SYann Gautier 		RCC_SELR_REFCLK_SRC_MASK;
18827839a050SYann Gautier 
18830d21680cSYann Gautier 	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
18847839a050SYann Gautier 		 (pllcfg[PLLCFG_M] + 1U);
18857839a050SYann Gautier 
18867839a050SYann Gautier 	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
18877839a050SYann Gautier 	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
18887839a050SYann Gautier 		return -EINVAL;
18897839a050SYann Gautier 	}
18907839a050SYann Gautier 
18917839a050SYann Gautier 	if ((type == PLL_800) && (refclk >= 8000000U)) {
18927839a050SYann Gautier 		ifrge = 1U;
18937839a050SYann Gautier 	}
18947839a050SYann Gautier 
18957839a050SYann Gautier 	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
18967839a050SYann Gautier 		RCC_PLLNCFGR1_DIVN_MASK;
18977839a050SYann Gautier 	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
18987839a050SYann Gautier 		 RCC_PLLNCFGR1_DIVM_MASK;
18997839a050SYann Gautier 	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
19007839a050SYann Gautier 		 RCC_PLLNCFGR1_IFRGE_MASK;
19010d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxcfgr1, value);
19027839a050SYann Gautier 
19037839a050SYann Gautier 	/* Fractional configuration */
19047839a050SYann Gautier 	value = 0;
19050d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
19067839a050SYann Gautier 
19077839a050SYann Gautier 	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
19080d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
19097839a050SYann Gautier 
19107839a050SYann Gautier 	value |= RCC_PLLNFRACR_FRACLE;
19110d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
19127839a050SYann Gautier 
19130d21680cSYann Gautier 	stm32mp1_pll_config_output(pll_id, pllcfg);
19147839a050SYann Gautier 
19157839a050SYann Gautier 	return 0;
19167839a050SYann Gautier }
19177839a050SYann Gautier 
stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id,uint32_t * csg)19180d21680cSYann Gautier static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg)
19197839a050SYann Gautier {
19200d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
19217839a050SYann Gautier 	uint32_t pllxcsg = 0;
19227839a050SYann Gautier 
19237839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) &
19247839a050SYann Gautier 		    RCC_PLLNCSGR_MOD_PER_MASK;
19257839a050SYann Gautier 
19267839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) &
19277839a050SYann Gautier 		    RCC_PLLNCSGR_INC_STEP_MASK;
19287839a050SYann Gautier 
19297839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) &
19307839a050SYann Gautier 		    RCC_PLLNCSGR_SSCG_MODE_MASK;
19317839a050SYann Gautier 
19320d21680cSYann Gautier 	mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg);
1933dd98aec8SYann Gautier 
1934dd98aec8SYann Gautier 	mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr,
1935dd98aec8SYann Gautier 			RCC_PLLNCR_SSCG_CTRL);
19367839a050SYann Gautier }
19377839a050SYann Gautier 
clk_compute_pll1_settings(unsigned long input_freq,uint32_t freq_khz,uint32_t * pllcfg,uint32_t * fracv)1938f6559227SYann Gautier static int clk_compute_pll1_settings(unsigned long input_freq,
1939f6559227SYann Gautier 				     uint32_t freq_khz,
1940f6559227SYann Gautier 				     uint32_t *pllcfg, uint32_t *fracv)
1941f6559227SYann Gautier {
1942f6559227SYann Gautier 	unsigned long long best_diff = ULLONG_MAX;
1943f6559227SYann Gautier 	unsigned int divm;
1944f6559227SYann Gautier 
1945f6559227SYann Gautier 	/* Following parameters have always the same value */
1946f6559227SYann Gautier 	pllcfg[PLLCFG_Q] = 0U;
1947f6559227SYann Gautier 	pllcfg[PLLCFG_R] = 0U;
1948f6559227SYann Gautier 	pllcfg[PLLCFG_O] = PQR(1, 0, 0);
1949f6559227SYann Gautier 
1950f6559227SYann Gautier 	for (divm = (DIVM_MAX + 1U); divm != DIVM_MIN; divm--) {
1951f6559227SYann Gautier 		unsigned long post_divm = input_freq / divm;
1952f6559227SYann Gautier 		unsigned int divp;
1953f6559227SYann Gautier 
1954f6559227SYann Gautier 		if ((post_divm < POST_DIVM_MIN) || (post_divm > POST_DIVM_MAX)) {
1955f6559227SYann Gautier 			continue;
1956f6559227SYann Gautier 		}
1957f6559227SYann Gautier 
1958f6559227SYann Gautier 		for (divp = DIVP_MIN; divp <= DIVP_MAX; divp++) {
1959f6559227SYann Gautier 			unsigned long long output_freq = freq_khz * 1000ULL;
1960f6559227SYann Gautier 			unsigned long long freq;
1961f6559227SYann Gautier 			unsigned long long divn;
1962f6559227SYann Gautier 			unsigned long long frac;
1963f6559227SYann Gautier 			unsigned int i;
1964f6559227SYann Gautier 
1965f6559227SYann Gautier 			freq = output_freq * divm * (divp + 1U);
1966f6559227SYann Gautier 
1967f6559227SYann Gautier 			divn = (freq / input_freq) - 1U;
1968f6559227SYann Gautier 			if ((divn < DIVN_MIN) || (divn > DIVN_MAX)) {
1969f6559227SYann Gautier 				continue;
1970f6559227SYann Gautier 			}
1971f6559227SYann Gautier 
1972f6559227SYann Gautier 			frac = ((freq * FRAC_MAX) / input_freq) - ((divn + 1U) * FRAC_MAX);
1973f6559227SYann Gautier 
1974f6559227SYann Gautier 			/* 2 loops to refine the fractional part */
1975f6559227SYann Gautier 			for (i = 2U; i != 0U; i--) {
1976f6559227SYann Gautier 				unsigned long long diff;
1977f6559227SYann Gautier 				unsigned long long vco;
1978f6559227SYann Gautier 
1979f6559227SYann Gautier 				if (frac > FRAC_MAX) {
1980f6559227SYann Gautier 					break;
1981f6559227SYann Gautier 				}
1982f6559227SYann Gautier 
1983f6559227SYann Gautier 				vco = (post_divm * (divn + 1U)) + ((post_divm * frac) / FRAC_MAX);
1984f6559227SYann Gautier 
1985f6559227SYann Gautier 				if ((vco < (VCO_MIN / 2U)) || (vco > (VCO_MAX / 2U))) {
1986f6559227SYann Gautier 					frac++;
1987f6559227SYann Gautier 					continue;
1988f6559227SYann Gautier 				}
1989f6559227SYann Gautier 
1990f6559227SYann Gautier 				freq = vco / (divp + 1U);
1991f6559227SYann Gautier 				if (output_freq < freq) {
1992f6559227SYann Gautier 					diff = freq - output_freq;
1993f6559227SYann Gautier 				} else {
1994f6559227SYann Gautier 					diff = output_freq - freq;
1995f6559227SYann Gautier 				}
1996f6559227SYann Gautier 
1997f6559227SYann Gautier 				if (diff < best_diff)  {
1998f6559227SYann Gautier 					pllcfg[PLLCFG_M] = divm - 1U;
1999f6559227SYann Gautier 					pllcfg[PLLCFG_N] = (uint32_t)divn;
2000f6559227SYann Gautier 					pllcfg[PLLCFG_P] = divp;
2001f6559227SYann Gautier 					*fracv = (uint32_t)frac;
2002f6559227SYann Gautier 
2003f6559227SYann Gautier 					if (diff == 0U) {
2004f6559227SYann Gautier 						return 0;
2005f6559227SYann Gautier 					}
2006f6559227SYann Gautier 
2007f6559227SYann Gautier 					best_diff = diff;
2008f6559227SYann Gautier 				}
2009f6559227SYann Gautier 
2010f6559227SYann Gautier 				frac++;
2011f6559227SYann Gautier 			}
2012f6559227SYann Gautier 		}
2013f6559227SYann Gautier 	}
2014f6559227SYann Gautier 
2015f6559227SYann Gautier 	if (best_diff == ULLONG_MAX) {
2016f6559227SYann Gautier 		return -EINVAL;
2017f6559227SYann Gautier 	}
2018f6559227SYann Gautier 
2019f6559227SYann Gautier 	return 0;
2020f6559227SYann Gautier }
2021f6559227SYann Gautier 
clk_get_pll1_settings(uint32_t clksrc,uint32_t freq_khz,uint32_t * pllcfg,uint32_t * fracv)2022f6559227SYann Gautier static int clk_get_pll1_settings(uint32_t clksrc, uint32_t freq_khz,
2023f6559227SYann Gautier 				 uint32_t *pllcfg, uint32_t *fracv)
2024f6559227SYann Gautier {
2025f6559227SYann Gautier 	unsigned long input_freq = 0UL;
2026f6559227SYann Gautier 
2027f6559227SYann Gautier 	assert(pllcfg != NULL);
2028f6559227SYann Gautier 	assert(fracv != NULL);
2029f6559227SYann Gautier 
2030f6559227SYann Gautier 	switch (clksrc) {
2031f6559227SYann Gautier 	case CLK_PLL12_HSI:
2032f6559227SYann Gautier 		input_freq = stm32mp_clk_get_rate(CK_HSI);
2033f6559227SYann Gautier 		break;
2034f6559227SYann Gautier 	case CLK_PLL12_HSE:
2035f6559227SYann Gautier 		input_freq = stm32mp_clk_get_rate(CK_HSE);
2036f6559227SYann Gautier 		break;
2037f6559227SYann Gautier 	default:
2038f6559227SYann Gautier 		break;
2039f6559227SYann Gautier 	}
2040f6559227SYann Gautier 
2041f6559227SYann Gautier 	if (input_freq == 0UL) {
2042f6559227SYann Gautier 		panic();
2043f6559227SYann Gautier 	}
2044f6559227SYann Gautier 
2045f6559227SYann Gautier 	return clk_compute_pll1_settings(input_freq, freq_khz, pllcfg, fracv);
2046f6559227SYann Gautier }
2047f6559227SYann Gautier 
stm32_clk_dividers_configure(struct stm32_clk_priv * priv)2048ae1e5037SGabriel Fernandez static int stm32_clk_dividers_configure(struct stm32_clk_priv *priv)
20497839a050SYann Gautier {
2050ae1e5037SGabriel Fernandez 	struct stm32_clk_platdata *pdata = priv->pdata;
2051ae1e5037SGabriel Fernandez 	uint32_t i;
205252a616b4SAndre Przywara 
2053ae1e5037SGabriel Fernandez 	for (i = 0U; i < pdata->nclkdiv; i++) {
2054ae1e5037SGabriel Fernandez 		uint32_t div_id, div_n;
2055ae1e5037SGabriel Fernandez 		uint32_t val;
2056ae1e5037SGabriel Fernandez 		int ret;
2057ae1e5037SGabriel Fernandez 
2058ae1e5037SGabriel Fernandez 		val = pdata->clkdiv[i] & CMD_DATA_MASK;
2059ae1e5037SGabriel Fernandez 		div_id = (val & DIV_ID_MASK) >> DIV_ID_SHIFT;
2060ae1e5037SGabriel Fernandez 		div_n = (val & DIV_DIVN_MASK) >> DIV_DIVN_SHIFT;
2061ae1e5037SGabriel Fernandez 
2062ae1e5037SGabriel Fernandez 		ret = clk_stm32_set_div(priv, div_id, div_n);
2063ae1e5037SGabriel Fernandez 		if (ret != 0) {
2064ae1e5037SGabriel Fernandez 			return ret;
2065ae1e5037SGabriel Fernandez 		}
206652a616b4SAndre Przywara 	}
20677839a050SYann Gautier 
2068ae1e5037SGabriel Fernandez 	return 0;
20697839a050SYann Gautier }
20707839a050SYann Gautier 
stm32_clk_configure_clk(struct stm32_clk_priv * priv,uint32_t data)2071ae1e5037SGabriel Fernandez static int stm32_clk_configure_clk(struct stm32_clk_priv *priv, uint32_t data)
2072ae1e5037SGabriel Fernandez {
2073ae1e5037SGabriel Fernandez 	uint32_t sel = (data & CLK_SEL_MASK) >> CLK_SEL_SHIFT;
2074ae1e5037SGabriel Fernandez 	uint32_t enable = (data & CLK_ON_MASK) >> CLK_ON_SHIFT;
2075ae1e5037SGabriel Fernandez 	unsigned long binding_id = ((unsigned long)data & CLK_ID_MASK) >> CLK_ID_SHIFT;
2076eca51034SChristoph Fritz 	struct stm32_clk_platdata *pdata = priv->pdata;
2077ae1e5037SGabriel Fernandez 
2078ae1e5037SGabriel Fernandez 	if (binding_id == RTC) {
2079ae1e5037SGabriel Fernandez 		uintptr_t address = stm32mp_rcc_base() + RCC_BDCR;
2080ae1e5037SGabriel Fernandez 
2081ae1e5037SGabriel Fernandez 		if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) || (enable != 0U)) {
2082ae1e5037SGabriel Fernandez 			mmio_clrsetbits_32(address, RCC_BDCR_RTCSRC_MASK,
2083ae1e5037SGabriel Fernandez 					   (sel & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT);
2084ae1e5037SGabriel Fernandez 
2085ae1e5037SGabriel Fernandez 			mmio_setbits_32(address, RCC_BDCR_RTCCKEN);
2086eca51034SChristoph Fritz 			/* Configure LSE CSS */
2087eca51034SChristoph Fritz 			if (pdata->lse_css) {
2088eca51034SChristoph Fritz 				mmio_setbits_32(priv->base + RCC_BDCR, RCC_BDCR_LSECSSON);
2089eca51034SChristoph Fritz 			}
2090ae1e5037SGabriel Fernandez 		}
20917839a050SYann Gautier 	}
20927839a050SYann Gautier 
2093ae1e5037SGabriel Fernandez 	return 0;
2094ae1e5037SGabriel Fernandez }
20957839a050SYann Gautier 
stm32_clk_configure_by_addr_val(struct stm32_clk_priv * priv,uint32_t data)2096ae1e5037SGabriel Fernandez static int stm32_clk_configure_by_addr_val(struct stm32_clk_priv *priv,
2097ae1e5037SGabriel Fernandez 					   uint32_t data)
2098ae1e5037SGabriel Fernandez {
2099ae1e5037SGabriel Fernandez 	uint32_t addr = data >> CLK_ADDR_SHIFT;
2100ae1e5037SGabriel Fernandez 	uint32_t val = data & CLK_ADDR_VAL_MASK;
21017839a050SYann Gautier 
2102ae1e5037SGabriel Fernandez 	mmio_setbits_32(priv->base + addr, val);
2103ae1e5037SGabriel Fernandez 
2104ae1e5037SGabriel Fernandez 	return 0;
2105ae1e5037SGabriel Fernandez }
2106ae1e5037SGabriel Fernandez 
stm32_clk_source_configure(struct stm32_clk_priv * priv)2107ae1e5037SGabriel Fernandez static int stm32_clk_source_configure(struct stm32_clk_priv *priv)
2108ae1e5037SGabriel Fernandez {
2109ae1e5037SGabriel Fernandez 	struct stm32_clk_platdata *pdata = priv->pdata;
2110ae1e5037SGabriel Fernandez 	bool ckper_disabled = false;
2111ae1e5037SGabriel Fernandez 	uint32_t i;
2112ae1e5037SGabriel Fernandez 
2113ae1e5037SGabriel Fernandez 	for (i = 0U; i < pdata->nclksrc; i++) {
2114ae1e5037SGabriel Fernandez 		uint32_t val = pdata->clksrc[i];
2115ae1e5037SGabriel Fernandez 		uint32_t cmd, cmd_data;
2116ae1e5037SGabriel Fernandez 		int ret;
2117ae1e5037SGabriel Fernandez 
2118ae1e5037SGabriel Fernandez 		if (val & CMD_ADDR_BIT) {
2119ae1e5037SGabriel Fernandez 			ret = stm32_clk_configure_by_addr_val(priv, val & ~CMD_ADDR_BIT);
2120964e5ff1SNicolas Le Bayon 			if (ret != 0) {
2121964e5ff1SNicolas Le Bayon 				return ret;
21227839a050SYann Gautier 			}
2123f6559227SYann Gautier 
2124f6559227SYann Gautier 			continue;
2125f6559227SYann Gautier 		}
2126f6559227SYann Gautier 
2127ae1e5037SGabriel Fernandez 		if (val == (uint32_t)CLK_CKPER_DISABLED) {
2128ae1e5037SGabriel Fernandez 			ckper_disabled = true;
2129ae1e5037SGabriel Fernandez 			continue;
2130ae1e5037SGabriel Fernandez 		}
2131ae1e5037SGabriel Fernandez 
2132ae1e5037SGabriel Fernandez 		cmd = (val & CMD_MASK) >> CMD_SHIFT;
2133ae1e5037SGabriel Fernandez 		cmd_data = val & ~CMD_MASK;
2134ae1e5037SGabriel Fernandez 
2135ae1e5037SGabriel Fernandez 		switch (cmd) {
2136ae1e5037SGabriel Fernandez 		case CMD_MUX:
2137ae1e5037SGabriel Fernandez 			ret = stm32_clk_configure_mux(priv, cmd_data);
2138ae1e5037SGabriel Fernandez 			break;
2139ae1e5037SGabriel Fernandez 
2140ae1e5037SGabriel Fernandez 		case CMD_CLK:
2141ae1e5037SGabriel Fernandez 			ret = stm32_clk_configure_clk(priv, cmd_data);
2142ae1e5037SGabriel Fernandez 			break;
2143ae1e5037SGabriel Fernandez 		default:
2144ae1e5037SGabriel Fernandez 			ret = -EINVAL;
2145ae1e5037SGabriel Fernandez 			break;
2146ae1e5037SGabriel Fernandez 		}
2147ae1e5037SGabriel Fernandez 
2148ae1e5037SGabriel Fernandez 		if (ret != 0) {
2149ae1e5037SGabriel Fernandez 			return ret;
2150ae1e5037SGabriel Fernandez 		}
2151ae1e5037SGabriel Fernandez 	}
2152ae1e5037SGabriel Fernandez 
2153ae1e5037SGabriel Fernandez 	/*
2154ae1e5037SGabriel Fernandez 	 * CKPER is source for some peripheral clocks
2155ae1e5037SGabriel Fernandez 	 * (FMC-NAND / QPSI-NOR) and switching source is allowed
2156ae1e5037SGabriel Fernandez 	 * only if previous clock is still ON
2157ae1e5037SGabriel Fernandez 	 * => deactivate CKPER only after switching clock
2158ae1e5037SGabriel Fernandez 	 */
2159ae1e5037SGabriel Fernandez 	if (!ckper_disabled) {
2160ae1e5037SGabriel Fernandez 		return 0;
2161ae1e5037SGabriel Fernandez 	}
2162ae1e5037SGabriel Fernandez 
2163ae1e5037SGabriel Fernandez 	return stm32_clk_configure_mux(priv, CLK_CKPER_DISABLED);
2164ae1e5037SGabriel Fernandez }
2165ae1e5037SGabriel Fernandez 
stm32mp1_pll_configure_src(struct stm32_clk_priv * priv,int pll_idx)2166ae1e5037SGabriel Fernandez static int stm32mp1_pll_configure_src(struct stm32_clk_priv *priv, int pll_idx)
2167ae1e5037SGabriel Fernandez {
2168ae1e5037SGabriel Fernandez 	struct stm32_clk_platdata *pdata = priv->pdata;
2169ae1e5037SGabriel Fernandez 	struct stm32_pll_dt_cfg *pll_conf = &pdata->pll[pll_idx];
2170ae1e5037SGabriel Fernandez 
2171ae1e5037SGabriel Fernandez 	if (!pll_conf->status) {
2172ae1e5037SGabriel Fernandez 		return 0;
2173ae1e5037SGabriel Fernandez 	}
2174ae1e5037SGabriel Fernandez 
2175ae1e5037SGabriel Fernandez 	return stm32_clk_configure_mux(priv, pll_conf->src);
2176ae1e5037SGabriel Fernandez }
2177ae1e5037SGabriel Fernandez 
stm32mp1_clk_init(void)2178ae1e5037SGabriel Fernandez int stm32mp1_clk_init(void)
2179ae1e5037SGabriel Fernandez {
2180ae1e5037SGabriel Fernandez 	struct stm32_clk_priv *priv = clk_stm32_get_priv();
2181ae1e5037SGabriel Fernandez 	struct stm32_clk_platdata *pdata = priv->pdata;
2182ae1e5037SGabriel Fernandez 	struct stm32_pll_dt_cfg *pll_conf = pdata->pll;
2183ae1e5037SGabriel Fernandez 	int ret;
2184ae1e5037SGabriel Fernandez 	enum stm32mp1_pll_id i;
2185ae1e5037SGabriel Fernandez 	bool pll3_preserve = false;
2186ae1e5037SGabriel Fernandez 	bool pll4_preserve = false;
2187ae1e5037SGabriel Fernandez 	bool pll4_bootrom = false;
2188ae1e5037SGabriel Fernandez 	int stgen_p = stm32mp1_clk_get_parent(STGEN_K);
2189ae1e5037SGabriel Fernandez 	int usbphy_p = stm32mp1_clk_get_parent(USBPHY_K);
2190ae1e5037SGabriel Fernandez 	uint32_t usbreg_bootrom = 0U;
2191ae1e5037SGabriel Fernandez 
2192ae1e5037SGabriel Fernandez 	if (!pll_conf[_PLL1].status) {
2193ae1e5037SGabriel Fernandez 		ret = clk_get_pll1_settings(pll_conf[_PLL2].src, PLL1_NOMINAL_FREQ_IN_KHZ,
2194ae1e5037SGabriel Fernandez 					    pll_conf[_PLL1].cfg, &pll_conf[_PLL1].frac);
2195f6559227SYann Gautier 		if (ret != 0) {
2196f6559227SYann Gautier 			return ret;
2197f6559227SYann Gautier 		}
2198f6559227SYann Gautier 
2199ae1e5037SGabriel Fernandez 		pll_conf[_PLL1].status = true;
2200ae1e5037SGabriel Fernandez 		pll_conf[_PLL1].src = pll_conf[_PLL2].src;
2201f6559227SYann Gautier 	}
22027839a050SYann Gautier 
22037839a050SYann Gautier 	/*
22047839a050SYann Gautier 	 * Switch ON oscillator found in device-tree.
22057839a050SYann Gautier 	 * Note: HSI already ON after BootROM stage.
22067839a050SYann Gautier 	 */
22070d21680cSYann Gautier 	if (stm32mp1_osc[_LSI] != 0U) {
22080d21680cSYann Gautier 		stm32mp1_lsi_set(true);
22097839a050SYann Gautier 	}
22100d21680cSYann Gautier 	if (stm32mp1_osc[_LSE] != 0U) {
2211b208e3daSGabriel Fernandez 		const char *name = stm32mp_osc_node_label[_LSE];
22120d21680cSYann Gautier 		bool bypass, digbyp;
22137839a050SYann Gautier 		uint32_t lsedrv;
22147839a050SYann Gautier 
2215b208e3daSGabriel Fernandez 		bypass = fdt_clk_read_bool(name, "st,bypass");
2216b208e3daSGabriel Fernandez 		digbyp = fdt_clk_read_bool(name, "st,digbypass");
2217eca51034SChristoph Fritz 		pdata->lse_css = fdt_clk_read_bool(name, "st,css");
2218b208e3daSGabriel Fernandez 		lsedrv = fdt_clk_read_uint32_default(name, "st,drive",
22197839a050SYann Gautier 						     LSEDRV_MEDIUM_HIGH);
22200d21680cSYann Gautier 		stm32mp1_lse_enable(bypass, digbyp, lsedrv);
22217839a050SYann Gautier 	}
22220d21680cSYann Gautier 	if (stm32mp1_osc[_HSE] != 0U) {
2223b208e3daSGabriel Fernandez 		const char *name = stm32mp_osc_node_label[_HSE];
22240d21680cSYann Gautier 		bool bypass, digbyp, css;
22257839a050SYann Gautier 
2226b208e3daSGabriel Fernandez 		bypass = fdt_clk_read_bool(name, "st,bypass");
2227b208e3daSGabriel Fernandez 		digbyp = fdt_clk_read_bool(name, "st,digbypass");
2228b208e3daSGabriel Fernandez 		css = fdt_clk_read_bool(name, "st,css");
22290d21680cSYann Gautier 		stm32mp1_hse_enable(bypass, digbyp, css);
22307839a050SYann Gautier 	}
22317839a050SYann Gautier 	/*
22327839a050SYann Gautier 	 * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR)
22337839a050SYann Gautier 	 * => switch on CSI even if node is not present in device tree
22347839a050SYann Gautier 	 */
22350d21680cSYann Gautier 	stm32mp1_csi_set(true);
22367839a050SYann Gautier 
22377839a050SYann Gautier 	/* Come back to HSI */
2238ae1e5037SGabriel Fernandez 	ret = stm32_clk_configure_mux(priv, CLK_MPU_HSI);
22397839a050SYann Gautier 	if (ret != 0) {
22407839a050SYann Gautier 		return ret;
22417839a050SYann Gautier 	}
2242ae1e5037SGabriel Fernandez 	ret = stm32_clk_configure_mux(priv, CLK_AXI_HSI);
22437839a050SYann Gautier 	if (ret != 0) {
22447839a050SYann Gautier 		return ret;
22457839a050SYann Gautier 	}
2246ae1e5037SGabriel Fernandez 	ret = stm32_clk_configure_mux(priv, CLK_MCU_HSI);
2247b053a22eSYann Gautier 	if (ret != 0) {
2248b053a22eSYann Gautier 		return ret;
2249b053a22eSYann Gautier 	}
2250ae1e5037SGabriel Fernandez 	if ((mmio_read_32(priv->base + RCC_MP_RSTSCLRR) &
22510d21680cSYann Gautier 	     RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) {
2252ae1e5037SGabriel Fernandez 		pll3_preserve = stm32mp1_check_pll_conf(_PLL3,
2253ae1e5037SGabriel Fernandez 							pll_conf[_PLL3].src,
2254ae1e5037SGabriel Fernandez 							pll_conf[_PLL3].cfg,
2255ae1e5037SGabriel Fernandez 							pll_conf[_PLL3].frac);
2256ae1e5037SGabriel Fernandez 		pll4_preserve = stm32mp1_check_pll_conf(_PLL4,
2257ae1e5037SGabriel Fernandez 							pll_conf[_PLL4].src,
2258ae1e5037SGabriel Fernandez 							pll_conf[_PLL4].cfg,
2259ae1e5037SGabriel Fernandez 							pll_conf[_PLL4].frac);
2260175758b2SYann Gautier 	}
2261bf1af154SPatrick Delaunay 	/* Don't initialize PLL4, when used by BOOTROM */
2262bf1af154SPatrick Delaunay 	if ((stm32mp_get_boot_itf_selected() ==
2263bf1af154SPatrick Delaunay 	     BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) &&
2264bf1af154SPatrick Delaunay 	    ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) {
2265bf1af154SPatrick Delaunay 		pll4_bootrom = true;
2266bf1af154SPatrick Delaunay 		pll4_preserve = true;
2267bf1af154SPatrick Delaunay 	}
22680d21680cSYann Gautier 
22697839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
22700d21680cSYann Gautier 		if (((i == _PLL3) && pll3_preserve) ||
22710d21680cSYann Gautier 		    ((i == _PLL4) && pll4_preserve)) {
22727839a050SYann Gautier 			continue;
22730d21680cSYann Gautier 		}
22740d21680cSYann Gautier 
22750d21680cSYann Gautier 		ret = stm32mp1_pll_stop(i);
22767839a050SYann Gautier 		if (ret != 0) {
22777839a050SYann Gautier 			return ret;
22787839a050SYann Gautier 		}
22797839a050SYann Gautier 	}
22807839a050SYann Gautier 
22817839a050SYann Gautier 	/* Configure HSIDIV */
22820d21680cSYann Gautier 	if (stm32mp1_osc[_HSI] != 0U) {
22830d21680cSYann Gautier 		ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]);
22847839a050SYann Gautier 		if (ret != 0) {
22857839a050SYann Gautier 			return ret;
22867839a050SYann Gautier 		}
2287591d80c8SLionel Debieve 
2288591d80c8SLionel Debieve 		stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
22897839a050SYann Gautier 	}
22907839a050SYann Gautier 
2291ae1e5037SGabriel Fernandez 	/* Configure dividers */
2292ae1e5037SGabriel Fernandez 	ret = stm32_clk_dividers_configure(priv);
22937839a050SYann Gautier 	if (ret != 0) {
22947839a050SYann Gautier 		return ret;
22957839a050SYann Gautier 	}
22967839a050SYann Gautier 
22977839a050SYann Gautier 	/* Configure PLLs source */
2298ae1e5037SGabriel Fernandez 	ret = stm32mp1_pll_configure_src(priv, _PLL1);
22997839a050SYann Gautier 	if (ret != 0) {
23007839a050SYann Gautier 		return ret;
23017839a050SYann Gautier 	}
23027839a050SYann Gautier 
23030d21680cSYann Gautier 	if (!pll3_preserve) {
2304ae1e5037SGabriel Fernandez 		ret = stm32mp1_pll_configure_src(priv, _PLL3);
23057839a050SYann Gautier 		if (ret != 0) {
23067839a050SYann Gautier 			return ret;
23077839a050SYann Gautier 		}
23080d21680cSYann Gautier 	}
23090d21680cSYann Gautier 
23100d21680cSYann Gautier 	if (!pll4_preserve) {
2311ae1e5037SGabriel Fernandez 		ret = stm32mp1_pll_configure_src(priv, _PLL4);
23120d21680cSYann Gautier 		if (ret != 0) {
23130d21680cSYann Gautier 			return ret;
23140d21680cSYann Gautier 		}
23150d21680cSYann Gautier 	}
23167839a050SYann Gautier 
23177839a050SYann Gautier 	/* Configure and start PLLs */
23187839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
23190d21680cSYann Gautier 		if (((i == _PLL3) && pll3_preserve) ||
23200d21680cSYann Gautier 		    ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) {
23210d21680cSYann Gautier 			continue;
23220d21680cSYann Gautier 		}
23230d21680cSYann Gautier 
2324ae1e5037SGabriel Fernandez 		if (!pll_conf[i].status) {
23257839a050SYann Gautier 			continue;
23267839a050SYann Gautier 		}
23277839a050SYann Gautier 
23280d21680cSYann Gautier 		if ((i == _PLL4) && pll4_bootrom) {
23290d21680cSYann Gautier 			/* Set output divider if not done by the Bootrom */
2330ae1e5037SGabriel Fernandez 			stm32mp1_pll_config_output(i, pll_conf[i].cfg);
23310d21680cSYann Gautier 			continue;
23320d21680cSYann Gautier 		}
23330d21680cSYann Gautier 
2334ae1e5037SGabriel Fernandez 		ret = stm32mp1_pll_config(i, pll_conf[i].cfg, pll_conf[i].frac);
23357839a050SYann Gautier 		if (ret != 0) {
23367839a050SYann Gautier 			return ret;
23377839a050SYann Gautier 		}
2338964e5ff1SNicolas Le Bayon 
2339ae1e5037SGabriel Fernandez 		if (pll_conf[i].csg_enabled) {
2340ae1e5037SGabriel Fernandez 			stm32mp1_pll_csg(i, pll_conf[i].csg);
23417839a050SYann Gautier 		}
23427839a050SYann Gautier 
23430d21680cSYann Gautier 		stm32mp1_pll_start(i);
23447839a050SYann Gautier 	}
23451b491eeaSElyes Haouas 	/* Wait and start PLLs output when ready */
23467839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
2347ae1e5037SGabriel Fernandez 		if (!pll_conf[i].status) {
23487839a050SYann Gautier 			continue;
23497839a050SYann Gautier 		}
23507839a050SYann Gautier 
2351ae1e5037SGabriel Fernandez 		ret = stm32mp1_pll_output(i, pll_conf[i].cfg[PLLCFG_O]);
23527839a050SYann Gautier 		if (ret != 0) {
23537839a050SYann Gautier 			return ret;
23547839a050SYann Gautier 		}
23557839a050SYann Gautier 	}
23567839a050SYann Gautier 	/* Wait LSE ready before to use it */
23570d21680cSYann Gautier 	if (stm32mp1_osc[_LSE] != 0U) {
23580d21680cSYann Gautier 		stm32mp1_lse_wait();
23597839a050SYann Gautier 	}
23607839a050SYann Gautier 
2361bf1af154SPatrick Delaunay 	if (pll4_bootrom) {
2362ae1e5037SGabriel Fernandez 		usbreg_bootrom = mmio_read_32(priv->base + RCC_USBCKSELR);
2363bf1af154SPatrick Delaunay 	}
23647839a050SYann Gautier 
2365ae1e5037SGabriel Fernandez 	/* Configure with expected clock source */
2366ae1e5037SGabriel Fernandez 	ret = stm32_clk_source_configure(priv);
2367ae1e5037SGabriel Fernandez 	if (ret != 0) {
2368ae1e5037SGabriel Fernandez 		panic();
23697839a050SYann Gautier 	}
2370bf1af154SPatrick Delaunay 
2371bf1af154SPatrick Delaunay 	if (pll4_bootrom) {
2372bf1af154SPatrick Delaunay 		uint32_t usbreg_value, usbreg_mask;
2373bf1af154SPatrick Delaunay 		const struct stm32mp1_clk_sel *sel;
2374bf1af154SPatrick Delaunay 
2375bf1af154SPatrick Delaunay 		sel = clk_sel_ref(_USBPHY_SEL);
2376bf1af154SPatrick Delaunay 		usbreg_mask = (uint32_t)sel->msk << sel->src;
2377bf1af154SPatrick Delaunay 		sel = clk_sel_ref(_USBO_SEL);
2378bf1af154SPatrick Delaunay 		usbreg_mask |= (uint32_t)sel->msk << sel->src;
2379bf1af154SPatrick Delaunay 
2380ae1e5037SGabriel Fernandez 		usbreg_value = mmio_read_32(priv->base + RCC_USBCKSELR) &
2381bf1af154SPatrick Delaunay 			       usbreg_mask;
2382bf1af154SPatrick Delaunay 		usbreg_bootrom &= usbreg_mask;
2383bf1af154SPatrick Delaunay 		if (usbreg_bootrom != usbreg_value) {
2384*1a25db19SYann Gautier 			EARLY_ERROR("forbidden new USB clk path\n");
2385*1a25db19SYann Gautier 			EARLY_ERROR("vs bootrom on USB boot\n");
2386bf1af154SPatrick Delaunay 			return -FDT_ERR_BADVALUE;
2387bf1af154SPatrick Delaunay 		}
2388bf1af154SPatrick Delaunay 	}
2389ae1e5037SGabriel Fernandez 
23907839a050SYann Gautier 	/* Switch OFF HSI if not found in device-tree */
23910d21680cSYann Gautier 	if (stm32mp1_osc[_HSI] == 0U) {
23920d21680cSYann Gautier 		stm32mp1_hsi_set(false);
23937839a050SYann Gautier 	}
2394591d80c8SLionel Debieve 
2395591d80c8SLionel Debieve 	stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
23967839a050SYann Gautier 
23977839a050SYann Gautier 	/* Software Self-Refresh mode (SSR) during DDR initilialization */
2398ae1e5037SGabriel Fernandez 	mmio_clrsetbits_32(priv->base + RCC_DDRITFCR,
23997839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_MASK,
24007839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_SSR <<
24017839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_SHIFT);
24027839a050SYann Gautier 
24037839a050SYann Gautier 	return 0;
24047839a050SYann Gautier }
24057839a050SYann Gautier 
stm32mp1_osc_clk_init(const char * name,enum stm32mp_osc_id index)24067839a050SYann Gautier static void stm32mp1_osc_clk_init(const char *name,
24077839a050SYann Gautier 				  enum stm32mp_osc_id index)
24087839a050SYann Gautier {
24097839a050SYann Gautier 	uint32_t frequency;
24107839a050SYann Gautier 
24110d21680cSYann Gautier 	if (fdt_osc_read_freq(name, &frequency) == 0) {
24120d21680cSYann Gautier 		stm32mp1_osc[index] = frequency;
24137839a050SYann Gautier 	}
24147839a050SYann Gautier }
24157839a050SYann Gautier 
stm32mp1_osc_init(void)24167839a050SYann Gautier static void stm32mp1_osc_init(void)
24177839a050SYann Gautier {
24187839a050SYann Gautier 	enum stm32mp_osc_id i;
24197839a050SYann Gautier 
24207839a050SYann Gautier 	for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) {
24210d21680cSYann Gautier 		stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i);
24227839a050SYann Gautier 	}
24237839a050SYann Gautier }
24247839a050SYann Gautier 
242537e8295aSEtienne Carriere #ifdef STM32MP_SHARED_RESOURCES
242637e8295aSEtienne Carriere /*
242737e8295aSEtienne Carriere  * Get the parent ID of the target parent clock, for tagging as secure
242837e8295aSEtienne Carriere  * shared clock dependencies.
242937e8295aSEtienne Carriere  */
get_parent_id_parent(unsigned int parent_id)243037e8295aSEtienne Carriere static int get_parent_id_parent(unsigned int parent_id)
243137e8295aSEtienne Carriere {
243237e8295aSEtienne Carriere 	enum stm32mp1_parent_sel s = _UNKNOWN_SEL;
243337e8295aSEtienne Carriere 	enum stm32mp1_pll_id pll_id;
243437e8295aSEtienne Carriere 	uint32_t p_sel;
243537e8295aSEtienne Carriere 	uintptr_t rcc_base = stm32mp_rcc_base();
243637e8295aSEtienne Carriere 
243737e8295aSEtienne Carriere 	switch (parent_id) {
243837e8295aSEtienne Carriere 	case _ACLK:
243937e8295aSEtienne Carriere 	case _PCLK4:
244037e8295aSEtienne Carriere 	case _PCLK5:
244137e8295aSEtienne Carriere 		s = _AXIS_SEL;
244237e8295aSEtienne Carriere 		break;
244337e8295aSEtienne Carriere 	case _PLL1_P:
244437e8295aSEtienne Carriere 	case _PLL1_Q:
244537e8295aSEtienne Carriere 	case _PLL1_R:
244637e8295aSEtienne Carriere 		pll_id = _PLL1;
244737e8295aSEtienne Carriere 		break;
244837e8295aSEtienne Carriere 	case _PLL2_P:
244937e8295aSEtienne Carriere 	case _PLL2_Q:
245037e8295aSEtienne Carriere 	case _PLL2_R:
245137e8295aSEtienne Carriere 		pll_id = _PLL2;
245237e8295aSEtienne Carriere 		break;
245337e8295aSEtienne Carriere 	case _PLL3_P:
245437e8295aSEtienne Carriere 	case _PLL3_Q:
245537e8295aSEtienne Carriere 	case _PLL3_R:
245637e8295aSEtienne Carriere 		pll_id = _PLL3;
245737e8295aSEtienne Carriere 		break;
245837e8295aSEtienne Carriere 	case _PLL4_P:
245937e8295aSEtienne Carriere 	case _PLL4_Q:
246037e8295aSEtienne Carriere 	case _PLL4_R:
246137e8295aSEtienne Carriere 		pll_id = _PLL4;
246237e8295aSEtienne Carriere 		break;
246337e8295aSEtienne Carriere 	case _PCLK1:
246437e8295aSEtienne Carriere 	case _PCLK2:
246537e8295aSEtienne Carriere 	case _HCLK2:
246637e8295aSEtienne Carriere 	case _HCLK6:
246737e8295aSEtienne Carriere 	case _CK_PER:
246837e8295aSEtienne Carriere 	case _CK_MPU:
246937e8295aSEtienne Carriere 	case _CK_MCU:
247037e8295aSEtienne Carriere 	case _USB_PHY_48:
247137e8295aSEtienne Carriere 		/* We do not expect to access these */
247237e8295aSEtienne Carriere 		panic();
247337e8295aSEtienne Carriere 		break;
247437e8295aSEtienne Carriere 	default:
247537e8295aSEtienne Carriere 		/* Other parents have no parent */
247637e8295aSEtienne Carriere 		return -1;
247737e8295aSEtienne Carriere 	}
247837e8295aSEtienne Carriere 
247937e8295aSEtienne Carriere 	if (s != _UNKNOWN_SEL) {
248037e8295aSEtienne Carriere 		const struct stm32mp1_clk_sel *sel = clk_sel_ref(s);
248137e8295aSEtienne Carriere 
248237e8295aSEtienne Carriere 		p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) &
248337e8295aSEtienne Carriere 			sel->msk;
248437e8295aSEtienne Carriere 
248537e8295aSEtienne Carriere 		if (p_sel < sel->nb_parent) {
248637e8295aSEtienne Carriere 			return (int)sel->parent[p_sel];
248737e8295aSEtienne Carriere 		}
248837e8295aSEtienne Carriere 	} else {
248937e8295aSEtienne Carriere 		const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
249037e8295aSEtienne Carriere 
249137e8295aSEtienne Carriere 		p_sel = mmio_read_32(rcc_base + pll->rckxselr) &
249237e8295aSEtienne Carriere 			RCC_SELR_REFCLK_SRC_MASK;
249337e8295aSEtienne Carriere 
249437e8295aSEtienne Carriere 		if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) {
249537e8295aSEtienne Carriere 			return (int)pll->refclk[p_sel];
249637e8295aSEtienne Carriere 		}
249737e8295aSEtienne Carriere 	}
249837e8295aSEtienne Carriere 
249937e8295aSEtienne Carriere 	VERBOSE("No parent selected for %s\n",
250037e8295aSEtienne Carriere 		stm32mp1_clk_parent_name[parent_id]);
250137e8295aSEtienne Carriere 
250237e8295aSEtienne Carriere 	return -1;
250337e8295aSEtienne Carriere }
250437e8295aSEtienne Carriere 
secure_parent_clocks(unsigned long parent_id)250537e8295aSEtienne Carriere static void secure_parent_clocks(unsigned long parent_id)
250637e8295aSEtienne Carriere {
250737e8295aSEtienne Carriere 	int grandparent_id;
250837e8295aSEtienne Carriere 
250937e8295aSEtienne Carriere 	switch (parent_id) {
251037e8295aSEtienne Carriere 	case _PLL3_P:
251137e8295aSEtienne Carriere 	case _PLL3_Q:
251237e8295aSEtienne Carriere 	case _PLL3_R:
251337e8295aSEtienne Carriere 		stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
251437e8295aSEtienne Carriere 		break;
251537e8295aSEtienne Carriere 
251637e8295aSEtienne Carriere 	/* These clocks are always secure when RCC is secure */
251737e8295aSEtienne Carriere 	case _ACLK:
251837e8295aSEtienne Carriere 	case _HCLK2:
251937e8295aSEtienne Carriere 	case _HCLK6:
252037e8295aSEtienne Carriere 	case _PCLK4:
252137e8295aSEtienne Carriere 	case _PCLK5:
252237e8295aSEtienne Carriere 	case _PLL1_P:
252337e8295aSEtienne Carriere 	case _PLL1_Q:
252437e8295aSEtienne Carriere 	case _PLL1_R:
252537e8295aSEtienne Carriere 	case _PLL2_P:
252637e8295aSEtienne Carriere 	case _PLL2_Q:
252737e8295aSEtienne Carriere 	case _PLL2_R:
252837e8295aSEtienne Carriere 	case _HSI:
252937e8295aSEtienne Carriere 	case _HSI_KER:
253037e8295aSEtienne Carriere 	case _LSI:
253137e8295aSEtienne Carriere 	case _CSI:
253237e8295aSEtienne Carriere 	case _CSI_KER:
253337e8295aSEtienne Carriere 	case _HSE:
253437e8295aSEtienne Carriere 	case _HSE_KER:
253537e8295aSEtienne Carriere 	case _HSE_KER_DIV2:
2536cbd2e8a6SGabriel Fernandez 	case _HSE_RTC:
253737e8295aSEtienne Carriere 	case _LSE:
253837e8295aSEtienne Carriere 		break;
253937e8295aSEtienne Carriere 
254037e8295aSEtienne Carriere 	default:
254137e8295aSEtienne Carriere 		VERBOSE("Cannot secure parent clock %s\n",
254237e8295aSEtienne Carriere 			stm32mp1_clk_parent_name[parent_id]);
254337e8295aSEtienne Carriere 		panic();
254437e8295aSEtienne Carriere 	}
254537e8295aSEtienne Carriere 
254637e8295aSEtienne Carriere 	grandparent_id = get_parent_id_parent(parent_id);
254737e8295aSEtienne Carriere 	if (grandparent_id >= 0) {
254837e8295aSEtienne Carriere 		secure_parent_clocks(grandparent_id);
254937e8295aSEtienne Carriere 	}
255037e8295aSEtienne Carriere }
255137e8295aSEtienne Carriere 
stm32mp1_register_clock_parents_secure(unsigned long clock_id)255237e8295aSEtienne Carriere void stm32mp1_register_clock_parents_secure(unsigned long clock_id)
255337e8295aSEtienne Carriere {
255437e8295aSEtienne Carriere 	int parent_id;
255537e8295aSEtienne Carriere 
255637e8295aSEtienne Carriere 	if (!stm32mp1_rcc_is_secure()) {
255737e8295aSEtienne Carriere 		return;
255837e8295aSEtienne Carriere 	}
255937e8295aSEtienne Carriere 
256037e8295aSEtienne Carriere 	switch (clock_id) {
256137e8295aSEtienne Carriere 	case PLL1:
256237e8295aSEtienne Carriere 	case PLL2:
256337e8295aSEtienne Carriere 		/* PLL1/PLL2 are always secure: nothing to do */
256437e8295aSEtienne Carriere 		break;
256537e8295aSEtienne Carriere 	case PLL3:
256637e8295aSEtienne Carriere 		stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
256737e8295aSEtienne Carriere 		break;
256837e8295aSEtienne Carriere 	case PLL4:
256937e8295aSEtienne Carriere 		ERROR("PLL4 cannot be secured\n");
257037e8295aSEtienne Carriere 		panic();
257137e8295aSEtienne Carriere 		break;
257237e8295aSEtienne Carriere 	default:
257337e8295aSEtienne Carriere 		/* Others are expected gateable clock */
257437e8295aSEtienne Carriere 		parent_id = stm32mp1_clk_get_parent(clock_id);
257537e8295aSEtienne Carriere 		if (parent_id < 0) {
257637e8295aSEtienne Carriere 			INFO("No parent found for clock %lu\n", clock_id);
257737e8295aSEtienne Carriere 		} else {
257837e8295aSEtienne Carriere 			secure_parent_clocks(parent_id);
257937e8295aSEtienne Carriere 		}
258037e8295aSEtienne Carriere 		break;
258137e8295aSEtienne Carriere 	}
258237e8295aSEtienne Carriere }
258337e8295aSEtienne Carriere #endif /* STM32MP_SHARED_RESOURCES */
258437e8295aSEtienne Carriere 
stm32mp1_clk_mcuss_protect(bool enable)258577b4ca0bSLionel Debieve void stm32mp1_clk_mcuss_protect(bool enable)
258677b4ca0bSLionel Debieve {
258777b4ca0bSLionel Debieve 	uintptr_t rcc_base = stm32mp_rcc_base();
258877b4ca0bSLionel Debieve 
258977b4ca0bSLionel Debieve 	if (enable) {
259077b4ca0bSLionel Debieve 		mmio_setbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
259177b4ca0bSLionel Debieve 	} else {
259277b4ca0bSLionel Debieve 		mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
259377b4ca0bSLionel Debieve 	}
259477b4ca0bSLionel Debieve }
259577b4ca0bSLionel Debieve 
sync_earlyboot_clocks_state(void)25966cb45f89SYann Gautier static void sync_earlyboot_clocks_state(void)
25976cb45f89SYann Gautier {
2598033b6c3aSEtienne Carriere 	unsigned int idx;
2599033b6c3aSEtienne Carriere 	const unsigned long secure_enable[] = {
2600033b6c3aSEtienne Carriere 		AXIDCG,
2601033b6c3aSEtienne Carriere 		BSEC,
2602033b6c3aSEtienne Carriere 		DDRC1, DDRC1LP,
2603033b6c3aSEtienne Carriere 		DDRC2, DDRC2LP,
2604033b6c3aSEtienne Carriere 		DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP,
2605033b6c3aSEtienne Carriere 		DDRPHYC, DDRPHYCLP,
2606373f06beSLionel Debieve 		RTCAPB,
2607033b6c3aSEtienne Carriere 		TZC1, TZC2,
2608033b6c3aSEtienne Carriere 		TZPC,
2609033b6c3aSEtienne Carriere 		STGEN_K,
2610033b6c3aSEtienne Carriere 	};
2611033b6c3aSEtienne Carriere 
2612033b6c3aSEtienne Carriere 	for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) {
2613033b6c3aSEtienne Carriere 		stm32mp_clk_enable(secure_enable[idx]);
2614033b6c3aSEtienne Carriere 	}
26156cb45f89SYann Gautier }
26166cb45f89SYann Gautier 
261733667d29SYann Gautier static const struct clk_ops stm32mp_clk_ops = {
261833667d29SYann Gautier 	.enable		= stm32mp_clk_enable,
261933667d29SYann Gautier 	.disable	= stm32mp_clk_disable,
262033667d29SYann Gautier 	.is_enabled	= stm32mp_clk_is_enabled,
262133667d29SYann Gautier 	.get_rate	= stm32mp_clk_get_rate,
262233667d29SYann Gautier 	.get_parent	= stm32mp1_clk_get_parent,
262333667d29SYann Gautier };
262433667d29SYann Gautier 
2625ae1e5037SGabriel Fernandez struct stm32_pll_dt_cfg mp15_pll[_PLL_NB];
2626ae1e5037SGabriel Fernandez uint32_t mp15_clksrc[MUX_NB];
2627ae1e5037SGabriel Fernandez uint32_t mp15_clkdiv[DIV_NB];
2628ae1e5037SGabriel Fernandez 
2629ae1e5037SGabriel Fernandez struct stm32_clk_platdata stm32mp15_clock_pdata = {
2630ae1e5037SGabriel Fernandez 	.pll		= mp15_pll,
2631ae1e5037SGabriel Fernandez 	.npll		= _PLL_NB,
2632ae1e5037SGabriel Fernandez 	.clksrc		= mp15_clksrc,
2633ae1e5037SGabriel Fernandez 	.nclksrc	= MUX_NB,
2634ae1e5037SGabriel Fernandez 	.clkdiv		= mp15_clkdiv,
2635ae1e5037SGabriel Fernandez 	.nclkdiv	= DIV_NB,
2636ae1e5037SGabriel Fernandez };
2637ae1e5037SGabriel Fernandez 
2638ae1e5037SGabriel Fernandez static struct stm32_clk_priv stm32mp15_clock_data = {
2639ae1e5037SGabriel Fernandez 	.base		= RCC_BASE,
2640ae1e5037SGabriel Fernandez 	.parents	= parent_mp15,
2641ae1e5037SGabriel Fernandez 	.nb_parents	= ARRAY_SIZE(parent_mp15),
2642ae1e5037SGabriel Fernandez 	.div		= dividers_mp15,
2643ae1e5037SGabriel Fernandez 	.nb_div		= ARRAY_SIZE(dividers_mp15),
2644ae1e5037SGabriel Fernandez 	.pdata		= &stm32mp15_clock_pdata,
2645ae1e5037SGabriel Fernandez };
2646ae1e5037SGabriel Fernandez 
stm32_clk_parse_fdt_by_name(void * fdt,int node,const char * name,uint32_t * tab,uint32_t * nb)2647ae1e5037SGabriel Fernandez static int stm32_clk_parse_fdt_by_name(void *fdt, int node, const char *name,
2648ae1e5037SGabriel Fernandez 				       uint32_t *tab, uint32_t *nb)
2649ae1e5037SGabriel Fernandez {
2650ae1e5037SGabriel Fernandez 	const fdt32_t *cell;
2651ae1e5037SGabriel Fernandez 	int len = 0;
2652ae1e5037SGabriel Fernandez 	uint32_t i;
2653ae1e5037SGabriel Fernandez 
2654ae1e5037SGabriel Fernandez 	cell = fdt_getprop(fdt, node, name, &len);
2655ae1e5037SGabriel Fernandez 	if (cell == NULL) {
2656ae1e5037SGabriel Fernandez 		*nb = 0U;
2657ae1e5037SGabriel Fernandez 		return 0;
2658ae1e5037SGabriel Fernandez 	}
2659ae1e5037SGabriel Fernandez 
2660ae1e5037SGabriel Fernandez 	for (i = 0U; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
2661ae1e5037SGabriel Fernandez 		tab[i] = fdt32_to_cpu(cell[i]);
2662ae1e5037SGabriel Fernandez 	}
2663ae1e5037SGabriel Fernandez 
2664ae1e5037SGabriel Fernandez 	*nb = (uint32_t)len / sizeof(uint32_t);
2665ae1e5037SGabriel Fernandez 
2666ae1e5037SGabriel Fernandez 	return 0;
2667ae1e5037SGabriel Fernandez }
2668ae1e5037SGabriel Fernandez 
2669ae1e5037SGabriel Fernandez #define RCC_PLL_NAME_SIZE 12
2670ae1e5037SGabriel Fernandez 
clk_stm32_load_vco_config(void * fdt,int subnode,struct stm32_pll_dt_cfg * pll)2671ae1e5037SGabriel Fernandez static int clk_stm32_load_vco_config(void *fdt, int subnode, struct stm32_pll_dt_cfg *pll)
2672ae1e5037SGabriel Fernandez {
2673ae1e5037SGabriel Fernandez 	int err;
2674ae1e5037SGabriel Fernandez 
2675ae1e5037SGabriel Fernandez 	err = fdt_read_uint32_array(fdt, subnode, "divmn", (int)PLL_DIV_MN_NB, &pll->cfg[PLLCFG_M]);
2676ae1e5037SGabriel Fernandez 	if (err != 0) {
2677ae1e5037SGabriel Fernandez 		return err;
2678ae1e5037SGabriel Fernandez 	}
2679ae1e5037SGabriel Fernandez 
2680ae1e5037SGabriel Fernandez 	err = fdt_read_uint32_array(fdt, subnode, "csg", (int)PLLCSG_NB, pll->csg);
2681ae1e5037SGabriel Fernandez 	if (err == 0) {
2682ae1e5037SGabriel Fernandez 		pll->csg_enabled = true;
2683ae1e5037SGabriel Fernandez 	} else if (err == -FDT_ERR_NOTFOUND) {
2684ae1e5037SGabriel Fernandez 		pll->csg_enabled = false;
2685ae1e5037SGabriel Fernandez 	} else {
2686ae1e5037SGabriel Fernandez 		return err;
2687ae1e5037SGabriel Fernandez 	}
2688ae1e5037SGabriel Fernandez 
2689ae1e5037SGabriel Fernandez 	pll->status = true;
2690ae1e5037SGabriel Fernandez 
2691ae1e5037SGabriel Fernandez 	pll->frac = fdt_read_uint32_default(fdt, subnode, "frac", 0);
2692ae1e5037SGabriel Fernandez 
2693ae1e5037SGabriel Fernandez 	pll->src = fdt_read_uint32_default(fdt, subnode, "src", UINT32_MAX);
2694ae1e5037SGabriel Fernandez 
2695ae1e5037SGabriel Fernandez 	return 0;
2696ae1e5037SGabriel Fernandez }
2697ae1e5037SGabriel Fernandez 
clk_stm32_load_output_config(void * fdt,int subnode,struct stm32_pll_dt_cfg * pll)2698ae1e5037SGabriel Fernandez static int clk_stm32_load_output_config(void *fdt, int subnode, struct stm32_pll_dt_cfg *pll)
2699ae1e5037SGabriel Fernandez {
2700ae1e5037SGabriel Fernandez 	int err;
2701ae1e5037SGabriel Fernandez 
2702ae1e5037SGabriel Fernandez 	err = fdt_read_uint32_array(fdt, subnode, "st,pll_div_pqr", (int)PLL_DIV_PQR_NB,
2703ae1e5037SGabriel Fernandez 				    &pll->cfg[PLLCFG_P]);
2704ae1e5037SGabriel Fernandez 	if (err != 0) {
2705ae1e5037SGabriel Fernandez 		return err;
2706ae1e5037SGabriel Fernandez 	}
2707ae1e5037SGabriel Fernandez 
2708ae1e5037SGabriel Fernandez 	pll->cfg[PLLCFG_O] = PQR(1, 1, 1);
2709ae1e5037SGabriel Fernandez 
2710ae1e5037SGabriel Fernandez 	return 0;
2711ae1e5037SGabriel Fernandez }
2712ae1e5037SGabriel Fernandez 
clk_stm32_parse_pll_fdt(void * fdt,int subnode,struct stm32_pll_dt_cfg * pll)2713ae1e5037SGabriel Fernandez static int clk_stm32_parse_pll_fdt(void *fdt, int subnode, struct stm32_pll_dt_cfg *pll)
2714ae1e5037SGabriel Fernandez {
2715ae1e5037SGabriel Fernandez 	const fdt32_t *cuint;
2716ae1e5037SGabriel Fernandez 	int subnode_pll;
2717ae1e5037SGabriel Fernandez 	int subnode_vco;
2718ae1e5037SGabriel Fernandez 	int err;
2719ae1e5037SGabriel Fernandez 
2720ae1e5037SGabriel Fernandez 	cuint = fdt_getprop(fdt, subnode, "st,pll", NULL);
2721ae1e5037SGabriel Fernandez 	if (cuint == NULL) {
2722ae1e5037SGabriel Fernandez 		/* Case of no pll is defined */
2723ae1e5037SGabriel Fernandez 		return 0;
2724ae1e5037SGabriel Fernandez 	}
2725ae1e5037SGabriel Fernandez 
2726ae1e5037SGabriel Fernandez 	subnode_pll = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
2727ae1e5037SGabriel Fernandez 	if (subnode_pll < 0) {
2728ae1e5037SGabriel Fernandez 		return -FDT_ERR_NOTFOUND;
2729ae1e5037SGabriel Fernandez 	}
2730ae1e5037SGabriel Fernandez 
2731ae1e5037SGabriel Fernandez 	cuint = fdt_getprop(fdt, subnode_pll, "st,pll_vco", NULL);
2732ae1e5037SGabriel Fernandez 	if (cuint == NULL) {
2733ae1e5037SGabriel Fernandez 		return -FDT_ERR_NOTFOUND;
2734ae1e5037SGabriel Fernandez 	}
2735ae1e5037SGabriel Fernandez 
2736ae1e5037SGabriel Fernandez 	subnode_vco = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
2737ae1e5037SGabriel Fernandez 	if (subnode_vco < 0) {
2738ae1e5037SGabriel Fernandez 		return -FDT_ERR_NOTFOUND;
2739ae1e5037SGabriel Fernandez 	}
2740ae1e5037SGabriel Fernandez 
2741ae1e5037SGabriel Fernandez 	err = clk_stm32_load_vco_config(fdt, subnode_vco, pll);
2742ae1e5037SGabriel Fernandez 	if (err != 0) {
2743ae1e5037SGabriel Fernandez 		return err;
2744ae1e5037SGabriel Fernandez 	}
2745ae1e5037SGabriel Fernandez 
2746ae1e5037SGabriel Fernandez 	err = clk_stm32_load_output_config(fdt, subnode_pll, pll);
2747ae1e5037SGabriel Fernandez 	if (err != 0) {
2748ae1e5037SGabriel Fernandez 		return err;
2749ae1e5037SGabriel Fernandez 	}
2750ae1e5037SGabriel Fernandez 
2751ae1e5037SGabriel Fernandez 	return 0;
2752ae1e5037SGabriel Fernandez }
2753ae1e5037SGabriel Fernandez 
stm32_clk_parse_fdt_all_pll(void * fdt,int node,struct stm32_clk_platdata * pdata)2754ae1e5037SGabriel Fernandez static int stm32_clk_parse_fdt_all_pll(void *fdt, int node, struct stm32_clk_platdata *pdata)
2755ae1e5037SGabriel Fernandez {
2756ae1e5037SGabriel Fernandez 	size_t i = 0U;
2757ae1e5037SGabriel Fernandez 
2758ae1e5037SGabriel Fernandez 	for (i = _PLL1; i < pdata->npll; i++) {
2759ae1e5037SGabriel Fernandez 		struct stm32_pll_dt_cfg *pll = pdata->pll + i;
2760ae1e5037SGabriel Fernandez 		char name[RCC_PLL_NAME_SIZE];
2761ae1e5037SGabriel Fernandez 		int subnode;
2762ae1e5037SGabriel Fernandez 		int err;
2763ae1e5037SGabriel Fernandez 
2764ae1e5037SGabriel Fernandez 		snprintf(name, sizeof(name), "st,pll@%u", i);
2765ae1e5037SGabriel Fernandez 
2766ae1e5037SGabriel Fernandez 		subnode = fdt_subnode_offset(fdt, node, name);
2767ae1e5037SGabriel Fernandez 		if (!fdt_check_node(subnode)) {
2768ae1e5037SGabriel Fernandez 			continue;
2769ae1e5037SGabriel Fernandez 		}
2770ae1e5037SGabriel Fernandez 
2771ae1e5037SGabriel Fernandez 		err = clk_stm32_parse_pll_fdt(fdt, subnode, pll);
2772ae1e5037SGabriel Fernandez 		if (err != 0) {
2773ae1e5037SGabriel Fernandez 			panic();
2774ae1e5037SGabriel Fernandez 		}
2775ae1e5037SGabriel Fernandez 	}
2776ae1e5037SGabriel Fernandez 
2777ae1e5037SGabriel Fernandez 	return 0;
2778ae1e5037SGabriel Fernandez }
2779ae1e5037SGabriel Fernandez 
stm32_clk_parse_fdt(struct stm32_clk_platdata * pdata)2780ae1e5037SGabriel Fernandez static int stm32_clk_parse_fdt(struct stm32_clk_platdata *pdata)
2781ae1e5037SGabriel Fernandez {
2782ae1e5037SGabriel Fernandez 	void *fdt = NULL;
2783ae1e5037SGabriel Fernandez 	int node;
2784ae1e5037SGabriel Fernandez 	uint32_t err;
2785ae1e5037SGabriel Fernandez 
2786ae1e5037SGabriel Fernandez 	if (fdt_get_address(&fdt) == 0) {
2787ae1e5037SGabriel Fernandez 		return -ENOENT;
2788ae1e5037SGabriel Fernandez 	}
2789ae1e5037SGabriel Fernandez 
2790ae1e5037SGabriel Fernandez 	node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
2791ae1e5037SGabriel Fernandez 	if (node < 0) {
2792ae1e5037SGabriel Fernandez 		panic();
2793ae1e5037SGabriel Fernandez 	}
2794ae1e5037SGabriel Fernandez 
2795ae1e5037SGabriel Fernandez 	err = stm32_clk_parse_fdt_all_pll(fdt, node, pdata);
2796ae1e5037SGabriel Fernandez 	if (err != 0) {
2797ae1e5037SGabriel Fernandez 		return err;
2798ae1e5037SGabriel Fernandez 	}
2799ae1e5037SGabriel Fernandez 
2800ae1e5037SGabriel Fernandez 	err = stm32_clk_parse_fdt_by_name(fdt, node, "st,clkdiv", pdata->clkdiv, &pdata->nclkdiv);
2801ae1e5037SGabriel Fernandez 	if (err != 0) {
2802ae1e5037SGabriel Fernandez 		return err;
2803ae1e5037SGabriel Fernandez 	}
2804ae1e5037SGabriel Fernandez 
2805ae1e5037SGabriel Fernandez 	err = stm32_clk_parse_fdt_by_name(fdt, node, "st,clksrc", pdata->clksrc, &pdata->nclksrc);
2806ae1e5037SGabriel Fernandez 	if (err != 0) {
2807ae1e5037SGabriel Fernandez 		return err;
2808ae1e5037SGabriel Fernandez 	}
2809ae1e5037SGabriel Fernandez 
2810ae1e5037SGabriel Fernandez 	return 0;
2811ae1e5037SGabriel Fernandez }
2812ae1e5037SGabriel Fernandez 
stm32mp1_clk_probe(void)28137839a050SYann Gautier int stm32mp1_clk_probe(void)
28147839a050SYann Gautier {
2815ae1e5037SGabriel Fernandez 	uintptr_t base = RCC_BASE;
2816ae1e5037SGabriel Fernandez 	int ret;
2817ae1e5037SGabriel Fernandez 
2818812daf91SLionel Debieve #if defined(IMAGE_BL32)
2819812daf91SLionel Debieve 	if (!fdt_get_rcc_secure_state()) {
2820812daf91SLionel Debieve 		mmio_write_32(stm32mp_rcc_base() + RCC_TZCR, 0U);
2821812daf91SLionel Debieve 	}
2822812daf91SLionel Debieve #endif
2823812daf91SLionel Debieve 
28247839a050SYann Gautier 	stm32mp1_osc_init();
28257839a050SYann Gautier 
2826ae1e5037SGabriel Fernandez 	ret = stm32_clk_parse_fdt(&stm32mp15_clock_pdata);
2827ae1e5037SGabriel Fernandez 	if (ret != 0) {
2828ae1e5037SGabriel Fernandez 		return ret;
2829ae1e5037SGabriel Fernandez 	}
2830ae1e5037SGabriel Fernandez 
2831ae1e5037SGabriel Fernandez 	ret = clk_stm32_init(&stm32mp15_clock_data, base);
2832ae1e5037SGabriel Fernandez 	if (ret != 0) {
2833ae1e5037SGabriel Fernandez 		return ret;
2834ae1e5037SGabriel Fernandez 	}
2835ae1e5037SGabriel Fernandez 
28366cb45f89SYann Gautier 	sync_earlyboot_clocks_state();
28376cb45f89SYann Gautier 
283833667d29SYann Gautier 	clk_register(&stm32mp_clk_ops);
283933667d29SYann Gautier 
28407839a050SYann Gautier 	return 0;
28417839a050SYann Gautier }
2842