blob: a0ae89d09120a80763ceb4c9a9dd4bca727eb6c5 [file] [log] [blame]
Gabriel Fernandez3db088a2022-11-24 11:36:04 +01001// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
2/*
3 * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
4 * Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics.
5 */
6
7#define LOG_CATEGORY UCLASS_CLK
8
Gabriel Fernandez3db088a2022-11-24 11:36:04 +01009#include <clk-uclass.h>
10#include <dm.h>
11#include <log.h>
12#include <asm/io.h>
13#include <dm/device_compat.h>
14#include <linux/clk-provider.h>
15#include "clk-stm32-core.h"
16
17int stm32_rcc_init(struct udevice *dev,
18 const struct stm32_clock_match_data *data)
19{
20 int i;
21 u8 *cpt;
22 struct stm32mp_rcc_priv *priv = dev_get_priv(dev);
23 fdt_addr_t base = dev_read_addr(dev->parent);
24 const struct clk_stm32_clock_data *clock_data = data->clock_data;
25
26 if (base == FDT_ADDR_T_NONE)
27 return -EINVAL;
28
29 priv->base = (void __iomem *)base;
30
31 /* allocate the counter of user for internal RCC gates, common for several user */
32 cpt = kzalloc(clock_data->num_gates, GFP_KERNEL);
33 if (!cpt)
34 return -ENOMEM;
35
36 priv->gate_cpt = cpt;
37
38 priv->data = clock_data;
39
40 for (i = 0; i < data->num_clocks; i++) {
41 const struct clock_config *cfg = &data->tab_clocks[i];
42 struct clk *clk = ERR_PTR(-ENOENT);
43
Gabriel Fernandez299487c2025-05-27 15:27:45 +020044 if (data->check_security && data->check_security(dev, priv->base, cfg))
Gabriel Fernandez3db088a2022-11-24 11:36:04 +010045 continue;
46
47 if (cfg->setup) {
48 clk = cfg->setup(dev, cfg);
Patrick Delaunaycfe57af2025-05-27 15:27:46 +020049 /* set identifier of clock provider*/
50 dev_clk_dm(dev, cfg->id, clk);
Gabriel Fernandez3db088a2022-11-24 11:36:04 +010051 } else {
52 dev_err(dev, "failed to register clock %s\n", cfg->name);
53 return -ENOENT;
54 }
55 }
56
57 return 0;
58}
59
60ulong clk_stm32_get_rate_by_name(const char *name)
61{
62 struct udevice *dev;
63
64 if (!uclass_get_device_by_name(UCLASS_CLK, name, &dev)) {
65 struct clk *clk = dev_get_clk_ptr(dev);
66
67 return clk_get_rate(clk);
68 }
69
70 return 0;
71}
72
Gabriel Fernandez27cc3b92025-05-27 15:27:52 +020073static const struct clk_ops *clk_dev_ops(struct udevice *dev)
74{
75 return (const struct clk_ops *)dev->driver->ops;
76}
77
78static int stm32_clk_endisable(struct clk *clk, bool enable)
79{
80 const struct clk_ops *ops;
81 struct clk *c = NULL;
82
83 if (!clk->id || clk_get_by_id(clk->id, &c))
84 return -ENOENT;
85
86 ops = clk_dev_ops(c->dev);
87 if (!ops->enable || !ops->disable)
88 return 0;
89
90 return enable ? ops->enable(c) : ops->disable(c);
91}
92
93static int stm32_clk_enable(struct clk *clk)
94{
95 return stm32_clk_endisable(clk, true);
96}
97
98static int stm32_clk_disable(struct clk *clk)
99{
100 return stm32_clk_endisable(clk, false);
101}
102
103static ulong stm32_clk_get_rate(struct clk *clk)
104{
105 const struct clk_ops *ops;
106 struct clk *c = NULL;
107
108 if (!clk->id || clk_get_by_id(clk->id, &c))
109 return -ENOENT;
110
111 ops = clk_dev_ops(c->dev);
112 if (!ops->get_rate)
113 return -ENOSYS;
114
115 return ops->get_rate(c);
116}
117
118static ulong stm32_clk_set_rate(struct clk *clk, unsigned long clk_rate)
119{
120 const struct clk_ops *ops;
121 struct clk *c = NULL;
122
123 if (!clk->id || clk_get_by_id(clk->id, &c))
124 return -ENOENT;
125
126 ops = clk_dev_ops(c->dev);
127 if (!ops->set_rate)
128 return -ENOSYS;
129
130 return ops->set_rate(c, clk_rate);
131}
132
Gabriel Fernandez3db088a2022-11-24 11:36:04 +0100133const struct clk_ops stm32_clk_ops = {
Gabriel Fernandez27cc3b92025-05-27 15:27:52 +0200134 .enable = stm32_clk_enable,
135 .disable = stm32_clk_disable,
136 .get_rate = stm32_clk_get_rate,
137 .set_rate = stm32_clk_set_rate,
Gabriel Fernandez3db088a2022-11-24 11:36:04 +0100138};
139
140#define RCC_MP_ENCLRR_OFFSET 4
141
142static void clk_stm32_gate_set_state(void __iomem *base,
143 const struct clk_stm32_clock_data *data,
144 u8 *cpt, u16 gate_id, int enable)
145{
146 const struct stm32_gate_cfg *gate_cfg = &data->gates[gate_id];
147 void __iomem *addr = base + gate_cfg->reg_off;
148 u8 set_clr = gate_cfg->set_clr ? RCC_MP_ENCLRR_OFFSET : 0;
149
150 if (enable) {
151 if (cpt[gate_id]++ > 0)
152 return;
153
154 if (set_clr)
155 writel(BIT(gate_cfg->bit_idx), addr);
156 else
157 writel(readl(addr) | BIT(gate_cfg->bit_idx), addr);
158 } else {
159 if (--cpt[gate_id] > 0)
160 return;
161
162 if (set_clr)
163 writel(BIT(gate_cfg->bit_idx), addr + set_clr);
164 else
165 writel(readl(addr) & ~BIT(gate_cfg->bit_idx), addr);
166 }
167}
168
169static int clk_stm32_gate_enable(struct clk *clk)
170{
171 struct clk_stm32_gate *stm32_gate = to_clk_stm32_gate(clk);
172 struct stm32mp_rcc_priv *priv = stm32_gate->priv;
173
174 clk_stm32_gate_set_state(priv->base, priv->data, priv->gate_cpt,
175 stm32_gate->gate_id, 1);
176
177 return 0;
178}
179
180static int clk_stm32_gate_disable(struct clk *clk)
181{
182 struct clk_stm32_gate *stm32_gate = to_clk_stm32_gate(clk);
183 struct stm32mp_rcc_priv *priv = stm32_gate->priv;
184
185 clk_stm32_gate_set_state(priv->base, priv->data, priv->gate_cpt,
186 stm32_gate->gate_id, 0);
187
188 return 0;
189}
190
191static const struct clk_ops clk_stm32_gate_ops = {
192 .enable = clk_stm32_gate_enable,
193 .disable = clk_stm32_gate_disable,
194 .get_rate = clk_generic_get_rate,
195};
196
197#define UBOOT_DM_CLK_STM32_GATE "clk_stm32_gate"
198
199U_BOOT_DRIVER(clk_stm32_gate) = {
200 .name = UBOOT_DM_CLK_STM32_GATE,
201 .id = UCLASS_CLK,
202 .ops = &clk_stm32_gate_ops,
203};
204
205struct clk *clk_stm32_gate_register(struct udevice *dev,
206 const struct clock_config *cfg)
207{
208 struct stm32mp_rcc_priv *priv = dev_get_priv(dev);
209 struct stm32_clk_gate_cfg *clk_cfg = cfg->clock_cfg;
210 struct clk_stm32_gate *stm32_gate;
211 struct clk *clk;
212 int ret;
213
214 stm32_gate = kzalloc(sizeof(*stm32_gate), GFP_KERNEL);
215 if (!stm32_gate)
216 return ERR_PTR(-ENOMEM);
217
218 stm32_gate->priv = priv;
219 stm32_gate->gate_id = clk_cfg->gate_id;
220
221 clk = &stm32_gate->clk;
222 clk->flags = cfg->flags;
223
224 ret = clk_register(clk, UBOOT_DM_CLK_STM32_GATE,
225 cfg->name, cfg->parent_name);
226 if (ret) {
227 kfree(stm32_gate);
228 return ERR_PTR(ret);
229 }
230
231 return clk;
232}
233
234struct clk *
235clk_stm32_register_composite(struct udevice *dev,
236 const struct clock_config *cfg)
237{
238 struct stm32_clk_composite_cfg *composite = cfg->clock_cfg;
239 const char *const *parent_names;
240 int num_parents;
241 struct clk *clk = ERR_PTR(-ENOMEM);
242 struct clk_mux *mux = NULL;
243 struct clk_stm32_gate *gate = NULL;
244 struct clk_divider *div = NULL;
245 struct clk *mux_clk = NULL;
246 const struct clk_ops *mux_ops = NULL;
247 struct clk *gate_clk = NULL;
248 const struct clk_ops *gate_ops = NULL;
249 struct clk *div_clk = NULL;
250 const struct clk_ops *div_ops = NULL;
251 struct stm32mp_rcc_priv *priv = dev_get_priv(dev);
252 const struct clk_stm32_clock_data *data = priv->data;
253
254 if (composite->mux_id != NO_STM32_MUX) {
255 const struct stm32_mux_cfg *mux_cfg;
256
257 mux = kzalloc(sizeof(*mux), GFP_KERNEL);
258 if (!mux)
259 goto fail;
260
261 mux_cfg = &data->muxes[composite->mux_id];
262
263 mux->reg = priv->base + mux_cfg->reg_off;
264 mux->shift = mux_cfg->shift;
265 mux->mask = BIT(mux_cfg->width) - 1;
266 mux->num_parents = mux_cfg->num_parents;
267 mux->flags = 0;
268 mux->parent_names = mux_cfg->parent_names;
269
270 mux_clk = &mux->clk;
271 mux_ops = &clk_mux_ops;
272
273 parent_names = mux_cfg->parent_names;
274 num_parents = mux_cfg->num_parents;
275 } else {
276 parent_names = &cfg->parent_name;
277 num_parents = 1;
278 }
279
280 if (composite->div_id != NO_STM32_DIV) {
281 const struct stm32_div_cfg *div_cfg;
282
283 div = kzalloc(sizeof(*div), GFP_KERNEL);
284 if (!div)
285 goto fail;
286
287 div_cfg = &data->dividers[composite->div_id];
288
289 div->reg = priv->base + div_cfg->reg_off;
290 div->shift = div_cfg->shift;
291 div->width = div_cfg->width;
292 div->width = div_cfg->width;
293 div->flags = div_cfg->div_flags;
294 div->table = div_cfg->table;
295
296 div_clk = &div->clk;
297 div_ops = &clk_divider_ops;
298 }
299
300 if (composite->gate_id != NO_STM32_GATE) {
301 gate = kzalloc(sizeof(*gate), GFP_KERNEL);
302 if (!gate)
303 goto fail;
304
305 gate->priv = priv;
306 gate->gate_id = composite->gate_id;
307
308 gate_clk = &gate->clk;
309 gate_ops = &clk_stm32_gate_ops;
310 }
311
312 clk = clk_register_composite(NULL, cfg->name,
313 parent_names, num_parents,
314 mux_clk, mux_ops,
315 div_clk, div_ops,
316 gate_clk, gate_ops,
317 cfg->flags);
318 if (IS_ERR(clk))
319 goto fail;
320
321 return clk;
322
323fail:
324 kfree(gate);
325 kfree(div);
326 kfree(mux);
327 return ERR_CAST(clk);
328}