xref: /rk3399_ARM-atf/drivers/st/clk/stm32mp1_clk.c (revision ae1e503763c8bc52eba1a38e320539d61ebe2043)
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 
30*ae1e5037SGabriel Fernandez enum stm32mp1_pllcfg {
31*ae1e5037SGabriel Fernandez 	PLLCFG_M,
32*ae1e5037SGabriel Fernandez 	PLLCFG_N,
33*ae1e5037SGabriel Fernandez 	PLL_DIV_MN_NB,
34*ae1e5037SGabriel Fernandez 	PLLCFG_P = PLL_DIV_MN_NB,
35*ae1e5037SGabriel Fernandez 	PLLCFG_Q,
36*ae1e5037SGabriel Fernandez 	PLLCFG_R,
37*ae1e5037SGabriel Fernandez 	PLLCFG_O,
38*ae1e5037SGabriel Fernandez 	PLLCFG_NB
39*ae1e5037SGabriel Fernandez };
40*ae1e5037SGabriel Fernandez 
41*ae1e5037SGabriel Fernandez #define PLL_DIV_MN_NB	2
42*ae1e5037SGabriel Fernandez #define PLL_DIV_PQR_NB	3
43*ae1e5037SGabriel Fernandez 
44*ae1e5037SGabriel Fernandez enum stm32mp1_pllcsg {
45*ae1e5037SGabriel Fernandez 	PLLCSG_MOD_PER,
46*ae1e5037SGabriel Fernandez 	PLLCSG_INC_STEP,
47*ae1e5037SGabriel Fernandez 	PLLCSG_SSCG_MODE,
48*ae1e5037SGabriel Fernandez 	PLLCSG_NB
49*ae1e5037SGabriel Fernandez };
50*ae1e5037SGabriel Fernandez 
51*ae1e5037SGabriel Fernandez struct stm32_pll_dt_cfg {
52*ae1e5037SGabriel Fernandez 	bool status;
53*ae1e5037SGabriel Fernandez 	uint32_t src;
54*ae1e5037SGabriel Fernandez 	uint32_t cfg[PLLCFG_NB];
55*ae1e5037SGabriel Fernandez 	uint32_t frac;
56*ae1e5037SGabriel Fernandez 	bool csg_enabled;
57*ae1e5037SGabriel Fernandez 	uint32_t csg[PLLCSG_NB];
58*ae1e5037SGabriel Fernandez };
59*ae1e5037SGabriel Fernandez 
60*ae1e5037SGabriel Fernandez struct stm32_clk_platdata {
61*ae1e5037SGabriel Fernandez 	uint32_t npll;
62*ae1e5037SGabriel Fernandez 	struct stm32_pll_dt_cfg *pll;
63*ae1e5037SGabriel Fernandez 	uint32_t nclksrc;
64*ae1e5037SGabriel Fernandez 	uint32_t *clksrc;
65*ae1e5037SGabriel Fernandez 	uint32_t nclkdiv;
66*ae1e5037SGabriel Fernandez 	uint32_t *clkdiv;
67*ae1e5037SGabriel Fernandez };
68*ae1e5037SGabriel Fernandez 
69*ae1e5037SGabriel Fernandez struct stm32_clk_priv {
70*ae1e5037SGabriel Fernandez 	uintptr_t base;
71*ae1e5037SGabriel Fernandez 	const struct mux_cfg *parents;
72*ae1e5037SGabriel Fernandez 	const uint32_t nb_parents;
73*ae1e5037SGabriel Fernandez 	const struct div_cfg *div;
74*ae1e5037SGabriel Fernandez 	const uint32_t nb_div;
75*ae1e5037SGabriel Fernandez 	void *pdata;
76*ae1e5037SGabriel Fernandez };
77*ae1e5037SGabriel Fernandez 
78*ae1e5037SGabriel Fernandez static struct stm32_clk_priv *stm32_clock_data;
79*ae1e5037SGabriel Fernandez 
80*ae1e5037SGabriel Fernandez static struct stm32_clk_priv *clk_stm32_get_priv(void)
81*ae1e5037SGabriel Fernandez {
82*ae1e5037SGabriel Fernandez 	return stm32_clock_data;
83*ae1e5037SGabriel Fernandez }
84*ae1e5037SGabriel Fernandez 
85*ae1e5037SGabriel Fernandez static int clk_stm32_init(struct stm32_clk_priv *priv, uintptr_t base)
86*ae1e5037SGabriel Fernandez {
87*ae1e5037SGabriel Fernandez 	stm32_clock_data = priv;
88*ae1e5037SGabriel Fernandez 
89*ae1e5037SGabriel Fernandez 	priv->base = base;
90*ae1e5037SGabriel Fernandez 
91*ae1e5037SGabriel Fernandez 	return 0;
92*ae1e5037SGabriel Fernandez }
93*ae1e5037SGabriel Fernandez 
947839a050SYann Gautier #define MAX_HSI_HZ		64000000
950d21680cSYann Gautier #define USB_PHY_48_MHZ		48000000
967839a050SYann Gautier 
97dfdb057aSYann Gautier #define TIMEOUT_US_200MS	U(200000)
98dfdb057aSYann Gautier #define TIMEOUT_US_1S		U(1000000)
997839a050SYann Gautier 
100dfdb057aSYann Gautier #define PLLRDY_TIMEOUT		TIMEOUT_US_200MS
101dfdb057aSYann Gautier #define CLKSRC_TIMEOUT		TIMEOUT_US_200MS
102dfdb057aSYann Gautier #define CLKDIV_TIMEOUT		TIMEOUT_US_200MS
103dfdb057aSYann Gautier #define HSIDIV_TIMEOUT		TIMEOUT_US_200MS
104dfdb057aSYann Gautier #define OSCRDY_TIMEOUT		TIMEOUT_US_1S
1057839a050SYann Gautier 
106*ae1e5037SGabriel Fernandez struct mux_cfg {
107*ae1e5037SGabriel Fernandez 	uint16_t offset;
108*ae1e5037SGabriel Fernandez 	uint8_t shift;
109*ae1e5037SGabriel Fernandez 	uint8_t width;
110*ae1e5037SGabriel Fernandez 	uint8_t bitrdy;
111*ae1e5037SGabriel Fernandez };
112*ae1e5037SGabriel Fernandez 
113*ae1e5037SGabriel Fernandez struct div_cfg {
114*ae1e5037SGabriel Fernandez 	uint16_t offset;
115*ae1e5037SGabriel Fernandez 	uint8_t shift;
116*ae1e5037SGabriel Fernandez 	uint8_t width;
117*ae1e5037SGabriel Fernandez 	uint8_t bitrdy;
118*ae1e5037SGabriel Fernandez };
119*ae1e5037SGabriel Fernandez 
120*ae1e5037SGabriel Fernandez #define DIV_NO_BIT_RDY UINT8_MAX
121*ae1e5037SGabriel Fernandez 
122*ae1e5037SGabriel Fernandez #define DIV_CFG(_id, _offset, _shift, _width,  _bitrdy)\
123*ae1e5037SGabriel Fernandez 	[(_id)] = {\
124*ae1e5037SGabriel Fernandez 		.offset	= (_offset),\
125*ae1e5037SGabriel Fernandez 		.shift	= (_shift),\
126*ae1e5037SGabriel Fernandez 		.width	= (_width),\
127*ae1e5037SGabriel Fernandez 		.bitrdy	= (_bitrdy),\
128*ae1e5037SGabriel Fernandez 	}
129*ae1e5037SGabriel Fernandez 
130*ae1e5037SGabriel Fernandez static const struct div_cfg dividers_mp15[] = {
131*ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_MPU, RCC_MPCKDIVR, 0, 4, 31),
132*ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_AXI, RCC_AXIDIVR, 0, 3, 31),
133*ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_MCU, RCC_MCUDIVR, 0, 4, 31),
134*ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_APB1, RCC_APB1DIVR, 0, 3, 31),
135*ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_APB2, RCC_APB2DIVR, 0, 3, 31),
136*ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_APB3, RCC_APB3DIVR, 0, 3, 31),
137*ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_APB4, RCC_APB4DIVR, 0, 3, 31),
138*ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_APB5, RCC_APB5DIVR, 0, 3, 31),
139*ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_RTC, RCC_RTCDIVR, 0, 6, DIV_NO_BIT_RDY),
140*ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_MCO1, RCC_MCO1CFGR, 4, 4, DIV_NO_BIT_RDY),
141*ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_MCO2, RCC_MCO2CFGR, 4, 4, DIV_NO_BIT_RDY),
142*ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_TRACE, RCC_DBGCFGR, 0, 3, DIV_NO_BIT_RDY),
143*ae1e5037SGabriel Fernandez 	DIV_CFG(DIV_ETHPTP, RCC_ETHCKSELR, 4, 4, DIV_NO_BIT_RDY),
144*ae1e5037SGabriel Fernandez };
145*ae1e5037SGabriel Fernandez 
146*ae1e5037SGabriel Fernandez /*
147*ae1e5037SGabriel Fernandez  * MUX CONFIG
148*ae1e5037SGabriel Fernandez  */
149*ae1e5037SGabriel Fernandez 
150*ae1e5037SGabriel Fernandez #define MUX_NO_BIT_RDY		UINT8_MAX
151*ae1e5037SGabriel Fernandez 
152*ae1e5037SGabriel Fernandez #define MUXRDY_CFG(_id, _offset, _shift, _width,  _bitrdy)\
153*ae1e5037SGabriel Fernandez 	[(_id)] = {\
154*ae1e5037SGabriel Fernandez 		.offset	= (_offset),\
155*ae1e5037SGabriel Fernandez 		.shift	= (_shift),\
156*ae1e5037SGabriel Fernandez 		.width	= (_width),\
157*ae1e5037SGabriel Fernandez 		.bitrdy = (_bitrdy),\
158*ae1e5037SGabriel Fernandez 	}
159*ae1e5037SGabriel Fernandez 
160*ae1e5037SGabriel Fernandez #define MUX_CFG(_id, _offset, _shift, _width)\
161*ae1e5037SGabriel Fernandez 	MUXRDY_CFG(_id, _offset, _shift, _width,  MUX_NO_BIT_RDY)
162*ae1e5037SGabriel Fernandez 
163*ae1e5037SGabriel Fernandez static const struct mux_cfg parent_mp15[MUX_NB] = {
164*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_PLL12,	RCC_RCK12SELR, 0, 2),
165*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_PLL3,	RCC_RCK3SELR, 0, 2),
166*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_PLL4,	RCC_RCK4SELR, 0, 2),
167*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_CKPER,	RCC_CPERCKSELR, 0, 2),
168*ae1e5037SGabriel Fernandez 	MUXRDY_CFG(MUX_MPU,	RCC_MPCKSELR, 0, 2, 31),
169*ae1e5037SGabriel Fernandez 	MUXRDY_CFG(MUX_AXI,	RCC_ASSCKSELR, 0, 3, 31),
170*ae1e5037SGabriel Fernandez 	MUXRDY_CFG(MUX_MCU,	RCC_MSSCKSELR, 0, 2, 31),
171*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_RTC,	RCC_BDCR, 16, 2),
172*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SDMMC12,	RCC_SDMMC12CKSELR, 0, 3),
173*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SPI2S23,	RCC_SPI2S23CKSELR, 0, 3),
174*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SPI45,	RCC_SPI45CKSELR, 0, 3),
175*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_I2C12,	RCC_I2C12CKSELR, 0, 3),
176*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_I2C35,	RCC_I2C35CKSELR, 0, 3),
177*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_LPTIM23,	RCC_LPTIM23CKSELR, 0, 3),
178*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_LPTIM45,	RCC_LPTIM45CKSELR, 0, 3),
179*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_UART24,	RCC_UART24CKSELR, 0, 3),
180*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_UART35,	RCC_UART35CKSELR, 0, 3),
181*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_UART78,	RCC_UART78CKSELR, 0, 3),
182*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SAI1,	RCC_SAI1CKSELR, 0, 3),
183*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_ETH,	RCC_ETHCKSELR, 0, 2),
184*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_I2C46,	RCC_I2C46CKSELR, 0, 3),
185*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_RNG2,	RCC_RNG2CKSELR, 0, 2),
186*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SDMMC3,	RCC_SDMMC3CKSELR, 0, 3),
187*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_FMC,	RCC_FMCCKSELR, 0, 2),
188*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_QSPI,	RCC_QSPICKSELR, 0, 2),
189*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_USBPHY,	RCC_USBCKSELR, 0, 2),
190*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_USBO,	RCC_USBCKSELR, 4, 1),
191*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SPDIF,	RCC_SPDIFCKSELR, 0, 2),
192*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SPI2S1,	RCC_SPI2S1CKSELR, 0, 3),
193*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_CEC,	RCC_CECCKSELR, 0, 2),
194*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_LPTIM1,	RCC_LPTIM1CKSELR, 0, 3),
195*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_UART6,	RCC_UART6CKSELR, 0, 3),
196*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_FDCAN,	RCC_FDCANCKSELR, 0, 2),
197*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SAI2,	RCC_SAI2CKSELR, 0, 3),
198*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SAI3,	RCC_SAI3CKSELR, 0, 3),
199*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SAI4,	RCC_SAI4CKSELR, 0, 3),
200*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_ADC,	RCC_ADCCKSELR, 0, 2),
201*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_DSI,	RCC_DSICKSELR, 0, 1),
202*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_RNG1,	RCC_RNG1CKSELR, 0, 2),
203*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_STGEN,	RCC_STGENCKSELR, 0, 2),
204*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_UART1,	RCC_UART1CKSELR, 0, 3),
205*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_SPI6,	RCC_SPI6CKSELR, 0, 3),
206*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_MCO1,	RCC_MCO1CFGR, 0, 3),
207*ae1e5037SGabriel Fernandez 	MUX_CFG(MUX_MCO2,	RCC_MCO2CFGR, 0, 3),
208*ae1e5037SGabriel Fernandez };
209*ae1e5037SGabriel Fernandez 
210*ae1e5037SGabriel Fernandez #define MASK_WIDTH_SHIFT(_width, _shift) \
211*ae1e5037SGabriel Fernandez 	GENMASK(((_width) + (_shift) - 1U), (_shift))
212*ae1e5037SGabriel Fernandez 
213*ae1e5037SGabriel Fernandez int clk_mux_get_parent(struct stm32_clk_priv *priv, uint32_t mux_id)
214*ae1e5037SGabriel Fernandez {
215*ae1e5037SGabriel Fernandez 	const struct mux_cfg *mux;
216*ae1e5037SGabriel Fernandez 	uint32_t mask;
217*ae1e5037SGabriel Fernandez 
218*ae1e5037SGabriel Fernandez 	if (mux_id >= priv->nb_parents) {
219*ae1e5037SGabriel Fernandez 		panic();
220*ae1e5037SGabriel Fernandez 	}
221*ae1e5037SGabriel Fernandez 
222*ae1e5037SGabriel Fernandez 	mux = &priv->parents[mux_id];
223*ae1e5037SGabriel Fernandez 
224*ae1e5037SGabriel Fernandez 	mask = MASK_WIDTH_SHIFT(mux->width, mux->shift);
225*ae1e5037SGabriel Fernandez 
226*ae1e5037SGabriel Fernandez 	return (mmio_read_32(priv->base + mux->offset) & mask) >> mux->shift;
227*ae1e5037SGabriel Fernandez }
228*ae1e5037SGabriel Fernandez 
229*ae1e5037SGabriel Fernandez static int clk_mux_set_parent(struct stm32_clk_priv *priv, uint16_t pid, uint8_t sel)
230*ae1e5037SGabriel Fernandez {
231*ae1e5037SGabriel Fernandez 	const struct mux_cfg *mux = &priv->parents[pid];
232*ae1e5037SGabriel Fernandez 	uintptr_t address = priv->base + mux->offset;
233*ae1e5037SGabriel Fernandez 	uint32_t mask;
234*ae1e5037SGabriel Fernandez 	uint64_t timeout;
235*ae1e5037SGabriel Fernandez 
236*ae1e5037SGabriel Fernandez 	mask = MASK_WIDTH_SHIFT(mux->width, mux->shift);
237*ae1e5037SGabriel Fernandez 
238*ae1e5037SGabriel Fernandez 	mmio_clrsetbits_32(address, mask, (sel << mux->shift) & mask);
239*ae1e5037SGabriel Fernandez 
240*ae1e5037SGabriel Fernandez 	if (mux->bitrdy == MUX_NO_BIT_RDY) {
241*ae1e5037SGabriel Fernandez 		return 0;
242*ae1e5037SGabriel Fernandez 	}
243*ae1e5037SGabriel Fernandez 
244*ae1e5037SGabriel Fernandez 	timeout = timeout_init_us(CLKSRC_TIMEOUT);
245*ae1e5037SGabriel Fernandez 
246*ae1e5037SGabriel Fernandez 	mask = BIT(mux->bitrdy);
247*ae1e5037SGabriel Fernandez 
248*ae1e5037SGabriel Fernandez 	while ((mmio_read_32(address) & mask) == 0U) {
249*ae1e5037SGabriel Fernandez 		if (timeout_elapsed(timeout)) {
250*ae1e5037SGabriel Fernandez 			return -ETIMEDOUT;
251*ae1e5037SGabriel Fernandez 		}
252*ae1e5037SGabriel Fernandez 	}
253*ae1e5037SGabriel Fernandez 
254*ae1e5037SGabriel Fernandez 	return 0;
255*ae1e5037SGabriel Fernandez }
256*ae1e5037SGabriel Fernandez 
257*ae1e5037SGabriel Fernandez static int stm32_clk_configure_mux(struct stm32_clk_priv *priv, uint32_t val)
258*ae1e5037SGabriel Fernandez {
259*ae1e5037SGabriel Fernandez 	uint32_t data = val & CMD_DATA_MASK;
260*ae1e5037SGabriel Fernandez 	int mux = (data & MUX_ID_MASK) >> MUX_ID_SHIFT;
261*ae1e5037SGabriel Fernandez 	int sel = (data & MUX_SEL_MASK) >> MUX_SEL_SHIFT;
262*ae1e5037SGabriel Fernandez 
263*ae1e5037SGabriel Fernandez 	return clk_mux_set_parent(priv, mux, sel);
264*ae1e5037SGabriel Fernandez }
265*ae1e5037SGabriel Fernandez 
266*ae1e5037SGabriel Fernandez int clk_stm32_set_div(struct stm32_clk_priv *priv, uint32_t div_id, uint32_t value)
267*ae1e5037SGabriel Fernandez {
268*ae1e5037SGabriel Fernandez 	const struct div_cfg *divider;
269*ae1e5037SGabriel Fernandez 	uintptr_t address;
270*ae1e5037SGabriel Fernandez 	uint64_t timeout;
271*ae1e5037SGabriel Fernandez 	uint32_t mask;
272*ae1e5037SGabriel Fernandez 
273*ae1e5037SGabriel Fernandez 	if (div_id >= priv->nb_div) {
274*ae1e5037SGabriel Fernandez 		panic();
275*ae1e5037SGabriel Fernandez 	}
276*ae1e5037SGabriel Fernandez 
277*ae1e5037SGabriel Fernandez 	divider = &priv->div[div_id];
278*ae1e5037SGabriel Fernandez 	address = priv->base + divider->offset;
279*ae1e5037SGabriel Fernandez 
280*ae1e5037SGabriel Fernandez 	mask = MASK_WIDTH_SHIFT(divider->width, divider->shift);
281*ae1e5037SGabriel Fernandez 	mmio_clrsetbits_32(address, mask, (value << divider->shift) & mask);
282*ae1e5037SGabriel Fernandez 
283*ae1e5037SGabriel Fernandez 	if (divider->bitrdy == DIV_NO_BIT_RDY) {
284*ae1e5037SGabriel Fernandez 		return 0;
285*ae1e5037SGabriel Fernandez 	}
286*ae1e5037SGabriel Fernandez 
287*ae1e5037SGabriel Fernandez 	timeout = timeout_init_us(CLKSRC_TIMEOUT);
288*ae1e5037SGabriel Fernandez 	mask = BIT(divider->bitrdy);
289*ae1e5037SGabriel Fernandez 
290*ae1e5037SGabriel Fernandez 	while ((mmio_read_32(address) & mask) == 0U) {
291*ae1e5037SGabriel Fernandez 		if (timeout_elapsed(timeout)) {
292*ae1e5037SGabriel Fernandez 			return -ETIMEDOUT;
293*ae1e5037SGabriel Fernandez 		}
294*ae1e5037SGabriel Fernandez 	}
295*ae1e5037SGabriel Fernandez 
296*ae1e5037SGabriel Fernandez 	return 0;
297*ae1e5037SGabriel Fernandez }
298*ae1e5037SGabriel Fernandez 
299f66358afSYann Gautier const char *stm32mp_osc_node_label[NB_OSC] = {
300f66358afSYann Gautier 	[_LSI] = "clk-lsi",
301f66358afSYann Gautier 	[_LSE] = "clk-lse",
302f66358afSYann Gautier 	[_HSI] = "clk-hsi",
303f66358afSYann Gautier 	[_HSE] = "clk-hse",
304f66358afSYann Gautier 	[_CSI] = "clk-csi",
305f66358afSYann Gautier 	[_I2S_CKIN] = "i2s_ckin",
306f66358afSYann Gautier };
307f66358afSYann Gautier 
3087839a050SYann Gautier enum stm32mp1_parent_id {
3097839a050SYann Gautier /* Oscillators are defined in enum stm32mp_osc_id */
3107839a050SYann Gautier 
3117839a050SYann Gautier /* Other parent source */
3127839a050SYann Gautier 	_HSI_KER = NB_OSC,
3137839a050SYann Gautier 	_HSE_KER,
3147839a050SYann Gautier 	_HSE_KER_DIV2,
315cbd2e8a6SGabriel Fernandez 	_HSE_RTC,
3167839a050SYann Gautier 	_CSI_KER,
3177839a050SYann Gautier 	_PLL1_P,
3187839a050SYann Gautier 	_PLL1_Q,
3197839a050SYann Gautier 	_PLL1_R,
3207839a050SYann Gautier 	_PLL2_P,
3217839a050SYann Gautier 	_PLL2_Q,
3227839a050SYann Gautier 	_PLL2_R,
3237839a050SYann Gautier 	_PLL3_P,
3247839a050SYann Gautier 	_PLL3_Q,
3257839a050SYann Gautier 	_PLL3_R,
3267839a050SYann Gautier 	_PLL4_P,
3277839a050SYann Gautier 	_PLL4_Q,
3287839a050SYann Gautier 	_PLL4_R,
3297839a050SYann Gautier 	_ACLK,
3307839a050SYann Gautier 	_PCLK1,
3317839a050SYann Gautier 	_PCLK2,
3327839a050SYann Gautier 	_PCLK3,
3337839a050SYann Gautier 	_PCLK4,
3347839a050SYann Gautier 	_PCLK5,
3357839a050SYann Gautier 	_HCLK6,
3367839a050SYann Gautier 	_HCLK2,
3377839a050SYann Gautier 	_CK_PER,
3387839a050SYann Gautier 	_CK_MPU,
339b053a22eSYann Gautier 	_CK_MCU,
3400d21680cSYann Gautier 	_USB_PHY_48,
3417839a050SYann Gautier 	_PARENT_NB,
3427839a050SYann Gautier 	_UNKNOWN_ID = 0xff,
3437839a050SYann Gautier };
3447839a050SYann Gautier 
3450d21680cSYann Gautier /* Lists only the parent clock we are interested in */
3467839a050SYann Gautier enum stm32mp1_parent_sel {
3470d21680cSYann Gautier 	_I2C12_SEL,
3480d21680cSYann Gautier 	_I2C35_SEL,
3490d21680cSYann Gautier 	_STGEN_SEL,
3507839a050SYann Gautier 	_I2C46_SEL,
3510d21680cSYann Gautier 	_SPI6_SEL,
352d4151d2fSYann Gautier 	_UART1_SEL,
3530d21680cSYann Gautier 	_RNG1_SEL,
3547839a050SYann Gautier 	_UART6_SEL,
3557839a050SYann Gautier 	_UART24_SEL,
3567839a050SYann Gautier 	_UART35_SEL,
3577839a050SYann Gautier 	_UART78_SEL,
3587839a050SYann Gautier 	_SDMMC12_SEL,
3597839a050SYann Gautier 	_SDMMC3_SEL,
3607839a050SYann Gautier 	_QSPI_SEL,
3617839a050SYann Gautier 	_FMC_SEL,
362d4151d2fSYann Gautier 	_AXIS_SEL,
363d4151d2fSYann Gautier 	_MCUS_SEL,
3647839a050SYann Gautier 	_USBPHY_SEL,
3657839a050SYann Gautier 	_USBO_SEL,
3668fbcd9e4SEtienne Carriere 	_MPU_SEL,
367288f5cf2SYann Gautier 	_CKPER_SEL,
368016af006SEtienne Carriere 	_RTC_SEL,
3697839a050SYann Gautier 	_PARENT_SEL_NB,
3707839a050SYann Gautier 	_UNKNOWN_SEL = 0xff,
3717839a050SYann Gautier };
3727839a050SYann Gautier 
3738fbcd9e4SEtienne Carriere /* State the parent clock ID straight related to a clock */
3748fbcd9e4SEtienne Carriere static const uint8_t parent_id_clock_id[_PARENT_NB] = {
3758fbcd9e4SEtienne Carriere 	[_HSE] = CK_HSE,
3768fbcd9e4SEtienne Carriere 	[_HSI] = CK_HSI,
3778fbcd9e4SEtienne Carriere 	[_CSI] = CK_CSI,
3788fbcd9e4SEtienne Carriere 	[_LSE] = CK_LSE,
3798fbcd9e4SEtienne Carriere 	[_LSI] = CK_LSI,
3808fbcd9e4SEtienne Carriere 	[_I2S_CKIN] = _UNKNOWN_ID,
3818fbcd9e4SEtienne Carriere 	[_USB_PHY_48] = _UNKNOWN_ID,
3828fbcd9e4SEtienne Carriere 	[_HSI_KER] = CK_HSI,
3838fbcd9e4SEtienne Carriere 	[_HSE_KER] = CK_HSE,
3848fbcd9e4SEtienne Carriere 	[_HSE_KER_DIV2] = CK_HSE_DIV2,
385cbd2e8a6SGabriel Fernandez 	[_HSE_RTC] = _UNKNOWN_ID,
3868fbcd9e4SEtienne Carriere 	[_CSI_KER] = CK_CSI,
3878fbcd9e4SEtienne Carriere 	[_PLL1_P] = PLL1_P,
3888fbcd9e4SEtienne Carriere 	[_PLL1_Q] = PLL1_Q,
3898fbcd9e4SEtienne Carriere 	[_PLL1_R] = PLL1_R,
3908fbcd9e4SEtienne Carriere 	[_PLL2_P] = PLL2_P,
3918fbcd9e4SEtienne Carriere 	[_PLL2_Q] = PLL2_Q,
3928fbcd9e4SEtienne Carriere 	[_PLL2_R] = PLL2_R,
3938fbcd9e4SEtienne Carriere 	[_PLL3_P] = PLL3_P,
3948fbcd9e4SEtienne Carriere 	[_PLL3_Q] = PLL3_Q,
3958fbcd9e4SEtienne Carriere 	[_PLL3_R] = PLL3_R,
3968fbcd9e4SEtienne Carriere 	[_PLL4_P] = PLL4_P,
3978fbcd9e4SEtienne Carriere 	[_PLL4_Q] = PLL4_Q,
3988fbcd9e4SEtienne Carriere 	[_PLL4_R] = PLL4_R,
3998fbcd9e4SEtienne Carriere 	[_ACLK] = CK_AXI,
4008fbcd9e4SEtienne Carriere 	[_PCLK1] = CK_AXI,
4018fbcd9e4SEtienne Carriere 	[_PCLK2] = CK_AXI,
4028fbcd9e4SEtienne Carriere 	[_PCLK3] = CK_AXI,
4038fbcd9e4SEtienne Carriere 	[_PCLK4] = CK_AXI,
4048fbcd9e4SEtienne Carriere 	[_PCLK5] = CK_AXI,
4058fbcd9e4SEtienne Carriere 	[_CK_PER] = CK_PER,
4068fbcd9e4SEtienne Carriere 	[_CK_MPU] = CK_MPU,
4078fbcd9e4SEtienne Carriere 	[_CK_MCU] = CK_MCU,
4088fbcd9e4SEtienne Carriere };
4098fbcd9e4SEtienne Carriere 
4108fbcd9e4SEtienne Carriere static unsigned int clock_id2parent_id(unsigned long id)
4118fbcd9e4SEtienne Carriere {
4128fbcd9e4SEtienne Carriere 	unsigned int n;
4138fbcd9e4SEtienne Carriere 
4148fbcd9e4SEtienne Carriere 	for (n = 0U; n < ARRAY_SIZE(parent_id_clock_id); n++) {
4158fbcd9e4SEtienne Carriere 		if (parent_id_clock_id[n] == id) {
4168fbcd9e4SEtienne Carriere 			return n;
4178fbcd9e4SEtienne Carriere 		}
4188fbcd9e4SEtienne Carriere 	}
4198fbcd9e4SEtienne Carriere 
4208fbcd9e4SEtienne Carriere 	return _UNKNOWN_ID;
4218fbcd9e4SEtienne Carriere }
4228fbcd9e4SEtienne Carriere 
4237839a050SYann Gautier enum stm32mp1_pll_id {
4247839a050SYann Gautier 	_PLL1,
4257839a050SYann Gautier 	_PLL2,
4267839a050SYann Gautier 	_PLL3,
4277839a050SYann Gautier 	_PLL4,
4287839a050SYann Gautier 	_PLL_NB
4297839a050SYann Gautier };
4307839a050SYann Gautier 
4317839a050SYann Gautier enum stm32mp1_div_id {
4327839a050SYann Gautier 	_DIV_P,
4337839a050SYann Gautier 	_DIV_Q,
4347839a050SYann Gautier 	_DIV_R,
4357839a050SYann Gautier 	_DIV_NB,
4367839a050SYann Gautier };
4377839a050SYann Gautier 
4387839a050SYann Gautier enum stm32mp1_clksrc_id {
4397839a050SYann Gautier 	CLKSRC_MPU,
4407839a050SYann Gautier 	CLKSRC_AXI,
441b053a22eSYann Gautier 	CLKSRC_MCU,
4427839a050SYann Gautier 	CLKSRC_PLL12,
4437839a050SYann Gautier 	CLKSRC_PLL3,
4447839a050SYann Gautier 	CLKSRC_PLL4,
4457839a050SYann Gautier 	CLKSRC_RTC,
4467839a050SYann Gautier 	CLKSRC_MCO1,
4477839a050SYann Gautier 	CLKSRC_MCO2,
4487839a050SYann Gautier 	CLKSRC_NB
4497839a050SYann Gautier };
4507839a050SYann Gautier 
4517839a050SYann Gautier enum stm32mp1_clkdiv_id {
4527839a050SYann Gautier 	CLKDIV_MPU,
4537839a050SYann Gautier 	CLKDIV_AXI,
454b053a22eSYann Gautier 	CLKDIV_MCU,
4557839a050SYann Gautier 	CLKDIV_APB1,
4567839a050SYann Gautier 	CLKDIV_APB2,
4577839a050SYann Gautier 	CLKDIV_APB3,
4587839a050SYann Gautier 	CLKDIV_APB4,
4597839a050SYann Gautier 	CLKDIV_APB5,
4607839a050SYann Gautier 	CLKDIV_RTC,
4617839a050SYann Gautier 	CLKDIV_MCO1,
4627839a050SYann Gautier 	CLKDIV_MCO2,
4637839a050SYann Gautier 	CLKDIV_NB
4647839a050SYann Gautier };
4657839a050SYann Gautier 
4667839a050SYann Gautier enum stm32mp1_plltype {
4677839a050SYann Gautier 	PLL_800,
4687839a050SYann Gautier 	PLL_1600,
4697839a050SYann Gautier 	PLL_TYPE_NB
4707839a050SYann Gautier };
4717839a050SYann Gautier 
4727839a050SYann Gautier struct stm32mp1_pll {
4737839a050SYann Gautier 	uint8_t refclk_min;
4747839a050SYann Gautier 	uint8_t refclk_max;
4757839a050SYann Gautier };
4767839a050SYann Gautier 
4777839a050SYann Gautier struct stm32mp1_clk_gate {
4787839a050SYann Gautier 	uint16_t offset;
4797839a050SYann Gautier 	uint8_t bit;
4807839a050SYann Gautier 	uint8_t index;
4817839a050SYann Gautier 	uint8_t set_clr;
482aaa09b71SYann Gautier 	uint8_t secure;
4830d21680cSYann Gautier 	uint8_t sel; /* Relates to enum stm32mp1_parent_sel */
4840d21680cSYann Gautier 	uint8_t fixed; /* Relates to enum stm32mp1_parent_id */
4857839a050SYann Gautier };
4867839a050SYann Gautier 
4877839a050SYann Gautier struct stm32mp1_clk_sel {
4887839a050SYann Gautier 	uint16_t offset;
4897839a050SYann Gautier 	uint8_t src;
4907839a050SYann Gautier 	uint8_t msk;
4917839a050SYann Gautier 	uint8_t nb_parent;
4927839a050SYann Gautier 	const uint8_t *parent;
4937839a050SYann Gautier };
4947839a050SYann Gautier 
4957839a050SYann Gautier #define REFCLK_SIZE 4
4967839a050SYann Gautier struct stm32mp1_clk_pll {
4977839a050SYann Gautier 	enum stm32mp1_plltype plltype;
4987839a050SYann Gautier 	uint16_t rckxselr;
4997839a050SYann Gautier 	uint16_t pllxcfgr1;
5007839a050SYann Gautier 	uint16_t pllxcfgr2;
5017839a050SYann Gautier 	uint16_t pllxfracr;
5027839a050SYann Gautier 	uint16_t pllxcr;
5037839a050SYann Gautier 	uint16_t pllxcsgr;
5047839a050SYann Gautier 	enum stm32mp_osc_id refclk[REFCLK_SIZE];
5057839a050SYann Gautier };
5067839a050SYann Gautier 
5070d21680cSYann Gautier /* Clocks with selectable source and non set/clr register access */
508aaa09b71SYann Gautier #define _CLK_SELEC(sec, off, b, idx, s)			\
5097839a050SYann Gautier 	{						\
5107839a050SYann Gautier 		.offset = (off),			\
5117839a050SYann Gautier 		.bit = (b),				\
5127839a050SYann Gautier 		.index = (idx),				\
5137839a050SYann Gautier 		.set_clr = 0,				\
514aaa09b71SYann Gautier 		.secure = (sec),			\
5157839a050SYann Gautier 		.sel = (s),				\
5167839a050SYann Gautier 		.fixed = _UNKNOWN_ID,			\
5177839a050SYann Gautier 	}
5187839a050SYann Gautier 
5190d21680cSYann Gautier /* Clocks with fixed source and non set/clr register access */
520aaa09b71SYann Gautier #define _CLK_FIXED(sec, off, b, idx, f)			\
5217839a050SYann Gautier 	{						\
5227839a050SYann Gautier 		.offset = (off),			\
5237839a050SYann Gautier 		.bit = (b),				\
5247839a050SYann Gautier 		.index = (idx),				\
5257839a050SYann Gautier 		.set_clr = 0,				\
526aaa09b71SYann Gautier 		.secure = (sec),			\
5277839a050SYann Gautier 		.sel = _UNKNOWN_SEL,			\
5287839a050SYann Gautier 		.fixed = (f),				\
5297839a050SYann Gautier 	}
5307839a050SYann Gautier 
5310d21680cSYann Gautier /* Clocks with selectable source and set/clr register access */
532aaa09b71SYann Gautier #define _CLK_SC_SELEC(sec, off, b, idx, s)			\
5337839a050SYann Gautier 	{						\
5347839a050SYann Gautier 		.offset = (off),			\
5357839a050SYann Gautier 		.bit = (b),				\
5367839a050SYann Gautier 		.index = (idx),				\
5377839a050SYann Gautier 		.set_clr = 1,				\
538aaa09b71SYann Gautier 		.secure = (sec),			\
5397839a050SYann Gautier 		.sel = (s),				\
5407839a050SYann Gautier 		.fixed = _UNKNOWN_ID,			\
5417839a050SYann Gautier 	}
5427839a050SYann Gautier 
5430d21680cSYann Gautier /* Clocks with fixed source and set/clr register access */
544aaa09b71SYann Gautier #define _CLK_SC_FIXED(sec, off, b, idx, f)			\
5457839a050SYann Gautier 	{						\
5467839a050SYann Gautier 		.offset = (off),			\
5477839a050SYann Gautier 		.bit = (b),				\
5487839a050SYann Gautier 		.index = (idx),				\
5497839a050SYann Gautier 		.set_clr = 1,				\
550aaa09b71SYann Gautier 		.secure = (sec),			\
5517839a050SYann Gautier 		.sel = _UNKNOWN_SEL,			\
5527839a050SYann Gautier 		.fixed = (f),				\
5537839a050SYann Gautier 	}
5547839a050SYann Gautier 
555d4151d2fSYann Gautier #define _CLK_PARENT_SEL(_label, _rcc_selr, _parents)		\
556d4151d2fSYann Gautier 	[_ ## _label ## _SEL] = {				\
557d4151d2fSYann Gautier 		.offset = _rcc_selr,				\
558d4151d2fSYann Gautier 		.src = _rcc_selr ## _ ## _label ## SRC_SHIFT,	\
5598ae08dcdSEtienne Carriere 		.msk = (_rcc_selr ## _ ## _label ## SRC_MASK) >> \
5608ae08dcdSEtienne Carriere 		       (_rcc_selr ## _ ## _label ## SRC_SHIFT), \
561d4151d2fSYann Gautier 		.parent = (_parents),				\
562d4151d2fSYann Gautier 		.nb_parent = ARRAY_SIZE(_parents)		\
5637839a050SYann Gautier 	}
5647839a050SYann Gautier 
5650d21680cSYann Gautier #define _CLK_PLL(idx, type, off1, off2, off3,		\
5667839a050SYann Gautier 		 off4, off5, off6,			\
5677839a050SYann Gautier 		 p1, p2, p3, p4)			\
5687839a050SYann Gautier 	[(idx)] = {					\
5697839a050SYann Gautier 		.plltype = (type),			\
5707839a050SYann Gautier 		.rckxselr = (off1),			\
5717839a050SYann Gautier 		.pllxcfgr1 = (off2),			\
5727839a050SYann Gautier 		.pllxcfgr2 = (off3),			\
5737839a050SYann Gautier 		.pllxfracr = (off4),			\
5747839a050SYann Gautier 		.pllxcr = (off5),			\
5757839a050SYann Gautier 		.pllxcsgr = (off6),			\
5767839a050SYann Gautier 		.refclk[0] = (p1),			\
5777839a050SYann Gautier 		.refclk[1] = (p2),			\
5787839a050SYann Gautier 		.refclk[2] = (p3),			\
5797839a050SYann Gautier 		.refclk[3] = (p4),			\
5807839a050SYann Gautier 	}
5817839a050SYann Gautier 
5820d21680cSYann Gautier #define NB_GATES	ARRAY_SIZE(stm32mp1_clk_gate)
5830d21680cSYann Gautier 
584aaa09b71SYann Gautier #define SEC		1
585aaa09b71SYann Gautier #define N_S		0
586aaa09b71SYann Gautier 
5877839a050SYann Gautier static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
588aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK),
589aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
590aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK),
591aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
592aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
593aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
594aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
595aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
596aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK),
597aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
598aaa09b71SYann Gautier 	_CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
5997839a050SYann Gautier 
6007418cf39SYann Gautier #if defined(IMAGE_BL32)
601aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
6027418cf39SYann Gautier #endif
603aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
604aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
605aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
606aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
607aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
608aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
609aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL),
610aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL),
611aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL),
612aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL),
6137839a050SYann Gautier 
6147418cf39SYann Gautier #if defined(IMAGE_BL32)
615aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
6167418cf39SYann Gautier #endif
617aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
6187839a050SYann Gautier 
619aaa09b71SYann Gautier 	_CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID),
620f33b2433SYann Gautier 
621aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
622aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
623aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
6247839a050SYann Gautier 
625aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL),
626aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
627aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL),
628aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL),
629aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
630aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5),
631aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5),
632aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5),
633aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5),
634aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5),
635aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
6367839a050SYann Gautier 
6377418cf39SYann Gautier #if defined(IMAGE_BL32)
638aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
639aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
6407418cf39SYann Gautier #endif
6417839a050SYann Gautier 
642aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
643aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
644aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
645aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
646aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
647aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
648aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
649aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
650aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
651aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
652aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
6537839a050SYann Gautier 
654aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5),
655aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5),
656aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5),
657aaa09b71SYann Gautier 	_CLK_SC_SELEC(SEC, RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL),
658aaa09b71SYann Gautier 	_CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5),
6597839a050SYann Gautier 
6607418cf39SYann Gautier #if defined(IMAGE_BL2)
661aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
662aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
6637418cf39SYann Gautier #endif
664aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
665aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
6667418cf39SYann Gautier #if defined(IMAGE_BL32)
667aaa09b71SYann Gautier 	_CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
6687418cf39SYann Gautier #endif
6697839a050SYann Gautier 
670aaa09b71SYann Gautier 	_CLK_SELEC(SEC, RCC_BDCR, 20, RTC, _RTC_SEL),
671aaa09b71SYann Gautier 	_CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
6727839a050SYann Gautier };
6737839a050SYann Gautier 
6740d21680cSYann Gautier static const uint8_t i2c12_parents[] = {
6750d21680cSYann Gautier 	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
6760d21680cSYann Gautier };
6770d21680cSYann Gautier 
6780d21680cSYann Gautier static const uint8_t i2c35_parents[] = {
6790d21680cSYann Gautier 	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
6800d21680cSYann Gautier };
6810d21680cSYann Gautier 
6820d21680cSYann Gautier static const uint8_t stgen_parents[] = {
6830d21680cSYann Gautier 	_HSI_KER, _HSE_KER
6840d21680cSYann Gautier };
6850d21680cSYann Gautier 
6860d21680cSYann Gautier static const uint8_t i2c46_parents[] = {
6870d21680cSYann Gautier 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER
6880d21680cSYann Gautier };
6890d21680cSYann Gautier 
6900d21680cSYann Gautier static const uint8_t spi6_parents[] = {
6910d21680cSYann Gautier 	_PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q
6920d21680cSYann Gautier };
6930d21680cSYann Gautier 
6940d21680cSYann Gautier static const uint8_t usart1_parents[] = {
6950d21680cSYann Gautier 	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER
6960d21680cSYann Gautier };
6970d21680cSYann Gautier 
6980d21680cSYann Gautier static const uint8_t rng1_parents[] = {
6990d21680cSYann Gautier 	_CSI, _PLL4_R, _LSE, _LSI
7000d21680cSYann Gautier };
7010d21680cSYann Gautier 
7020d21680cSYann Gautier static const uint8_t uart6_parents[] = {
7030d21680cSYann Gautier 	_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
7040d21680cSYann Gautier };
7050d21680cSYann Gautier 
7060d21680cSYann Gautier static const uint8_t uart234578_parents[] = {
7070d21680cSYann Gautier 	_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
7080d21680cSYann Gautier };
7090d21680cSYann Gautier 
7100d21680cSYann Gautier static const uint8_t sdmmc12_parents[] = {
7110d21680cSYann Gautier 	_HCLK6, _PLL3_R, _PLL4_P, _HSI_KER
7120d21680cSYann Gautier };
7130d21680cSYann Gautier 
7140d21680cSYann Gautier static const uint8_t sdmmc3_parents[] = {
7150d21680cSYann Gautier 	_HCLK2, _PLL3_R, _PLL4_P, _HSI_KER
7160d21680cSYann Gautier };
7170d21680cSYann Gautier 
7180d21680cSYann Gautier static const uint8_t qspi_parents[] = {
7190d21680cSYann Gautier 	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
7200d21680cSYann Gautier };
7210d21680cSYann Gautier 
7220d21680cSYann Gautier static const uint8_t fmc_parents[] = {
7230d21680cSYann Gautier 	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
7240d21680cSYann Gautier };
7250d21680cSYann Gautier 
726b8fe48b6SEtienne Carriere static const uint8_t axiss_parents[] = {
727b8fe48b6SEtienne Carriere 	_HSI, _HSE, _PLL2_P
7280d21680cSYann Gautier };
7290d21680cSYann Gautier 
730b8fe48b6SEtienne Carriere static const uint8_t mcuss_parents[] = {
731b8fe48b6SEtienne Carriere 	_HSI, _HSE, _CSI, _PLL3_P
732b053a22eSYann Gautier };
733b053a22eSYann Gautier 
7340d21680cSYann Gautier static const uint8_t usbphy_parents[] = {
7350d21680cSYann Gautier 	_HSE_KER, _PLL4_R, _HSE_KER_DIV2
7360d21680cSYann Gautier };
7370d21680cSYann Gautier 
7380d21680cSYann Gautier static const uint8_t usbo_parents[] = {
7390d21680cSYann Gautier 	_PLL4_R, _USB_PHY_48
7400d21680cSYann Gautier };
7417839a050SYann Gautier 
7428fbcd9e4SEtienne Carriere static const uint8_t mpu_parents[] = {
7438fbcd9e4SEtienne Carriere 	_HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */
7448fbcd9e4SEtienne Carriere };
7458fbcd9e4SEtienne Carriere 
7468fbcd9e4SEtienne Carriere static const uint8_t per_parents[] = {
7478fbcd9e4SEtienne Carriere 	_HSI, _HSE, _CSI,
7488fbcd9e4SEtienne Carriere };
7498fbcd9e4SEtienne Carriere 
750016af006SEtienne Carriere static const uint8_t rtc_parents[] = {
751cbd2e8a6SGabriel Fernandez 	_UNKNOWN_ID, _LSE, _LSI, _HSE_RTC
752016af006SEtienne Carriere };
753016af006SEtienne Carriere 
7547839a050SYann Gautier static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
755d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents),
756d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents),
757d4151d2fSYann Gautier 	_CLK_PARENT_SEL(STGEN, RCC_STGENCKSELR, stgen_parents),
758d4151d2fSYann Gautier 	_CLK_PARENT_SEL(I2C46, RCC_I2C46CKSELR, i2c46_parents),
759d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents),
760d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents),
761d4151d2fSYann Gautier 	_CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents),
7628fbcd9e4SEtienne Carriere 	_CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents),
763288f5cf2SYann Gautier 	_CLK_PARENT_SEL(CKPER, RCC_CPERCKSELR, per_parents),
764016af006SEtienne Carriere 	_CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents),
765d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents),
766d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents),
767d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents),
768d4151d2fSYann Gautier 	_CLK_PARENT_SEL(UART78, RCC_UART78CKSELR, uart234578_parents),
769d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SDMMC12, RCC_SDMMC12CKSELR, sdmmc12_parents),
770d4151d2fSYann Gautier 	_CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents),
771d4151d2fSYann Gautier 	_CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents),
772d4151d2fSYann Gautier 	_CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents),
773b8fe48b6SEtienne Carriere 	_CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, axiss_parents),
774b8fe48b6SEtienne Carriere 	_CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mcuss_parents),
775d4151d2fSYann Gautier 	_CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents),
776d4151d2fSYann Gautier 	_CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents),
7777839a050SYann Gautier };
7787839a050SYann Gautier 
7797839a050SYann Gautier /* Define characteristic of PLL according type */
780f6559227SYann Gautier #define POST_DIVM_MIN	8000000U
781f6559227SYann Gautier #define POST_DIVM_MAX	16000000U
782f6559227SYann Gautier #define DIVM_MIN	0U
783f6559227SYann Gautier #define DIVM_MAX	63U
784f6559227SYann Gautier #define DIVN_MIN	24U
785f6559227SYann Gautier #define DIVN_MAX	99U
786f6559227SYann Gautier #define DIVP_MIN	0U
787f6559227SYann Gautier #define DIVP_MAX	127U
788f6559227SYann Gautier #define FRAC_MAX	8192U
789f6559227SYann Gautier #define VCO_MIN		800000000U
790f6559227SYann Gautier #define VCO_MAX		1600000000U
791f6559227SYann Gautier 
7927839a050SYann Gautier static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
7937839a050SYann Gautier 	[PLL_800] = {
7947839a050SYann Gautier 		.refclk_min = 4,
7957839a050SYann Gautier 		.refclk_max = 16,
7967839a050SYann Gautier 	},
7977839a050SYann Gautier 	[PLL_1600] = {
7987839a050SYann Gautier 		.refclk_min = 8,
7997839a050SYann Gautier 		.refclk_max = 16,
8007839a050SYann Gautier 	},
8017839a050SYann Gautier };
8027839a050SYann Gautier 
8037839a050SYann Gautier /* PLLNCFGR2 register divider by output */
8047839a050SYann Gautier static const uint8_t pllncfgr2[_DIV_NB] = {
8057839a050SYann Gautier 	[_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT,
8067839a050SYann Gautier 	[_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT,
8070d21680cSYann Gautier 	[_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT,
8087839a050SYann Gautier };
8097839a050SYann Gautier 
8107839a050SYann Gautier static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = {
8110d21680cSYann Gautier 	_CLK_PLL(_PLL1, PLL_1600,
8127839a050SYann Gautier 		 RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2,
8137839a050SYann Gautier 		 RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR,
8147839a050SYann Gautier 		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
8150d21680cSYann Gautier 	_CLK_PLL(_PLL2, PLL_1600,
8167839a050SYann Gautier 		 RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2,
8177839a050SYann Gautier 		 RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR,
8187839a050SYann Gautier 		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
8190d21680cSYann Gautier 	_CLK_PLL(_PLL3, PLL_800,
8207839a050SYann Gautier 		 RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2,
8217839a050SYann Gautier 		 RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR,
8227839a050SYann Gautier 		 _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID),
8230d21680cSYann Gautier 	_CLK_PLL(_PLL4, PLL_800,
8247839a050SYann Gautier 		 RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2,
8257839a050SYann Gautier 		 RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR,
8267839a050SYann Gautier 		 _HSI, _HSE, _CSI, _I2S_CKIN),
8277839a050SYann Gautier };
8287839a050SYann Gautier 
8297839a050SYann Gautier /* Prescaler table lookups for clock computation */
830b053a22eSYann Gautier /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */
831b053a22eSYann Gautier static const uint8_t stm32mp1_mcu_div[16] = {
832b053a22eSYann Gautier 	0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9
833b053a22eSYann Gautier };
8347839a050SYann Gautier 
8357839a050SYann Gautier /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */
8367839a050SYann Gautier #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div
8377839a050SYann Gautier #define stm32mp1_apbx_div stm32mp1_mpu_apbx_div
8387839a050SYann Gautier static const uint8_t stm32mp1_mpu_apbx_div[8] = {
8397839a050SYann Gautier 	0, 1, 2, 3, 4, 4, 4, 4
8407839a050SYann Gautier };
8417839a050SYann Gautier 
8427839a050SYann Gautier /* div = /1 /2 /3 /4 */
8437839a050SYann Gautier static const uint8_t stm32mp1_axi_div[8] = {
8447839a050SYann Gautier 	1, 2, 3, 4, 4, 4, 4, 4
8457839a050SYann Gautier };
8467839a050SYann Gautier 
84737e8295aSEtienne Carriere static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = {
84837e8295aSEtienne Carriere 	[_HSI] = "HSI",
84937e8295aSEtienne Carriere 	[_HSE] = "HSE",
85037e8295aSEtienne Carriere 	[_CSI] = "CSI",
85137e8295aSEtienne Carriere 	[_LSI] = "LSI",
85237e8295aSEtienne Carriere 	[_LSE] = "LSE",
85337e8295aSEtienne Carriere 	[_I2S_CKIN] = "I2S_CKIN",
85437e8295aSEtienne Carriere 	[_HSI_KER] = "HSI_KER",
85537e8295aSEtienne Carriere 	[_HSE_KER] = "HSE_KER",
85637e8295aSEtienne Carriere 	[_HSE_KER_DIV2] = "HSE_KER_DIV2",
857cbd2e8a6SGabriel Fernandez 	[_HSE_RTC] = "HSE_RTC",
85837e8295aSEtienne Carriere 	[_CSI_KER] = "CSI_KER",
85937e8295aSEtienne Carriere 	[_PLL1_P] = "PLL1_P",
86037e8295aSEtienne Carriere 	[_PLL1_Q] = "PLL1_Q",
86137e8295aSEtienne Carriere 	[_PLL1_R] = "PLL1_R",
86237e8295aSEtienne Carriere 	[_PLL2_P] = "PLL2_P",
86337e8295aSEtienne Carriere 	[_PLL2_Q] = "PLL2_Q",
86437e8295aSEtienne Carriere 	[_PLL2_R] = "PLL2_R",
86537e8295aSEtienne Carriere 	[_PLL3_P] = "PLL3_P",
86637e8295aSEtienne Carriere 	[_PLL3_Q] = "PLL3_Q",
86737e8295aSEtienne Carriere 	[_PLL3_R] = "PLL3_R",
86837e8295aSEtienne Carriere 	[_PLL4_P] = "PLL4_P",
86937e8295aSEtienne Carriere 	[_PLL4_Q] = "PLL4_Q",
87037e8295aSEtienne Carriere 	[_PLL4_R] = "PLL4_R",
87137e8295aSEtienne Carriere 	[_ACLK] = "ACLK",
87237e8295aSEtienne Carriere 	[_PCLK1] = "PCLK1",
87337e8295aSEtienne Carriere 	[_PCLK2] = "PCLK2",
87437e8295aSEtienne Carriere 	[_PCLK3] = "PCLK3",
87537e8295aSEtienne Carriere 	[_PCLK4] = "PCLK4",
87637e8295aSEtienne Carriere 	[_PCLK5] = "PCLK5",
87737e8295aSEtienne Carriere 	[_HCLK6] = "KCLK6",
87837e8295aSEtienne Carriere 	[_HCLK2] = "HCLK2",
87937e8295aSEtienne Carriere 	[_CK_PER] = "CK_PER",
88037e8295aSEtienne Carriere 	[_CK_MPU] = "CK_MPU",
88137e8295aSEtienne Carriere 	[_CK_MCU] = "CK_MCU",
88237e8295aSEtienne Carriere 	[_USB_PHY_48] = "USB_PHY_48",
88337e8295aSEtienne Carriere };
88437e8295aSEtienne Carriere 
8850d21680cSYann Gautier /* RCC clock device driver private */
8860d21680cSYann Gautier static unsigned long stm32mp1_osc[NB_OSC];
8870d21680cSYann Gautier static struct spinlock reg_lock;
8880d21680cSYann Gautier static unsigned int gate_refcounts[NB_GATES];
8890d21680cSYann Gautier static struct spinlock refcount_lock;
8907839a050SYann Gautier 
8910d21680cSYann Gautier static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx)
8920d21680cSYann Gautier {
8930d21680cSYann Gautier 	return &stm32mp1_clk_gate[idx];
8940d21680cSYann Gautier }
8957839a050SYann Gautier 
8963d69149aSYann Gautier #if defined(IMAGE_BL32)
8973d69149aSYann Gautier static bool gate_is_non_secure(const struct stm32mp1_clk_gate *gate)
8983d69149aSYann Gautier {
8993d69149aSYann Gautier 	return gate->secure == N_S;
9003d69149aSYann Gautier }
9013d69149aSYann Gautier #endif
9023d69149aSYann Gautier 
9030d21680cSYann Gautier static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx)
9040d21680cSYann Gautier {
9050d21680cSYann Gautier 	return &stm32mp1_clk_sel[idx];
9060d21680cSYann Gautier }
9070d21680cSYann Gautier 
9080d21680cSYann Gautier static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx)
9090d21680cSYann Gautier {
9100d21680cSYann Gautier 	return &stm32mp1_clk_pll[idx];
9110d21680cSYann Gautier }
9120d21680cSYann Gautier 
9130d21680cSYann Gautier static void stm32mp1_clk_lock(struct spinlock *lock)
9140d21680cSYann Gautier {
915e463d3f4SYann Gautier 	if (stm32mp_lock_available()) {
9160d21680cSYann Gautier 		/* Assume interrupts are masked */
9170d21680cSYann Gautier 		spin_lock(lock);
9180d21680cSYann Gautier 	}
919e463d3f4SYann Gautier }
9200d21680cSYann Gautier 
9210d21680cSYann Gautier static void stm32mp1_clk_unlock(struct spinlock *lock)
9220d21680cSYann Gautier {
923e463d3f4SYann Gautier 	if (stm32mp_lock_available()) {
9240d21680cSYann Gautier 		spin_unlock(lock);
9250d21680cSYann Gautier 	}
926e463d3f4SYann Gautier }
9270d21680cSYann Gautier 
9280d21680cSYann Gautier bool stm32mp1_rcc_is_secure(void)
9290d21680cSYann Gautier {
9300d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
9311bb9072aSEtienne Carriere 	uint32_t mask = RCC_TZCR_TZEN;
9320d21680cSYann Gautier 
9331bb9072aSEtienne Carriere 	return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
9340d21680cSYann Gautier }
9350d21680cSYann Gautier 
936b053a22eSYann Gautier bool stm32mp1_rcc_is_mckprot(void)
937b053a22eSYann Gautier {
938b053a22eSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
9391bb9072aSEtienne Carriere 	uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT;
940b053a22eSYann Gautier 
9411bb9072aSEtienne Carriere 	return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
942b053a22eSYann Gautier }
943b053a22eSYann Gautier 
9440d21680cSYann Gautier void stm32mp1_clk_rcc_regs_lock(void)
9450d21680cSYann Gautier {
9460d21680cSYann Gautier 	stm32mp1_clk_lock(&reg_lock);
9470d21680cSYann Gautier }
9480d21680cSYann Gautier 
9490d21680cSYann Gautier void stm32mp1_clk_rcc_regs_unlock(void)
9500d21680cSYann Gautier {
9510d21680cSYann Gautier 	stm32mp1_clk_unlock(&reg_lock);
9520d21680cSYann Gautier }
9530d21680cSYann Gautier 
9540d21680cSYann Gautier static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx)
9557839a050SYann Gautier {
9567839a050SYann Gautier 	if (idx >= NB_OSC) {
9577839a050SYann Gautier 		return 0;
9587839a050SYann Gautier 	}
9597839a050SYann Gautier 
9600d21680cSYann Gautier 	return stm32mp1_osc[idx];
9617839a050SYann Gautier }
9627839a050SYann Gautier 
9630d21680cSYann Gautier static int stm32mp1_clk_get_gated_id(unsigned long id)
9647839a050SYann Gautier {
9650d21680cSYann Gautier 	unsigned int i;
9667839a050SYann Gautier 
9670d21680cSYann Gautier 	for (i = 0U; i < NB_GATES; i++) {
9680d21680cSYann Gautier 		if (gate_ref(i)->index == id) {
9697839a050SYann Gautier 			return i;
9707839a050SYann Gautier 		}
9717839a050SYann Gautier 	}
9727839a050SYann Gautier 
97344fb470bSYann Gautier 	ERROR("%s: clk id %lu not found\n", __func__, id);
9747839a050SYann Gautier 
9757839a050SYann Gautier 	return -EINVAL;
9767839a050SYann Gautier }
9777839a050SYann Gautier 
9780d21680cSYann Gautier static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i)
9797839a050SYann Gautier {
9800d21680cSYann Gautier 	return (enum stm32mp1_parent_sel)(gate_ref(i)->sel);
9817839a050SYann Gautier }
9827839a050SYann Gautier 
9830d21680cSYann Gautier static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i)
9847839a050SYann Gautier {
9850d21680cSYann Gautier 	return (enum stm32mp1_parent_id)(gate_ref(i)->fixed);
9867839a050SYann Gautier }
9877839a050SYann Gautier 
9880d21680cSYann Gautier static int stm32mp1_clk_get_parent(unsigned long id)
9897839a050SYann Gautier {
9900d21680cSYann Gautier 	const struct stm32mp1_clk_sel *sel;
9918fbcd9e4SEtienne Carriere 	uint32_t p_sel;
9927839a050SYann Gautier 	int i;
9937839a050SYann Gautier 	enum stm32mp1_parent_id p;
9947839a050SYann Gautier 	enum stm32mp1_parent_sel s;
9950d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
9967839a050SYann Gautier 
9978fbcd9e4SEtienne Carriere 	/* Few non gateable clock have a static parent ID, find them */
9988fbcd9e4SEtienne Carriere 	i = (int)clock_id2parent_id(id);
9998fbcd9e4SEtienne Carriere 	if (i != _UNKNOWN_ID) {
10008fbcd9e4SEtienne Carriere 		return i;
10017839a050SYann Gautier 	}
10027839a050SYann Gautier 
10030d21680cSYann Gautier 	i = stm32mp1_clk_get_gated_id(id);
10047839a050SYann Gautier 	if (i < 0) {
10050d21680cSYann Gautier 		panic();
10067839a050SYann Gautier 	}
10077839a050SYann Gautier 
10080d21680cSYann Gautier 	p = stm32mp1_clk_get_fixed_parent(i);
10097839a050SYann Gautier 	if (p < _PARENT_NB) {
10107839a050SYann Gautier 		return (int)p;
10117839a050SYann Gautier 	}
10127839a050SYann Gautier 
10130d21680cSYann Gautier 	s = stm32mp1_clk_get_sel(i);
10140d21680cSYann Gautier 	if (s == _UNKNOWN_SEL) {
10150d21680cSYann Gautier 		return -EINVAL;
10160d21680cSYann Gautier 	}
10177839a050SYann Gautier 	if (s >= _PARENT_SEL_NB) {
10180d21680cSYann Gautier 		panic();
10197839a050SYann Gautier 	}
10207839a050SYann Gautier 
10210d21680cSYann Gautier 	sel = clk_sel_ref(s);
10228ae08dcdSEtienne Carriere 	p_sel = (mmio_read_32(rcc_base + sel->offset) &
10238ae08dcdSEtienne Carriere 		 (sel->msk << sel->src)) >> sel->src;
10240d21680cSYann Gautier 	if (p_sel < sel->nb_parent) {
10250d21680cSYann Gautier 		return (int)sel->parent[p_sel];
10267839a050SYann Gautier 	}
10277839a050SYann Gautier 
10287839a050SYann Gautier 	return -EINVAL;
10297839a050SYann Gautier }
10307839a050SYann Gautier 
10310d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll)
10327839a050SYann Gautier {
10330d21680cSYann Gautier 	uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr);
10340d21680cSYann Gautier 	uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK;
10357839a050SYann Gautier 
10360d21680cSYann Gautier 	return stm32mp1_clk_get_fixed(pll->refclk[src]);
10377839a050SYann Gautier }
10387839a050SYann Gautier 
10397839a050SYann Gautier /*
10407839a050SYann Gautier  * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL
10417839a050SYann Gautier  * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1)
10427839a050SYann Gautier  * - PLL3 & PLL4 => return VCO     with Fpll_y_ck = FVCO / (DIVy + 1)
10437839a050SYann Gautier  * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1)
10447839a050SYann Gautier  */
10450d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll)
10467839a050SYann Gautier {
10477839a050SYann Gautier 	unsigned long refclk, fvco;
10487839a050SYann Gautier 	uint32_t cfgr1, fracr, divm, divn;
10490d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
10507839a050SYann Gautier 
10510d21680cSYann Gautier 	cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1);
10520d21680cSYann Gautier 	fracr = mmio_read_32(rcc_base + pll->pllxfracr);
10537839a050SYann Gautier 
10547839a050SYann Gautier 	divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT;
10557839a050SYann Gautier 	divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK;
10567839a050SYann Gautier 
10570d21680cSYann Gautier 	refclk = stm32mp1_pll_get_fref(pll);
10587839a050SYann Gautier 
10597839a050SYann Gautier 	/*
10607839a050SYann Gautier 	 * With FRACV :
10617839a050SYann Gautier 	 *   Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1)
10627839a050SYann Gautier 	 * Without FRACV
10637839a050SYann Gautier 	 *   Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1)
10647839a050SYann Gautier 	 */
10657839a050SYann Gautier 	if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) {
10660d21680cSYann Gautier 		uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >>
10670d21680cSYann Gautier 				 RCC_PLLNFRACR_FRACV_SHIFT;
10687839a050SYann Gautier 		unsigned long long numerator, denominator;
10697839a050SYann Gautier 
10700d21680cSYann Gautier 		numerator = (((unsigned long long)divn + 1U) << 13) + fracv;
10710d21680cSYann Gautier 		numerator = refclk * numerator;
10727839a050SYann Gautier 		denominator = ((unsigned long long)divm + 1U) << 13;
10737839a050SYann Gautier 		fvco = (unsigned long)(numerator / denominator);
10747839a050SYann Gautier 	} else {
10757839a050SYann Gautier 		fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U));
10767839a050SYann Gautier 	}
10777839a050SYann Gautier 
10787839a050SYann Gautier 	return fvco;
10797839a050SYann Gautier }
10807839a050SYann Gautier 
10810d21680cSYann Gautier static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id,
10827839a050SYann Gautier 					    enum stm32mp1_div_id div_id)
10837839a050SYann Gautier {
10840d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
10857839a050SYann Gautier 	unsigned long dfout;
10867839a050SYann Gautier 	uint32_t cfgr2, divy;
10877839a050SYann Gautier 
10887839a050SYann Gautier 	if (div_id >= _DIV_NB) {
10897839a050SYann Gautier 		return 0;
10907839a050SYann Gautier 	}
10917839a050SYann Gautier 
10920d21680cSYann Gautier 	cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2);
10937839a050SYann Gautier 	divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK;
10947839a050SYann Gautier 
10950d21680cSYann Gautier 	dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U);
10967839a050SYann Gautier 
10977839a050SYann Gautier 	return dfout;
10987839a050SYann Gautier }
10997839a050SYann Gautier 
11000d21680cSYann Gautier static unsigned long get_clock_rate(int p)
11017839a050SYann Gautier {
11027839a050SYann Gautier 	uint32_t reg, clkdiv;
11037839a050SYann Gautier 	unsigned long clock = 0;
11040d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
11057839a050SYann Gautier 
11067839a050SYann Gautier 	switch (p) {
11077839a050SYann Gautier 	case _CK_MPU:
11087839a050SYann Gautier 	/* MPU sub system */
11090d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MPCKSELR);
11107839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
11117839a050SYann Gautier 		case RCC_MPCKSELR_HSI:
11120d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
11137839a050SYann Gautier 			break;
11147839a050SYann Gautier 		case RCC_MPCKSELR_HSE:
11150d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
11167839a050SYann Gautier 			break;
11177839a050SYann Gautier 		case RCC_MPCKSELR_PLL:
11180d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
11197839a050SYann Gautier 			break;
11207839a050SYann Gautier 		case RCC_MPCKSELR_PLL_MPUDIV:
11210d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
11227839a050SYann Gautier 
11230d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_MPCKDIVR);
11247839a050SYann Gautier 			clkdiv = reg & RCC_MPUDIV_MASK;
1125602ae2f2SGabriel Fernandez 			clock >>= stm32mp1_mpu_div[clkdiv];
11267839a050SYann Gautier 			break;
11277839a050SYann Gautier 		default:
11287839a050SYann Gautier 			break;
11297839a050SYann Gautier 		}
11307839a050SYann Gautier 		break;
11317839a050SYann Gautier 	/* AXI sub system */
11327839a050SYann Gautier 	case _ACLK:
11337839a050SYann Gautier 	case _HCLK2:
11347839a050SYann Gautier 	case _HCLK6:
11357839a050SYann Gautier 	case _PCLK4:
11367839a050SYann Gautier 	case _PCLK5:
11370d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_ASSCKSELR);
11387839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
11397839a050SYann Gautier 		case RCC_ASSCKSELR_HSI:
11400d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
11417839a050SYann Gautier 			break;
11427839a050SYann Gautier 		case RCC_ASSCKSELR_HSE:
11430d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
11447839a050SYann Gautier 			break;
11457839a050SYann Gautier 		case RCC_ASSCKSELR_PLL:
11460d21680cSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
11477839a050SYann Gautier 			break;
11487839a050SYann Gautier 		default:
11497839a050SYann Gautier 			break;
11507839a050SYann Gautier 		}
11517839a050SYann Gautier 
11527839a050SYann Gautier 		/* System clock divider */
11530d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_AXIDIVR);
11547839a050SYann Gautier 		clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK];
11557839a050SYann Gautier 
11567839a050SYann Gautier 		switch (p) {
11577839a050SYann Gautier 		case _PCLK4:
11580d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB4DIVR);
11597839a050SYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
11607839a050SYann Gautier 			break;
11617839a050SYann Gautier 		case _PCLK5:
11620d21680cSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB5DIVR);
11637839a050SYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
11647839a050SYann Gautier 			break;
11657839a050SYann Gautier 		default:
11667839a050SYann Gautier 			break;
11677839a050SYann Gautier 		}
11687839a050SYann Gautier 		break;
1169b053a22eSYann Gautier 	/* MCU sub system */
1170b053a22eSYann Gautier 	case _CK_MCU:
1171b053a22eSYann Gautier 	case _PCLK1:
1172b053a22eSYann Gautier 	case _PCLK2:
1173b053a22eSYann Gautier 	case _PCLK3:
1174b053a22eSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MSSCKSELR);
1175b053a22eSYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
1176b053a22eSYann Gautier 		case RCC_MSSCKSELR_HSI:
1177b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
1178b053a22eSYann Gautier 			break;
1179b053a22eSYann Gautier 		case RCC_MSSCKSELR_HSE:
1180b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
1181b053a22eSYann Gautier 			break;
1182b053a22eSYann Gautier 		case RCC_MSSCKSELR_CSI:
1183b053a22eSYann Gautier 			clock = stm32mp1_clk_get_fixed(_CSI);
1184b053a22eSYann Gautier 			break;
1185b053a22eSYann Gautier 		case RCC_MSSCKSELR_PLL:
1186b053a22eSYann Gautier 			clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
1187b053a22eSYann Gautier 			break;
1188b053a22eSYann Gautier 		default:
1189b053a22eSYann Gautier 			break;
1190b053a22eSYann Gautier 		}
1191b053a22eSYann Gautier 
1192b053a22eSYann Gautier 		/* MCU clock divider */
1193b053a22eSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_MCUDIVR);
1194b053a22eSYann Gautier 		clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK];
1195b053a22eSYann Gautier 
1196b053a22eSYann Gautier 		switch (p) {
1197b053a22eSYann Gautier 		case _PCLK1:
1198b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB1DIVR);
1199b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
1200b053a22eSYann Gautier 			break;
1201b053a22eSYann Gautier 		case _PCLK2:
1202b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB2DIVR);
1203b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
1204b053a22eSYann Gautier 			break;
1205b053a22eSYann Gautier 		case _PCLK3:
1206b053a22eSYann Gautier 			reg = mmio_read_32(rcc_base + RCC_APB3DIVR);
1207b053a22eSYann Gautier 			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
1208b053a22eSYann Gautier 			break;
1209b053a22eSYann Gautier 		case _CK_MCU:
1210b053a22eSYann Gautier 		default:
1211b053a22eSYann Gautier 			break;
1212b053a22eSYann Gautier 		}
1213b053a22eSYann Gautier 		break;
12147839a050SYann Gautier 	case _CK_PER:
12150d21680cSYann Gautier 		reg = mmio_read_32(rcc_base + RCC_CPERCKSELR);
12167839a050SYann Gautier 		switch (reg & RCC_SELR_SRC_MASK) {
12177839a050SYann Gautier 		case RCC_CPERCKSELR_HSI:
12180d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSI);
12197839a050SYann Gautier 			break;
12207839a050SYann Gautier 		case RCC_CPERCKSELR_HSE:
12210d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_HSE);
12227839a050SYann Gautier 			break;
12237839a050SYann Gautier 		case RCC_CPERCKSELR_CSI:
12240d21680cSYann Gautier 			clock = stm32mp1_clk_get_fixed(_CSI);
12257839a050SYann Gautier 			break;
12267839a050SYann Gautier 		default:
12277839a050SYann Gautier 			break;
12287839a050SYann Gautier 		}
12297839a050SYann Gautier 		break;
12307839a050SYann Gautier 	case _HSI:
12317839a050SYann Gautier 	case _HSI_KER:
12320d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSI);
12337839a050SYann Gautier 		break;
12347839a050SYann Gautier 	case _CSI:
12357839a050SYann Gautier 	case _CSI_KER:
12360d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_CSI);
12377839a050SYann Gautier 		break;
12387839a050SYann Gautier 	case _HSE:
12397839a050SYann Gautier 	case _HSE_KER:
12400d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSE);
12417839a050SYann Gautier 		break;
12427839a050SYann Gautier 	case _HSE_KER_DIV2:
12430d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_HSE) >> 1;
12447839a050SYann Gautier 		break;
1245cbd2e8a6SGabriel Fernandez 	case _HSE_RTC:
1246cbd2e8a6SGabriel Fernandez 		clock = stm32mp1_clk_get_fixed(_HSE);
1247cbd2e8a6SGabriel Fernandez 		clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U;
1248cbd2e8a6SGabriel Fernandez 		break;
12497839a050SYann Gautier 	case _LSI:
12500d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_LSI);
12517839a050SYann Gautier 		break;
12527839a050SYann Gautier 	case _LSE:
12530d21680cSYann Gautier 		clock = stm32mp1_clk_get_fixed(_LSE);
12547839a050SYann Gautier 		break;
12557839a050SYann Gautier 	/* PLL */
12567839a050SYann Gautier 	case _PLL1_P:
12570d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
12587839a050SYann Gautier 		break;
12597839a050SYann Gautier 	case _PLL1_Q:
12600d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q);
12617839a050SYann Gautier 		break;
12627839a050SYann Gautier 	case _PLL1_R:
12630d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R);
12647839a050SYann Gautier 		break;
12657839a050SYann Gautier 	case _PLL2_P:
12660d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
12677839a050SYann Gautier 		break;
12687839a050SYann Gautier 	case _PLL2_Q:
12690d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q);
12707839a050SYann Gautier 		break;
12717839a050SYann Gautier 	case _PLL2_R:
12720d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R);
12737839a050SYann Gautier 		break;
12747839a050SYann Gautier 	case _PLL3_P:
12750d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
12767839a050SYann Gautier 		break;
12777839a050SYann Gautier 	case _PLL3_Q:
12780d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q);
12797839a050SYann Gautier 		break;
12807839a050SYann Gautier 	case _PLL3_R:
12810d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R);
12827839a050SYann Gautier 		break;
12837839a050SYann Gautier 	case _PLL4_P:
12840d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P);
12857839a050SYann Gautier 		break;
12867839a050SYann Gautier 	case _PLL4_Q:
12870d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q);
12887839a050SYann Gautier 		break;
12897839a050SYann Gautier 	case _PLL4_R:
12900d21680cSYann Gautier 		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R);
12917839a050SYann Gautier 		break;
12927839a050SYann Gautier 	/* Other */
12937839a050SYann Gautier 	case _USB_PHY_48:
12940d21680cSYann Gautier 		clock = USB_PHY_48_MHZ;
12957839a050SYann Gautier 		break;
12967839a050SYann Gautier 	default:
12977839a050SYann Gautier 		break;
12987839a050SYann Gautier 	}
12997839a050SYann Gautier 
13007839a050SYann Gautier 	return clock;
13017839a050SYann Gautier }
13027839a050SYann Gautier 
13030d21680cSYann Gautier static void __clk_enable(struct stm32mp1_clk_gate const *gate)
13040d21680cSYann Gautier {
13050d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13060d21680cSYann Gautier 
130725be845eSEtienne Carriere 	VERBOSE("Enable clock %u\n", gate->index);
130825be845eSEtienne Carriere 
13090d21680cSYann Gautier 	if (gate->set_clr != 0U) {
13100d21680cSYann Gautier 		mmio_write_32(rcc_base + gate->offset, BIT(gate->bit));
13110d21680cSYann Gautier 	} else {
13120d21680cSYann Gautier 		mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit));
13130d21680cSYann Gautier 	}
13140d21680cSYann Gautier }
13150d21680cSYann Gautier 
13160d21680cSYann Gautier static void __clk_disable(struct stm32mp1_clk_gate const *gate)
13170d21680cSYann Gautier {
13180d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13190d21680cSYann Gautier 
132025be845eSEtienne Carriere 	VERBOSE("Disable clock %u\n", gate->index);
132125be845eSEtienne Carriere 
13220d21680cSYann Gautier 	if (gate->set_clr != 0U) {
13230d21680cSYann Gautier 		mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET,
13240d21680cSYann Gautier 			      BIT(gate->bit));
13250d21680cSYann Gautier 	} else {
13260d21680cSYann Gautier 		mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit));
13270d21680cSYann Gautier 	}
13280d21680cSYann Gautier }
13290d21680cSYann Gautier 
13300d21680cSYann Gautier static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate)
13310d21680cSYann Gautier {
13320d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
13330d21680cSYann Gautier 
13340d21680cSYann Gautier 	return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit);
13350d21680cSYann Gautier }
13360d21680cSYann Gautier 
133735848200SEtienne Carriere /* Oscillators and PLLs are not gated at runtime */
133835848200SEtienne Carriere static bool clock_is_always_on(unsigned long id)
133935848200SEtienne Carriere {
134035848200SEtienne Carriere 	switch (id) {
134135848200SEtienne Carriere 	case CK_HSE:
134235848200SEtienne Carriere 	case CK_CSI:
134335848200SEtienne Carriere 	case CK_LSI:
134435848200SEtienne Carriere 	case CK_LSE:
134535848200SEtienne Carriere 	case CK_HSI:
134635848200SEtienne Carriere 	case CK_HSE_DIV2:
134735848200SEtienne Carriere 	case PLL1_Q:
134835848200SEtienne Carriere 	case PLL1_R:
134935848200SEtienne Carriere 	case PLL2_P:
135035848200SEtienne Carriere 	case PLL2_Q:
135135848200SEtienne Carriere 	case PLL2_R:
135235848200SEtienne Carriere 	case PLL3_P:
135335848200SEtienne Carriere 	case PLL3_Q:
135435848200SEtienne Carriere 	case PLL3_R:
1355bf39318dSYann Gautier 	case CK_AXI:
1356bf39318dSYann Gautier 	case CK_MPU:
1357bf39318dSYann Gautier 	case CK_MCU:
13585b111c74SHE Shushan 	case RTC:
135935848200SEtienne Carriere 		return true;
136035848200SEtienne Carriere 	default:
136135848200SEtienne Carriere 		return false;
136235848200SEtienne Carriere 	}
136335848200SEtienne Carriere }
136435848200SEtienne Carriere 
13652444d231SYann Gautier static void __stm32mp1_clk_enable(unsigned long id, bool with_refcnt)
13660d21680cSYann Gautier {
13670d21680cSYann Gautier 	const struct stm32mp1_clk_gate *gate;
136835848200SEtienne Carriere 	int i;
13690d21680cSYann Gautier 
137035848200SEtienne Carriere 	if (clock_is_always_on(id)) {
137135848200SEtienne Carriere 		return;
137235848200SEtienne Carriere 	}
137335848200SEtienne Carriere 
137435848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
13750d21680cSYann Gautier 	if (i < 0) {
137644fb470bSYann Gautier 		ERROR("Clock %lu can't be enabled\n", id);
13770d21680cSYann Gautier 		panic();
13780d21680cSYann Gautier 	}
13790d21680cSYann Gautier 
13800d21680cSYann Gautier 	gate = gate_ref(i);
13812444d231SYann Gautier 
13822444d231SYann Gautier 	if (!with_refcnt) {
13832444d231SYann Gautier 		__clk_enable(gate);
13842444d231SYann Gautier 		return;
13852444d231SYann Gautier 	}
13860d21680cSYann Gautier 
13873d69149aSYann Gautier #if defined(IMAGE_BL32)
13883d69149aSYann Gautier 	if (gate_is_non_secure(gate)) {
13893d69149aSYann Gautier 		/* Enable non-secure clock w/o any refcounting */
13903d69149aSYann Gautier 		__clk_enable(gate);
13913d69149aSYann Gautier 		return;
13923d69149aSYann Gautier 	}
13933d69149aSYann Gautier #endif
13943d69149aSYann Gautier 
13950d21680cSYann Gautier 	stm32mp1_clk_lock(&refcount_lock);
13960d21680cSYann Gautier 
13972444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
13980d21680cSYann Gautier 		__clk_enable(gate);
13990d21680cSYann Gautier 	}
14000d21680cSYann Gautier 
14012444d231SYann Gautier 	gate_refcounts[i]++;
14022444d231SYann Gautier 	if (gate_refcounts[i] == UINT_MAX) {
14032444d231SYann Gautier 		ERROR("Clock %lu refcount reached max value\n", id);
14042444d231SYann Gautier 		panic();
14052444d231SYann Gautier 	}
14062444d231SYann Gautier 
14070d21680cSYann Gautier 	stm32mp1_clk_unlock(&refcount_lock);
14080d21680cSYann Gautier }
14090d21680cSYann Gautier 
14102444d231SYann Gautier static void __stm32mp1_clk_disable(unsigned long id, bool with_refcnt)
14110d21680cSYann Gautier {
14120d21680cSYann Gautier 	const struct stm32mp1_clk_gate *gate;
141335848200SEtienne Carriere 	int i;
14140d21680cSYann Gautier 
141535848200SEtienne Carriere 	if (clock_is_always_on(id)) {
141635848200SEtienne Carriere 		return;
141735848200SEtienne Carriere 	}
141835848200SEtienne Carriere 
141935848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
14200d21680cSYann Gautier 	if (i < 0) {
142144fb470bSYann Gautier 		ERROR("Clock %lu can't be disabled\n", id);
14220d21680cSYann Gautier 		panic();
14230d21680cSYann Gautier 	}
14240d21680cSYann Gautier 
14250d21680cSYann Gautier 	gate = gate_ref(i);
14262444d231SYann Gautier 
14272444d231SYann Gautier 	if (!with_refcnt) {
14282444d231SYann Gautier 		__clk_disable(gate);
14292444d231SYann Gautier 		return;
14302444d231SYann Gautier 	}
14310d21680cSYann Gautier 
14323d69149aSYann Gautier #if defined(IMAGE_BL32)
14333d69149aSYann Gautier 	if (gate_is_non_secure(gate)) {
14343d69149aSYann Gautier 		/* Don't disable non-secure clocks */
14353d69149aSYann Gautier 		return;
14363d69149aSYann Gautier 	}
14373d69149aSYann Gautier #endif
14383d69149aSYann Gautier 
14390d21680cSYann Gautier 	stm32mp1_clk_lock(&refcount_lock);
14400d21680cSYann Gautier 
14412444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
14422444d231SYann Gautier 		ERROR("Clock %lu refcount reached 0\n", id);
14432444d231SYann Gautier 		panic();
14442444d231SYann Gautier 	}
14452444d231SYann Gautier 	gate_refcounts[i]--;
14462444d231SYann Gautier 
14472444d231SYann Gautier 	if (gate_refcounts[i] == 0U) {
14480d21680cSYann Gautier 		__clk_disable(gate);
14490d21680cSYann Gautier 	}
14500d21680cSYann Gautier 
14510d21680cSYann Gautier 	stm32mp1_clk_unlock(&refcount_lock);
14520d21680cSYann Gautier }
14530d21680cSYann Gautier 
145433667d29SYann Gautier static int stm32mp_clk_enable(unsigned long id)
14550d21680cSYann Gautier {
14560d21680cSYann Gautier 	__stm32mp1_clk_enable(id, true);
145733667d29SYann Gautier 
145833667d29SYann Gautier 	return 0;
14590d21680cSYann Gautier }
14600d21680cSYann Gautier 
146133667d29SYann Gautier static void stm32mp_clk_disable(unsigned long id)
14620d21680cSYann Gautier {
14630d21680cSYann Gautier 	__stm32mp1_clk_disable(id, true);
14640d21680cSYann Gautier }
14650d21680cSYann Gautier 
146633667d29SYann Gautier static bool stm32mp_clk_is_enabled(unsigned long id)
14677839a050SYann Gautier {
146835848200SEtienne Carriere 	int i;
14697839a050SYann Gautier 
147035848200SEtienne Carriere 	if (clock_is_always_on(id)) {
147135848200SEtienne Carriere 		return true;
147235848200SEtienne Carriere 	}
147335848200SEtienne Carriere 
147435848200SEtienne Carriere 	i = stm32mp1_clk_get_gated_id(id);
14757839a050SYann Gautier 	if (i < 0) {
14760d21680cSYann Gautier 		panic();
14777839a050SYann Gautier 	}
14787839a050SYann Gautier 
14790d21680cSYann Gautier 	return __clk_is_enabled(gate_ref(i));
14807839a050SYann Gautier }
14817839a050SYann Gautier 
148233667d29SYann Gautier static unsigned long stm32mp_clk_get_rate(unsigned long id)
14837839a050SYann Gautier {
148433667d29SYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
14850d21680cSYann Gautier 	int p = stm32mp1_clk_get_parent(id);
148633667d29SYann Gautier 	uint32_t prescaler, timpre;
148733667d29SYann Gautier 	unsigned long parent_rate;
14887839a050SYann Gautier 
14897839a050SYann Gautier 	if (p < 0) {
14907839a050SYann Gautier 		return 0;
14917839a050SYann Gautier 	}
14927839a050SYann Gautier 
149333667d29SYann Gautier 	parent_rate = get_clock_rate(p);
149433667d29SYann Gautier 
149533667d29SYann Gautier 	switch (id) {
149633667d29SYann Gautier 	case TIM2_K:
149733667d29SYann Gautier 	case TIM3_K:
149833667d29SYann Gautier 	case TIM4_K:
149933667d29SYann Gautier 	case TIM5_K:
150033667d29SYann Gautier 	case TIM6_K:
150133667d29SYann Gautier 	case TIM7_K:
150233667d29SYann Gautier 	case TIM12_K:
150333667d29SYann Gautier 	case TIM13_K:
150433667d29SYann Gautier 	case TIM14_K:
150533667d29SYann Gautier 		prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) &
150633667d29SYann Gautier 			    RCC_APBXDIV_MASK;
150733667d29SYann Gautier 		timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) &
150833667d29SYann Gautier 			 RCC_TIMGXPRER_TIMGXPRE;
150933667d29SYann Gautier 		break;
151033667d29SYann Gautier 
151133667d29SYann Gautier 	case TIM1_K:
151233667d29SYann Gautier 	case TIM8_K:
151333667d29SYann Gautier 	case TIM15_K:
151433667d29SYann Gautier 	case TIM16_K:
151533667d29SYann Gautier 	case TIM17_K:
151633667d29SYann Gautier 		prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) &
151733667d29SYann Gautier 			    RCC_APBXDIV_MASK;
151833667d29SYann Gautier 		timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) &
151933667d29SYann Gautier 			 RCC_TIMGXPRER_TIMGXPRE;
152033667d29SYann Gautier 		break;
152133667d29SYann Gautier 
152233667d29SYann Gautier 	default:
152333667d29SYann Gautier 		return parent_rate;
152433667d29SYann Gautier 	}
152533667d29SYann Gautier 
152633667d29SYann Gautier 	if (prescaler == 0U) {
152733667d29SYann Gautier 		return parent_rate;
152833667d29SYann Gautier 	}
152933667d29SYann Gautier 
153033667d29SYann Gautier 	return parent_rate * (timpre + 1U) * 2U;
15317839a050SYann Gautier }
15327839a050SYann Gautier 
15330d21680cSYann Gautier static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on)
15347839a050SYann Gautier {
15350d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
15367839a050SYann Gautier 
15370d21680cSYann Gautier 	if (enable) {
15387839a050SYann Gautier 		mmio_setbits_32(address, mask_on);
15397839a050SYann Gautier 	} else {
15407839a050SYann Gautier 		mmio_clrbits_32(address, mask_on);
15417839a050SYann Gautier 	}
15427839a050SYann Gautier }
15437839a050SYann Gautier 
15440d21680cSYann Gautier static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on)
15457839a050SYann Gautier {
15460d21680cSYann Gautier 	uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR;
15470d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
15480d21680cSYann Gautier 
15490d21680cSYann Gautier 	mmio_write_32(address, mask_on);
15507839a050SYann Gautier }
15517839a050SYann Gautier 
15520d21680cSYann Gautier static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy)
15537839a050SYann Gautier {
1554dfdb057aSYann Gautier 	uint64_t timeout;
15557839a050SYann Gautier 	uint32_t mask_test;
15560d21680cSYann Gautier 	uintptr_t address = stm32mp_rcc_base() + offset;
15577839a050SYann Gautier 
15580d21680cSYann Gautier 	if (enable) {
15597839a050SYann Gautier 		mask_test = mask_rdy;
15607839a050SYann Gautier 	} else {
15617839a050SYann Gautier 		mask_test = 0;
15627839a050SYann Gautier 	}
15637839a050SYann Gautier 
1564dfdb057aSYann Gautier 	timeout = timeout_init_us(OSCRDY_TIMEOUT);
15657839a050SYann Gautier 	while ((mmio_read_32(address) & mask_rdy) != mask_test) {
1566dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
15670d21680cSYann Gautier 			ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n",
15687839a050SYann Gautier 			      mask_rdy, address, enable, mmio_read_32(address));
15697839a050SYann Gautier 			return -ETIMEDOUT;
15707839a050SYann Gautier 		}
15717839a050SYann Gautier 	}
15727839a050SYann Gautier 
15737839a050SYann Gautier 	return 0;
15747839a050SYann Gautier }
15757839a050SYann Gautier 
15760d21680cSYann Gautier static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv)
15777839a050SYann Gautier {
15787839a050SYann Gautier 	uint32_t value;
15790d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
15807839a050SYann Gautier 
1581f4a2bb98SYann Gautier 	/* Do not reconfigure LSE if it is already ON */
1582f4a2bb98SYann Gautier 	if ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEON) == RCC_BDCR_LSEON) {
1583f4a2bb98SYann Gautier 		return;
1584f4a2bb98SYann Gautier 	}
1585f4a2bb98SYann Gautier 
15860d21680cSYann Gautier 	if (digbyp) {
15870d21680cSYann Gautier 		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP);
15880d21680cSYann Gautier 	}
15890d21680cSYann Gautier 
15900d21680cSYann Gautier 	if (bypass || digbyp) {
15910d21680cSYann Gautier 		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP);
15927839a050SYann Gautier 	}
15937839a050SYann Gautier 
15947839a050SYann Gautier 	/*
15957839a050SYann Gautier 	 * Warning: not recommended to switch directly from "high drive"
15967839a050SYann Gautier 	 * to "medium low drive", and vice-versa.
15977839a050SYann Gautier 	 */
15980d21680cSYann Gautier 	value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >>
15997839a050SYann Gautier 		RCC_BDCR_LSEDRV_SHIFT;
16007839a050SYann Gautier 
16017839a050SYann Gautier 	while (value != lsedrv) {
16027839a050SYann Gautier 		if (value > lsedrv) {
16037839a050SYann Gautier 			value--;
16047839a050SYann Gautier 		} else {
16057839a050SYann Gautier 			value++;
16067839a050SYann Gautier 		}
16077839a050SYann Gautier 
16080d21680cSYann Gautier 		mmio_clrsetbits_32(rcc_base + RCC_BDCR,
16097839a050SYann Gautier 				   RCC_BDCR_LSEDRV_MASK,
16107839a050SYann Gautier 				   value << RCC_BDCR_LSEDRV_SHIFT);
16117839a050SYann Gautier 	}
16127839a050SYann Gautier 
16130d21680cSYann Gautier 	stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON);
16147839a050SYann Gautier }
16157839a050SYann Gautier 
16160d21680cSYann Gautier static void stm32mp1_lse_wait(void)
16177839a050SYann Gautier {
16180d21680cSYann Gautier 	if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) {
16197839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
16207839a050SYann Gautier 	}
16217839a050SYann Gautier }
16227839a050SYann Gautier 
16230d21680cSYann Gautier static void stm32mp1_lsi_set(bool enable)
16247839a050SYann Gautier {
16250d21680cSYann Gautier 	stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION);
16260d21680cSYann Gautier 
16270d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) {
16287839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
16297839a050SYann Gautier 	}
16307839a050SYann Gautier }
16317839a050SYann Gautier 
16320d21680cSYann Gautier static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css)
16337839a050SYann Gautier {
16340d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
16350d21680cSYann Gautier 
16360d21680cSYann Gautier 	if (digbyp) {
16370d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP);
16387839a050SYann Gautier 	}
16397839a050SYann Gautier 
16400d21680cSYann Gautier 	if (bypass || digbyp) {
16410d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP);
16420d21680cSYann Gautier 	}
16430d21680cSYann Gautier 
16440d21680cSYann Gautier 	stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON);
16450d21680cSYann Gautier 	if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) {
16467839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
16477839a050SYann Gautier 	}
16487839a050SYann Gautier 
16497839a050SYann Gautier 	if (css) {
16500d21680cSYann Gautier 		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON);
16517839a050SYann Gautier 	}
165231e9750bSLionel Debieve 
165331e9750bSLionel Debieve #if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
165431e9750bSLionel Debieve 	if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) &&
165531e9750bSLionel Debieve 	    (!(digbyp || bypass))) {
165631e9750bSLionel Debieve 		panic();
165731e9750bSLionel Debieve 	}
165831e9750bSLionel Debieve #endif
16597839a050SYann Gautier }
16607839a050SYann Gautier 
16610d21680cSYann Gautier static void stm32mp1_csi_set(bool enable)
16627839a050SYann Gautier {
16630d21680cSYann Gautier 	stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION);
16640d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) {
16657839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
16667839a050SYann Gautier 	}
16677839a050SYann Gautier }
16687839a050SYann Gautier 
16690d21680cSYann Gautier static void stm32mp1_hsi_set(bool enable)
16707839a050SYann Gautier {
16710d21680cSYann Gautier 	stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION);
16720d21680cSYann Gautier 	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) {
16737839a050SYann Gautier 		VERBOSE("%s: failed\n", __func__);
16747839a050SYann Gautier 	}
16757839a050SYann Gautier }
16767839a050SYann Gautier 
16770d21680cSYann Gautier static int stm32mp1_set_hsidiv(uint8_t hsidiv)
16787839a050SYann Gautier {
1679dfdb057aSYann Gautier 	uint64_t timeout;
16800d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
16810d21680cSYann Gautier 	uintptr_t address = rcc_base + RCC_OCRDYR;
16827839a050SYann Gautier 
16830d21680cSYann Gautier 	mmio_clrsetbits_32(rcc_base + RCC_HSICFGR,
16847839a050SYann Gautier 			   RCC_HSICFGR_HSIDIV_MASK,
16857839a050SYann Gautier 			   RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv);
16867839a050SYann Gautier 
1687dfdb057aSYann Gautier 	timeout = timeout_init_us(HSIDIV_TIMEOUT);
16887839a050SYann Gautier 	while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) {
1689dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
16900d21680cSYann Gautier 			ERROR("HSIDIV failed @ 0x%lx: 0x%x\n",
16917839a050SYann Gautier 			      address, mmio_read_32(address));
16927839a050SYann Gautier 			return -ETIMEDOUT;
16937839a050SYann Gautier 		}
16947839a050SYann Gautier 	}
16957839a050SYann Gautier 
16967839a050SYann Gautier 	return 0;
16977839a050SYann Gautier }
16987839a050SYann Gautier 
16990d21680cSYann Gautier static int stm32mp1_hsidiv(unsigned long hsifreq)
17007839a050SYann Gautier {
17017839a050SYann Gautier 	uint8_t hsidiv;
17027839a050SYann Gautier 	uint32_t hsidivfreq = MAX_HSI_HZ;
17037839a050SYann Gautier 
17047839a050SYann Gautier 	for (hsidiv = 0; hsidiv < 4U; hsidiv++) {
17057839a050SYann Gautier 		if (hsidivfreq == hsifreq) {
17067839a050SYann Gautier 			break;
17077839a050SYann Gautier 		}
17087839a050SYann Gautier 
17097839a050SYann Gautier 		hsidivfreq /= 2U;
17107839a050SYann Gautier 	}
17117839a050SYann Gautier 
17127839a050SYann Gautier 	if (hsidiv == 4U) {
17137839a050SYann Gautier 		ERROR("Invalid clk-hsi frequency\n");
17147839a050SYann Gautier 		return -1;
17157839a050SYann Gautier 	}
17167839a050SYann Gautier 
17177839a050SYann Gautier 	if (hsidiv != 0U) {
17180d21680cSYann Gautier 		return stm32mp1_set_hsidiv(hsidiv);
17197839a050SYann Gautier 	}
17207839a050SYann Gautier 
17217839a050SYann Gautier 	return 0;
17227839a050SYann Gautier }
17237839a050SYann Gautier 
17240d21680cSYann Gautier static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id,
17250d21680cSYann Gautier 				    unsigned int clksrc,
1726*ae1e5037SGabriel Fernandez 				    uint32_t *pllcfg, uint32_t fracv)
17277839a050SYann Gautier {
17280d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
17290d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
17300d21680cSYann Gautier 	uintptr_t pllxcr = rcc_base + pll->pllxcr;
17310d21680cSYann Gautier 	enum stm32mp1_plltype type = pll->plltype;
17320d21680cSYann Gautier 	uintptr_t clksrc_address = rcc_base + (clksrc >> 4);
17330d21680cSYann Gautier 	unsigned long refclk;
17340d21680cSYann Gautier 	uint32_t ifrge = 0U;
1735*ae1e5037SGabriel Fernandez 	uint32_t src, value;
17367839a050SYann Gautier 
17370d21680cSYann Gautier 	/* Check PLL output */
17380d21680cSYann Gautier 	if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) {
17390d21680cSYann Gautier 		return false;
17407839a050SYann Gautier 	}
17417839a050SYann Gautier 
17420d21680cSYann Gautier 	/* Check current clksrc */
17430d21680cSYann Gautier 	src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK;
17440d21680cSYann Gautier 	if (src != (clksrc & RCC_SELR_SRC_MASK)) {
17450d21680cSYann Gautier 		return false;
17460d21680cSYann Gautier 	}
17470d21680cSYann Gautier 
17480d21680cSYann Gautier 	/* Check Div */
17490d21680cSYann Gautier 	src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK;
17500d21680cSYann Gautier 
17510d21680cSYann Gautier 	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
17520d21680cSYann Gautier 		 (pllcfg[PLLCFG_M] + 1U);
17530d21680cSYann Gautier 
17540d21680cSYann Gautier 	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
17550d21680cSYann Gautier 	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
17560d21680cSYann Gautier 		return false;
17570d21680cSYann Gautier 	}
17580d21680cSYann Gautier 
17590d21680cSYann Gautier 	if ((type == PLL_800) && (refclk >= 8000000U)) {
17600d21680cSYann Gautier 		ifrge = 1U;
17610d21680cSYann Gautier 	}
17620d21680cSYann Gautier 
17630d21680cSYann Gautier 	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
17640d21680cSYann Gautier 		RCC_PLLNCFGR1_DIVN_MASK;
17650d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
17660d21680cSYann Gautier 		 RCC_PLLNCFGR1_DIVM_MASK;
17670d21680cSYann Gautier 	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
17680d21680cSYann Gautier 		 RCC_PLLNCFGR1_IFRGE_MASK;
17690d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) {
17700d21680cSYann Gautier 		return false;
17710d21680cSYann Gautier 	}
17720d21680cSYann Gautier 
17730d21680cSYann Gautier 	/* Fractional configuration */
17740d21680cSYann Gautier 	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
17750d21680cSYann Gautier 	value |= RCC_PLLNFRACR_FRACLE;
17760d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxfracr) != value) {
17770d21680cSYann Gautier 		return false;
17780d21680cSYann Gautier 	}
17790d21680cSYann Gautier 
17800d21680cSYann Gautier 	/* Output config */
17810d21680cSYann Gautier 	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
17820d21680cSYann Gautier 		RCC_PLLNCFGR2_DIVP_MASK;
17830d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
17840d21680cSYann Gautier 		 RCC_PLLNCFGR2_DIVQ_MASK;
17850d21680cSYann Gautier 	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
17860d21680cSYann Gautier 		 RCC_PLLNCFGR2_DIVR_MASK;
17870d21680cSYann Gautier 	if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) {
17880d21680cSYann Gautier 		return false;
17890d21680cSYann Gautier 	}
17900d21680cSYann Gautier 
17910d21680cSYann Gautier 	return true;
17920d21680cSYann Gautier }
17930d21680cSYann Gautier 
17940d21680cSYann Gautier static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id)
17957839a050SYann Gautier {
17960d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
17970d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
17980d21680cSYann Gautier 
1799dd98aec8SYann Gautier 	/* Preserve RCC_PLLNCR_SSCG_CTRL value */
1800dd98aec8SYann Gautier 	mmio_clrsetbits_32(pllxcr,
1801dd98aec8SYann Gautier 			   RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
1802dd98aec8SYann Gautier 			   RCC_PLLNCR_DIVREN,
1803dd98aec8SYann Gautier 			   RCC_PLLNCR_PLLON);
18040d21680cSYann Gautier }
18050d21680cSYann Gautier 
18060d21680cSYann Gautier static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output)
18070d21680cSYann Gautier {
18080d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
18090d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
1810dfdb057aSYann Gautier 	uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT);
18117839a050SYann Gautier 
18127839a050SYann Gautier 	/* Wait PLL lock */
18137839a050SYann Gautier 	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) {
1814dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
18159fa9a0c5SYann Gautier 			ERROR("PLL%u start failed @ 0x%lx: 0x%x\n",
18167839a050SYann Gautier 			      pll_id, pllxcr, mmio_read_32(pllxcr));
18177839a050SYann Gautier 			return -ETIMEDOUT;
18187839a050SYann Gautier 		}
18197839a050SYann Gautier 	}
18207839a050SYann Gautier 
18217839a050SYann Gautier 	/* Start the requested output */
18227839a050SYann Gautier 	mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT);
18237839a050SYann Gautier 
18247839a050SYann Gautier 	return 0;
18257839a050SYann Gautier }
18267839a050SYann Gautier 
18270d21680cSYann Gautier static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id)
18287839a050SYann Gautier {
18290d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
18300d21680cSYann Gautier 	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
1831dfdb057aSYann Gautier 	uint64_t timeout;
18327839a050SYann Gautier 
18337839a050SYann Gautier 	/* Stop all output */
18347839a050SYann Gautier 	mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
18357839a050SYann Gautier 			RCC_PLLNCR_DIVREN);
18367839a050SYann Gautier 
18377839a050SYann Gautier 	/* Stop PLL */
18387839a050SYann Gautier 	mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON);
18397839a050SYann Gautier 
1840dfdb057aSYann Gautier 	timeout = timeout_init_us(PLLRDY_TIMEOUT);
18417839a050SYann Gautier 	/* Wait PLL stopped */
18427839a050SYann Gautier 	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) {
1843dfdb057aSYann Gautier 		if (timeout_elapsed(timeout)) {
18449fa9a0c5SYann Gautier 			ERROR("PLL%u stop failed @ 0x%lx: 0x%x\n",
18457839a050SYann Gautier 			      pll_id, pllxcr, mmio_read_32(pllxcr));
18467839a050SYann Gautier 			return -ETIMEDOUT;
18477839a050SYann Gautier 		}
18487839a050SYann Gautier 	}
18497839a050SYann Gautier 
18507839a050SYann Gautier 	return 0;
18517839a050SYann Gautier }
18527839a050SYann Gautier 
18530d21680cSYann Gautier static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id,
18547839a050SYann Gautier 				       uint32_t *pllcfg)
18557839a050SYann Gautier {
18560d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
18570d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
18587839a050SYann Gautier 	uint32_t value;
18597839a050SYann Gautier 
18607839a050SYann Gautier 	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
18617839a050SYann Gautier 		RCC_PLLNCFGR2_DIVP_MASK;
18627839a050SYann Gautier 	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
18637839a050SYann Gautier 		 RCC_PLLNCFGR2_DIVQ_MASK;
18647839a050SYann Gautier 	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
18657839a050SYann Gautier 		 RCC_PLLNCFGR2_DIVR_MASK;
18660d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxcfgr2, value);
18677839a050SYann Gautier }
18687839a050SYann Gautier 
18690d21680cSYann Gautier static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id,
18707839a050SYann Gautier 			       uint32_t *pllcfg, uint32_t fracv)
18717839a050SYann Gautier {
18720d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
18730d21680cSYann Gautier 	uintptr_t rcc_base = stm32mp_rcc_base();
18740d21680cSYann Gautier 	enum stm32mp1_plltype type = pll->plltype;
18757839a050SYann Gautier 	unsigned long refclk;
18767839a050SYann Gautier 	uint32_t ifrge = 0;
18777839a050SYann Gautier 	uint32_t src, value;
18787839a050SYann Gautier 
18790d21680cSYann Gautier 	src = mmio_read_32(rcc_base + pll->rckxselr) &
18807839a050SYann Gautier 		RCC_SELR_REFCLK_SRC_MASK;
18817839a050SYann Gautier 
18820d21680cSYann Gautier 	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
18837839a050SYann Gautier 		 (pllcfg[PLLCFG_M] + 1U);
18847839a050SYann Gautier 
18857839a050SYann Gautier 	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
18867839a050SYann Gautier 	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
18877839a050SYann Gautier 		return -EINVAL;
18887839a050SYann Gautier 	}
18897839a050SYann Gautier 
18907839a050SYann Gautier 	if ((type == PLL_800) && (refclk >= 8000000U)) {
18917839a050SYann Gautier 		ifrge = 1U;
18927839a050SYann Gautier 	}
18937839a050SYann Gautier 
18947839a050SYann Gautier 	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
18957839a050SYann Gautier 		RCC_PLLNCFGR1_DIVN_MASK;
18967839a050SYann Gautier 	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
18977839a050SYann Gautier 		 RCC_PLLNCFGR1_DIVM_MASK;
18987839a050SYann Gautier 	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
18997839a050SYann Gautier 		 RCC_PLLNCFGR1_IFRGE_MASK;
19000d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxcfgr1, value);
19017839a050SYann Gautier 
19027839a050SYann Gautier 	/* Fractional configuration */
19037839a050SYann Gautier 	value = 0;
19040d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
19057839a050SYann Gautier 
19067839a050SYann Gautier 	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
19070d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
19087839a050SYann Gautier 
19097839a050SYann Gautier 	value |= RCC_PLLNFRACR_FRACLE;
19100d21680cSYann Gautier 	mmio_write_32(rcc_base + pll->pllxfracr, value);
19117839a050SYann Gautier 
19120d21680cSYann Gautier 	stm32mp1_pll_config_output(pll_id, pllcfg);
19137839a050SYann Gautier 
19147839a050SYann Gautier 	return 0;
19157839a050SYann Gautier }
19167839a050SYann Gautier 
19170d21680cSYann Gautier static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg)
19187839a050SYann Gautier {
19190d21680cSYann Gautier 	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
19207839a050SYann Gautier 	uint32_t pllxcsg = 0;
19217839a050SYann Gautier 
19227839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) &
19237839a050SYann Gautier 		    RCC_PLLNCSGR_MOD_PER_MASK;
19247839a050SYann Gautier 
19257839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) &
19267839a050SYann Gautier 		    RCC_PLLNCSGR_INC_STEP_MASK;
19277839a050SYann Gautier 
19287839a050SYann Gautier 	pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) &
19297839a050SYann Gautier 		    RCC_PLLNCSGR_SSCG_MODE_MASK;
19307839a050SYann Gautier 
19310d21680cSYann Gautier 	mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg);
1932dd98aec8SYann Gautier 
1933dd98aec8SYann Gautier 	mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr,
1934dd98aec8SYann Gautier 			RCC_PLLNCR_SSCG_CTRL);
19357839a050SYann Gautier }
19367839a050SYann Gautier 
1937f6559227SYann Gautier static int clk_compute_pll1_settings(unsigned long input_freq,
1938f6559227SYann Gautier 				     uint32_t freq_khz,
1939f6559227SYann Gautier 				     uint32_t *pllcfg, uint32_t *fracv)
1940f6559227SYann Gautier {
1941f6559227SYann Gautier 	unsigned long long best_diff = ULLONG_MAX;
1942f6559227SYann Gautier 	unsigned int divm;
1943f6559227SYann Gautier 
1944f6559227SYann Gautier 	/* Following parameters have always the same value */
1945f6559227SYann Gautier 	pllcfg[PLLCFG_Q] = 0U;
1946f6559227SYann Gautier 	pllcfg[PLLCFG_R] = 0U;
1947f6559227SYann Gautier 	pllcfg[PLLCFG_O] = PQR(1, 0, 0);
1948f6559227SYann Gautier 
1949f6559227SYann Gautier 	for (divm = (DIVM_MAX + 1U); divm != DIVM_MIN; divm--) {
1950f6559227SYann Gautier 		unsigned long post_divm = input_freq / divm;
1951f6559227SYann Gautier 		unsigned int divp;
1952f6559227SYann Gautier 
1953f6559227SYann Gautier 		if ((post_divm < POST_DIVM_MIN) || (post_divm > POST_DIVM_MAX)) {
1954f6559227SYann Gautier 			continue;
1955f6559227SYann Gautier 		}
1956f6559227SYann Gautier 
1957f6559227SYann Gautier 		for (divp = DIVP_MIN; divp <= DIVP_MAX; divp++) {
1958f6559227SYann Gautier 			unsigned long long output_freq = freq_khz * 1000ULL;
1959f6559227SYann Gautier 			unsigned long long freq;
1960f6559227SYann Gautier 			unsigned long long divn;
1961f6559227SYann Gautier 			unsigned long long frac;
1962f6559227SYann Gautier 			unsigned int i;
1963f6559227SYann Gautier 
1964f6559227SYann Gautier 			freq = output_freq * divm * (divp + 1U);
1965f6559227SYann Gautier 
1966f6559227SYann Gautier 			divn = (freq / input_freq) - 1U;
1967f6559227SYann Gautier 			if ((divn < DIVN_MIN) || (divn > DIVN_MAX)) {
1968f6559227SYann Gautier 				continue;
1969f6559227SYann Gautier 			}
1970f6559227SYann Gautier 
1971f6559227SYann Gautier 			frac = ((freq * FRAC_MAX) / input_freq) - ((divn + 1U) * FRAC_MAX);
1972f6559227SYann Gautier 
1973f6559227SYann Gautier 			/* 2 loops to refine the fractional part */
1974f6559227SYann Gautier 			for (i = 2U; i != 0U; i--) {
1975f6559227SYann Gautier 				unsigned long long diff;
1976f6559227SYann Gautier 				unsigned long long vco;
1977f6559227SYann Gautier 
1978f6559227SYann Gautier 				if (frac > FRAC_MAX) {
1979f6559227SYann Gautier 					break;
1980f6559227SYann Gautier 				}
1981f6559227SYann Gautier 
1982f6559227SYann Gautier 				vco = (post_divm * (divn + 1U)) + ((post_divm * frac) / FRAC_MAX);
1983f6559227SYann Gautier 
1984f6559227SYann Gautier 				if ((vco < (VCO_MIN / 2U)) || (vco > (VCO_MAX / 2U))) {
1985f6559227SYann Gautier 					frac++;
1986f6559227SYann Gautier 					continue;
1987f6559227SYann Gautier 				}
1988f6559227SYann Gautier 
1989f6559227SYann Gautier 				freq = vco / (divp + 1U);
1990f6559227SYann Gautier 				if (output_freq < freq) {
1991f6559227SYann Gautier 					diff = freq - output_freq;
1992f6559227SYann Gautier 				} else {
1993f6559227SYann Gautier 					diff = output_freq - freq;
1994f6559227SYann Gautier 				}
1995f6559227SYann Gautier 
1996f6559227SYann Gautier 				if (diff < best_diff)  {
1997f6559227SYann Gautier 					pllcfg[PLLCFG_M] = divm - 1U;
1998f6559227SYann Gautier 					pllcfg[PLLCFG_N] = (uint32_t)divn;
1999f6559227SYann Gautier 					pllcfg[PLLCFG_P] = divp;
2000f6559227SYann Gautier 					*fracv = (uint32_t)frac;
2001f6559227SYann Gautier 
2002f6559227SYann Gautier 					if (diff == 0U) {
2003f6559227SYann Gautier 						return 0;
2004f6559227SYann Gautier 					}
2005f6559227SYann Gautier 
2006f6559227SYann Gautier 					best_diff = diff;
2007f6559227SYann Gautier 				}
2008f6559227SYann Gautier 
2009f6559227SYann Gautier 				frac++;
2010f6559227SYann Gautier 			}
2011f6559227SYann Gautier 		}
2012f6559227SYann Gautier 	}
2013f6559227SYann Gautier 
2014f6559227SYann Gautier 	if (best_diff == ULLONG_MAX) {
2015f6559227SYann Gautier 		return -EINVAL;
2016f6559227SYann Gautier 	}
2017f6559227SYann Gautier 
2018f6559227SYann Gautier 	return 0;
2019f6559227SYann Gautier }
2020f6559227SYann Gautier 
2021f6559227SYann Gautier static int clk_get_pll1_settings(uint32_t clksrc, uint32_t freq_khz,
2022f6559227SYann Gautier 				 uint32_t *pllcfg, uint32_t *fracv)
2023f6559227SYann Gautier {
2024f6559227SYann Gautier 	unsigned long input_freq = 0UL;
2025f6559227SYann Gautier 
2026f6559227SYann Gautier 	assert(pllcfg != NULL);
2027f6559227SYann Gautier 	assert(fracv != NULL);
2028f6559227SYann Gautier 
2029f6559227SYann Gautier 	switch (clksrc) {
2030f6559227SYann Gautier 	case CLK_PLL12_HSI:
2031f6559227SYann Gautier 		input_freq = stm32mp_clk_get_rate(CK_HSI);
2032f6559227SYann Gautier 		break;
2033f6559227SYann Gautier 	case CLK_PLL12_HSE:
2034f6559227SYann Gautier 		input_freq = stm32mp_clk_get_rate(CK_HSE);
2035f6559227SYann Gautier 		break;
2036f6559227SYann Gautier 	default:
2037f6559227SYann Gautier 		break;
2038f6559227SYann Gautier 	}
2039f6559227SYann Gautier 
2040f6559227SYann Gautier 	if (input_freq == 0UL) {
2041f6559227SYann Gautier 		panic();
2042f6559227SYann Gautier 	}
2043f6559227SYann Gautier 
2044f6559227SYann Gautier 	return clk_compute_pll1_settings(input_freq, freq_khz, pllcfg, fracv);
2045f6559227SYann Gautier }
2046f6559227SYann Gautier 
2047*ae1e5037SGabriel Fernandez static int stm32_clk_dividers_configure(struct stm32_clk_priv *priv)
20487839a050SYann Gautier {
2049*ae1e5037SGabriel Fernandez 	struct stm32_clk_platdata *pdata = priv->pdata;
2050*ae1e5037SGabriel Fernandez 	uint32_t i;
205152a616b4SAndre Przywara 
2052*ae1e5037SGabriel Fernandez 	for (i = 0U; i < pdata->nclkdiv; i++) {
2053*ae1e5037SGabriel Fernandez 		uint32_t div_id, div_n;
2054*ae1e5037SGabriel Fernandez 		uint32_t val;
2055*ae1e5037SGabriel Fernandez 		int ret;
2056*ae1e5037SGabriel Fernandez 
2057*ae1e5037SGabriel Fernandez 		val = pdata->clkdiv[i] & CMD_DATA_MASK;
2058*ae1e5037SGabriel Fernandez 		div_id = (val & DIV_ID_MASK) >> DIV_ID_SHIFT;
2059*ae1e5037SGabriel Fernandez 		div_n = (val & DIV_DIVN_MASK) >> DIV_DIVN_SHIFT;
2060*ae1e5037SGabriel Fernandez 
2061*ae1e5037SGabriel Fernandez 		ret = clk_stm32_set_div(priv, div_id, div_n);
2062*ae1e5037SGabriel Fernandez 		if (ret != 0) {
2063*ae1e5037SGabriel Fernandez 			return ret;
2064*ae1e5037SGabriel Fernandez 		}
206552a616b4SAndre Przywara 	}
20667839a050SYann Gautier 
2067*ae1e5037SGabriel Fernandez 	return 0;
20687839a050SYann Gautier }
20697839a050SYann Gautier 
2070*ae1e5037SGabriel Fernandez static int stm32_clk_configure_clk(struct stm32_clk_priv *priv, uint32_t data)
2071*ae1e5037SGabriel Fernandez {
2072*ae1e5037SGabriel Fernandez 	uint32_t sel = (data & CLK_SEL_MASK) >> CLK_SEL_SHIFT;
2073*ae1e5037SGabriel Fernandez 	uint32_t enable = (data & CLK_ON_MASK) >> CLK_ON_SHIFT;
2074*ae1e5037SGabriel Fernandez 	unsigned long binding_id = ((unsigned long)data & CLK_ID_MASK) >> CLK_ID_SHIFT;
2075*ae1e5037SGabriel Fernandez 
2076*ae1e5037SGabriel Fernandez 	if (binding_id == RTC) {
2077*ae1e5037SGabriel Fernandez 		uintptr_t address = stm32mp_rcc_base() + RCC_BDCR;
2078*ae1e5037SGabriel Fernandez 
2079*ae1e5037SGabriel Fernandez 		if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) || (enable != 0U)) {
2080*ae1e5037SGabriel Fernandez 			mmio_clrsetbits_32(address, RCC_BDCR_RTCSRC_MASK,
2081*ae1e5037SGabriel Fernandez 					   (sel & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT);
2082*ae1e5037SGabriel Fernandez 
2083*ae1e5037SGabriel Fernandez 			mmio_setbits_32(address, RCC_BDCR_RTCCKEN);
2084*ae1e5037SGabriel Fernandez 		}
20857839a050SYann Gautier 	}
20867839a050SYann Gautier 
2087*ae1e5037SGabriel Fernandez 	return 0;
2088*ae1e5037SGabriel Fernandez }
20897839a050SYann Gautier 
2090*ae1e5037SGabriel Fernandez static int stm32_clk_configure_by_addr_val(struct stm32_clk_priv *priv,
2091*ae1e5037SGabriel Fernandez 					   uint32_t data)
2092*ae1e5037SGabriel Fernandez {
2093*ae1e5037SGabriel Fernandez 	uint32_t addr = data >> CLK_ADDR_SHIFT;
2094*ae1e5037SGabriel Fernandez 	uint32_t val = data & CLK_ADDR_VAL_MASK;
20957839a050SYann Gautier 
2096*ae1e5037SGabriel Fernandez 	mmio_setbits_32(priv->base + addr, val);
2097*ae1e5037SGabriel Fernandez 
2098*ae1e5037SGabriel Fernandez 	return 0;
2099*ae1e5037SGabriel Fernandez }
2100*ae1e5037SGabriel Fernandez 
2101*ae1e5037SGabriel Fernandez static int stm32_clk_source_configure(struct stm32_clk_priv *priv)
2102*ae1e5037SGabriel Fernandez {
2103*ae1e5037SGabriel Fernandez 	struct stm32_clk_platdata *pdata = priv->pdata;
2104*ae1e5037SGabriel Fernandez 	bool ckper_disabled = false;
2105*ae1e5037SGabriel Fernandez 	uint32_t i;
2106*ae1e5037SGabriel Fernandez 
2107*ae1e5037SGabriel Fernandez 	for (i = 0U; i < pdata->nclksrc; i++) {
2108*ae1e5037SGabriel Fernandez 		uint32_t val = pdata->clksrc[i];
2109*ae1e5037SGabriel Fernandez 		uint32_t cmd, cmd_data;
2110*ae1e5037SGabriel Fernandez 		int ret;
2111*ae1e5037SGabriel Fernandez 
2112*ae1e5037SGabriel Fernandez 		if (val & CMD_ADDR_BIT) {
2113*ae1e5037SGabriel Fernandez 			ret = stm32_clk_configure_by_addr_val(priv, val & ~CMD_ADDR_BIT);
2114964e5ff1SNicolas Le Bayon 			if (ret != 0) {
2115964e5ff1SNicolas Le Bayon 				return ret;
21167839a050SYann Gautier 			}
2117f6559227SYann Gautier 
2118f6559227SYann Gautier 			continue;
2119f6559227SYann Gautier 		}
2120f6559227SYann Gautier 
2121*ae1e5037SGabriel Fernandez 		if (val == (uint32_t)CLK_CKPER_DISABLED) {
2122*ae1e5037SGabriel Fernandez 			ckper_disabled = true;
2123*ae1e5037SGabriel Fernandez 			continue;
2124*ae1e5037SGabriel Fernandez 		}
2125*ae1e5037SGabriel Fernandez 
2126*ae1e5037SGabriel Fernandez 		cmd = (val & CMD_MASK) >> CMD_SHIFT;
2127*ae1e5037SGabriel Fernandez 		cmd_data = val & ~CMD_MASK;
2128*ae1e5037SGabriel Fernandez 
2129*ae1e5037SGabriel Fernandez 		switch (cmd) {
2130*ae1e5037SGabriel Fernandez 		case CMD_MUX:
2131*ae1e5037SGabriel Fernandez 			ret = stm32_clk_configure_mux(priv, cmd_data);
2132*ae1e5037SGabriel Fernandez 			break;
2133*ae1e5037SGabriel Fernandez 
2134*ae1e5037SGabriel Fernandez 		case CMD_CLK:
2135*ae1e5037SGabriel Fernandez 			ret = stm32_clk_configure_clk(priv, cmd_data);
2136*ae1e5037SGabriel Fernandez 			break;
2137*ae1e5037SGabriel Fernandez 		default:
2138*ae1e5037SGabriel Fernandez 			ret = -EINVAL;
2139*ae1e5037SGabriel Fernandez 			break;
2140*ae1e5037SGabriel Fernandez 		}
2141*ae1e5037SGabriel Fernandez 
2142*ae1e5037SGabriel Fernandez 		if (ret != 0) {
2143*ae1e5037SGabriel Fernandez 			return ret;
2144*ae1e5037SGabriel Fernandez 		}
2145*ae1e5037SGabriel Fernandez 	}
2146*ae1e5037SGabriel Fernandez 
2147*ae1e5037SGabriel Fernandez 	/*
2148*ae1e5037SGabriel Fernandez 	 * CKPER is source for some peripheral clocks
2149*ae1e5037SGabriel Fernandez 	 * (FMC-NAND / QPSI-NOR) and switching source is allowed
2150*ae1e5037SGabriel Fernandez 	 * only if previous clock is still ON
2151*ae1e5037SGabriel Fernandez 	 * => deactivate CKPER only after switching clock
2152*ae1e5037SGabriel Fernandez 	 */
2153*ae1e5037SGabriel Fernandez 	if (!ckper_disabled) {
2154*ae1e5037SGabriel Fernandez 		return 0;
2155*ae1e5037SGabriel Fernandez 	}
2156*ae1e5037SGabriel Fernandez 
2157*ae1e5037SGabriel Fernandez 	return stm32_clk_configure_mux(priv, CLK_CKPER_DISABLED);
2158*ae1e5037SGabriel Fernandez }
2159*ae1e5037SGabriel Fernandez 
2160*ae1e5037SGabriel Fernandez static int stm32mp1_pll_configure_src(struct stm32_clk_priv *priv, int pll_idx)
2161*ae1e5037SGabriel Fernandez {
2162*ae1e5037SGabriel Fernandez 	struct stm32_clk_platdata *pdata = priv->pdata;
2163*ae1e5037SGabriel Fernandez 	struct stm32_pll_dt_cfg *pll_conf = &pdata->pll[pll_idx];
2164*ae1e5037SGabriel Fernandez 
2165*ae1e5037SGabriel Fernandez 	if (!pll_conf->status) {
2166*ae1e5037SGabriel Fernandez 		return 0;
2167*ae1e5037SGabriel Fernandez 	}
2168*ae1e5037SGabriel Fernandez 
2169*ae1e5037SGabriel Fernandez 	return stm32_clk_configure_mux(priv, pll_conf->src);
2170*ae1e5037SGabriel Fernandez }
2171*ae1e5037SGabriel Fernandez 
2172*ae1e5037SGabriel Fernandez int stm32mp1_clk_init(void)
2173*ae1e5037SGabriel Fernandez {
2174*ae1e5037SGabriel Fernandez 	struct stm32_clk_priv *priv = clk_stm32_get_priv();
2175*ae1e5037SGabriel Fernandez 	struct stm32_clk_platdata *pdata = priv->pdata;
2176*ae1e5037SGabriel Fernandez 	struct stm32_pll_dt_cfg *pll_conf = pdata->pll;
2177*ae1e5037SGabriel Fernandez 	int ret;
2178*ae1e5037SGabriel Fernandez 	enum stm32mp1_pll_id i;
2179*ae1e5037SGabriel Fernandez 	bool lse_css = false;
2180*ae1e5037SGabriel Fernandez 	bool pll3_preserve = false;
2181*ae1e5037SGabriel Fernandez 	bool pll4_preserve = false;
2182*ae1e5037SGabriel Fernandez 	bool pll4_bootrom = false;
2183*ae1e5037SGabriel Fernandez 	int stgen_p = stm32mp1_clk_get_parent(STGEN_K);
2184*ae1e5037SGabriel Fernandez 	int usbphy_p = stm32mp1_clk_get_parent(USBPHY_K);
2185*ae1e5037SGabriel Fernandez 	uint32_t usbreg_bootrom = 0U;
2186*ae1e5037SGabriel Fernandez 
2187*ae1e5037SGabriel Fernandez 	if (!pll_conf[_PLL1].status) {
2188*ae1e5037SGabriel Fernandez 		ret = clk_get_pll1_settings(pll_conf[_PLL2].src, PLL1_NOMINAL_FREQ_IN_KHZ,
2189*ae1e5037SGabriel Fernandez 					    pll_conf[_PLL1].cfg, &pll_conf[_PLL1].frac);
2190f6559227SYann Gautier 		if (ret != 0) {
2191f6559227SYann Gautier 			return ret;
2192f6559227SYann Gautier 		}
2193f6559227SYann Gautier 
2194*ae1e5037SGabriel Fernandez 		pll_conf[_PLL1].status = true;
2195*ae1e5037SGabriel Fernandez 		pll_conf[_PLL1].src = pll_conf[_PLL2].src;
2196f6559227SYann Gautier 	}
21977839a050SYann Gautier 
21987839a050SYann Gautier 	/*
21997839a050SYann Gautier 	 * Switch ON oscillator found in device-tree.
22007839a050SYann Gautier 	 * Note: HSI already ON after BootROM stage.
22017839a050SYann Gautier 	 */
22020d21680cSYann Gautier 	if (stm32mp1_osc[_LSI] != 0U) {
22030d21680cSYann Gautier 		stm32mp1_lsi_set(true);
22047839a050SYann Gautier 	}
22050d21680cSYann Gautier 	if (stm32mp1_osc[_LSE] != 0U) {
2206b208e3daSGabriel Fernandez 		const char *name = stm32mp_osc_node_label[_LSE];
22070d21680cSYann Gautier 		bool bypass, digbyp;
22087839a050SYann Gautier 		uint32_t lsedrv;
22097839a050SYann Gautier 
2210b208e3daSGabriel Fernandez 		bypass = fdt_clk_read_bool(name, "st,bypass");
2211b208e3daSGabriel Fernandez 		digbyp = fdt_clk_read_bool(name, "st,digbypass");
2212b208e3daSGabriel Fernandez 		lse_css = fdt_clk_read_bool(name, "st,css");
2213b208e3daSGabriel Fernandez 		lsedrv = fdt_clk_read_uint32_default(name, "st,drive",
22147839a050SYann Gautier 						     LSEDRV_MEDIUM_HIGH);
22150d21680cSYann Gautier 		stm32mp1_lse_enable(bypass, digbyp, lsedrv);
22167839a050SYann Gautier 	}
22170d21680cSYann Gautier 	if (stm32mp1_osc[_HSE] != 0U) {
2218b208e3daSGabriel Fernandez 		const char *name = stm32mp_osc_node_label[_HSE];
22190d21680cSYann Gautier 		bool bypass, digbyp, css;
22207839a050SYann Gautier 
2221b208e3daSGabriel Fernandez 		bypass = fdt_clk_read_bool(name, "st,bypass");
2222b208e3daSGabriel Fernandez 		digbyp = fdt_clk_read_bool(name, "st,digbypass");
2223b208e3daSGabriel Fernandez 		css = fdt_clk_read_bool(name, "st,css");
22240d21680cSYann Gautier 		stm32mp1_hse_enable(bypass, digbyp, css);
22257839a050SYann Gautier 	}
22267839a050SYann Gautier 	/*
22277839a050SYann Gautier 	 * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR)
22287839a050SYann Gautier 	 * => switch on CSI even if node is not present in device tree
22297839a050SYann Gautier 	 */
22300d21680cSYann Gautier 	stm32mp1_csi_set(true);
22317839a050SYann Gautier 
22327839a050SYann Gautier 	/* Come back to HSI */
2233*ae1e5037SGabriel Fernandez 	ret = stm32_clk_configure_mux(priv, CLK_MPU_HSI);
22347839a050SYann Gautier 	if (ret != 0) {
22357839a050SYann Gautier 		return ret;
22367839a050SYann Gautier 	}
2237*ae1e5037SGabriel Fernandez 	ret = stm32_clk_configure_mux(priv, CLK_AXI_HSI);
22387839a050SYann Gautier 	if (ret != 0) {
22397839a050SYann Gautier 		return ret;
22407839a050SYann Gautier 	}
2241*ae1e5037SGabriel Fernandez 	ret = stm32_clk_configure_mux(priv, CLK_MCU_HSI);
2242b053a22eSYann Gautier 	if (ret != 0) {
2243b053a22eSYann Gautier 		return ret;
2244b053a22eSYann Gautier 	}
2245*ae1e5037SGabriel Fernandez 	if ((mmio_read_32(priv->base + RCC_MP_RSTSCLRR) &
22460d21680cSYann Gautier 	     RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) {
2247*ae1e5037SGabriel Fernandez 		pll3_preserve = stm32mp1_check_pll_conf(_PLL3,
2248*ae1e5037SGabriel Fernandez 							pll_conf[_PLL3].src,
2249*ae1e5037SGabriel Fernandez 							pll_conf[_PLL3].cfg,
2250*ae1e5037SGabriel Fernandez 							pll_conf[_PLL3].frac);
2251*ae1e5037SGabriel Fernandez 		pll4_preserve = stm32mp1_check_pll_conf(_PLL4,
2252*ae1e5037SGabriel Fernandez 							pll_conf[_PLL4].src,
2253*ae1e5037SGabriel Fernandez 							pll_conf[_PLL4].cfg,
2254*ae1e5037SGabriel Fernandez 							pll_conf[_PLL4].frac);
2255175758b2SYann Gautier 	}
2256bf1af154SPatrick Delaunay 	/* Don't initialize PLL4, when used by BOOTROM */
2257bf1af154SPatrick Delaunay 	if ((stm32mp_get_boot_itf_selected() ==
2258bf1af154SPatrick Delaunay 	     BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) &&
2259bf1af154SPatrick Delaunay 	    ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) {
2260bf1af154SPatrick Delaunay 		pll4_bootrom = true;
2261bf1af154SPatrick Delaunay 		pll4_preserve = true;
2262bf1af154SPatrick Delaunay 	}
22630d21680cSYann Gautier 
22647839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
22650d21680cSYann Gautier 		if (((i == _PLL3) && pll3_preserve) ||
22660d21680cSYann Gautier 		    ((i == _PLL4) && pll4_preserve)) {
22677839a050SYann Gautier 			continue;
22680d21680cSYann Gautier 		}
22690d21680cSYann Gautier 
22700d21680cSYann Gautier 		ret = stm32mp1_pll_stop(i);
22717839a050SYann Gautier 		if (ret != 0) {
22727839a050SYann Gautier 			return ret;
22737839a050SYann Gautier 		}
22747839a050SYann Gautier 	}
22757839a050SYann Gautier 
22767839a050SYann Gautier 	/* Configure HSIDIV */
22770d21680cSYann Gautier 	if (stm32mp1_osc[_HSI] != 0U) {
22780d21680cSYann Gautier 		ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]);
22797839a050SYann Gautier 		if (ret != 0) {
22807839a050SYann Gautier 			return ret;
22817839a050SYann Gautier 		}
2282591d80c8SLionel Debieve 
2283591d80c8SLionel Debieve 		stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
22847839a050SYann Gautier 	}
22857839a050SYann Gautier 
2286*ae1e5037SGabriel Fernandez 	/* Configure dividers */
2287*ae1e5037SGabriel Fernandez 	ret = stm32_clk_dividers_configure(priv);
22887839a050SYann Gautier 	if (ret != 0) {
22897839a050SYann Gautier 		return ret;
22907839a050SYann Gautier 	}
22917839a050SYann Gautier 
22927839a050SYann Gautier 	/* Configure PLLs source */
2293*ae1e5037SGabriel Fernandez 	ret = stm32mp1_pll_configure_src(priv, _PLL1);
22947839a050SYann Gautier 	if (ret != 0) {
22957839a050SYann Gautier 		return ret;
22967839a050SYann Gautier 	}
22977839a050SYann Gautier 
22980d21680cSYann Gautier 	if (!pll3_preserve) {
2299*ae1e5037SGabriel Fernandez 		ret = stm32mp1_pll_configure_src(priv, _PLL3);
23007839a050SYann Gautier 		if (ret != 0) {
23017839a050SYann Gautier 			return ret;
23027839a050SYann Gautier 		}
23030d21680cSYann Gautier 	}
23040d21680cSYann Gautier 
23050d21680cSYann Gautier 	if (!pll4_preserve) {
2306*ae1e5037SGabriel Fernandez 		ret = stm32mp1_pll_configure_src(priv, _PLL4);
23070d21680cSYann Gautier 		if (ret != 0) {
23080d21680cSYann Gautier 			return ret;
23090d21680cSYann Gautier 		}
23100d21680cSYann Gautier 	}
23117839a050SYann Gautier 
23127839a050SYann Gautier 	/* Configure and start PLLs */
23137839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
23140d21680cSYann Gautier 		if (((i == _PLL3) && pll3_preserve) ||
23150d21680cSYann Gautier 		    ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) {
23160d21680cSYann Gautier 			continue;
23170d21680cSYann Gautier 		}
23180d21680cSYann Gautier 
2319*ae1e5037SGabriel Fernandez 		if (!pll_conf[i].status) {
23207839a050SYann Gautier 			continue;
23217839a050SYann Gautier 		}
23227839a050SYann Gautier 
23230d21680cSYann Gautier 		if ((i == _PLL4) && pll4_bootrom) {
23240d21680cSYann Gautier 			/* Set output divider if not done by the Bootrom */
2325*ae1e5037SGabriel Fernandez 			stm32mp1_pll_config_output(i, pll_conf[i].cfg);
23260d21680cSYann Gautier 			continue;
23270d21680cSYann Gautier 		}
23280d21680cSYann Gautier 
2329*ae1e5037SGabriel Fernandez 		ret = stm32mp1_pll_config(i, pll_conf[i].cfg, pll_conf[i].frac);
23307839a050SYann Gautier 		if (ret != 0) {
23317839a050SYann Gautier 			return ret;
23327839a050SYann Gautier 		}
2333964e5ff1SNicolas Le Bayon 
2334*ae1e5037SGabriel Fernandez 		if (pll_conf[i].csg_enabled) {
2335*ae1e5037SGabriel Fernandez 			stm32mp1_pll_csg(i, pll_conf[i].csg);
23367839a050SYann Gautier 		}
23377839a050SYann Gautier 
23380d21680cSYann Gautier 		stm32mp1_pll_start(i);
23397839a050SYann Gautier 	}
23401b491eeaSElyes Haouas 	/* Wait and start PLLs output when ready */
23417839a050SYann Gautier 	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
2342*ae1e5037SGabriel Fernandez 		if (!pll_conf[i].status) {
23437839a050SYann Gautier 			continue;
23447839a050SYann Gautier 		}
23457839a050SYann Gautier 
2346*ae1e5037SGabriel Fernandez 		ret = stm32mp1_pll_output(i, pll_conf[i].cfg[PLLCFG_O]);
23477839a050SYann Gautier 		if (ret != 0) {
23487839a050SYann Gautier 			return ret;
23497839a050SYann Gautier 		}
23507839a050SYann Gautier 	}
23517839a050SYann Gautier 	/* Wait LSE ready before to use it */
23520d21680cSYann Gautier 	if (stm32mp1_osc[_LSE] != 0U) {
23530d21680cSYann Gautier 		stm32mp1_lse_wait();
23547839a050SYann Gautier 	}
23557839a050SYann Gautier 
2356bf1af154SPatrick Delaunay 	if (pll4_bootrom) {
2357*ae1e5037SGabriel Fernandez 		usbreg_bootrom = mmio_read_32(priv->base + RCC_USBCKSELR);
2358bf1af154SPatrick Delaunay 	}
23597839a050SYann Gautier 
2360*ae1e5037SGabriel Fernandez 	/* Configure with expected clock source */
2361*ae1e5037SGabriel Fernandez 	ret = stm32_clk_source_configure(priv);
2362*ae1e5037SGabriel Fernandez 	if (ret != 0) {
2363*ae1e5037SGabriel Fernandez 		panic();
23647839a050SYann Gautier 	}
2365bf1af154SPatrick Delaunay 
2366bf1af154SPatrick Delaunay 	if (pll4_bootrom) {
2367bf1af154SPatrick Delaunay 		uint32_t usbreg_value, usbreg_mask;
2368bf1af154SPatrick Delaunay 		const struct stm32mp1_clk_sel *sel;
2369bf1af154SPatrick Delaunay 
2370bf1af154SPatrick Delaunay 		sel = clk_sel_ref(_USBPHY_SEL);
2371bf1af154SPatrick Delaunay 		usbreg_mask = (uint32_t)sel->msk << sel->src;
2372bf1af154SPatrick Delaunay 		sel = clk_sel_ref(_USBO_SEL);
2373bf1af154SPatrick Delaunay 		usbreg_mask |= (uint32_t)sel->msk << sel->src;
2374bf1af154SPatrick Delaunay 
2375*ae1e5037SGabriel Fernandez 		usbreg_value = mmio_read_32(priv->base + RCC_USBCKSELR) &
2376bf1af154SPatrick Delaunay 			       usbreg_mask;
2377bf1af154SPatrick Delaunay 		usbreg_bootrom &= usbreg_mask;
2378bf1af154SPatrick Delaunay 		if (usbreg_bootrom != usbreg_value) {
2379bf1af154SPatrick Delaunay 			VERBOSE("forbidden new USB clk path\n");
2380bf1af154SPatrick Delaunay 			VERBOSE("vs bootrom on USB boot\n");
2381bf1af154SPatrick Delaunay 			return -FDT_ERR_BADVALUE;
2382bf1af154SPatrick Delaunay 		}
2383bf1af154SPatrick Delaunay 	}
2384*ae1e5037SGabriel Fernandez 
2385*ae1e5037SGabriel Fernandez 	if (lse_css) {
2386*ae1e5037SGabriel Fernandez 		mmio_setbits_32(priv->base + RCC_BDCR, RCC_BDCR_LSECSSON);
23877839a050SYann Gautier 	}
23887839a050SYann Gautier 
23897839a050SYann Gautier 	/* Switch OFF HSI if not found in device-tree */
23900d21680cSYann Gautier 	if (stm32mp1_osc[_HSI] == 0U) {
23910d21680cSYann Gautier 		stm32mp1_hsi_set(false);
23927839a050SYann Gautier 	}
2393591d80c8SLionel Debieve 
2394591d80c8SLionel Debieve 	stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
23957839a050SYann Gautier 
23967839a050SYann Gautier 	/* Software Self-Refresh mode (SSR) during DDR initilialization */
2397*ae1e5037SGabriel Fernandez 	mmio_clrsetbits_32(priv->base + RCC_DDRITFCR,
23987839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_MASK,
23997839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_SSR <<
24007839a050SYann Gautier 			   RCC_DDRITFCR_DDRCKMOD_SHIFT);
24017839a050SYann Gautier 
24027839a050SYann Gautier 	return 0;
24037839a050SYann Gautier }
24047839a050SYann Gautier 
24057839a050SYann Gautier static void stm32mp1_osc_clk_init(const char *name,
24067839a050SYann Gautier 				  enum stm32mp_osc_id index)
24077839a050SYann Gautier {
24087839a050SYann Gautier 	uint32_t frequency;
24097839a050SYann Gautier 
24100d21680cSYann Gautier 	if (fdt_osc_read_freq(name, &frequency) == 0) {
24110d21680cSYann Gautier 		stm32mp1_osc[index] = frequency;
24127839a050SYann Gautier 	}
24137839a050SYann Gautier }
24147839a050SYann Gautier 
24157839a050SYann Gautier static void stm32mp1_osc_init(void)
24167839a050SYann Gautier {
24177839a050SYann Gautier 	enum stm32mp_osc_id i;
24187839a050SYann Gautier 
24197839a050SYann Gautier 	for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) {
24200d21680cSYann Gautier 		stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i);
24217839a050SYann Gautier 	}
24227839a050SYann Gautier }
24237839a050SYann Gautier 
242437e8295aSEtienne Carriere #ifdef STM32MP_SHARED_RESOURCES
242537e8295aSEtienne Carriere /*
242637e8295aSEtienne Carriere  * Get the parent ID of the target parent clock, for tagging as secure
242737e8295aSEtienne Carriere  * shared clock dependencies.
242837e8295aSEtienne Carriere  */
242937e8295aSEtienne Carriere static int get_parent_id_parent(unsigned int parent_id)
243037e8295aSEtienne Carriere {
243137e8295aSEtienne Carriere 	enum stm32mp1_parent_sel s = _UNKNOWN_SEL;
243237e8295aSEtienne Carriere 	enum stm32mp1_pll_id pll_id;
243337e8295aSEtienne Carriere 	uint32_t p_sel;
243437e8295aSEtienne Carriere 	uintptr_t rcc_base = stm32mp_rcc_base();
243537e8295aSEtienne Carriere 
243637e8295aSEtienne Carriere 	switch (parent_id) {
243737e8295aSEtienne Carriere 	case _ACLK:
243837e8295aSEtienne Carriere 	case _PCLK4:
243937e8295aSEtienne Carriere 	case _PCLK5:
244037e8295aSEtienne Carriere 		s = _AXIS_SEL;
244137e8295aSEtienne Carriere 		break;
244237e8295aSEtienne Carriere 	case _PLL1_P:
244337e8295aSEtienne Carriere 	case _PLL1_Q:
244437e8295aSEtienne Carriere 	case _PLL1_R:
244537e8295aSEtienne Carriere 		pll_id = _PLL1;
244637e8295aSEtienne Carriere 		break;
244737e8295aSEtienne Carriere 	case _PLL2_P:
244837e8295aSEtienne Carriere 	case _PLL2_Q:
244937e8295aSEtienne Carriere 	case _PLL2_R:
245037e8295aSEtienne Carriere 		pll_id = _PLL2;
245137e8295aSEtienne Carriere 		break;
245237e8295aSEtienne Carriere 	case _PLL3_P:
245337e8295aSEtienne Carriere 	case _PLL3_Q:
245437e8295aSEtienne Carriere 	case _PLL3_R:
245537e8295aSEtienne Carriere 		pll_id = _PLL3;
245637e8295aSEtienne Carriere 		break;
245737e8295aSEtienne Carriere 	case _PLL4_P:
245837e8295aSEtienne Carriere 	case _PLL4_Q:
245937e8295aSEtienne Carriere 	case _PLL4_R:
246037e8295aSEtienne Carriere 		pll_id = _PLL4;
246137e8295aSEtienne Carriere 		break;
246237e8295aSEtienne Carriere 	case _PCLK1:
246337e8295aSEtienne Carriere 	case _PCLK2:
246437e8295aSEtienne Carriere 	case _HCLK2:
246537e8295aSEtienne Carriere 	case _HCLK6:
246637e8295aSEtienne Carriere 	case _CK_PER:
246737e8295aSEtienne Carriere 	case _CK_MPU:
246837e8295aSEtienne Carriere 	case _CK_MCU:
246937e8295aSEtienne Carriere 	case _USB_PHY_48:
247037e8295aSEtienne Carriere 		/* We do not expect to access these */
247137e8295aSEtienne Carriere 		panic();
247237e8295aSEtienne Carriere 		break;
247337e8295aSEtienne Carriere 	default:
247437e8295aSEtienne Carriere 		/* Other parents have no parent */
247537e8295aSEtienne Carriere 		return -1;
247637e8295aSEtienne Carriere 	}
247737e8295aSEtienne Carriere 
247837e8295aSEtienne Carriere 	if (s != _UNKNOWN_SEL) {
247937e8295aSEtienne Carriere 		const struct stm32mp1_clk_sel *sel = clk_sel_ref(s);
248037e8295aSEtienne Carriere 
248137e8295aSEtienne Carriere 		p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) &
248237e8295aSEtienne Carriere 			sel->msk;
248337e8295aSEtienne Carriere 
248437e8295aSEtienne Carriere 		if (p_sel < sel->nb_parent) {
248537e8295aSEtienne Carriere 			return (int)sel->parent[p_sel];
248637e8295aSEtienne Carriere 		}
248737e8295aSEtienne Carriere 	} else {
248837e8295aSEtienne Carriere 		const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
248937e8295aSEtienne Carriere 
249037e8295aSEtienne Carriere 		p_sel = mmio_read_32(rcc_base + pll->rckxselr) &
249137e8295aSEtienne Carriere 			RCC_SELR_REFCLK_SRC_MASK;
249237e8295aSEtienne Carriere 
249337e8295aSEtienne Carriere 		if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) {
249437e8295aSEtienne Carriere 			return (int)pll->refclk[p_sel];
249537e8295aSEtienne Carriere 		}
249637e8295aSEtienne Carriere 	}
249737e8295aSEtienne Carriere 
249837e8295aSEtienne Carriere 	VERBOSE("No parent selected for %s\n",
249937e8295aSEtienne Carriere 		stm32mp1_clk_parent_name[parent_id]);
250037e8295aSEtienne Carriere 
250137e8295aSEtienne Carriere 	return -1;
250237e8295aSEtienne Carriere }
250337e8295aSEtienne Carriere 
250437e8295aSEtienne Carriere static void secure_parent_clocks(unsigned long parent_id)
250537e8295aSEtienne Carriere {
250637e8295aSEtienne Carriere 	int grandparent_id;
250737e8295aSEtienne Carriere 
250837e8295aSEtienne Carriere 	switch (parent_id) {
250937e8295aSEtienne Carriere 	case _PLL3_P:
251037e8295aSEtienne Carriere 	case _PLL3_Q:
251137e8295aSEtienne Carriere 	case _PLL3_R:
251237e8295aSEtienne Carriere 		stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
251337e8295aSEtienne Carriere 		break;
251437e8295aSEtienne Carriere 
251537e8295aSEtienne Carriere 	/* These clocks are always secure when RCC is secure */
251637e8295aSEtienne Carriere 	case _ACLK:
251737e8295aSEtienne Carriere 	case _HCLK2:
251837e8295aSEtienne Carriere 	case _HCLK6:
251937e8295aSEtienne Carriere 	case _PCLK4:
252037e8295aSEtienne Carriere 	case _PCLK5:
252137e8295aSEtienne Carriere 	case _PLL1_P:
252237e8295aSEtienne Carriere 	case _PLL1_Q:
252337e8295aSEtienne Carriere 	case _PLL1_R:
252437e8295aSEtienne Carriere 	case _PLL2_P:
252537e8295aSEtienne Carriere 	case _PLL2_Q:
252637e8295aSEtienne Carriere 	case _PLL2_R:
252737e8295aSEtienne Carriere 	case _HSI:
252837e8295aSEtienne Carriere 	case _HSI_KER:
252937e8295aSEtienne Carriere 	case _LSI:
253037e8295aSEtienne Carriere 	case _CSI:
253137e8295aSEtienne Carriere 	case _CSI_KER:
253237e8295aSEtienne Carriere 	case _HSE:
253337e8295aSEtienne Carriere 	case _HSE_KER:
253437e8295aSEtienne Carriere 	case _HSE_KER_DIV2:
2535cbd2e8a6SGabriel Fernandez 	case _HSE_RTC:
253637e8295aSEtienne Carriere 	case _LSE:
253737e8295aSEtienne Carriere 		break;
253837e8295aSEtienne Carriere 
253937e8295aSEtienne Carriere 	default:
254037e8295aSEtienne Carriere 		VERBOSE("Cannot secure parent clock %s\n",
254137e8295aSEtienne Carriere 			stm32mp1_clk_parent_name[parent_id]);
254237e8295aSEtienne Carriere 		panic();
254337e8295aSEtienne Carriere 	}
254437e8295aSEtienne Carriere 
254537e8295aSEtienne Carriere 	grandparent_id = get_parent_id_parent(parent_id);
254637e8295aSEtienne Carriere 	if (grandparent_id >= 0) {
254737e8295aSEtienne Carriere 		secure_parent_clocks(grandparent_id);
254837e8295aSEtienne Carriere 	}
254937e8295aSEtienne Carriere }
255037e8295aSEtienne Carriere 
255137e8295aSEtienne Carriere void stm32mp1_register_clock_parents_secure(unsigned long clock_id)
255237e8295aSEtienne Carriere {
255337e8295aSEtienne Carriere 	int parent_id;
255437e8295aSEtienne Carriere 
255537e8295aSEtienne Carriere 	if (!stm32mp1_rcc_is_secure()) {
255637e8295aSEtienne Carriere 		return;
255737e8295aSEtienne Carriere 	}
255837e8295aSEtienne Carriere 
255937e8295aSEtienne Carriere 	switch (clock_id) {
256037e8295aSEtienne Carriere 	case PLL1:
256137e8295aSEtienne Carriere 	case PLL2:
256237e8295aSEtienne Carriere 		/* PLL1/PLL2 are always secure: nothing to do */
256337e8295aSEtienne Carriere 		break;
256437e8295aSEtienne Carriere 	case PLL3:
256537e8295aSEtienne Carriere 		stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
256637e8295aSEtienne Carriere 		break;
256737e8295aSEtienne Carriere 	case PLL4:
256837e8295aSEtienne Carriere 		ERROR("PLL4 cannot be secured\n");
256937e8295aSEtienne Carriere 		panic();
257037e8295aSEtienne Carriere 		break;
257137e8295aSEtienne Carriere 	default:
257237e8295aSEtienne Carriere 		/* Others are expected gateable clock */
257337e8295aSEtienne Carriere 		parent_id = stm32mp1_clk_get_parent(clock_id);
257437e8295aSEtienne Carriere 		if (parent_id < 0) {
257537e8295aSEtienne Carriere 			INFO("No parent found for clock %lu\n", clock_id);
257637e8295aSEtienne Carriere 		} else {
257737e8295aSEtienne Carriere 			secure_parent_clocks(parent_id);
257837e8295aSEtienne Carriere 		}
257937e8295aSEtienne Carriere 		break;
258037e8295aSEtienne Carriere 	}
258137e8295aSEtienne Carriere }
258237e8295aSEtienne Carriere #endif /* STM32MP_SHARED_RESOURCES */
258337e8295aSEtienne Carriere 
258477b4ca0bSLionel Debieve void stm32mp1_clk_mcuss_protect(bool enable)
258577b4ca0bSLionel Debieve {
258677b4ca0bSLionel Debieve 	uintptr_t rcc_base = stm32mp_rcc_base();
258777b4ca0bSLionel Debieve 
258877b4ca0bSLionel Debieve 	if (enable) {
258977b4ca0bSLionel Debieve 		mmio_setbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
259077b4ca0bSLionel Debieve 	} else {
259177b4ca0bSLionel Debieve 		mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
259277b4ca0bSLionel Debieve 	}
259377b4ca0bSLionel Debieve }
259477b4ca0bSLionel Debieve 
25956cb45f89SYann Gautier static void sync_earlyboot_clocks_state(void)
25966cb45f89SYann Gautier {
2597033b6c3aSEtienne Carriere 	unsigned int idx;
2598033b6c3aSEtienne Carriere 	const unsigned long secure_enable[] = {
2599033b6c3aSEtienne Carriere 		AXIDCG,
2600033b6c3aSEtienne Carriere 		BSEC,
2601033b6c3aSEtienne Carriere 		DDRC1, DDRC1LP,
2602033b6c3aSEtienne Carriere 		DDRC2, DDRC2LP,
2603033b6c3aSEtienne Carriere 		DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP,
2604033b6c3aSEtienne Carriere 		DDRPHYC, DDRPHYCLP,
2605373f06beSLionel Debieve 		RTCAPB,
2606033b6c3aSEtienne Carriere 		TZC1, TZC2,
2607033b6c3aSEtienne Carriere 		TZPC,
2608033b6c3aSEtienne Carriere 		STGEN_K,
2609033b6c3aSEtienne Carriere 	};
2610033b6c3aSEtienne Carriere 
2611033b6c3aSEtienne Carriere 	for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) {
2612033b6c3aSEtienne Carriere 		stm32mp_clk_enable(secure_enable[idx]);
2613033b6c3aSEtienne Carriere 	}
26146cb45f89SYann Gautier }
26156cb45f89SYann Gautier 
261633667d29SYann Gautier static const struct clk_ops stm32mp_clk_ops = {
261733667d29SYann Gautier 	.enable		= stm32mp_clk_enable,
261833667d29SYann Gautier 	.disable	= stm32mp_clk_disable,
261933667d29SYann Gautier 	.is_enabled	= stm32mp_clk_is_enabled,
262033667d29SYann Gautier 	.get_rate	= stm32mp_clk_get_rate,
262133667d29SYann Gautier 	.get_parent	= stm32mp1_clk_get_parent,
262233667d29SYann Gautier };
262333667d29SYann Gautier 
2624*ae1e5037SGabriel Fernandez struct stm32_pll_dt_cfg mp15_pll[_PLL_NB];
2625*ae1e5037SGabriel Fernandez uint32_t mp15_clksrc[MUX_NB];
2626*ae1e5037SGabriel Fernandez uint32_t mp15_clkdiv[DIV_NB];
2627*ae1e5037SGabriel Fernandez 
2628*ae1e5037SGabriel Fernandez struct stm32_clk_platdata stm32mp15_clock_pdata = {
2629*ae1e5037SGabriel Fernandez 	.pll		= mp15_pll,
2630*ae1e5037SGabriel Fernandez 	.npll		= _PLL_NB,
2631*ae1e5037SGabriel Fernandez 	.clksrc		= mp15_clksrc,
2632*ae1e5037SGabriel Fernandez 	.nclksrc	= MUX_NB,
2633*ae1e5037SGabriel Fernandez 	.clkdiv		= mp15_clkdiv,
2634*ae1e5037SGabriel Fernandez 	.nclkdiv	= DIV_NB,
2635*ae1e5037SGabriel Fernandez };
2636*ae1e5037SGabriel Fernandez 
2637*ae1e5037SGabriel Fernandez static struct stm32_clk_priv stm32mp15_clock_data = {
2638*ae1e5037SGabriel Fernandez 	.base		= RCC_BASE,
2639*ae1e5037SGabriel Fernandez 	.parents	= parent_mp15,
2640*ae1e5037SGabriel Fernandez 	.nb_parents	= ARRAY_SIZE(parent_mp15),
2641*ae1e5037SGabriel Fernandez 	.div		= dividers_mp15,
2642*ae1e5037SGabriel Fernandez 	.nb_div		= ARRAY_SIZE(dividers_mp15),
2643*ae1e5037SGabriel Fernandez 	.pdata		= &stm32mp15_clock_pdata,
2644*ae1e5037SGabriel Fernandez };
2645*ae1e5037SGabriel Fernandez 
2646*ae1e5037SGabriel Fernandez static int stm32_clk_parse_fdt_by_name(void *fdt, int node, const char *name,
2647*ae1e5037SGabriel Fernandez 				       uint32_t *tab, uint32_t *nb)
2648*ae1e5037SGabriel Fernandez {
2649*ae1e5037SGabriel Fernandez 	const fdt32_t *cell;
2650*ae1e5037SGabriel Fernandez 	int len = 0;
2651*ae1e5037SGabriel Fernandez 	uint32_t i;
2652*ae1e5037SGabriel Fernandez 
2653*ae1e5037SGabriel Fernandez 	cell = fdt_getprop(fdt, node, name, &len);
2654*ae1e5037SGabriel Fernandez 	if (cell == NULL) {
2655*ae1e5037SGabriel Fernandez 		*nb = 0U;
2656*ae1e5037SGabriel Fernandez 		return 0;
2657*ae1e5037SGabriel Fernandez 	}
2658*ae1e5037SGabriel Fernandez 
2659*ae1e5037SGabriel Fernandez 	for (i = 0U; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
2660*ae1e5037SGabriel Fernandez 		tab[i] = fdt32_to_cpu(cell[i]);
2661*ae1e5037SGabriel Fernandez 	}
2662*ae1e5037SGabriel Fernandez 
2663*ae1e5037SGabriel Fernandez 	*nb = (uint32_t)len / sizeof(uint32_t);
2664*ae1e5037SGabriel Fernandez 
2665*ae1e5037SGabriel Fernandez 	return 0;
2666*ae1e5037SGabriel Fernandez }
2667*ae1e5037SGabriel Fernandez 
2668*ae1e5037SGabriel Fernandez #define RCC_PLL_NAME_SIZE 12
2669*ae1e5037SGabriel Fernandez 
2670*ae1e5037SGabriel Fernandez static int clk_stm32_load_vco_config(void *fdt, int subnode, struct stm32_pll_dt_cfg *pll)
2671*ae1e5037SGabriel Fernandez {
2672*ae1e5037SGabriel Fernandez 	int err;
2673*ae1e5037SGabriel Fernandez 
2674*ae1e5037SGabriel Fernandez 	err = fdt_read_uint32_array(fdt, subnode, "divmn", (int)PLL_DIV_MN_NB, &pll->cfg[PLLCFG_M]);
2675*ae1e5037SGabriel Fernandez 	if (err != 0) {
2676*ae1e5037SGabriel Fernandez 		return err;
2677*ae1e5037SGabriel Fernandez 	}
2678*ae1e5037SGabriel Fernandez 
2679*ae1e5037SGabriel Fernandez 	err = fdt_read_uint32_array(fdt, subnode, "csg", (int)PLLCSG_NB, pll->csg);
2680*ae1e5037SGabriel Fernandez 	if (err == 0) {
2681*ae1e5037SGabriel Fernandez 		pll->csg_enabled = true;
2682*ae1e5037SGabriel Fernandez 	} else if (err == -FDT_ERR_NOTFOUND) {
2683*ae1e5037SGabriel Fernandez 		pll->csg_enabled = false;
2684*ae1e5037SGabriel Fernandez 	} else {
2685*ae1e5037SGabriel Fernandez 		return err;
2686*ae1e5037SGabriel Fernandez 	}
2687*ae1e5037SGabriel Fernandez 
2688*ae1e5037SGabriel Fernandez 	pll->status = true;
2689*ae1e5037SGabriel Fernandez 
2690*ae1e5037SGabriel Fernandez 	pll->frac = fdt_read_uint32_default(fdt, subnode, "frac", 0);
2691*ae1e5037SGabriel Fernandez 
2692*ae1e5037SGabriel Fernandez 	pll->src = fdt_read_uint32_default(fdt, subnode, "src", UINT32_MAX);
2693*ae1e5037SGabriel Fernandez 
2694*ae1e5037SGabriel Fernandez 	return 0;
2695*ae1e5037SGabriel Fernandez }
2696*ae1e5037SGabriel Fernandez 
2697*ae1e5037SGabriel Fernandez static int clk_stm32_load_output_config(void *fdt, int subnode, struct stm32_pll_dt_cfg *pll)
2698*ae1e5037SGabriel Fernandez {
2699*ae1e5037SGabriel Fernandez 	int err;
2700*ae1e5037SGabriel Fernandez 
2701*ae1e5037SGabriel Fernandez 	err = fdt_read_uint32_array(fdt, subnode, "st,pll_div_pqr", (int)PLL_DIV_PQR_NB,
2702*ae1e5037SGabriel Fernandez 				    &pll->cfg[PLLCFG_P]);
2703*ae1e5037SGabriel Fernandez 	if (err != 0) {
2704*ae1e5037SGabriel Fernandez 		return err;
2705*ae1e5037SGabriel Fernandez 	}
2706*ae1e5037SGabriel Fernandez 
2707*ae1e5037SGabriel Fernandez 	pll->cfg[PLLCFG_O] = PQR(1, 1, 1);
2708*ae1e5037SGabriel Fernandez 
2709*ae1e5037SGabriel Fernandez 	return 0;
2710*ae1e5037SGabriel Fernandez }
2711*ae1e5037SGabriel Fernandez 
2712*ae1e5037SGabriel Fernandez static int clk_stm32_parse_pll_fdt(void *fdt, int subnode, struct stm32_pll_dt_cfg *pll)
2713*ae1e5037SGabriel Fernandez {
2714*ae1e5037SGabriel Fernandez 	const fdt32_t *cuint;
2715*ae1e5037SGabriel Fernandez 	int subnode_pll;
2716*ae1e5037SGabriel Fernandez 	int subnode_vco;
2717*ae1e5037SGabriel Fernandez 	int err;
2718*ae1e5037SGabriel Fernandez 
2719*ae1e5037SGabriel Fernandez 	cuint = fdt_getprop(fdt, subnode, "st,pll", NULL);
2720*ae1e5037SGabriel Fernandez 	if (cuint == NULL) {
2721*ae1e5037SGabriel Fernandez 		/* Case of no pll is defined */
2722*ae1e5037SGabriel Fernandez 		return 0;
2723*ae1e5037SGabriel Fernandez 	}
2724*ae1e5037SGabriel Fernandez 
2725*ae1e5037SGabriel Fernandez 	subnode_pll = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
2726*ae1e5037SGabriel Fernandez 	if (subnode_pll < 0) {
2727*ae1e5037SGabriel Fernandez 		return -FDT_ERR_NOTFOUND;
2728*ae1e5037SGabriel Fernandez 	}
2729*ae1e5037SGabriel Fernandez 
2730*ae1e5037SGabriel Fernandez 	cuint = fdt_getprop(fdt, subnode_pll, "st,pll_vco", NULL);
2731*ae1e5037SGabriel Fernandez 	if (cuint == NULL) {
2732*ae1e5037SGabriel Fernandez 		return -FDT_ERR_NOTFOUND;
2733*ae1e5037SGabriel Fernandez 	}
2734*ae1e5037SGabriel Fernandez 
2735*ae1e5037SGabriel Fernandez 	subnode_vco = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
2736*ae1e5037SGabriel Fernandez 	if (subnode_vco < 0) {
2737*ae1e5037SGabriel Fernandez 		return -FDT_ERR_NOTFOUND;
2738*ae1e5037SGabriel Fernandez 	}
2739*ae1e5037SGabriel Fernandez 
2740*ae1e5037SGabriel Fernandez 	err = clk_stm32_load_vco_config(fdt, subnode_vco, pll);
2741*ae1e5037SGabriel Fernandez 	if (err != 0) {
2742*ae1e5037SGabriel Fernandez 		return err;
2743*ae1e5037SGabriel Fernandez 	}
2744*ae1e5037SGabriel Fernandez 
2745*ae1e5037SGabriel Fernandez 	err = clk_stm32_load_output_config(fdt, subnode_pll, pll);
2746*ae1e5037SGabriel Fernandez 	if (err != 0) {
2747*ae1e5037SGabriel Fernandez 		return err;
2748*ae1e5037SGabriel Fernandez 	}
2749*ae1e5037SGabriel Fernandez 
2750*ae1e5037SGabriel Fernandez 	return 0;
2751*ae1e5037SGabriel Fernandez }
2752*ae1e5037SGabriel Fernandez 
2753*ae1e5037SGabriel Fernandez static int stm32_clk_parse_fdt_all_pll(void *fdt, int node, struct stm32_clk_platdata *pdata)
2754*ae1e5037SGabriel Fernandez {
2755*ae1e5037SGabriel Fernandez 	size_t i = 0U;
2756*ae1e5037SGabriel Fernandez 
2757*ae1e5037SGabriel Fernandez 	for (i = _PLL1; i < pdata->npll; i++) {
2758*ae1e5037SGabriel Fernandez 		struct stm32_pll_dt_cfg *pll = pdata->pll + i;
2759*ae1e5037SGabriel Fernandez 		char name[RCC_PLL_NAME_SIZE];
2760*ae1e5037SGabriel Fernandez 		int subnode;
2761*ae1e5037SGabriel Fernandez 		int err;
2762*ae1e5037SGabriel Fernandez 
2763*ae1e5037SGabriel Fernandez 		snprintf(name, sizeof(name), "st,pll@%u", i);
2764*ae1e5037SGabriel Fernandez 
2765*ae1e5037SGabriel Fernandez 		subnode = fdt_subnode_offset(fdt, node, name);
2766*ae1e5037SGabriel Fernandez 		if (!fdt_check_node(subnode)) {
2767*ae1e5037SGabriel Fernandez 			continue;
2768*ae1e5037SGabriel Fernandez 		}
2769*ae1e5037SGabriel Fernandez 
2770*ae1e5037SGabriel Fernandez 		err = clk_stm32_parse_pll_fdt(fdt, subnode, pll);
2771*ae1e5037SGabriel Fernandez 		if (err != 0) {
2772*ae1e5037SGabriel Fernandez 			panic();
2773*ae1e5037SGabriel Fernandez 		}
2774*ae1e5037SGabriel Fernandez 	}
2775*ae1e5037SGabriel Fernandez 
2776*ae1e5037SGabriel Fernandez 	return 0;
2777*ae1e5037SGabriel Fernandez }
2778*ae1e5037SGabriel Fernandez 
2779*ae1e5037SGabriel Fernandez static int stm32_clk_parse_fdt(struct stm32_clk_platdata *pdata)
2780*ae1e5037SGabriel Fernandez {
2781*ae1e5037SGabriel Fernandez 	void *fdt = NULL;
2782*ae1e5037SGabriel Fernandez 	int node;
2783*ae1e5037SGabriel Fernandez 	uint32_t err;
2784*ae1e5037SGabriel Fernandez 
2785*ae1e5037SGabriel Fernandez 	if (fdt_get_address(&fdt) == 0) {
2786*ae1e5037SGabriel Fernandez 		return -ENOENT;
2787*ae1e5037SGabriel Fernandez 	}
2788*ae1e5037SGabriel Fernandez 
2789*ae1e5037SGabriel Fernandez 	node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
2790*ae1e5037SGabriel Fernandez 	if (node < 0) {
2791*ae1e5037SGabriel Fernandez 		panic();
2792*ae1e5037SGabriel Fernandez 	}
2793*ae1e5037SGabriel Fernandez 
2794*ae1e5037SGabriel Fernandez 	err = stm32_clk_parse_fdt_all_pll(fdt, node, pdata);
2795*ae1e5037SGabriel Fernandez 	if (err != 0) {
2796*ae1e5037SGabriel Fernandez 		return err;
2797*ae1e5037SGabriel Fernandez 	}
2798*ae1e5037SGabriel Fernandez 
2799*ae1e5037SGabriel Fernandez 	err = stm32_clk_parse_fdt_by_name(fdt, node, "st,clkdiv", pdata->clkdiv, &pdata->nclkdiv);
2800*ae1e5037SGabriel Fernandez 	if (err != 0) {
2801*ae1e5037SGabriel Fernandez 		return err;
2802*ae1e5037SGabriel Fernandez 	}
2803*ae1e5037SGabriel Fernandez 
2804*ae1e5037SGabriel Fernandez 	err = stm32_clk_parse_fdt_by_name(fdt, node, "st,clksrc", pdata->clksrc, &pdata->nclksrc);
2805*ae1e5037SGabriel Fernandez 	if (err != 0) {
2806*ae1e5037SGabriel Fernandez 		return err;
2807*ae1e5037SGabriel Fernandez 	}
2808*ae1e5037SGabriel Fernandez 
2809*ae1e5037SGabriel Fernandez 	return 0;
2810*ae1e5037SGabriel Fernandez }
2811*ae1e5037SGabriel Fernandez 
28127839a050SYann Gautier int stm32mp1_clk_probe(void)
28137839a050SYann Gautier {
2814*ae1e5037SGabriel Fernandez 	uintptr_t base = RCC_BASE;
2815*ae1e5037SGabriel Fernandez 	int ret;
2816*ae1e5037SGabriel Fernandez 
2817812daf91SLionel Debieve #if defined(IMAGE_BL32)
2818812daf91SLionel Debieve 	if (!fdt_get_rcc_secure_state()) {
2819812daf91SLionel Debieve 		mmio_write_32(stm32mp_rcc_base() + RCC_TZCR, 0U);
2820812daf91SLionel Debieve 	}
2821812daf91SLionel Debieve #endif
2822812daf91SLionel Debieve 
28237839a050SYann Gautier 	stm32mp1_osc_init();
28247839a050SYann Gautier 
2825*ae1e5037SGabriel Fernandez 	ret = stm32_clk_parse_fdt(&stm32mp15_clock_pdata);
2826*ae1e5037SGabriel Fernandez 	if (ret != 0) {
2827*ae1e5037SGabriel Fernandez 		return ret;
2828*ae1e5037SGabriel Fernandez 	}
2829*ae1e5037SGabriel Fernandez 
2830*ae1e5037SGabriel Fernandez 	ret = clk_stm32_init(&stm32mp15_clock_data, base);
2831*ae1e5037SGabriel Fernandez 	if (ret != 0) {
2832*ae1e5037SGabriel Fernandez 		return ret;
2833*ae1e5037SGabriel Fernandez 	}
2834*ae1e5037SGabriel Fernandez 
28356cb45f89SYann Gautier 	sync_earlyboot_clocks_state();
28366cb45f89SYann Gautier 
283733667d29SYann Gautier 	clk_register(&stm32mp_clk_ops);
283833667d29SYann Gautier 
28397839a050SYann Gautier 	return 0;
28407839a050SYann Gautier }
2841