1
2
3
4
5
6
7
8
9
10
11#include <linux/clk.h>
12#include <linux/clk-provider.h>
13#include <linux/device.h>
14#include <linux/errno.h>
15#include <linux/io.h>
16#include <linux/iopoll.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/of_address.h>
20#include <linux/of_platform.h>
21#include <linux/platform_device.h>
22#include <linux/slab.h>
23#include <soc/xilinx/xlnx_vcu.h>
24
25
26#define VCU_PLL_CTRL 0x24
27#define VCU_PLL_CTRL_RESET_MASK BIT(0)
28#define VCU_PLL_CTRL_RESET_SHIFT 0
29#define VCU_PLL_CTRL_BYPASS_MASK BIT(3)
30#define VCU_PLL_CTRL_BYPASS_SHIFT 3
31#define VCU_PLL_CTRL_FBDIV_MASK 0x7f
32#define VCU_PLL_CTRL_FBDIV_SHIFT 8
33#define VCU_PLL_CTRL_POR_IN_MASK BIT(1)
34#define VCU_PLL_CTRL_POR_IN_SHIFT 1
35#define VCU_PLL_CTRL_PWR_POR_MASK BIT(2)
36#define VCU_PLL_CTRL_PWR_POR_SHIFT 2
37#define VCU_PLL_CTRL_CLKOUTDIV_MASK 0x03
38#define VCU_PLL_CTRL_CLKOUTDIV_SHIFT 16
39#define VCU_PLL_CTRL_DEFAULT 0
40
41#define VCU_PLL_CFG 0x28
42#define VCU_PLL_CFG_RES_MASK 0x0f
43#define VCU_PLL_CFG_RES_SHIFT 0
44#define VCU_PLL_CFG_CP_MASK 0x0f
45#define VCU_PLL_CFG_CP_SHIFT 5
46#define VCU_PLL_CFG_LFHF_MASK 0x03
47#define VCU_PLL_CFG_LFHF_SHIFT 10
48#define VCU_PLL_CFG_LOCK_CNT_MASK 0x03ff
49#define VCU_PLL_CFG_LOCK_CNT_SHIFT 13
50#define VCU_PLL_CFG_LOCK_DLY_MASK 0x7f
51#define VCU_PLL_CFG_LOCK_DLY_SHIFT 25
52#define VCU_ENC_CORE_CTRL 0x30
53#define VCU_ENC_MCU_CTRL 0x34
54#define VCU_ENC_MCU_CTRL_GATE_BIT BIT(12)
55#define VCU_DEC_CORE_CTRL 0x38
56#define VCU_DEC_MCU_CTRL 0x3c
57#define VCU_PLL_DIVISOR_MASK 0x3f
58#define VCU_PLL_DIVISOR_SHIFT 4
59#define VCU_SRCSEL_MASK 0x01
60#define VCU_SRCSEL_SHIFT 0
61#define VCU_SRCSEL_PLL 1
62
63#define VCU_PLL_STATUS 0x60
64#define VCU_PLL_STATUS_LOCK_STATUS_MASK 0x01
65#define VCU_PLL_LOCK_TIMEOUT 2000000
66
67#define PLL_FBDIV_MIN 25
68#define PLL_FBDIV_MAX 125
69
70#define MHZ 1000000
71#define FVCO_MIN (1500U * MHZ)
72#define FVCO_MAX (3000U * MHZ)
73#define DIVISOR_MIN 0
74#define DIVISOR_MAX 63
75#define FRAC 100
76#define LIMIT (10 * MHZ)
77
78#define FRAC_OFFSET 0x8
79#define PLLFCFG_FRAC_EN BIT(31)
80#define FRAC_DIV 0x10000
81
82#define to_vcu_pll(_hw) container_of(_hw, struct vcu_pll, hw)
83#define div_mask(width) ((1 << (width)) - 1)
84
85enum pll_mode {
86 PLL_MODE_INT,
87 PLL_MODE_FRAC,
88};
89
90enum vcu_clks {
91 vcu_pll_half, vcu_core_enc, vcu_core_dec,
92 mcu_core_enc, mcu_core_dec, clk_max
93};
94
95
96
97
98
99
100
101
102
103
104struct xvcu_pll_cfg {
105 u32 fbdiv;
106 u32 cp;
107 u32 res;
108 u32 lfhf;
109 u32 lock_dly;
110 u32 lock_cnt;
111};
112
113
114
115
116
117
118
119
120
121struct vcu_pll {
122 struct clk_hw hw;
123 void __iomem *pll_ctrl;
124 void __iomem *pll_status;
125 void __iomem *pll_cfg;
126 u8 lockbit;
127};
128
129static struct clk_hw_onecell_data *vcu_clk_data;
130static const char * const vcu_mux_parents[] = {
131 "dummy_name",
132 "vcu_pll_half"
133};
134
135static DEFINE_SPINLOCK(mcu_enc_lock);
136static DEFINE_SPINLOCK(mcu_dec_lock);
137static DEFINE_SPINLOCK(core_enc_lock);
138static DEFINE_SPINLOCK(core_dec_lock);
139
140static const struct xvcu_pll_cfg xvcu_pll_cfg[] = {
141 { 25, 3, 10, 3, 63, 1000 },
142 { 26, 3, 10, 3, 63, 1000 },
143 { 27, 4, 6, 3, 63, 1000 },
144 { 28, 4, 6, 3, 63, 1000 },
145 { 29, 4, 6, 3, 63, 1000 },
146 { 30, 4, 6, 3, 63, 1000 },
147 { 31, 6, 1, 3, 63, 1000 },
148 { 32, 6, 1, 3, 63, 1000 },
149 { 33, 4, 10, 3, 63, 1000 },
150 { 34, 5, 6, 3, 63, 1000 },
151 { 35, 5, 6, 3, 63, 1000 },
152 { 36, 5, 6, 3, 63, 1000 },
153 { 37, 5, 6, 3, 63, 1000 },
154 { 38, 5, 6, 3, 63, 975 },
155 { 39, 3, 12, 3, 63, 950 },
156 { 40, 3, 12, 3, 63, 925 },
157 { 41, 3, 12, 3, 63, 900 },
158 { 42, 3, 12, 3, 63, 875 },
159 { 43, 3, 12, 3, 63, 850 },
160 { 44, 3, 12, 3, 63, 850 },
161 { 45, 3, 12, 3, 63, 825 },
162 { 46, 3, 12, 3, 63, 800 },
163 { 47, 3, 12, 3, 63, 775 },
164 { 48, 3, 12, 3, 63, 775 },
165 { 49, 3, 12, 3, 63, 750 },
166 { 50, 3, 12, 3, 63, 750 },
167 { 51, 3, 2, 3, 63, 725 },
168 { 52, 3, 2, 3, 63, 700 },
169 { 53, 3, 2, 3, 63, 700 },
170 { 54, 3, 2, 3, 63, 675 },
171 { 55, 3, 2, 3, 63, 675 },
172 { 56, 3, 2, 3, 63, 650 },
173 { 57, 3, 2, 3, 63, 650 },
174 { 58, 3, 2, 3, 63, 625 },
175 { 59, 3, 2, 3, 63, 625 },
176 { 60, 3, 2, 3, 63, 625 },
177 { 61, 3, 2, 3, 63, 600 },
178 { 62, 3, 2, 3, 63, 600 },
179 { 63, 3, 2, 3, 63, 600 },
180 { 64, 3, 2, 3, 63, 600 },
181 { 65, 3, 2, 3, 63, 600 },
182 { 66, 3, 2, 3, 63, 600 },
183 { 67, 3, 2, 3, 63, 600 },
184 { 68, 3, 2, 3, 63, 600 },
185 { 69, 3, 2, 3, 63, 600 },
186 { 70, 3, 2, 3, 63, 600 },
187 { 71, 3, 2, 3, 63, 600 },
188 { 72, 3, 2, 3, 63, 600 },
189 { 73, 3, 2, 3, 63, 600 },
190 { 74, 3, 2, 3, 63, 600 },
191 { 75, 3, 2, 3, 63, 600 },
192 { 76, 3, 2, 3, 63, 600 },
193 { 77, 3, 2, 3, 63, 600 },
194 { 78, 3, 2, 3, 63, 600 },
195 { 79, 3, 2, 3, 63, 600 },
196 { 80, 3, 2, 3, 63, 600 },
197 { 81, 3, 2, 3, 63, 600 },
198 { 82, 3, 2, 3, 63, 600 },
199 { 83, 4, 2, 3, 63, 600 },
200 { 84, 4, 2, 3, 63, 600 },
201 { 85, 4, 2, 3, 63, 600 },
202 { 86, 4, 2, 3, 63, 600 },
203 { 87, 4, 2, 3, 63, 600 },
204 { 88, 4, 2, 3, 63, 600 },
205 { 89, 4, 2, 3, 63, 600 },
206 { 90, 4, 2, 3, 63, 600 },
207 { 91, 4, 2, 3, 63, 600 },
208 { 92, 4, 2, 3, 63, 600 },
209 { 93, 4, 2, 3, 63, 600 },
210 { 94, 4, 2, 3, 63, 600 },
211 { 95, 4, 2, 3, 63, 600 },
212 { 96, 4, 2, 3, 63, 600 },
213 { 97, 4, 2, 3, 63, 600 },
214 { 98, 4, 2, 3, 63, 600 },
215 { 99, 4, 2, 3, 63, 600 },
216 { 100, 4, 2, 3, 63, 600 },
217 { 101, 4, 2, 3, 63, 600 },
218 { 102, 4, 2, 3, 63, 600 },
219 { 103, 5, 2, 3, 63, 600 },
220 { 104, 5, 2, 3, 63, 600 },
221 { 105, 5, 2, 3, 63, 600 },
222 { 106, 5, 2, 3, 63, 600 },
223 { 107, 3, 4, 3, 63, 600 },
224 { 108, 3, 4, 3, 63, 600 },
225 { 109, 3, 4, 3, 63, 600 },
226 { 110, 3, 4, 3, 63, 600 },
227 { 111, 3, 4, 3, 63, 600 },
228 { 112, 3, 4, 3, 63, 600 },
229 { 113, 3, 4, 3, 63, 600 },
230 { 114, 3, 4, 3, 63, 600 },
231 { 115, 3, 4, 3, 63, 600 },
232 { 116, 3, 4, 3, 63, 600 },
233 { 117, 3, 4, 3, 63, 600 },
234 { 118, 3, 4, 3, 63, 600 },
235 { 119, 3, 4, 3, 63, 600 },
236 { 120, 3, 4, 3, 63, 600 },
237 { 121, 3, 4, 3, 63, 600 },
238 { 122, 3, 4, 3, 63, 600 },
239 { 123, 3, 4, 3, 63, 600 },
240 { 124, 3, 4, 3, 63, 600 },
241 { 125, 3, 4, 3, 63, 600 },
242};
243
244static int xvcu_divider_get_val(unsigned long rate, unsigned long parent_rate,
245 const struct clk_div_table *table, u8 width,
246 unsigned long flags)
247{
248 unsigned int div;
249
250 if (flags & CLK_DIVIDER_ROUND_CLOSEST)
251 div = DIV_ROUND_CLOSEST_ULL((u64)parent_rate, rate);
252 else
253 div = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
254
255 return min_t(unsigned int, div, div_mask(width));
256}
257
258static unsigned long xvcu_divider_recalc_rate(struct clk_hw *hw,
259 unsigned long parent_rate)
260{
261 struct clk_divider *divider = to_clk_divider(hw);
262 unsigned int val;
263
264 val = clk_readl(divider->reg) >> divider->shift;
265 val &= div_mask(divider->width);
266
267 return divider_recalc_rate(hw, parent_rate, val, divider->table,
268 divider->flags, divider->width);
269}
270
271static long xvcu_divider_round_rate(struct clk_hw *hw, unsigned long rate,
272 unsigned long *prate)
273{
274 struct clk_divider *divider = to_clk_divider(hw);
275 int bestdiv;
276
277 bestdiv = xvcu_divider_get_val(rate, *prate, divider->table,
278 divider->width, divider->flags);
279
280 *prate = rate * bestdiv;
281
282 return rate;
283}
284
285static int xvcu_divider_set_rate(struct clk_hw *hw, unsigned long rate,
286 unsigned long parent_rate)
287{
288 struct clk_divider *divider = to_clk_divider(hw);
289 int value;
290 u32 val;
291
292 value = xvcu_divider_get_val(rate, parent_rate, divider->table,
293 divider->width, divider->flags);
294 if (value < 0)
295 return value;
296
297 val = clk_readl(divider->reg);
298 val &= ~(div_mask(divider->width) << divider->shift);
299 val |= (u32)value << divider->shift;
300 clk_writel(val, divider->reg);
301
302 return 0;
303}
304
305static const struct clk_ops xvcu_divider_ops = {
306 .recalc_rate = xvcu_divider_recalc_rate,
307 .round_rate = xvcu_divider_round_rate,
308 .set_rate = xvcu_divider_set_rate,
309};
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327static struct clk_hw *xvcu_register_divider(struct device *dev,
328 const char *name,
329 const char *parent_name,
330 unsigned long flags,
331 void __iomem *reg, u8 shift,
332 u8 width, u8 clk_divider_flags,
333 spinlock_t *lock)
334{
335 struct clk_divider *div;
336 struct clk_hw *hw;
337 struct clk_init_data init;
338 int ret;
339
340
341 div = kzalloc(sizeof(*div), GFP_KERNEL);
342 if (!div)
343 return ERR_PTR(-ENOMEM);
344
345 init.name = name;
346 init.ops = &xvcu_divider_ops;
347 init.flags = flags | CLK_IS_BASIC;
348 init.parent_names = (parent_name ? &parent_name : NULL);
349 init.num_parents = (parent_name ? 1 : 0);
350
351
352 div->reg = reg;
353 div->shift = shift;
354 div->width = width;
355 div->flags = clk_divider_flags;
356 div->lock = lock;
357 div->hw.init = &init;
358
359
360 hw = &div->hw;
361 ret = clk_hw_register(dev, hw);
362 if (ret) {
363 kfree(div);
364 hw = ERR_PTR(ret);
365 }
366
367 return hw;
368}
369
370
371
372
373
374
375
376
377
378
379static void xvcu_pll_bypass_ctrl(struct vcu_pll *pll, bool enable)
380{
381 u32 reg;
382
383 reg = clk_readl(pll->pll_ctrl);
384 if (enable)
385 reg |= VCU_PLL_CTRL_BYPASS_MASK;
386 else
387 reg &= ~VCU_PLL_CTRL_BYPASS_MASK;
388 clk_writel(reg, pll->pll_ctrl);
389}
390
391
392
393
394
395
396
397
398static void xvcu_pll_config(struct vcu_pll *pll)
399{
400 unsigned int fbdiv, reg;
401 int i;
402
403 reg = clk_readl(pll->pll_ctrl);
404 fbdiv = (reg >> VCU_PLL_CTRL_FBDIV_SHIFT) & VCU_PLL_CTRL_FBDIV_MASK;
405
406 for (i = ARRAY_SIZE(xvcu_pll_cfg) - 1; i >= 0; i--) {
407 if (fbdiv != xvcu_pll_cfg[i].fbdiv)
408 continue;
409
410
411 reg = (xvcu_pll_cfg[i].res << VCU_PLL_CFG_RES_SHIFT) |
412 (xvcu_pll_cfg[i].cp << VCU_PLL_CFG_CP_SHIFT) |
413 (xvcu_pll_cfg[i].lfhf << VCU_PLL_CFG_LFHF_SHIFT) |
414 (xvcu_pll_cfg[i].lock_cnt << VCU_PLL_CFG_LOCK_CNT_SHIFT) |
415 (xvcu_pll_cfg[i].lock_dly << VCU_PLL_CFG_LOCK_DLY_SHIFT);
416 clk_writel(reg, pll->pll_cfg);
417 }
418}
419
420
421
422
423
424
425
426
427
428
429static void xvcu_pll_enable_disable(struct vcu_pll *pll, bool enable)
430{
431 u32 reg;
432
433 reg = clk_readl(pll->pll_ctrl);
434 if (enable)
435 reg &= ~(VCU_PLL_CTRL_RESET_MASK | VCU_PLL_CTRL_POR_IN_MASK |
436 VCU_PLL_CTRL_PWR_POR_MASK);
437 else
438 reg |= (VCU_PLL_CTRL_RESET_MASK | VCU_PLL_CTRL_POR_IN_MASK |
439 VCU_PLL_CTRL_PWR_POR_MASK);
440 clk_writel(reg, pll->pll_ctrl);
441}
442
443
444
445
446
447
448
449
450
451
452static int xvcu_pll_is_enabled(struct clk_hw *hw)
453{
454 struct vcu_pll *pll = to_vcu_pll(hw);
455 u32 reg;
456
457 reg = clk_readl(pll->pll_ctrl);
458
459 return !(reg & (VCU_PLL_CTRL_RESET_MASK | VCU_PLL_CTRL_POR_IN_MASK |
460 VCU_PLL_CTRL_PWR_POR_MASK));
461}
462
463
464
465
466
467
468
469
470
471
472static int xvcu_pll_enable(struct clk_hw *hw)
473{
474 struct vcu_pll *pll = to_vcu_pll(hw);
475 u32 reg;
476 int ret;
477
478 if (xvcu_pll_is_enabled(hw))
479 return 0;
480
481 pr_info("VCU PLL: enable\n");
482
483 xvcu_pll_bypass_ctrl(pll, 1);
484
485 xvcu_pll_config(pll);
486
487 xvcu_pll_enable_disable(pll, 1);
488
489 ret = readl_poll_timeout_atomic(pll->pll_status, reg,
490 reg & VCU_PLL_STATUS_LOCK_STATUS_MASK,
491 1, VCU_PLL_LOCK_TIMEOUT);
492 if (ret) {
493 pr_err("VCU PLL is not locked\n");
494 return ret;
495 }
496
497 xvcu_pll_bypass_ctrl(pll, 0);
498
499 return ret;
500}
501
502
503
504
505
506
507
508
509
510static void xvcu_pll_disable(struct clk_hw *hw)
511{
512 struct vcu_pll *pll = to_vcu_pll(hw);
513
514 if (!xvcu_pll_is_enabled(hw))
515 return;
516
517 pr_info("PLL: shutdown\n");
518 xvcu_pll_enable_disable(pll, 0);
519}
520
521
522
523
524
525
526
527
528
529
530
531static inline enum pll_mode xvcu_pll_frac_get_mode(struct clk_hw *hw)
532{
533 struct vcu_pll *clk = to_vcu_pll(hw);
534 u32 reg;
535
536 reg = clk_readl(clk->pll_ctrl + FRAC_OFFSET);
537
538 reg = reg & PLLFCFG_FRAC_EN;
539 return reg ? PLL_MODE_FRAC : PLL_MODE_INT;
540}
541
542
543
544
545
546
547
548
549
550
551static inline void xvcu_pll_frac_set_mode(struct clk_hw *hw, bool on)
552{
553 struct vcu_pll *clk = to_vcu_pll(hw);
554 u32 reg = 0;
555
556 if (on)
557 reg = PLLFCFG_FRAC_EN;
558
559 reg = clk_readl(clk->pll_ctrl + FRAC_OFFSET);
560 reg |= PLLFCFG_FRAC_EN;
561 clk_writel(reg, (clk->pll_ctrl + FRAC_OFFSET));
562}
563
564static long vcu_pll_round_rate(struct clk_hw *hw, unsigned long rate,
565 unsigned long *prate)
566{
567 u32 fbdiv;
568 long rate_div, f;
569
570
571 rate_div = (rate * FRAC_DIV) / *prate;
572 f = rate_div % FRAC_DIV;
573 xvcu_pll_frac_set_mode(hw, !!f);
574
575 if (xvcu_pll_frac_get_mode(hw) == PLL_MODE_FRAC) {
576 if (rate > FVCO_MAX) {
577 fbdiv = rate / FVCO_MAX;
578 rate = rate / (fbdiv + 1);
579 }
580 if (rate < FVCO_MIN) {
581 fbdiv = DIV_ROUND_UP(FVCO_MIN, rate);
582 rate = rate * fbdiv;
583 }
584 return rate;
585 }
586
587 fbdiv = DIV_ROUND_CLOSEST(rate, *prate);
588 fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
589 return *prate * fbdiv;
590}
591
592static unsigned long vcu_pll_recalc_rate(struct clk_hw *hw,
593 unsigned long parent_rate)
594{
595 struct vcu_pll *pll = to_vcu_pll(hw);
596 u32 fbdiv, data, reg;
597 unsigned long rate, frac;
598
599 reg = clk_readl(pll->pll_ctrl);
600 fbdiv = (reg >> VCU_PLL_CTRL_FBDIV_SHIFT) & VCU_PLL_CTRL_FBDIV_MASK;
601
602 rate = parent_rate * fbdiv;
603 if (xvcu_pll_frac_get_mode(hw) == PLL_MODE_FRAC) {
604 data = (clk_readl(pll->pll_ctrl + FRAC_OFFSET) & 0xFFFF);
605 frac = (parent_rate * data) / FRAC_DIV;
606 rate = rate + frac;
607 }
608
609 return rate;
610}
611
612static int vcu_pll_set_rate(struct clk_hw *hw, unsigned long rate,
613 unsigned long parent_rate)
614{
615 struct vcu_pll *pll = to_vcu_pll(hw);
616 u32 fbdiv, reg;
617 long rate_div, frac, m, f;
618
619 if (xvcu_pll_frac_get_mode(hw) == PLL_MODE_FRAC) {
620 rate_div = ((rate * FRAC_DIV) / parent_rate);
621 m = rate_div / FRAC_DIV;
622 f = rate_div % FRAC_DIV;
623 m = clamp_t(u32, m, (PLL_FBDIV_MIN), (PLL_FBDIV_MAX));
624 rate = parent_rate * m;
625 frac = (parent_rate * f) / FRAC_DIV;
626 reg = clk_readl(pll->pll_ctrl);
627 reg &= ~(VCU_PLL_CTRL_FBDIV_MASK << VCU_PLL_CTRL_FBDIV_SHIFT);
628 reg |= m << VCU_PLL_CTRL_FBDIV_SHIFT;
629 clk_writel(reg, pll->pll_ctrl);
630
631 reg = clk_readl(pll->pll_ctrl + FRAC_OFFSET);
632 reg &= ~0xFFFF;
633 reg |= (f & 0xFFFF);
634 clk_writel(reg, pll->pll_ctrl + FRAC_OFFSET);
635
636 return (rate + frac);
637 }
638
639 fbdiv = DIV_ROUND_CLOSEST(rate, parent_rate);
640 fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
641 reg = clk_readl(pll->pll_ctrl);
642 reg &= ~(VCU_PLL_CTRL_FBDIV_MASK << VCU_PLL_CTRL_FBDIV_SHIFT);
643 reg |= fbdiv << VCU_PLL_CTRL_FBDIV_SHIFT;
644 clk_writel(reg, pll->pll_ctrl);
645
646 return parent_rate * fbdiv;
647}
648
649static const struct clk_ops vcu_pll_ops = {
650 .enable = xvcu_pll_enable,
651 .disable = xvcu_pll_disable,
652 .is_enabled = xvcu_pll_is_enabled,
653 .round_rate = vcu_pll_round_rate,
654 .recalc_rate = vcu_pll_recalc_rate,
655 .set_rate = vcu_pll_set_rate,
656};
657
658
659
660
661
662
663
664
665
666
667
668
669
670static struct clk_hw *xvcu_register_pll(struct device *dev, const char *name,
671 const char *parent,
672 void __iomem *reg_base,
673 unsigned long flags)
674{
675 struct vcu_pll *pll;
676 struct clk_hw *hw;
677 struct clk_init_data init;
678 int ret;
679
680 init.name = name;
681 init.parent_names = &parent;
682 init.ops = &vcu_pll_ops;
683 init.num_parents = 1;
684 init.flags = flags;
685
686 pll = devm_kmalloc(dev, sizeof(*pll), GFP_KERNEL);
687 if (!pll)
688 return ERR_PTR(-ENOMEM);
689
690 pll->hw.init = &init;
691 pll->pll_ctrl = reg_base + VCU_PLL_CTRL;
692 pll->pll_status = reg_base + VCU_PLL_STATUS;
693 pll->pll_cfg = reg_base + VCU_PLL_CFG;
694 pll->lockbit = VCU_PLL_STATUS_LOCK_STATUS_MASK;
695
696 hw = &pll->hw;
697 ret = devm_clk_hw_register(dev, hw);
698 if (ret)
699 return ERR_PTR(ret);
700
701 clk_hw_set_rate_range(hw, FVCO_MIN, FVCO_MAX);
702 if (ret < 0)
703 pr_err("%s:ERROR clk_set_rate_range failed %d\n", name, ret);
704
705 return hw;
706}
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724static struct clk_hw *register_vcu_leaf_clocks(struct device *dev,
725 const char *name,
726 const char * const *parents,
727 u8 nparents,
728 struct clk *default_parent,
729 void __iomem *reg,
730 spinlock_t *lock)
731{
732 char *clk_mux, *clk_div;
733 struct clk_hw *hw;
734
735 clk_mux = devm_kasprintf(dev, GFP_KERNEL, "%s%s", name, "_mux");
736 hw = clk_hw_register_mux(dev, clk_mux, parents, nparents,
737 CLK_SET_RATE_PARENT | CLK_IS_BASIC |
738 CLK_SET_RATE_NO_REPARENT,
739 reg, VCU_SRCSEL_SHIFT, 1, 0, lock);
740
741 if (default_parent)
742 clk_set_parent(hw->clk, default_parent);
743
744 clk_div = devm_kasprintf(dev, GFP_KERNEL, "%s%s", name, "_div");
745 xvcu_register_divider(dev, clk_div, clk_mux,
746 CLK_IS_BASIC | CLK_SET_RATE_PARENT |
747 CLK_SET_RATE_NO_REPARENT,
748 reg, VCU_PLL_DIVISOR_SHIFT, 6,
749 CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO |
750 CLK_DIVIDER_ROUND_CLOSEST,
751 lock);
752
753 return clk_hw_register_gate(dev, name, clk_div,
754 CLK_SET_RATE_PARENT | CLK_IS_BASIC,
755 reg, 12, 0, lock);
756}
757
758
759
760
761
762
763
764
765
766
767static void unregister_vcu_leaf_clocks(struct clk_hw *hw)
768{
769 struct clk_hw *parent;
770
771 parent = clk_hw_get_parent(hw);
772 clk_hw_unregister_gate(hw);
773 hw = parent;
774
775 parent = clk_hw_get_parent(hw);
776 clk_hw_unregister_divider(hw);
777 hw = parent;
778
779 clk_hw_unregister_mux(hw);
780}
781
782
783
784
785
786
787
788
789
790
791static int xvcu_clock_init(struct device *dev, void __iomem *reg_base)
792{
793 struct clk_hw *hw;
794 struct clk *ref_clk;
795 const char *parent;
796 u32 vcu_pll_ctrl, clkoutdiv;
797 int i;
798
799 ref_clk = devm_clk_get(dev, "pll_ref");
800 if (IS_ERR(ref_clk)) {
801 dev_err(dev, "failed to get pll_ref clock\n");
802 return PTR_ERR(ref_clk);
803 }
804
805 vcu_clk_data = devm_kzalloc(dev, sizeof(*vcu_clk_data) +
806 sizeof(*vcu_clk_data->hws) * clk_max,
807 GFP_KERNEL);
808 if (!vcu_clk_data)
809 return -ENOMEM;
810
811 parent = __clk_get_name(ref_clk);
812 hw = xvcu_register_pll(dev, "vcu_pll", parent, reg_base,
813 CLK_SET_RATE_NO_REPARENT);
814 if (IS_ERR(hw)) {
815 dev_err(dev, "VCU PLL registration failed\n");
816 return PTR_ERR(hw);
817 }
818
819
820
821
822
823 vcu_pll_ctrl = clk_readl(reg_base + VCU_PLL_CTRL);
824 clkoutdiv = vcu_pll_ctrl >> VCU_PLL_CTRL_CLKOUTDIV_SHIFT;
825 clkoutdiv = clkoutdiv & VCU_PLL_CTRL_CLKOUTDIV_MASK;
826 if (clkoutdiv != 1) {
827 dev_err(dev, "clkoutdiv is invalid\n");
828 return -EINVAL;
829 }
830
831 vcu_clk_data->hws[vcu_pll_half] =
832 clk_hw_register_fixed_factor(dev, "vcu_pll_half", "vcu_pll",
833 CLK_SET_RATE_NO_REPARENT |
834 CLK_SET_RATE_PARENT,
835 1, 2);
836
837 vcu_clk_data->hws[vcu_core_enc] =
838 register_vcu_leaf_clocks(dev, "vcu_core_enc_clk",
839 vcu_mux_parents, 2,
840 vcu_clk_data->hws[vcu_pll_half]->clk,
841 reg_base + VCU_ENC_CORE_CTRL,
842 &core_enc_lock);
843 vcu_clk_data->hws[vcu_core_dec] =
844 register_vcu_leaf_clocks(dev, "vcu_core_dec_clk",
845 vcu_mux_parents, 2,
846 vcu_clk_data->hws[vcu_pll_half]->clk,
847 reg_base + VCU_DEC_CORE_CTRL,
848 &core_dec_lock);
849 vcu_clk_data->hws[mcu_core_enc] =
850 register_vcu_leaf_clocks(dev, "mcu_core_enc_clk",
851 vcu_mux_parents, 2,
852 vcu_clk_data->hws[vcu_pll_half]->clk,
853 reg_base + VCU_ENC_MCU_CTRL,
854 &mcu_enc_lock);
855 vcu_clk_data->hws[mcu_core_dec] =
856 register_vcu_leaf_clocks(dev, "mcu_core_dec_clk",
857 vcu_mux_parents, 2,
858 vcu_clk_data->hws[vcu_pll_half]->clk,
859 reg_base + VCU_DEC_MCU_CTRL,
860 &mcu_dec_lock);
861
862 for (i = 0; i < clk_max; i++) {
863 if (IS_ERR(vcu_clk_data->hws[i])) {
864 dev_err(dev, "clk %d: register failed with %ld\n",
865 i, PTR_ERR(vcu_clk_data->hws[i]));
866 }
867 }
868
869 vcu_clk_data->num = clk_max;
870 return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
871 vcu_clk_data);
872}
873
874static int xvcu_clk_probe(struct platform_device *pdev)
875{
876 struct xvcu_device *xvcu = dev_get_drvdata(pdev->dev.parent);
877 int ret;
878
879 ret = xvcu_clock_init(pdev->dev.parent, xvcu->vcu_slcr_ba);
880 if (ret)
881 dev_err(&pdev->dev, "clock init fail with error %d\n", ret);
882 else
883 dev_dbg(&pdev->dev, "clock init successful\n");
884
885 return ret;
886}
887
888static int xvcu_clk_remove(struct platform_device *pdev)
889{
890 unregister_vcu_leaf_clocks(vcu_clk_data->hws[vcu_core_enc]);
891 unregister_vcu_leaf_clocks(vcu_clk_data->hws[vcu_core_dec]);
892 unregister_vcu_leaf_clocks(vcu_clk_data->hws[mcu_core_enc]);
893 unregister_vcu_leaf_clocks(vcu_clk_data->hws[mcu_core_dec]);
894 clk_hw_unregister(vcu_clk_data->hws[vcu_pll_half]);
895 of_clk_del_provider(pdev->dev.parent->of_node);
896
897 devm_kfree(pdev->dev.parent, vcu_clk_data);
898
899 return 0;
900}
901
902static struct platform_driver xvcu_clk_driver = {
903 .driver = {
904 .name = "xilinx-vcu-clk",
905 },
906 .probe = xvcu_clk_probe,
907 .remove = xvcu_clk_remove,
908};
909
910module_platform_driver(xvcu_clk_driver);
911
912MODULE_AUTHOR("Rajan Vaja <rajan.vaja@xilinx.com>");
913MODULE_DESCRIPTION("Xilinx VCU clock Driver");
914MODULE_LICENSE("GPL v2");
915MODULE_ALIAS("platform:xilinx-vcu-clk");
916