blob: 1b2c4c98de5419d9be0b8eed2e62660bee7f67e5 [file] [log] [blame]
Christian Marangieda1ade2025-03-14 19:59:22 +01001// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Based on the Linux clk-en7523.c but majorly reworked
4 * for U-Boot that doesn't require CCF subsystem.
5 *
6 * Major modification, support for set_rate, realtime
7 * get_rate and split for reset part to a different driver.
8 *
9 * Author: Lorenzo Bianconi <lorenzo@kernel.org> (original driver)
10 * Christian Marangi <ansuelsmth@gmail.com>
11 */
12
13#include <clk-uclass.h>
14#include <dm.h>
15#include <dm/devres.h>
16#include <dm/device_compat.h>
17#include <dm/lists.h>
18#include <regmap.h>
19#include <syscon.h>
20
21#include <dt-bindings/clock/en7523-clk.h>
22
23#define REG_GSW_CLK_DIV_SEL 0x1b4
24#define REG_EMI_CLK_DIV_SEL 0x1b8
25#define REG_BUS_CLK_DIV_SEL 0x1bc
26#define REG_SPI_CLK_DIV_SEL 0x1c4
27#define REG_SPI_CLK_FREQ_SEL 0x1c8
28#define REG_NPU_CLK_DIV_SEL 0x1fc
29
30#define REG_NP_SCU_PCIC 0x88
31#define REG_NP_SCU_SSTR 0x9c
32#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
33#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
34#define REG_CRYPTO_CLKSRC2 0x20c
35
36#define EN7581_MAX_CLKS 9
37
38struct airoha_clk_desc {
39 int id;
40 const char *name;
41 u32 base_reg;
42 u8 base_bits;
43 u8 base_shift;
44 union {
45 const unsigned int *base_values;
46 unsigned int base_value;
47 };
48 size_t n_base_values;
49
50 u16 div_reg;
51 u8 div_bits;
52 u8 div_shift;
53 u16 div_val0;
54 u8 div_step;
55 u8 div_offset;
56};
57
58struct airoha_clk_priv {
59 struct regmap *chip_scu_map;
60 struct airoha_clk_soc_data *data;
61};
62
63struct airoha_clk_soc_data {
64 u32 num_clocks;
65 const struct airoha_clk_desc *descs;
66};
67
68static const u32 gsw_base[] = { 400000000, 500000000 };
69static const u32 slic_base[] = { 100000000, 3125000 };
70
71static const u32 emi7581_base[] = { 540000000, 480000000, 400000000, 300000000 };
72static const u32 bus7581_base[] = { 600000000, 540000000 };
73static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 };
74static const u32 crypto_base[] = { 540000000, 480000000 };
75static const u32 emmc7581_base[] = { 200000000, 150000000 };
76
77static const struct airoha_clk_desc en7581_base_clks[EN7581_MAX_CLKS] = {
78 [EN7523_CLK_GSW] = {
79 .id = EN7523_CLK_GSW,
80 .name = "gsw",
81
82 .base_reg = REG_GSW_CLK_DIV_SEL,
83 .base_bits = 1,
84 .base_shift = 8,
85 .base_values = gsw_base,
86 .n_base_values = ARRAY_SIZE(gsw_base),
87
88 .div_bits = 3,
89 .div_shift = 0,
90 .div_step = 1,
91 .div_offset = 1,
92 },
93 [EN7523_CLK_EMI] = {
94 .id = EN7523_CLK_EMI,
95 .name = "emi",
96
97 .base_reg = REG_EMI_CLK_DIV_SEL,
98 .base_bits = 2,
99 .base_shift = 8,
100 .base_values = emi7581_base,
101 .n_base_values = ARRAY_SIZE(emi7581_base),
102
103 .div_bits = 3,
104 .div_shift = 0,
105 .div_step = 1,
106 .div_offset = 1,
107 },
108 [EN7523_CLK_BUS] = {
109 .id = EN7523_CLK_BUS,
110 .name = "bus",
111
112 .base_reg = REG_BUS_CLK_DIV_SEL,
113 .base_bits = 1,
114 .base_shift = 8,
115 .base_values = bus7581_base,
116 .n_base_values = ARRAY_SIZE(bus7581_base),
117
118 .div_bits = 3,
119 .div_shift = 0,
120 .div_step = 1,
121 .div_offset = 1,
122 },
123 [EN7523_CLK_SLIC] = {
124 .id = EN7523_CLK_SLIC,
125 .name = "slic",
126
127 .base_reg = REG_SPI_CLK_FREQ_SEL,
128 .base_bits = 1,
129 .base_shift = 0,
130 .base_values = slic_base,
131 .n_base_values = ARRAY_SIZE(slic_base),
132
133 .div_reg = REG_SPI_CLK_DIV_SEL,
134 .div_bits = 5,
135 .div_shift = 24,
136 .div_val0 = 20,
137 .div_step = 2,
138 },
139 [EN7523_CLK_SPI] = {
140 .id = EN7523_CLK_SPI,
141 .name = "spi",
142
143 .base_reg = REG_SPI_CLK_DIV_SEL,
144
145 .base_value = 400000000,
146
147 .div_bits = 5,
148 .div_shift = 8,
149 .div_val0 = 40,
150 .div_step = 2,
151 },
152 [EN7523_CLK_NPU] = {
153 .id = EN7523_CLK_NPU,
154 .name = "npu",
155
156 .base_reg = REG_NPU_CLK_DIV_SEL,
157 .base_bits = 2,
158 .base_shift = 8,
159 .base_values = npu7581_base,
160 .n_base_values = ARRAY_SIZE(npu7581_base),
161
162 .div_bits = 3,
163 .div_shift = 0,
164 .div_step = 1,
165 .div_offset = 1,
166 },
167 [EN7523_CLK_CRYPTO] = {
168 .id = EN7523_CLK_CRYPTO,
169 .name = "crypto",
170
171 .base_reg = REG_CRYPTO_CLKSRC2,
172 .base_bits = 1,
173 .base_shift = 0,
174 .base_values = crypto_base,
175 .n_base_values = ARRAY_SIZE(crypto_base),
176 },
177 [EN7581_CLK_EMMC] = {
178 .id = EN7581_CLK_EMMC,
179 .name = "emmc",
180
181 .base_reg = REG_CRYPTO_CLKSRC2,
182 .base_bits = 1,
183 .base_shift = 12,
184 .base_values = emmc7581_base,
185 .n_base_values = ARRAY_SIZE(emmc7581_base),
186 }
187};
188
189static u32 airoha_clk_get_base_rate(const struct airoha_clk_desc *desc, u32 val)
190{
191 if (!desc->base_bits)
192 return desc->base_value;
193
194 val >>= desc->base_shift;
195 val &= (1 << desc->base_bits) - 1;
196
197 if (val >= desc->n_base_values)
198 return 0;
199
200 return desc->base_values[val];
201}
202
203static u32 airoha_clk_get_div(const struct airoha_clk_desc *desc, u32 val)
204{
205 if (!desc->div_bits)
206 return 1;
207
208 val >>= desc->div_shift;
209 val &= (1 << desc->div_bits) - 1;
210
211 if (!val && desc->div_val0)
212 return desc->div_val0;
213
214 return (val + desc->div_offset) * desc->div_step;
215}
216
217static int airoha_clk_enable(struct clk *clk)
218{
219 struct airoha_clk_priv *priv = dev_get_priv(clk->dev);
220 struct airoha_clk_soc_data *data = priv->data;
221 int id = clk->id;
222
223 if (id > data->num_clocks)
224 return -EINVAL;
225
226 return 0;
227}
228
229static int airoha_clk_disable(struct clk *clk)
230{
231 return 0;
232}
233
234static ulong airoha_clk_get_rate(struct clk *clk)
235{
236 struct airoha_clk_priv *priv = dev_get_priv(clk->dev);
237 struct airoha_clk_soc_data *data = priv->data;
238 const struct airoha_clk_desc *desc;
239 struct regmap *map = priv->chip_scu_map;
240 int id = clk->id;
241 u32 reg, val;
242 ulong rate;
243 int ret;
244
245 if (id > data->num_clocks) {
246 dev_err(clk->dev, "Invalid clk ID %d\n", id);
247 return 0;
248 }
249
250 desc = &data->descs[id];
251
252 ret = regmap_read(map, desc->base_reg, &val);
253 if (ret) {
254 dev_err(clk->dev, "Failed to read reg for clock %s\n",
255 desc->name);
256 return 0;
257 }
258
259 rate = airoha_clk_get_base_rate(desc, val);
260
261 reg = desc->div_reg ? desc->div_reg : desc->base_reg;
262 ret = regmap_read(map, reg, &val);
263 if (ret) {
264 dev_err(clk->dev, "Failed to read reg for clock %s\n",
265 desc->name);
266 return 0;
267 }
268
269 rate /= airoha_clk_get_div(desc, val);
270
271 return rate;
272}
273
274static int airoha_clk_search_rate(const struct airoha_clk_desc *desc, int div,
275 ulong rate)
276{
277 int i;
278
279 /* Single base rate */
280 if (!desc->base_bits) {
281 if (rate != desc->base_value / div)
282 goto err;
283
284 return 0;
285 }
286
287 /* Check every base rate with provided divisor */
288 for (i = 0; i < desc->n_base_values; i++)
289 if (rate == desc->base_values[i] / div)
290 return i;
291
292err:
293 return -EINVAL;
294}
295
296static ulong airoha_clk_set_rate(struct clk *clk, ulong rate)
297{
298 struct airoha_clk_priv *priv = dev_get_priv(clk->dev);
299 struct airoha_clk_soc_data *data = priv->data;
300 const struct airoha_clk_desc *desc;
301 struct regmap *map = priv->chip_scu_map;
302 int div_val, base_val;
303 u32 reg, val, mask;
304 int id = clk->id;
305 int div;
306 int ret;
307
308 if (id > data->num_clocks) {
309 dev_err(clk->dev, "Invalid clk ID %d\n", id);
310 return 0;
311 }
312
313 desc = &data->descs[id];
314
315 if (!desc->base_bits && !desc->div_bits) {
316 dev_err(clk->dev, "Can't set rate for fixed clock %s\n",
317 desc->name);
318 return 0;
319 }
320
321 if (!desc->div_bits) {
322 /* Divisor not supported, just search in base rate */
323 div_val = 0;
324 base_val = airoha_clk_search_rate(desc, 1, rate);
325 if (base_val < 0) {
326 dev_err(clk->dev, "Invalid rate for clock %s\n",
327 desc->name);
328 return 0;
329 }
330 } else {
331 div_val = 0;
332
333 /* Check if div0 satisfy the request */
334 if (desc->div_val0) {
335 base_val = airoha_clk_search_rate(desc, desc->div_val0,
336 rate);
337 if (base_val >= 0) {
338 div_val = 0;
339 goto apply;
340 }
341
342 /* Skip checking first divisor val */
343 div_val = 1;
344 }
345
346 /* Simulate rate with every divisor supported */
347 for (div_val = div_val + desc->div_offset;
348 div_val < BIT(desc->div_bits) - 1; div_val++) {
349 div = div_val * desc->div_step;
350
351 base_val = airoha_clk_search_rate(desc, div, rate);
352 if (base_val >= 0)
353 break;
354 }
355
356 if (div_val == BIT(desc->div_bits) - 1) {
357 dev_err(clk->dev, "Invalid rate for clock %s\n",
358 desc->name);
359 return 0;
360 }
361 }
362
363apply:
364 if (desc->div_bits) {
365 reg = desc->div_reg ? desc->div_reg : desc->base_reg;
366
367 mask = (BIT(desc->div_bits) - 1) << desc->div_shift;
368 val = div_val << desc->div_shift;
369
370 ret = regmap_update_bits(map, reg, mask, val);
371 if (ret) {
372 dev_err(clk->dev, "Failed to update div reg for clock %s\n",
373 desc->name);
374 return 0;
375 }
376 }
377
378 if (desc->base_bits) {
379 mask = (BIT(desc->base_bits) - 1) << desc->base_shift;
380 val = base_val << desc->base_shift;
381
382 ret = regmap_update_bits(map, desc->base_reg, mask, val);
383 if (ret) {
384 dev_err(clk->dev, "Failed to update reg for clock %s\n",
385 desc->name);
386 return 0;
387 }
388 }
389
390 return rate;
391}
392
393const struct clk_ops airoha_clk_ops = {
394 .enable = airoha_clk_enable,
395 .disable = airoha_clk_disable,
396 .get_rate = airoha_clk_get_rate,
397 .set_rate = airoha_clk_set_rate,
398};
399
400static int airoha_clk_probe(struct udevice *dev)
401{
402 struct airoha_clk_priv *priv = dev_get_priv(dev);
403 ofnode chip_scu_node;
404
405 chip_scu_node = ofnode_by_compatible(ofnode_null(),
406 "airoha,en7581-chip-scu");
407 if (!ofnode_valid(chip_scu_node))
408 return -EINVAL;
409
410 priv->chip_scu_map = syscon_node_to_regmap(chip_scu_node);
411 if (IS_ERR(priv->chip_scu_map))
412 return PTR_ERR(priv->chip_scu_map);
413
414 priv->data = (void *)dev_get_driver_data(dev);
415
416 return 0;
417}
418
Christian Marangi101dce92025-03-14 19:59:23 +0100419static int airoha_clk_bind(struct udevice *dev)
420{
421 struct udevice *rst_dev;
422 int ret = 0;
423
424 if (CONFIG_IS_ENABLED(RESET_AIROHA)) {
425 ret = device_bind_driver_to_node(dev, "airoha-reset", "reset",
426 dev_ofnode(dev), &rst_dev);
427 if (ret)
428 debug("Warning: failed to bind reset controller\n");
429 }
430
431 return ret;
432}
433
Christian Marangieda1ade2025-03-14 19:59:22 +0100434static const struct airoha_clk_soc_data en7581_data = {
435 .num_clocks = ARRAY_SIZE(en7581_base_clks),
436 .descs = en7581_base_clks,
437};
438
439static const struct udevice_id airoha_clk_ids[] = {
440 { .compatible = "airoha,en7581-scu",
441 .data = (ulong)&en7581_data,
442 },
443 { }
444};
445
446U_BOOT_DRIVER(airoha_clk) = {
447 .name = "clk-airoha",
448 .id = UCLASS_CLK,
449 .of_match = airoha_clk_ids,
450 .probe = airoha_clk_probe,
Christian Marangi101dce92025-03-14 19:59:23 +0100451 .bind = airoha_clk_bind,
Christian Marangieda1ade2025-03-14 19:59:22 +0100452 .priv_auto = sizeof(struct airoha_clk_priv),
453 .ops = &airoha_clk_ops,
454};