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