blob: 37e996e78f96ca08c290ed7b40c651ac6536ae4b [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
9#include <common.h>
10#include <clk-uclass.h>
11#include <dm.h>
12#include <log.h>
13#include <asm/io.h>
14#include <dm/device_compat.h>
15#include <linux/clk-provider.h>
16#include "clk-stm32-core.h"
17
18int stm32_rcc_init(struct udevice *dev,
19 const struct stm32_clock_match_data *data)
20{
21 int i;
22 u8 *cpt;
23 struct stm32mp_rcc_priv *priv = dev_get_priv(dev);
24 fdt_addr_t base = dev_read_addr(dev->parent);
25 const struct clk_stm32_clock_data *clock_data = data->clock_data;
26
27 if (base == FDT_ADDR_T_NONE)
28 return -EINVAL;
29
30 priv->base = (void __iomem *)base;
31
32 /* allocate the counter of user for internal RCC gates, common for several user */
33 cpt = kzalloc(clock_data->num_gates, GFP_KERNEL);
34 if (!cpt)
35 return -ENOMEM;
36
37 priv->gate_cpt = cpt;
38
39 priv->data = clock_data;
40
41 for (i = 0; i < data->num_clocks; i++) {
42 const struct clock_config *cfg = &data->tab_clocks[i];
43 struct clk *clk = ERR_PTR(-ENOENT);
44
45 if (data->check_security && data->check_security(priv->base, cfg))
46 continue;
47
48 if (cfg->setup) {
49 clk = cfg->setup(dev, cfg);
50 clk->id = cfg->id;
51 } 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
73const struct clk_ops stm32_clk_ops = {
74 .enable = ccf_clk_enable,
75 .disable = ccf_clk_disable,
76 .get_rate = ccf_clk_get_rate,
77 .set_rate = ccf_clk_set_rate,
78};
79
80#define RCC_MP_ENCLRR_OFFSET 4
81
82static void clk_stm32_gate_set_state(void __iomem *base,
83 const struct clk_stm32_clock_data *data,
84 u8 *cpt, u16 gate_id, int enable)
85{
86 const struct stm32_gate_cfg *gate_cfg = &data->gates[gate_id];
87 void __iomem *addr = base + gate_cfg->reg_off;
88 u8 set_clr = gate_cfg->set_clr ? RCC_MP_ENCLRR_OFFSET : 0;
89
90 if (enable) {
91 if (cpt[gate_id]++ > 0)
92 return;
93
94 if (set_clr)
95 writel(BIT(gate_cfg->bit_idx), addr);
96 else
97 writel(readl(addr) | BIT(gate_cfg->bit_idx), addr);
98 } else {
99 if (--cpt[gate_id] > 0)
100 return;
101
102 if (set_clr)
103 writel(BIT(gate_cfg->bit_idx), addr + set_clr);
104 else
105 writel(readl(addr) & ~BIT(gate_cfg->bit_idx), addr);
106 }
107}
108
109static int clk_stm32_gate_enable(struct clk *clk)
110{
111 struct clk_stm32_gate *stm32_gate = to_clk_stm32_gate(clk);
112 struct stm32mp_rcc_priv *priv = stm32_gate->priv;
113
114 clk_stm32_gate_set_state(priv->base, priv->data, priv->gate_cpt,
115 stm32_gate->gate_id, 1);
116
117 return 0;
118}
119
120static int clk_stm32_gate_disable(struct clk *clk)
121{
122 struct clk_stm32_gate *stm32_gate = to_clk_stm32_gate(clk);
123 struct stm32mp_rcc_priv *priv = stm32_gate->priv;
124
125 clk_stm32_gate_set_state(priv->base, priv->data, priv->gate_cpt,
126 stm32_gate->gate_id, 0);
127
128 return 0;
129}
130
131static const struct clk_ops clk_stm32_gate_ops = {
132 .enable = clk_stm32_gate_enable,
133 .disable = clk_stm32_gate_disable,
134 .get_rate = clk_generic_get_rate,
135};
136
137#define UBOOT_DM_CLK_STM32_GATE "clk_stm32_gate"
138
139U_BOOT_DRIVER(clk_stm32_gate) = {
140 .name = UBOOT_DM_CLK_STM32_GATE,
141 .id = UCLASS_CLK,
142 .ops = &clk_stm32_gate_ops,
143};
144
145struct clk *clk_stm32_gate_register(struct udevice *dev,
146 const struct clock_config *cfg)
147{
148 struct stm32mp_rcc_priv *priv = dev_get_priv(dev);
149 struct stm32_clk_gate_cfg *clk_cfg = cfg->clock_cfg;
150 struct clk_stm32_gate *stm32_gate;
151 struct clk *clk;
152 int ret;
153
154 stm32_gate = kzalloc(sizeof(*stm32_gate), GFP_KERNEL);
155 if (!stm32_gate)
156 return ERR_PTR(-ENOMEM);
157
158 stm32_gate->priv = priv;
159 stm32_gate->gate_id = clk_cfg->gate_id;
160
161 clk = &stm32_gate->clk;
162 clk->flags = cfg->flags;
163
164 ret = clk_register(clk, UBOOT_DM_CLK_STM32_GATE,
165 cfg->name, cfg->parent_name);
166 if (ret) {
167 kfree(stm32_gate);
168 return ERR_PTR(ret);
169 }
170
171 return clk;
172}
173
174struct clk *
175clk_stm32_register_composite(struct udevice *dev,
176 const struct clock_config *cfg)
177{
178 struct stm32_clk_composite_cfg *composite = cfg->clock_cfg;
179 const char *const *parent_names;
180 int num_parents;
181 struct clk *clk = ERR_PTR(-ENOMEM);
182 struct clk_mux *mux = NULL;
183 struct clk_stm32_gate *gate = NULL;
184 struct clk_divider *div = NULL;
185 struct clk *mux_clk = NULL;
186 const struct clk_ops *mux_ops = NULL;
187 struct clk *gate_clk = NULL;
188 const struct clk_ops *gate_ops = NULL;
189 struct clk *div_clk = NULL;
190 const struct clk_ops *div_ops = NULL;
191 struct stm32mp_rcc_priv *priv = dev_get_priv(dev);
192 const struct clk_stm32_clock_data *data = priv->data;
193
194 if (composite->mux_id != NO_STM32_MUX) {
195 const struct stm32_mux_cfg *mux_cfg;
196
197 mux = kzalloc(sizeof(*mux), GFP_KERNEL);
198 if (!mux)
199 goto fail;
200
201 mux_cfg = &data->muxes[composite->mux_id];
202
203 mux->reg = priv->base + mux_cfg->reg_off;
204 mux->shift = mux_cfg->shift;
205 mux->mask = BIT(mux_cfg->width) - 1;
206 mux->num_parents = mux_cfg->num_parents;
207 mux->flags = 0;
208 mux->parent_names = mux_cfg->parent_names;
209
210 mux_clk = &mux->clk;
211 mux_ops = &clk_mux_ops;
212
213 parent_names = mux_cfg->parent_names;
214 num_parents = mux_cfg->num_parents;
215 } else {
216 parent_names = &cfg->parent_name;
217 num_parents = 1;
218 }
219
220 if (composite->div_id != NO_STM32_DIV) {
221 const struct stm32_div_cfg *div_cfg;
222
223 div = kzalloc(sizeof(*div), GFP_KERNEL);
224 if (!div)
225 goto fail;
226
227 div_cfg = &data->dividers[composite->div_id];
228
229 div->reg = priv->base + div_cfg->reg_off;
230 div->shift = div_cfg->shift;
231 div->width = div_cfg->width;
232 div->width = div_cfg->width;
233 div->flags = div_cfg->div_flags;
234 div->table = div_cfg->table;
235
236 div_clk = &div->clk;
237 div_ops = &clk_divider_ops;
238 }
239
240 if (composite->gate_id != NO_STM32_GATE) {
241 gate = kzalloc(sizeof(*gate), GFP_KERNEL);
242 if (!gate)
243 goto fail;
244
245 gate->priv = priv;
246 gate->gate_id = composite->gate_id;
247
248 gate_clk = &gate->clk;
249 gate_ops = &clk_stm32_gate_ops;
250 }
251
252 clk = clk_register_composite(NULL, cfg->name,
253 parent_names, num_parents,
254 mux_clk, mux_ops,
255 div_clk, div_ops,
256 gate_clk, gate_ops,
257 cfg->flags);
258 if (IS_ERR(clk))
259 goto fail;
260
261 return clk;
262
263fail:
264 kfree(gate);
265 kfree(div);
266 kfree(mux);
267 return ERR_CAST(clk);
268}