Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2026, Beijing ESWIN Computing Technology Co., Ltd..
4 * All rights reserved.
5 *
6 * Authors:
7 * Yifeng Huang <huangyifeng@eswincomputing.com>
8 * Xuyang Dong <dongxuyang@eswincomputing.com>
9 */
10
11#include <linux/bitfield.h>
12#include <linux/clk-provider.h>
13#include <linux/iopoll.h>
14#include <linux/math.h>
15#include <linux/platform_device.h>
16#include <linux/slab.h>
17
18#include "common.h"
19
20#define PLL_EN_MASK GENMASK(1, 0)
21#define PLL_REFDIV_MASK GENMASK(17, 12)
22#define PLL_FBDIV_MASK GENMASK(31, 20)
23#define PLL_FRAC_MASK GENMASK(27, 4)
24#define PLL_POSTDIV1_MASK GENMASK(10, 8)
25#define PLL_POSTDIV2_MASK GENMASK(18, 16)
26
27struct eswin_clock_data *eswin_clk_init(struct platform_device *pdev,
28 size_t nr_clks)
29{
30 struct eswin_clock_data *eclk_data;
31
32 eclk_data = devm_kzalloc(&pdev->dev,
33 struct_size(eclk_data, clk_data.hws, nr_clks),
34 GFP_KERNEL);
35 if (!eclk_data)
36 return ERR_PTR(-ENOMEM);
37
38 eclk_data->base = devm_platform_ioremap_resource(pdev, 0);
39 if (IS_ERR(eclk_data->base))
40 return ERR_PTR(-EINVAL);
41
42 eclk_data->clk_data.num = nr_clks;
43 spin_lock_init(&eclk_data->lock);
44
45 return eclk_data;
46}
47EXPORT_SYMBOL_GPL(eswin_clk_init);
48
49/**
50 * eswin_calc_pll - calculate PLL values
51 * @frac_val: fractional divider
52 * @fbdiv_val: feedback divider
53 * @rate: reference rate
54 * @parent_rate: parent rate
55 *
56 * Calculate PLL values for frac and fbdiv:
57 * fbdiv = rate * 4 / parent_rate
58 * frac = (rate * 4 % parent_rate * (2 ^ 24)) / parent_rate
59 */
60static void eswin_calc_pll(u32 *frac_val, u32 *fbdiv_val, unsigned long rate,
61 unsigned long parent_rate)
62{
63 u32 rem;
64 u64 tmp;
65
66 /* step 1: rate * 4 */
67 tmp = rate * 4;
68 /* step 2: use do_div() to get the quotient(tmp) and remainder(rem) */
69 rem = do_div(tmp, (u32)parent_rate);
70 /* fbdiv = rate * 4 / parent_rate */
71 *fbdiv_val = (u32)tmp;
72 /*
73 * step 3: rem << 24
74 * 24: 24-bit fractional accuracy
75 */
76 tmp = (u64)rem << 24;
77 /* step 4: use do_div() to get the quotient(tmp) */
78 do_div(tmp, (u32)parent_rate);
79 /* frac = (rate * 4 % parent_rate * (2 ^ 24)) / parent_rate */
80 *frac_val = (u32)tmp;
81}
82
83static inline struct eswin_clk_pll *to_pll_clk(struct clk_hw *hw)
84{
85 return container_of(hw, struct eswin_clk_pll, hw);
86}
87
88static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
89 unsigned long parent_rate)
90{
91 struct eswin_clk_pll *clk = to_pll_clk(hw);
92 u32 frac_val, fbdiv_val, val, mask;
93 int ret;
94
95 eswin_calc_pll(&frac_val, &fbdiv_val, rate, parent_rate);
96
97 /* First, disable pll */
98 val = readl_relaxed(clk->ctrl_reg0);
99 val &= ~PLL_EN_MASK;
100 val |= FIELD_PREP(PLL_EN_MASK, 0);
101 writel_relaxed(val, clk->ctrl_reg0);
102
103 val = readl_relaxed(clk->ctrl_reg0);
104 val &= ~(PLL_REFDIV_MASK | PLL_FBDIV_MASK);
105 val |= FIELD_PREP(PLL_FBDIV_MASK, fbdiv_val);
106 val |= FIELD_PREP(PLL_REFDIV_MASK, 1);
107 writel_relaxed(val, clk->ctrl_reg0);
108
109 val = readl_relaxed(clk->ctrl_reg1);
110 val &= ~PLL_FRAC_MASK;
111 val |= FIELD_PREP(PLL_FRAC_MASK, frac_val);
112 writel_relaxed(val, clk->ctrl_reg1);
113
114 val = readl_relaxed(clk->ctrl_reg2);
115 val &= ~(PLL_POSTDIV1_MASK | PLL_POSTDIV2_MASK);
116 val |= FIELD_PREP(PLL_POSTDIV1_MASK, 1);
117 val |= FIELD_PREP(PLL_POSTDIV2_MASK, 1);
118 writel_relaxed(val, clk->ctrl_reg2);
119
120 /* Last, enable pll */
121 val = readl_relaxed(clk->ctrl_reg0);
122 val &= ~PLL_EN_MASK;
123 val |= FIELD_PREP(PLL_EN_MASK, 1);
124 writel_relaxed(val, clk->ctrl_reg0);
125
126 /* Usually the pll will lock in 50us */
127 mask = GENMASK(clk->lock_shift + clk->lock_width - 1, clk->lock_shift);
128 ret = readl_poll_timeout(clk->status_reg, val, val & mask, 1, 50 * 2);
129 if (ret)
130 pr_err("failed to lock the pll!\n");
131
132 return ret;
133}
134
135static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
136 unsigned long parent_rate)
137{
138 struct eswin_clk_pll *clk = to_pll_clk(hw);
139 u64 fbdiv_val, frac_val, tmp;
140 u32 rem, val;
141
142 val = readl_relaxed(clk->ctrl_reg0);
143 val &= PLL_FBDIV_MASK;
144 fbdiv_val = (val >> clk->fbdiv_shift);
145
146 val = readl_relaxed(clk->ctrl_reg1);
147 val &= PLL_FRAC_MASK;
148 frac_val = (val >> clk->frac_shift);
149
150 /* rate = 24000000 * (fbdiv + frac / (2 ^ 24)) / 4 */
151 tmp = parent_rate * frac_val;
152 rem = do_div(tmp, BIT(24));
153 if (rem)
154 tmp = parent_rate * fbdiv_val + tmp + 1;
155 else
156 tmp = parent_rate * fbdiv_val + tmp;
157
158 do_div(tmp, 4);
159
160 return tmp;
161}
162
163static int clk_pll_determine_rate(struct clk_hw *hw,
164 struct clk_rate_request *req)
165{
166 struct eswin_clk_pll *clk = to_pll_clk(hw);
167
168 req->rate = clamp(req->rate, clk->min_rate, clk->max_rate);
169 req->min_rate = clk->min_rate;
170 req->max_rate = clk->max_rate;
171
172 return 0;
173}
174
175int eswin_clk_register_fixed_rate(struct device *dev,
176 struct eswin_fixed_rate_clock *clks,
177 int nums, struct eswin_clock_data *data)
178{
179 struct clk_hw *clk_hw;
180 int i;
181
182 for (i = 0; i < nums; i++) {
183 clk_hw = devm_clk_hw_register_fixed_rate(dev, clks[i].name,
184 NULL, clks[i].flags,
185 clks[i].rate);
186 if (IS_ERR(clk_hw))
187 return PTR_ERR(clk_hw);
188
189 clks[i].hw = *clk_hw;
190 data->clk_data.hws[clks[i].id] = clk_hw;
191 }
192
193 return 0;
194}
195EXPORT_SYMBOL_GPL(eswin_clk_register_fixed_rate);
196
197static const struct clk_ops eswin_clk_pll_ops = {
198 .set_rate = clk_pll_set_rate,
199 .recalc_rate = clk_pll_recalc_rate,
200 .determine_rate = clk_pll_determine_rate,
201};
202
203int eswin_clk_register_pll(struct device *dev, struct eswin_pll_clock *clks,
204 int nums, struct eswin_clock_data *data)
205{
206 struct eswin_clk_pll *p_clk = NULL;
207 struct clk_init_data init;
208 struct clk_hw *clk_hw;
209 int i, ret;
210
211 p_clk = devm_kzalloc(dev, sizeof(*p_clk) * nums, GFP_KERNEL);
212 if (!p_clk)
213 return -ENOMEM;
214
215 for (i = 0; i < nums; i++) {
216 p_clk->id = clks[i].id;
217 p_clk->ctrl_reg0 = data->base + clks[i].ctrl_reg0;
218 p_clk->fbdiv_shift = clks[i].fbdiv_shift;
219
220 p_clk->ctrl_reg1 = data->base + clks[i].ctrl_reg1;
221 p_clk->frac_shift = clks[i].frac_shift;
222
223 p_clk->ctrl_reg2 = data->base + clks[i].ctrl_reg2;
224
225 p_clk->status_reg = data->base + clks[i].status_reg;
226 p_clk->lock_shift = clks[i].lock_shift;
227 p_clk->lock_width = clks[i].lock_width;
228
229 p_clk->max_rate = clks[i].max_rate;
230 p_clk->min_rate = clks[i].min_rate;
231
232 init.name = clks[i].name;
233 init.flags = 0;
234 init.parent_data = clks[i].parent_data;
235 init.num_parents = 1;
236 init.ops = &eswin_clk_pll_ops;
237 p_clk->hw.init = &init;
238
239 clk_hw = &p_clk->hw;
240
241 ret = devm_clk_hw_register(dev, clk_hw);
242 if (ret)
243 return ret;
244
245 clks[i].hw = *clk_hw;
246 data->clk_data.hws[clks[i].id] = clk_hw;
247 p_clk++;
248 }
249
250 return 0;
251}
252EXPORT_SYMBOL_GPL(eswin_clk_register_pll);
253
254int eswin_clk_register_fixed_factor(struct device *dev,
255 struct eswin_fixed_factor_clock *clks,
256 int nums, struct eswin_clock_data *data)
257{
258 struct clk_hw *clk_hw;
259 int i;
260
261 for (i = 0; i < nums; i++) {
262 clk_hw = devm_clk_hw_register_fixed_factor_index(dev, clks[i].name,
263 clks[i].parent_data->index,
264 clks[i].flags, clks[i].mult,
265 clks[i].div);
266
267 if (IS_ERR(clk_hw))
268 return PTR_ERR(clk_hw);
269
270 clks[i].hw = *clk_hw;
271 data->clk_data.hws[clks[i].id] = clk_hw;
272 }
273
274 return 0;
275}
276EXPORT_SYMBOL_GPL(eswin_clk_register_fixed_factor);
277
278int eswin_clk_register_mux(struct device *dev, struct eswin_mux_clock *clks,
279 int nums, struct eswin_clock_data *data)
280{
281 struct clk_hw *clk_hw;
282 int i;
283
284 for (i = 0; i < nums; i++) {
285 clk_hw = devm_clk_hw_register_mux_parent_data_table(dev, clks[i].name,
286 clks[i].parent_data,
287 clks[i].num_parents,
288 clks[i].flags,
289 data->base + clks[i].reg,
290 clks[i].shift, clks[i].width,
291 clks[i].mux_flags,
292 clks[i].table, &data->lock);
293
294 if (IS_ERR(clk_hw))
295 return PTR_ERR(clk_hw);
296
297 clks[i].hw = *clk_hw;
298 data->clk_data.hws[clks[i].id] = clk_hw;
299 }
300
301 return 0;
302}
303EXPORT_SYMBOL_GPL(eswin_clk_register_mux);
304
305static unsigned int _eswin_get_val(unsigned int div, unsigned long flags,
306 u8 width)
307{
308 unsigned int maxdiv;
309
310 maxdiv = clk_div_mask(width);
311 div = div > maxdiv ? maxdiv : div;
312
313 if (flags & ESWIN_PRIV_DIV_MIN_2)
314 return (div < 2) ? 2 : div;
315
316 return div;
317}
318
319static unsigned int eswin_div_get_val(unsigned long rate,
320 unsigned long parent_rate, u8 width,
321 unsigned long flags)
322{
323 unsigned int div;
324
325 div = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
326
327 return _eswin_get_val(div, flags, width);
328}
329
330static inline struct eswin_divider_clock *to_div_clk(struct clk_hw *hw)
331{
332 return container_of(hw, struct eswin_divider_clock, hw);
333}
334
335static int clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
336 unsigned long parent_rate)
337{
338 struct eswin_divider_clock *dclk = to_div_clk(hw);
339 unsigned long flags;
340 unsigned int value;
341 u32 val;
342
343 value = eswin_div_get_val(rate, parent_rate, dclk->width,
344 dclk->priv_flag);
345
346 spin_lock_irqsave(dclk->lock, flags);
347
348 val = readl_relaxed(dclk->ctrl_reg);
349 val &= ~(clk_div_mask(dclk->width) << dclk->shift);
350 val |= (u32)value << dclk->shift;
351 writel_relaxed(val, dclk->ctrl_reg);
352
353 spin_unlock_irqrestore(dclk->lock, flags);
354
355 return 0;
356}
357
358static unsigned long clk_div_recalc_rate(struct clk_hw *hw,
359 unsigned long parent_rate)
360{
361 struct eswin_divider_clock *dclk = to_div_clk(hw);
362 unsigned int div, val;
363
364 val = readl_relaxed(dclk->ctrl_reg) >> dclk->shift;
365 val &= clk_div_mask(dclk->width);
366 div = _eswin_get_val(val, dclk->priv_flag, dclk->width);
367
368 return DIV_ROUND_UP_ULL((u64)parent_rate, div);
369}
370
371static int eswin_clk_bestdiv(unsigned long rate,
372 unsigned long best_parent_rate, u8 width,
373 unsigned long flags)
374{
375 unsigned long bestdiv, up_rate, down_rate;
376 int up, down;
377
378 if (!rate)
379 rate = 1;
380
381 /* closest round */
382 up = DIV_ROUND_UP_ULL((u64)best_parent_rate, rate);
383 down = best_parent_rate / rate;
384
385 up_rate = DIV_ROUND_UP_ULL((u64)best_parent_rate, up);
386 down_rate = DIV_ROUND_UP_ULL((u64)best_parent_rate, down);
387
388 bestdiv = (rate - up_rate) <= (down_rate - rate) ? up : down;
389
390 return bestdiv;
391}
392
393static int clk_div_determine_rate(struct clk_hw *hw,
394 struct clk_rate_request *req)
395{
396 struct eswin_divider_clock *dclk = to_div_clk(hw);
397 int div;
398
399 div = eswin_clk_bestdiv(req->rate, req->best_parent_rate, dclk->width,
400 dclk->priv_flag);
401 div = _eswin_get_val(div, dclk->priv_flag, dclk->width);
402 req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div);
403
404 return 0;
405}
406
407static const struct clk_ops eswin_clk_div_ops = {
408 .set_rate = clk_div_set_rate,
409 .recalc_rate = clk_div_recalc_rate,
410 .determine_rate = clk_div_determine_rate,
411};
412
413struct clk_hw *eswin_register_clkdiv(struct device *dev, unsigned int id,
414 const char *name,
415 const struct clk_hw *parent_hw,
416 unsigned long flags, void __iomem *reg,
417 u8 shift, u8 width,
418 unsigned long clk_divider_flags,
419 unsigned long priv_flag, spinlock_t *lock)
420{
421 struct eswin_divider_clock *dclk;
422 struct clk_init_data init;
423 struct clk_hw *clk_hw;
424 int ret;
425
426 dclk = devm_kzalloc(dev, sizeof(*dclk), GFP_KERNEL);
427 if (!dclk)
428 return ERR_PTR(-ENOMEM);
429
430 init.name = name;
431 init.ops = &eswin_clk_div_ops;
432 init.flags = flags;
433 init.parent_hws = &parent_hw;
434 init.num_parents = 1;
435
436 /* struct clk_divider assignments */
437 dclk->id = id;
438 dclk->ctrl_reg = reg;
439 dclk->shift = shift;
440 dclk->width = width;
441 dclk->div_flags = clk_divider_flags;
442 dclk->priv_flag = priv_flag;
443 dclk->lock = lock;
444 dclk->hw.init = &init;
445
446 /* register the clock */
447 clk_hw = &dclk->hw;
448 ret = devm_clk_hw_register(dev, clk_hw);
449 if (ret) {
450 dev_err(dev, "failed to register divider clock!\n");
451 return ERR_PTR(ret);
452 }
453
454 return clk_hw;
455}
456EXPORT_SYMBOL_GPL(eswin_register_clkdiv);
457
458int eswin_clk_register_divider(struct device *dev,
459 struct eswin_divider_clock *clks,
460 int nums, struct eswin_clock_data *data)
461{
462 struct clk_hw *clk_hw;
463 int i;
464
465 for (i = 0; i < nums; i++) {
466 clk_hw = devm_clk_hw_register_divider_parent_data(dev, clks[i].name,
467 clks[i].parent_data,
468 clks[i].flags,
469 data->base + clks[i].reg,
470 clks[i].shift, clks[i].width,
471 clks[i].div_flags, &data->lock);
472
473 if (IS_ERR(clk_hw))
474 return PTR_ERR(clk_hw);
475
476 clks[i].hw = *clk_hw;
477 data->clk_data.hws[clks[i].id] = clk_hw;
478 }
479
480 return 0;
481}
482EXPORT_SYMBOL_GPL(eswin_clk_register_divider);
483
484int eswin_clk_register_gate(struct device *dev, struct eswin_gate_clock *clks,
485 int nums, struct eswin_clock_data *data)
486{
487 struct clk_hw *clk_hw;
488 int i;
489
490 for (i = 0; i < nums; i++) {
491 clk_hw = devm_clk_hw_register_gate_parent_data(dev, clks[i].name,
492 clks[i].parent_data,
493 clks[i].flags,
494 data->base + clks[i].reg,
495 clks[i].bit_idx, clks[i].gate_flags,
496 &data->lock);
497
498 if (IS_ERR(clk_hw))
499 return PTR_ERR(clk_hw);
500
501 clks[i].hw = *clk_hw;
502 data->clk_data.hws[clks[i].id] = clk_hw;
503 }
504
505 return 0;
506}
507EXPORT_SYMBOL_GPL(eswin_clk_register_gate);
508
509int eswin_clk_register_clks(struct device *dev, struct eswin_clk_info *clks,
510 int nums, struct eswin_clock_data *data)
511{
512 struct eswin_clk_info *info;
513 const struct clk_hw *phw = NULL;
514 struct clk_hw *hw;
515 int i;
516
517 for (i = 0; i < nums; i++) {
518 info = &clks[i];
519 switch (info->type) {
520 case CLK_FIXED_FACTOR: {
521 const struct eswin_fixed_factor_clock *factor;
522
523 factor = &info->data.factor;
524 phw = data->clk_data.hws[info->pid];
525 hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, factor->name, phw,
526 factor->flags,
527 factor->mult,
528 factor->div);
529 break;
530 }
531 case CLK_MUX: {
532 const struct eswin_mux_clock *mux = &info->data.mux;
533
534 hw = devm_clk_hw_register_mux_parent_data_table(dev, mux->name,
535 mux->parent_data,
536 mux->num_parents,
537 mux->flags,
538 data->base + mux->reg,
539 mux->shift, mux->width,
540 mux->mux_flags,
541 mux->table, &data->lock);
542 break;
543 }
544 case CLK_DIVIDER: {
545 const struct eswin_divider_clock *div = &info->data.div;
546
547 phw = data->clk_data.hws[info->pid];
548 if (div->priv_flag)
549 hw = eswin_register_clkdiv(dev, div->id, div->name, phw,
550 div->flags, data->base + div->reg,
551 div->shift, div->width, div->div_flags,
552 div->priv_flag, &data->lock);
553 else
554 hw = devm_clk_hw_register_divider_parent_hw(dev, div->name, phw,
555 div->flags,
556 data->base + div->reg,
557 div->shift, div->width,
558 div->div_flags,
559 &data->lock);
560 break;
561 }
562 case CLK_GATE: {
563 const struct eswin_gate_clock *gate = &info->data.gate;
564
565 phw = data->clk_data.hws[info->pid];
566 hw = devm_clk_hw_register_gate_parent_hw(dev, gate->name, phw,
567 gate->flags,
568 data->base + gate->reg,
569 gate->bit_idx, gate->gate_flags,
570 &data->lock);
571 break;
572 }
573 default:
574 dev_err(dev, "Unidentifiable clock type!\n");
575 return -EINVAL;
576 }
577 if (IS_ERR(hw))
578 return PTR_ERR(hw);
579
580 info->hw = *hw;
581 data->clk_data.hws[info->id] = hw;
582 }
583
584 return 0;
585}
586EXPORT_SYMBOL_GPL(eswin_clk_register_clks);