1e5e793a6SGabriel Fernandez // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2e5e793a6SGabriel Fernandez /*
3e5e793a6SGabriel Fernandez * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
4e5e793a6SGabriel Fernandez */
5e5e793a6SGabriel Fernandez
6e5e793a6SGabriel Fernandez #include <config.h>
7e5e793a6SGabriel Fernandez #include <drivers/clk.h>
8e5e793a6SGabriel Fernandez #include <drivers/clk_dt.h>
91e1e5a4dSGatien Chevallier #include <drivers/stm32_shared_io.h>
10e5e793a6SGabriel Fernandez #include <io.h>
11e5e793a6SGabriel Fernandez #include <kernel/boot.h>
12e5e793a6SGabriel Fernandez #include <kernel/delay.h>
13e5e793a6SGabriel Fernandez #include <kernel/dt.h>
14e5e793a6SGabriel Fernandez #include <libfdt.h>
15e5e793a6SGabriel Fernandez #include <stdio.h>
16e5e793a6SGabriel Fernandez #include <stm32_util.h>
17e5e793a6SGabriel Fernandez
18e5e793a6SGabriel Fernandez #include "clk-stm32-core.h"
19e5e793a6SGabriel Fernandez
20e5e793a6SGabriel Fernandez #define RCC_MP_ENCLRR_OFFSET 0x4
21e5e793a6SGabriel Fernandez
22e5e793a6SGabriel Fernandez #define TIMEOUT_US_200MS U(200000)
23e5e793a6SGabriel Fernandez #define TIMEOUT_US_1S U(1000000)
24e5e793a6SGabriel Fernandez
25e5e793a6SGabriel Fernandez static struct clk_stm32_priv *stm32_clock_data;
26e5e793a6SGabriel Fernandez
clk_stm32_get_priv(void)27e5e793a6SGabriel Fernandez struct clk_stm32_priv *clk_stm32_get_priv(void)
28e5e793a6SGabriel Fernandez {
29e5e793a6SGabriel Fernandez return stm32_clock_data;
30e5e793a6SGabriel Fernandez }
31e5e793a6SGabriel Fernandez
clk_stm32_get_rcc_base(void)32e5e793a6SGabriel Fernandez uintptr_t clk_stm32_get_rcc_base(void)
33e5e793a6SGabriel Fernandez {
34e5e793a6SGabriel Fernandez struct clk_stm32_priv *priv = clk_stm32_get_priv();
35e5e793a6SGabriel Fernandez
36e5e793a6SGabriel Fernandez return priv->base;
37e5e793a6SGabriel Fernandez }
38e5e793a6SGabriel Fernandez
39e5e793a6SGabriel Fernandez /* STM32 MUX API */
stm32_mux_get_parent(uint32_t mux_id)40e5e793a6SGabriel Fernandez size_t stm32_mux_get_parent(uint32_t mux_id)
41e5e793a6SGabriel Fernandez {
42e5e793a6SGabriel Fernandez struct clk_stm32_priv *priv = clk_stm32_get_priv();
43e5e793a6SGabriel Fernandez const struct mux_cfg *mux = &priv->muxes[mux_id];
44e5e793a6SGabriel Fernandez uint32_t mask = MASK_WIDTH_SHIFT(mux->width, mux->shift);
45e5e793a6SGabriel Fernandez
46e5e793a6SGabriel Fernandez return (io_read32(priv->base + mux->offset) & mask) >> mux->shift;
47e5e793a6SGabriel Fernandez }
48e5e793a6SGabriel Fernandez
stm32_mux_set_parent(uint16_t mux_id,uint8_t sel)49e5e793a6SGabriel Fernandez TEE_Result stm32_mux_set_parent(uint16_t mux_id, uint8_t sel)
50e5e793a6SGabriel Fernandez {
51e5e793a6SGabriel Fernandez struct clk_stm32_priv *priv = clk_stm32_get_priv();
52e5e793a6SGabriel Fernandez const struct mux_cfg *mux = &priv->muxes[mux_id];
53e5e793a6SGabriel Fernandez uint32_t mask = MASK_WIDTH_SHIFT(mux->width, mux->shift);
54e5e793a6SGabriel Fernandez uintptr_t address = priv->base + mux->offset;
55e5e793a6SGabriel Fernandez
56e5e793a6SGabriel Fernandez io_clrsetbits32(address, mask, (sel << mux->shift) & mask);
57e5e793a6SGabriel Fernandez
58e5e793a6SGabriel Fernandez if (mux->ready != MUX_NO_RDY)
59e5e793a6SGabriel Fernandez return stm32_gate_wait_ready((uint16_t)mux->ready, true);
60e5e793a6SGabriel Fernandez
61e5e793a6SGabriel Fernandez return TEE_SUCCESS;
62e5e793a6SGabriel Fernandez }
63e5e793a6SGabriel Fernandez
64e5e793a6SGabriel Fernandez /* STM32 GATE API */
stm32_gate_endisable(uint16_t gate_id,bool enable)65e5e793a6SGabriel Fernandez static void stm32_gate_endisable(uint16_t gate_id, bool enable)
66e5e793a6SGabriel Fernandez {
67e5e793a6SGabriel Fernandez struct clk_stm32_priv *priv = clk_stm32_get_priv();
68e5e793a6SGabriel Fernandez const struct gate_cfg *gate = &priv->gates[gate_id];
69e5e793a6SGabriel Fernandez uintptr_t addr = priv->base + gate->offset;
70e5e793a6SGabriel Fernandez
71e5e793a6SGabriel Fernandez if (enable) {
72e5e793a6SGabriel Fernandez if (gate->set_clr)
73e5e793a6SGabriel Fernandez io_write32(addr, BIT(gate->bit_idx));
74e5e793a6SGabriel Fernandez else
75e5e793a6SGabriel Fernandez io_setbits32_stm32shregs(addr, BIT(gate->bit_idx));
76a86abe43SGatien Chevallier /* Make sure the clock is enabled before returning to caller */
77a86abe43SGatien Chevallier dsb();
78e5e793a6SGabriel Fernandez } else {
79a86abe43SGatien Chevallier /* Waiting pending operation before disabling clock */
80a86abe43SGatien Chevallier dsb();
81a86abe43SGatien Chevallier
82e5e793a6SGabriel Fernandez if (gate->set_clr)
83e5e793a6SGabriel Fernandez io_write32(addr + RCC_MP_ENCLRR_OFFSET,
84e5e793a6SGabriel Fernandez BIT(gate->bit_idx));
85e5e793a6SGabriel Fernandez else
86e5e793a6SGabriel Fernandez io_clrbits32_stm32shregs(addr, BIT(gate->bit_idx));
87e5e793a6SGabriel Fernandez }
88e5e793a6SGabriel Fernandez }
89e5e793a6SGabriel Fernandez
stm32_gate_set_init_state(uint16_t gate_id,bool enable)906a977fc4SEtienne Carriere void stm32_gate_set_init_state(uint16_t gate_id, bool enable)
916a977fc4SEtienne Carriere {
926a977fc4SEtienne Carriere struct clk_stm32_priv __maybe_unused *priv = clk_stm32_get_priv();
936a977fc4SEtienne Carriere
946a977fc4SEtienne Carriere assert(!priv->gate_cpt[gate_id]);
956a977fc4SEtienne Carriere stm32_gate_endisable(gate_id, enable);
966a977fc4SEtienne Carriere }
976a977fc4SEtienne Carriere
stm32_gate_disable(uint16_t gate_id)98e5e793a6SGabriel Fernandez void stm32_gate_disable(uint16_t gate_id)
99e5e793a6SGabriel Fernandez {
1002b028a2bSGatien Chevallier struct clk_stm32_priv *priv = clk_stm32_get_priv();
1012b028a2bSGatien Chevallier uint8_t *gate_cpt = priv->gate_cpt;
1022b028a2bSGatien Chevallier
1032b028a2bSGatien Chevallier assert(gate_cpt[gate_id] > 0);
1042b028a2bSGatien Chevallier if (gate_cpt[gate_id] == 1)
105e5e793a6SGabriel Fernandez stm32_gate_endisable(gate_id, false);
1062b028a2bSGatien Chevallier gate_cpt[gate_id]--;
107e5e793a6SGabriel Fernandez }
108e5e793a6SGabriel Fernandez
stm32_gate_enable(uint16_t gate_id)109e5e793a6SGabriel Fernandez void stm32_gate_enable(uint16_t gate_id)
110e5e793a6SGabriel Fernandez {
1112b028a2bSGatien Chevallier struct clk_stm32_priv *priv = clk_stm32_get_priv();
1122b028a2bSGatien Chevallier uint8_t *gate_cpt = priv->gate_cpt;
1132b028a2bSGatien Chevallier
1142b028a2bSGatien Chevallier assert(gate_cpt[gate_id] < 0xFF);
1152b028a2bSGatien Chevallier if (gate_cpt[gate_id] == 0)
116e5e793a6SGabriel Fernandez stm32_gate_endisable(gate_id, true);
1172b028a2bSGatien Chevallier gate_cpt[gate_id]++;
118e5e793a6SGabriel Fernandez }
119e5e793a6SGabriel Fernandez
stm32_gate_is_enabled(uint16_t gate_id)120e5e793a6SGabriel Fernandez bool stm32_gate_is_enabled(uint16_t gate_id)
121e5e793a6SGabriel Fernandez {
122e5e793a6SGabriel Fernandez struct clk_stm32_priv *priv = clk_stm32_get_priv();
123e5e793a6SGabriel Fernandez const struct gate_cfg *gate = &priv->gates[gate_id];
124e5e793a6SGabriel Fernandez uintptr_t addr = priv->base + gate->offset;
125e5e793a6SGabriel Fernandez
126e5e793a6SGabriel Fernandez return (io_read32(addr) & BIT(gate->bit_idx)) != 0U;
127e5e793a6SGabriel Fernandez }
128e5e793a6SGabriel Fernandez
stm32_gate_wait_ready(uint16_t gate_id,bool ready_on)129e5e793a6SGabriel Fernandez TEE_Result stm32_gate_wait_ready(uint16_t gate_id, bool ready_on)
130e5e793a6SGabriel Fernandez {
131e5e793a6SGabriel Fernandez struct clk_stm32_priv *priv = clk_stm32_get_priv();
132e5e793a6SGabriel Fernandez const struct gate_cfg *gate = &priv->gates[gate_id];
133e5e793a6SGabriel Fernandez uintptr_t address = priv->base + gate->offset;
134e5e793a6SGabriel Fernandez uint32_t mask_rdy = BIT(gate->bit_idx);
135e5e793a6SGabriel Fernandez uint64_t timeout = timeout_init_us(TIMEOUT_US_1S);
136e5e793a6SGabriel Fernandez uint32_t mask = 0U;
137e5e793a6SGabriel Fernandez
138e5e793a6SGabriel Fernandez if (ready_on)
139e5e793a6SGabriel Fernandez mask = BIT(gate->bit_idx);
140e5e793a6SGabriel Fernandez
141e5e793a6SGabriel Fernandez while ((io_read32(address) & mask_rdy) != mask)
142e5e793a6SGabriel Fernandez if (timeout_elapsed(timeout))
143e5e793a6SGabriel Fernandez break;
144e5e793a6SGabriel Fernandez
145e5e793a6SGabriel Fernandez if ((io_read32(address) & mask_rdy) != mask)
146e5e793a6SGabriel Fernandez return TEE_ERROR_GENERIC;
147e5e793a6SGabriel Fernandez
148e5e793a6SGabriel Fernandez return TEE_SUCCESS;
149e5e793a6SGabriel Fernandez }
150e5e793a6SGabriel Fernandez
151e5e793a6SGabriel Fernandez /* STM32 GATE READY clock operators */
stm32_gate_ready_endisable(uint16_t gate_id,bool enable,bool wait_rdy)152e5e793a6SGabriel Fernandez static TEE_Result stm32_gate_ready_endisable(uint16_t gate_id, bool enable,
153e5e793a6SGabriel Fernandez bool wait_rdy)
154e5e793a6SGabriel Fernandez {
15598642cf4SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC;
15698642cf4SEtienne Carriere
157e5e793a6SGabriel Fernandez stm32_gate_endisable(gate_id, enable);
158e5e793a6SGabriel Fernandez
15998642cf4SEtienne Carriere if (wait_rdy) {
16098642cf4SEtienne Carriere res = stm32_gate_wait_ready(gate_id + 1, enable);
16198642cf4SEtienne Carriere if (res) {
16298642cf4SEtienne Carriere stm32_gate_endisable(gate_id, !enable);
16398642cf4SEtienne Carriere if (stm32_gate_wait_ready(gate_id + 1, !enable))
16498642cf4SEtienne Carriere panic("Gate failed to sync");
16598642cf4SEtienne Carriere
16698642cf4SEtienne Carriere return res;
16798642cf4SEtienne Carriere }
16898642cf4SEtienne Carriere }
169e5e793a6SGabriel Fernandez
170e5e793a6SGabriel Fernandez return TEE_SUCCESS;
171e5e793a6SGabriel Fernandez }
172e5e793a6SGabriel Fernandez
stm32_gate_rdy_enable(uint16_t gate_id)173e5e793a6SGabriel Fernandez TEE_Result stm32_gate_rdy_enable(uint16_t gate_id)
174e5e793a6SGabriel Fernandez {
175e5e793a6SGabriel Fernandez return stm32_gate_ready_endisable(gate_id, true, true);
176e5e793a6SGabriel Fernandez }
177e5e793a6SGabriel Fernandez
stm32_gate_rdy_disable(uint16_t gate_id)178e5e793a6SGabriel Fernandez TEE_Result stm32_gate_rdy_disable(uint16_t gate_id)
179e5e793a6SGabriel Fernandez {
180e5e793a6SGabriel Fernandez return stm32_gate_ready_endisable(gate_id, false, true);
181e5e793a6SGabriel Fernandez }
182e5e793a6SGabriel Fernandez
183e5e793a6SGabriel Fernandez /* STM32 DIV API */
_get_table_div(const struct div_table_cfg * table,unsigned int val)184e5e793a6SGabriel Fernandez static unsigned int _get_table_div(const struct div_table_cfg *table,
185e5e793a6SGabriel Fernandez unsigned int val)
186e5e793a6SGabriel Fernandez {
187e5e793a6SGabriel Fernandez const struct div_table_cfg *clkt = NULL;
188e5e793a6SGabriel Fernandez
189e5e793a6SGabriel Fernandez for (clkt = table; clkt->div; clkt++)
190e5e793a6SGabriel Fernandez if (clkt->val == val)
191e5e793a6SGabriel Fernandez return clkt->div;
192e5e793a6SGabriel Fernandez
193e5e793a6SGabriel Fernandez return 0;
194e5e793a6SGabriel Fernandez }
195e5e793a6SGabriel Fernandez
_get_table_val(const struct div_table_cfg * table,unsigned int div)196e5e793a6SGabriel Fernandez static unsigned int _get_table_val(const struct div_table_cfg *table,
197e5e793a6SGabriel Fernandez unsigned int div)
198e5e793a6SGabriel Fernandez {
199e5e793a6SGabriel Fernandez const struct div_table_cfg *clkt = NULL;
200e5e793a6SGabriel Fernandez
201e5e793a6SGabriel Fernandez for (clkt = table; clkt->div; clkt++)
202e5e793a6SGabriel Fernandez if (clkt->div == div)
203e5e793a6SGabriel Fernandez return clkt->val;
204e5e793a6SGabriel Fernandez
205e5e793a6SGabriel Fernandez return 0;
206e5e793a6SGabriel Fernandez }
207e5e793a6SGabriel Fernandez
_get_div(const struct div_table_cfg * table,unsigned int val,unsigned long flags,uint8_t width)208e5e793a6SGabriel Fernandez static unsigned int _get_div(const struct div_table_cfg *table,
209e5e793a6SGabriel Fernandez unsigned int val, unsigned long flags,
210e5e793a6SGabriel Fernandez uint8_t width)
211e5e793a6SGabriel Fernandez {
212e5e793a6SGabriel Fernandez if (flags & CLK_DIVIDER_ONE_BASED)
213e5e793a6SGabriel Fernandez return val;
214e5e793a6SGabriel Fernandez
215e5e793a6SGabriel Fernandez if (flags & CLK_DIVIDER_POWER_OF_TWO)
216e5e793a6SGabriel Fernandez return BIT(val);
217e5e793a6SGabriel Fernandez
218e5e793a6SGabriel Fernandez if (flags & CLK_DIVIDER_MAX_AT_ZERO)
219e5e793a6SGabriel Fernandez return (val != 0U) ? val : BIT(width);
220e5e793a6SGabriel Fernandez
221e5e793a6SGabriel Fernandez if (table)
222e5e793a6SGabriel Fernandez return _get_table_div(table, val);
223e5e793a6SGabriel Fernandez
224e5e793a6SGabriel Fernandez return val + 1U;
225e5e793a6SGabriel Fernandez }
226e5e793a6SGabriel Fernandez
_get_val(const struct div_table_cfg * table,unsigned int div,unsigned long flags,uint8_t width)227e5e793a6SGabriel Fernandez static unsigned int _get_val(const struct div_table_cfg *table,
228e5e793a6SGabriel Fernandez unsigned int div, unsigned long flags,
229e5e793a6SGabriel Fernandez uint8_t width)
230e5e793a6SGabriel Fernandez {
231e5e793a6SGabriel Fernandez if (flags & CLK_DIVIDER_ONE_BASED)
232e5e793a6SGabriel Fernandez return div;
233e5e793a6SGabriel Fernandez
234e5e793a6SGabriel Fernandez if (flags & CLK_DIVIDER_POWER_OF_TWO)
235e5e793a6SGabriel Fernandez return __builtin_ffs(div) - 1;
236e5e793a6SGabriel Fernandez
237e5e793a6SGabriel Fernandez if (flags & CLK_DIVIDER_MAX_AT_ZERO)
238e5e793a6SGabriel Fernandez return (div != 0U) ? div : BIT(width);
239e5e793a6SGabriel Fernandez
240e5e793a6SGabriel Fernandez if (table)
241e5e793a6SGabriel Fernandez return _get_table_val(table, div);
242e5e793a6SGabriel Fernandez
243e5e793a6SGabriel Fernandez return div - 1U;
244e5e793a6SGabriel Fernandez }
245e5e793a6SGabriel Fernandez
_is_valid_table_div(const struct div_table_cfg * table,unsigned int div)246e5e793a6SGabriel Fernandez static bool _is_valid_table_div(const struct div_table_cfg *table,
247e5e793a6SGabriel Fernandez unsigned int div)
248e5e793a6SGabriel Fernandez {
249e5e793a6SGabriel Fernandez const struct div_table_cfg *clkt = NULL;
250e5e793a6SGabriel Fernandez
251e5e793a6SGabriel Fernandez for (clkt = table; clkt->div; clkt++)
252e5e793a6SGabriel Fernandez if (clkt->div == div)
253e5e793a6SGabriel Fernandez return true;
254e5e793a6SGabriel Fernandez
255e5e793a6SGabriel Fernandez return false;
256e5e793a6SGabriel Fernandez }
257e5e793a6SGabriel Fernandez
_is_valid_div(const struct div_table_cfg * table,unsigned int div,unsigned long flags)258e5e793a6SGabriel Fernandez static bool _is_valid_div(const struct div_table_cfg *table,
259e5e793a6SGabriel Fernandez unsigned int div, unsigned long flags)
260e5e793a6SGabriel Fernandez {
261e5e793a6SGabriel Fernandez if (flags & CLK_DIVIDER_POWER_OF_TWO)
262e5e793a6SGabriel Fernandez return IS_POWER_OF_TWO(div);
263e5e793a6SGabriel Fernandez
264e5e793a6SGabriel Fernandez if (table)
265e5e793a6SGabriel Fernandez return _is_valid_table_div(table, div);
266e5e793a6SGabriel Fernandez
267e5e793a6SGabriel Fernandez return true;
268e5e793a6SGabriel Fernandez }
269e5e793a6SGabriel Fernandez
divider_get_val(unsigned long rate,unsigned long parent_rate,const struct div_table_cfg * table,uint8_t width,unsigned long flags)270e5e793a6SGabriel Fernandez static int divider_get_val(unsigned long rate, unsigned long parent_rate,
271e5e793a6SGabriel Fernandez const struct div_table_cfg *table, uint8_t width,
272e5e793a6SGabriel Fernandez unsigned long flags)
273e5e793a6SGabriel Fernandez {
274e5e793a6SGabriel Fernandez unsigned int div = 0U;
275e5e793a6SGabriel Fernandez unsigned int value = 0U;
276e5e793a6SGabriel Fernandez
277e5e793a6SGabriel Fernandez div = UDIV_ROUND_NEAREST((uint64_t)parent_rate, rate);
278e5e793a6SGabriel Fernandez
279e5e793a6SGabriel Fernandez if (!_is_valid_div(table, div, flags))
280e5e793a6SGabriel Fernandez return -1;
281e5e793a6SGabriel Fernandez
282e5e793a6SGabriel Fernandez value = _get_val(table, div, flags, width);
283e5e793a6SGabriel Fernandez
284e5e793a6SGabriel Fernandez return MIN(value, MASK_WIDTH_SHIFT(width, 0));
285e5e793a6SGabriel Fernandez }
286e5e793a6SGabriel Fernandez
stm32_div_get_value(int div_id)287e5e793a6SGabriel Fernandez uint32_t stm32_div_get_value(int div_id)
288e5e793a6SGabriel Fernandez {
289e5e793a6SGabriel Fernandez struct clk_stm32_priv *priv = clk_stm32_get_priv();
290e5e793a6SGabriel Fernandez const struct div_cfg *divider = &priv->div[div_id];
291e5e793a6SGabriel Fernandez uint32_t val = 0;
292e5e793a6SGabriel Fernandez
293e5e793a6SGabriel Fernandez val = io_read32(priv->base + divider->offset) >> divider->shift;
294e5e793a6SGabriel Fernandez val &= MASK_WIDTH_SHIFT(divider->width, 0);
295e5e793a6SGabriel Fernandez
296e5e793a6SGabriel Fernandez return val;
297e5e793a6SGabriel Fernandez }
298e5e793a6SGabriel Fernandez
stm32_div_set_value(uint32_t div_id,uint32_t value)299e5e793a6SGabriel Fernandez TEE_Result stm32_div_set_value(uint32_t div_id, uint32_t value)
300e5e793a6SGabriel Fernandez {
301e5e793a6SGabriel Fernandez struct clk_stm32_priv *priv = clk_stm32_get_priv();
302e5e793a6SGabriel Fernandez const struct div_cfg *divider = NULL;
303e5e793a6SGabriel Fernandez uintptr_t address = 0;
304e5e793a6SGabriel Fernandez uint32_t mask = 0;
305e5e793a6SGabriel Fernandez
306e5e793a6SGabriel Fernandez if (div_id >= priv->nb_div)
307e5e793a6SGabriel Fernandez panic();
308e5e793a6SGabriel Fernandez
309e5e793a6SGabriel Fernandez divider = &priv->div[div_id];
310e5e793a6SGabriel Fernandez address = priv->base + divider->offset;
311e5e793a6SGabriel Fernandez
312e5e793a6SGabriel Fernandez mask = MASK_WIDTH_SHIFT(divider->width, divider->shift);
313e5e793a6SGabriel Fernandez io_clrsetbits32(address, mask, (value << divider->shift) & mask);
314e5e793a6SGabriel Fernandez
315e5e793a6SGabriel Fernandez if (divider->ready == DIV_NO_RDY)
316e5e793a6SGabriel Fernandez return TEE_SUCCESS;
317e5e793a6SGabriel Fernandez
318e5e793a6SGabriel Fernandez return stm32_gate_wait_ready((uint16_t)divider->ready, true);
319e5e793a6SGabriel Fernandez }
320e5e793a6SGabriel Fernandez
stm32_div_get_rate(int div_id,unsigned long prate)321e5e793a6SGabriel Fernandez static unsigned long stm32_div_get_rate(int div_id, unsigned long prate)
322e5e793a6SGabriel Fernandez {
323e5e793a6SGabriel Fernandez struct clk_stm32_priv *priv = clk_stm32_get_priv();
324e5e793a6SGabriel Fernandez const struct div_cfg *divider = &priv->div[div_id];
325e5e793a6SGabriel Fernandez uint32_t val = stm32_div_get_value(div_id);
326e5e793a6SGabriel Fernandez unsigned int div = 0U;
327e5e793a6SGabriel Fernandez
328e5e793a6SGabriel Fernandez div = _get_div(divider->table, val, divider->flags, divider->width);
329e5e793a6SGabriel Fernandez if (!div)
330e5e793a6SGabriel Fernandez return prate;
331e5e793a6SGabriel Fernandez
332*87823696SGatien Chevallier return ROUNDUP_DIV((uint64_t)prate, div);
333e5e793a6SGabriel Fernandez }
334e5e793a6SGabriel Fernandez
stm32_div_set_rate(int div_id,unsigned long rate,unsigned long prate)335e5e793a6SGabriel Fernandez TEE_Result stm32_div_set_rate(int div_id, unsigned long rate,
336e5e793a6SGabriel Fernandez unsigned long prate)
337e5e793a6SGabriel Fernandez {
338e5e793a6SGabriel Fernandez struct clk_stm32_priv *priv = clk_stm32_get_priv();
339e5e793a6SGabriel Fernandez const struct div_cfg *divider = &priv->div[div_id];
340e5e793a6SGabriel Fernandez int value = 0;
341e5e793a6SGabriel Fernandez
342e5e793a6SGabriel Fernandez value = divider_get_val(rate, prate, divider->table,
343e5e793a6SGabriel Fernandez divider->width, divider->flags);
344e5e793a6SGabriel Fernandez
345e5e793a6SGabriel Fernandez if (value < 0)
346e5e793a6SGabriel Fernandez return TEE_ERROR_GENERIC;
347e5e793a6SGabriel Fernandez
348e5e793a6SGabriel Fernandez return stm32_div_set_value(div_id, value);
349e5e793a6SGabriel Fernandez }
350e5e793a6SGabriel Fernandez
3515436921fSGabriel Fernandez /* STM32 MUX clock operators */
clk_stm32_mux_get_parent(struct clk * clk)3525436921fSGabriel Fernandez static size_t clk_stm32_mux_get_parent(struct clk *clk)
3535436921fSGabriel Fernandez {
3545436921fSGabriel Fernandez struct clk_stm32_mux_cfg *cfg = clk->priv;
3555436921fSGabriel Fernandez
3565436921fSGabriel Fernandez return stm32_mux_get_parent(cfg->mux_id);
3575436921fSGabriel Fernandez }
3585436921fSGabriel Fernandez
clk_stm32_mux_set_parent(struct clk * clk,size_t pidx)3595436921fSGabriel Fernandez static TEE_Result clk_stm32_mux_set_parent(struct clk *clk, size_t pidx)
3605436921fSGabriel Fernandez {
3615436921fSGabriel Fernandez struct clk_stm32_mux_cfg *cfg = clk->priv;
3625436921fSGabriel Fernandez
3635436921fSGabriel Fernandez return stm32_mux_set_parent(cfg->mux_id, pidx);
3645436921fSGabriel Fernandez }
3655436921fSGabriel Fernandez
3665436921fSGabriel Fernandez const struct clk_ops clk_stm32_mux_ops = {
3675436921fSGabriel Fernandez .get_parent = clk_stm32_mux_get_parent,
3685436921fSGabriel Fernandez .set_parent = clk_stm32_mux_set_parent,
3695436921fSGabriel Fernandez };
3705436921fSGabriel Fernandez
3715436921fSGabriel Fernandez /* STM32 GATE clock operators */
clk_stm32_gate_enable(struct clk * clk)3725436921fSGabriel Fernandez static TEE_Result clk_stm32_gate_enable(struct clk *clk)
3735436921fSGabriel Fernandez {
3745436921fSGabriel Fernandez struct clk_stm32_gate_cfg *cfg = clk->priv;
3755436921fSGabriel Fernandez
3765436921fSGabriel Fernandez stm32_gate_enable(cfg->gate_id);
3775436921fSGabriel Fernandez
3785436921fSGabriel Fernandez return TEE_SUCCESS;
3795436921fSGabriel Fernandez }
3805436921fSGabriel Fernandez
clk_stm32_gate_disable(struct clk * clk)3815436921fSGabriel Fernandez static void clk_stm32_gate_disable(struct clk *clk)
3825436921fSGabriel Fernandez {
3835436921fSGabriel Fernandez struct clk_stm32_gate_cfg *cfg = clk->priv;
3845436921fSGabriel Fernandez
3855436921fSGabriel Fernandez stm32_gate_disable(cfg->gate_id);
3865436921fSGabriel Fernandez }
3875436921fSGabriel Fernandez
3885436921fSGabriel Fernandez const struct clk_ops clk_stm32_gate_ops = {
3895436921fSGabriel Fernandez .enable = clk_stm32_gate_enable,
3905436921fSGabriel Fernandez .disable = clk_stm32_gate_disable,
3915436921fSGabriel Fernandez };
3925436921fSGabriel Fernandez
clk_stm32_gate_ready_enable(struct clk * clk)3935436921fSGabriel Fernandez static TEE_Result clk_stm32_gate_ready_enable(struct clk *clk)
3945436921fSGabriel Fernandez {
3955436921fSGabriel Fernandez struct clk_stm32_gate_cfg *cfg = clk->priv;
3965436921fSGabriel Fernandez
3975436921fSGabriel Fernandez return stm32_gate_rdy_enable(cfg->gate_id);
3985436921fSGabriel Fernandez }
3995436921fSGabriel Fernandez
clk_stm32_gate_ready_disable(struct clk * clk)4005436921fSGabriel Fernandez static void clk_stm32_gate_ready_disable(struct clk *clk)
4015436921fSGabriel Fernandez {
4025436921fSGabriel Fernandez struct clk_stm32_gate_cfg *cfg = clk->priv;
4035436921fSGabriel Fernandez
4045436921fSGabriel Fernandez if (stm32_gate_rdy_disable(cfg->gate_id))
4055436921fSGabriel Fernandez panic();
4065436921fSGabriel Fernandez }
4075436921fSGabriel Fernandez
4085436921fSGabriel Fernandez const struct clk_ops clk_stm32_gate_ready_ops = {
4095436921fSGabriel Fernandez .enable = clk_stm32_gate_ready_enable,
4105436921fSGabriel Fernandez .disable = clk_stm32_gate_ready_disable,
4115436921fSGabriel Fernandez };
4125436921fSGabriel Fernandez
4135436921fSGabriel Fernandez /* STM32 DIV clock operators */
clk_stm32_divider_get_rate(struct clk * clk,unsigned long parent_rate)4145436921fSGabriel Fernandez unsigned long clk_stm32_divider_get_rate(struct clk *clk,
4155436921fSGabriel Fernandez unsigned long parent_rate)
4165436921fSGabriel Fernandez {
4175436921fSGabriel Fernandez struct clk_stm32_div_cfg *cfg = clk->priv;
4185436921fSGabriel Fernandez
4195436921fSGabriel Fernandez return stm32_div_get_rate(cfg->div_id, parent_rate);
4205436921fSGabriel Fernandez }
4215436921fSGabriel Fernandez
clk_stm32_divider_set_rate(struct clk * clk,unsigned long rate,unsigned long parent_rate)4225436921fSGabriel Fernandez TEE_Result clk_stm32_divider_set_rate(struct clk *clk,
4235436921fSGabriel Fernandez unsigned long rate,
4245436921fSGabriel Fernandez unsigned long parent_rate)
4255436921fSGabriel Fernandez {
4265436921fSGabriel Fernandez struct clk_stm32_div_cfg *cfg = clk->priv;
4275436921fSGabriel Fernandez
4285436921fSGabriel Fernandez return stm32_div_set_rate(cfg->div_id, rate, parent_rate);
4295436921fSGabriel Fernandez }
4305436921fSGabriel Fernandez
4315436921fSGabriel Fernandez const struct clk_ops clk_stm32_divider_ops = {
4325436921fSGabriel Fernandez .get_rate = clk_stm32_divider_get_rate,
4335436921fSGabriel Fernandez .set_rate = clk_stm32_divider_set_rate,
4345436921fSGabriel Fernandez };
4355436921fSGabriel Fernandez
4365436921fSGabriel Fernandez /* STM32 COMPOSITE clock operators */
clk_stm32_composite_get_parent(struct clk * clk)4375436921fSGabriel Fernandez size_t clk_stm32_composite_get_parent(struct clk *clk)
4385436921fSGabriel Fernandez {
4395436921fSGabriel Fernandez struct clk_stm32_composite_cfg *cfg = clk->priv;
4405436921fSGabriel Fernandez
4415436921fSGabriel Fernandez if (cfg->mux_id == NO_MUX) {
4425436921fSGabriel Fernandez /* It could be a normal case */
4435436921fSGabriel Fernandez return 0;
4445436921fSGabriel Fernandez }
4455436921fSGabriel Fernandez
4465436921fSGabriel Fernandez return stm32_mux_get_parent(cfg->mux_id);
4475436921fSGabriel Fernandez }
4485436921fSGabriel Fernandez
clk_stm32_composite_set_parent(struct clk * clk,size_t pidx)4495436921fSGabriel Fernandez TEE_Result clk_stm32_composite_set_parent(struct clk *clk, size_t pidx)
4505436921fSGabriel Fernandez {
4515436921fSGabriel Fernandez struct clk_stm32_composite_cfg *cfg = clk->priv;
4525436921fSGabriel Fernandez
4535436921fSGabriel Fernandez if (cfg->mux_id == NO_MUX)
4545436921fSGabriel Fernandez panic();
4555436921fSGabriel Fernandez
4565436921fSGabriel Fernandez return stm32_mux_set_parent(cfg->mux_id, pidx);
4575436921fSGabriel Fernandez }
4585436921fSGabriel Fernandez
clk_stm32_composite_get_rate(struct clk * clk,unsigned long parent_rate)4595436921fSGabriel Fernandez unsigned long clk_stm32_composite_get_rate(struct clk *clk,
4605436921fSGabriel Fernandez unsigned long parent_rate)
4615436921fSGabriel Fernandez {
4625436921fSGabriel Fernandez struct clk_stm32_composite_cfg *cfg = clk->priv;
4635436921fSGabriel Fernandez
4645436921fSGabriel Fernandez if (cfg->div_id == NO_DIV)
4655436921fSGabriel Fernandez return parent_rate;
4665436921fSGabriel Fernandez
4675436921fSGabriel Fernandez return stm32_div_get_rate(cfg->div_id, parent_rate);
4685436921fSGabriel Fernandez }
4695436921fSGabriel Fernandez
clk_stm32_composite_set_rate(struct clk * clk,unsigned long rate,unsigned long parent_rate)4705436921fSGabriel Fernandez TEE_Result clk_stm32_composite_set_rate(struct clk *clk, unsigned long rate,
4715436921fSGabriel Fernandez unsigned long parent_rate)
4725436921fSGabriel Fernandez {
4735436921fSGabriel Fernandez struct clk_stm32_composite_cfg *cfg = clk->priv;
4745436921fSGabriel Fernandez
4755436921fSGabriel Fernandez if (cfg->div_id == NO_DIV)
4765436921fSGabriel Fernandez return TEE_SUCCESS;
4775436921fSGabriel Fernandez
4785436921fSGabriel Fernandez return stm32_div_set_rate(cfg->div_id, rate, parent_rate);
4795436921fSGabriel Fernandez }
4805436921fSGabriel Fernandez
clk_stm32_composite_gate_enable(struct clk * clk)4815436921fSGabriel Fernandez TEE_Result clk_stm32_composite_gate_enable(struct clk *clk)
4825436921fSGabriel Fernandez {
4835436921fSGabriel Fernandez struct clk_stm32_composite_cfg *cfg = clk->priv;
4845436921fSGabriel Fernandez
4855436921fSGabriel Fernandez stm32_gate_enable(cfg->gate_id);
4865436921fSGabriel Fernandez
4875436921fSGabriel Fernandez return TEE_SUCCESS;
4885436921fSGabriel Fernandez }
4895436921fSGabriel Fernandez
clk_stm32_composite_gate_disable(struct clk * clk)4905436921fSGabriel Fernandez void clk_stm32_composite_gate_disable(struct clk *clk)
4915436921fSGabriel Fernandez {
4925436921fSGabriel Fernandez struct clk_stm32_composite_cfg *cfg = clk->priv;
4935436921fSGabriel Fernandez
4945436921fSGabriel Fernandez stm32_gate_disable(cfg->gate_id);
4955436921fSGabriel Fernandez }
4965436921fSGabriel Fernandez
4975436921fSGabriel Fernandez const struct clk_ops clk_stm32_composite_ops = {
4985436921fSGabriel Fernandez .get_parent = clk_stm32_composite_get_parent,
4995436921fSGabriel Fernandez .set_parent = clk_stm32_composite_set_parent,
5005436921fSGabriel Fernandez .get_rate = clk_stm32_composite_get_rate,
5015436921fSGabriel Fernandez .set_rate = clk_stm32_composite_set_rate,
5025436921fSGabriel Fernandez .enable = clk_stm32_composite_gate_enable,
5035436921fSGabriel Fernandez .disable = clk_stm32_composite_gate_disable,
5045436921fSGabriel Fernandez };
5055436921fSGabriel Fernandez
clk_stm32_set_parent_by_index(struct clk * clk,size_t pidx)5065436921fSGabriel Fernandez TEE_Result clk_stm32_set_parent_by_index(struct clk *clk, size_t pidx)
5075436921fSGabriel Fernandez {
5085436921fSGabriel Fernandez struct clk *parent = clk_get_parent_by_index(clk, pidx);
5095436921fSGabriel Fernandez TEE_Result res = TEE_ERROR_GENERIC;
5105436921fSGabriel Fernandez
5115436921fSGabriel Fernandez if (parent)
5125436921fSGabriel Fernandez res = clk_set_parent(clk, parent);
5135436921fSGabriel Fernandez
5145436921fSGabriel Fernandez return res;
5155436921fSGabriel Fernandez }
5165436921fSGabriel Fernandez
clk_stm32_parse_fdt_by_name(const void * fdt,int node,const char * name,uint32_t * tab,uint32_t * nb)517e5e793a6SGabriel Fernandez int clk_stm32_parse_fdt_by_name(const void *fdt, int node, const char *name,
518e5e793a6SGabriel Fernandez uint32_t *tab, uint32_t *nb)
519e5e793a6SGabriel Fernandez {
520e5e793a6SGabriel Fernandez const fdt32_t *cell = NULL;
521e5e793a6SGabriel Fernandez int len = 0;
522e5e793a6SGabriel Fernandez uint32_t i = 0;
523e5e793a6SGabriel Fernandez
524e5e793a6SGabriel Fernandez cell = fdt_getprop(fdt, node, name, &len);
525cf0b089dSGatien Chevallier if (cell && len > 0) {
526e5e793a6SGabriel Fernandez for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++)
527e5e793a6SGabriel Fernandez tab[i] = fdt32_to_cpu(cell[i]);
528e5e793a6SGabriel Fernandez
529e5e793a6SGabriel Fernandez *nb = (uint32_t)len / sizeof(uint32_t);
530cf0b089dSGatien Chevallier } else {
531cf0b089dSGatien Chevallier *nb = 0;
532cf0b089dSGatien Chevallier }
533e5e793a6SGabriel Fernandez
534e5e793a6SGabriel Fernandez return 0;
535e5e793a6SGabriel Fernandez }
536e5e793a6SGabriel Fernandez
clk_stm32_init(struct clk_stm32_priv * priv,uintptr_t base)537e5e793a6SGabriel Fernandez TEE_Result clk_stm32_init(struct clk_stm32_priv *priv, uintptr_t base)
538e5e793a6SGabriel Fernandez {
539e5e793a6SGabriel Fernandez stm32_clock_data = priv;
540e5e793a6SGabriel Fernandez
541e5e793a6SGabriel Fernandez priv->base = base;
542e5e793a6SGabriel Fernandez
5432b028a2bSGatien Chevallier priv->gate_cpt = calloc(priv->nb_gates, sizeof(*priv->gate_cpt));
5442b028a2bSGatien Chevallier if (!priv->gate_cpt)
5452b028a2bSGatien Chevallier return TEE_ERROR_OUT_OF_MEMORY;
5462b028a2bSGatien Chevallier
547e5e793a6SGabriel Fernandez return TEE_SUCCESS;
548e5e793a6SGabriel Fernandez }
549e5e793a6SGabriel Fernandez
fixed_factor_get_rate(struct clk * clk,unsigned long parent_rate)5505436921fSGabriel Fernandez static unsigned long fixed_factor_get_rate(struct clk *clk,
5515436921fSGabriel Fernandez unsigned long parent_rate)
552e5e793a6SGabriel Fernandez {
5535436921fSGabriel Fernandez struct fixed_factor_cfg *d = clk->priv;
5545436921fSGabriel Fernandez
5555436921fSGabriel Fernandez unsigned long long rate = (unsigned long long)parent_rate * d->mult;
5565436921fSGabriel Fernandez
5575436921fSGabriel Fernandez if (d->div == 0U)
5585436921fSGabriel Fernandez panic("error division by zero");
5595436921fSGabriel Fernandez
5605436921fSGabriel Fernandez return (unsigned long)(rate / d->div);
5615436921fSGabriel Fernandez };
5625436921fSGabriel Fernandez
5635436921fSGabriel Fernandez const struct clk_ops clk_fixed_factor_ops = {
5645436921fSGabriel Fernandez .get_rate = fixed_factor_get_rate,
5655436921fSGabriel Fernandez };
5665436921fSGabriel Fernandez
clk_fixed_get_rate(struct clk * clk,unsigned long parent_rate __unused)5675436921fSGabriel Fernandez static unsigned long clk_fixed_get_rate(struct clk *clk,
5685436921fSGabriel Fernandez unsigned long parent_rate __unused)
5695436921fSGabriel Fernandez {
5705436921fSGabriel Fernandez struct clk_fixed_rate_cfg *cfg = clk->priv;
5715436921fSGabriel Fernandez
5725436921fSGabriel Fernandez return cfg->rate;
573e5e793a6SGabriel Fernandez }
574e5e793a6SGabriel Fernandez
5755436921fSGabriel Fernandez const struct clk_ops clk_fixed_clk_ops = {
5765436921fSGabriel Fernandez .get_rate = clk_fixed_get_rate,
5775436921fSGabriel Fernandez };
5785436921fSGabriel Fernandez
stm32mp_rcc_clock_id_to_clk(unsigned long clock_id)5795436921fSGabriel Fernandez struct clk *stm32mp_rcc_clock_id_to_clk(unsigned long clock_id)
5805436921fSGabriel Fernandez {
5815436921fSGabriel Fernandez struct clk_stm32_priv *priv = clk_stm32_get_priv();
5825436921fSGabriel Fernandez
5835436921fSGabriel Fernandez if (clock_id > priv->nb_clk_refs)
5845436921fSGabriel Fernandez return NULL;
5855436921fSGabriel Fernandez
5865436921fSGabriel Fernandez return priv->clk_refs[clock_id];
5875436921fSGabriel Fernandez }
5885436921fSGabriel Fernandez
stm32mp_clk_dt_get_clk(struct dt_pargs * pargs,void * data __unused,struct clk ** out_clk)589b357d34fSEtienne Carriere static TEE_Result stm32mp_clk_dt_get_clk(struct dt_pargs *pargs,
590b357d34fSEtienne Carriere void *data __unused,
591b357d34fSEtienne Carriere struct clk **out_clk)
5925436921fSGabriel Fernandez {
5935436921fSGabriel Fernandez unsigned long clock_id = pargs->args[0];
5945436921fSGabriel Fernandez struct clk *clk = NULL;
5955436921fSGabriel Fernandez
5965436921fSGabriel Fernandez if (pargs->args_count != 1)
597b357d34fSEtienne Carriere return TEE_ERROR_BAD_PARAMETERS;
5985436921fSGabriel Fernandez
5995436921fSGabriel Fernandez clk = stm32mp_rcc_clock_id_to_clk(clock_id);
6005436921fSGabriel Fernandez if (!clk)
601b357d34fSEtienne Carriere return TEE_ERROR_BAD_PARAMETERS;
6025436921fSGabriel Fernandez
603b357d34fSEtienne Carriere *out_clk = clk;
604b357d34fSEtienne Carriere
605b357d34fSEtienne Carriere return TEE_SUCCESS;
6065436921fSGabriel Fernandez }
6075436921fSGabriel Fernandez
clk_stm32_register_clocks(struct clk_stm32_priv * priv)6085436921fSGabriel Fernandez static void clk_stm32_register_clocks(struct clk_stm32_priv *priv)
6095436921fSGabriel Fernandez {
6105436921fSGabriel Fernandez unsigned int i = 0;
6115436921fSGabriel Fernandez
6125436921fSGabriel Fernandez for (i = 0; i < priv->nb_clk_refs; i++) {
6135436921fSGabriel Fernandez struct clk *clk = priv->clk_refs[i];
6145436921fSGabriel Fernandez
6155436921fSGabriel Fernandez if (!clk)
6165436921fSGabriel Fernandez continue;
6175436921fSGabriel Fernandez
6185436921fSGabriel Fernandez refcount_set(&clk->enabled_count, 0);
6195436921fSGabriel Fernandez
6205436921fSGabriel Fernandez if (clk_register(clk))
6215436921fSGabriel Fernandez panic();
6225436921fSGabriel Fernandez }
6235436921fSGabriel Fernandez
6245436921fSGabriel Fernandez /* Critical clocks management */
6255436921fSGabriel Fernandez for (i = 0; i < priv->nb_clk_refs; i++) {
6265436921fSGabriel Fernandez struct clk *clk = priv->clk_refs[i];
6275436921fSGabriel Fernandez
6285436921fSGabriel Fernandez if (!clk)
6295436921fSGabriel Fernandez continue;
6305436921fSGabriel Fernandez
6315436921fSGabriel Fernandez if (priv->is_critical && priv->is_critical(clk))
6325436921fSGabriel Fernandez clk_enable(clk);
6335436921fSGabriel Fernandez }
6345436921fSGabriel Fernandez }
6355436921fSGabriel Fernandez
stm32mp_clk_provider_probe_final(const void * fdt,int node,struct clk_stm32_priv * priv)6365436921fSGabriel Fernandez void stm32mp_clk_provider_probe_final(const void *fdt, int node,
6375436921fSGabriel Fernandez struct clk_stm32_priv *priv)
6385436921fSGabriel Fernandez {
6395436921fSGabriel Fernandez TEE_Result res = TEE_ERROR_GENERIC;
6405436921fSGabriel Fernandez
6415436921fSGabriel Fernandez clk_stm32_register_clocks(priv);
6425436921fSGabriel Fernandez
6435436921fSGabriel Fernandez res = clk_dt_register_clk_provider(fdt, node, stm32mp_clk_dt_get_clk,
6445436921fSGabriel Fernandez priv);
6455436921fSGabriel Fernandez if (res)
6465436921fSGabriel Fernandez panic("Couldn't register clock provider");
6475436921fSGabriel Fernandez }
648