8
8
*
9
9
*/
10
10
11
+ #include <linux/bitfield.h>
11
12
#include <linux/platform_device.h>
12
13
#include <linux/clk.h>
13
14
#include <linux/clk-provider.h>
14
15
#include <linux/slab.h>
15
16
#include <linux/io.h>
16
17
#include <linux/of.h>
18
+ #include <linux/math64.h>
17
19
#include <linux/module.h>
18
20
#include <linux/err.h>
19
21
#include <linux/iopoll.h>
37
39
#define WZRD_CLKOUT_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT)
38
40
#define WZRD_CLKOUT_FRAC_SHIFT 8
39
41
#define WZRD_CLKOUT_FRAC_MASK 0x3ff
42
+ #define WZRD_CLKOUT0_FRAC_MASK GENMASK(17, 8)
40
43
41
44
#define WZRD_DR_MAX_INT_DIV_VALUE 255
42
45
#define WZRD_DR_STATUS_REG_OFFSET 0x04
49
52
50
53
#define WZRD_USEC_POLL 10
51
54
#define WZRD_TIMEOUT_POLL 1000
55
+
56
+ /* Divider limits, from UG572 Table 3-4 for Ultrascale+ */
57
+ #define DIV_O 0x01
58
+ #define DIV_ALL 0x03
59
+
60
+ #define WZRD_M_MIN 2
61
+ #define WZRD_M_MAX 128
62
+ #define WZRD_D_MIN 1
63
+ #define WZRD_D_MAX 106
64
+ #define WZRD_VCO_MIN 800000000
65
+ #define WZRD_VCO_MAX 1600000000
66
+ #define WZRD_O_MIN 1
67
+ #define WZRD_O_MAX 128
68
+ #define WZRD_MIN_ERR 20000
69
+ #define WZRD_FRAC_POINTS 1000
70
+
52
71
/* Get the mask from width */
53
72
#define div_mask (width ) ((1 << (width)) - 1)
54
73
@@ -97,6 +116,9 @@ struct clk_wzrd {
97
116
* @width: width of the divider bit field
98
117
* @flags: clk_wzrd divider flags
99
118
* @table: array of value/divider pairs, last entry should have div = 0
119
+ * @m: value of the multiplier
120
+ * @d: value of the common divider
121
+ * @o: value of the leaf divider
100
122
* @lock: register lock
101
123
*/
102
124
struct clk_wzrd_divider {
@@ -107,6 +129,9 @@ struct clk_wzrd_divider {
107
129
u8 width ;
108
130
u8 flags ;
109
131
const struct clk_div_table * table ;
132
+ u32 m ;
133
+ u32 d ;
134
+ u32 o ;
110
135
spinlock_t * lock ; /* divider lock */
111
136
};
112
137
@@ -198,12 +223,155 @@ static long clk_wzrd_round_rate(struct clk_hw *hw, unsigned long rate,
198
223
return * prate / div ;
199
224
}
200
225
226
+ static int clk_wzrd_get_divisors (struct clk_hw * hw , unsigned long rate ,
227
+ unsigned long parent_rate )
228
+ {
229
+ struct clk_wzrd_divider * divider = to_clk_wzrd_divider (hw );
230
+ unsigned long vco_freq , freq , diff ;
231
+ u32 m , d , o ;
232
+
233
+ for (m = WZRD_M_MIN ; m <= WZRD_M_MAX ; m ++ ) {
234
+ for (d = WZRD_D_MIN ; d <= WZRD_D_MAX ; d ++ ) {
235
+ vco_freq = DIV_ROUND_CLOSEST ((parent_rate * m ), d );
236
+ if (vco_freq >= WZRD_VCO_MIN && vco_freq <= WZRD_VCO_MAX ) {
237
+ for (o = WZRD_O_MIN ; o <= WZRD_O_MAX ; o ++ ) {
238
+ freq = DIV_ROUND_CLOSEST_ULL (vco_freq , o );
239
+ diff = abs (freq - rate );
240
+
241
+ if (diff < WZRD_MIN_ERR ) {
242
+ divider -> m = m ;
243
+ divider -> d = d ;
244
+ divider -> o = o ;
245
+ return 0 ;
246
+ }
247
+ }
248
+ }
249
+ }
250
+ }
251
+ return - EBUSY ;
252
+ }
253
+
254
+ static int clk_wzrd_dynamic_all_nolock (struct clk_hw * hw , unsigned long rate ,
255
+ unsigned long parent_rate )
256
+ {
257
+ struct clk_wzrd_divider * divider = to_clk_wzrd_divider (hw );
258
+ unsigned long vco_freq , rate_div , clockout0_div ;
259
+ u32 reg , pre , value , f ;
260
+ int err ;
261
+
262
+ err = clk_wzrd_get_divisors (hw , rate , parent_rate );
263
+ if (err )
264
+ return err ;
265
+
266
+ vco_freq = DIV_ROUND_CLOSEST (parent_rate * divider -> m , divider -> d );
267
+ rate_div = DIV_ROUND_CLOSEST_ULL ((vco_freq * WZRD_FRAC_POINTS ), rate );
268
+
269
+ clockout0_div = div_u64 (rate_div , WZRD_FRAC_POINTS );
270
+
271
+ pre = DIV_ROUND_CLOSEST_ULL (vco_freq * WZRD_FRAC_POINTS , rate );
272
+ f = (pre - (clockout0_div * WZRD_FRAC_POINTS ));
273
+ f &= WZRD_CLKOUT_FRAC_MASK ;
274
+
275
+ reg = FIELD_PREP (WZRD_CLKOUT_DIVIDE_MASK , clockout0_div ) |
276
+ FIELD_PREP (WZRD_CLKOUT0_FRAC_MASK , f );
277
+
278
+ writel (reg , divider -> base + WZRD_CLK_CFG_REG (2 ));
279
+ /* Set divisor and clear phase offset */
280
+ reg = FIELD_PREP (WZRD_CLKFBOUT_MULT_MASK , divider -> m ) |
281
+ FIELD_PREP (WZRD_DIVCLK_DIVIDE_MASK , divider -> d );
282
+ writel (reg , divider -> base + WZRD_CLK_CFG_REG (0 ));
283
+ writel (divider -> o , divider -> base + WZRD_CLK_CFG_REG (2 ));
284
+ writel (0 , divider -> base + WZRD_CLK_CFG_REG (3 ));
285
+ /* Check status register */
286
+ err = readl_poll_timeout (divider -> base + WZRD_DR_STATUS_REG_OFFSET , value ,
287
+ value & WZRD_DR_LOCK_BIT_MASK ,
288
+ WZRD_USEC_POLL , WZRD_TIMEOUT_POLL );
289
+ if (err )
290
+ return - ETIMEDOUT ;
291
+
292
+ /* Initiate reconfiguration */
293
+ writel (WZRD_DR_BEGIN_DYNA_RECONF ,
294
+ divider -> base + WZRD_DR_INIT_REG_OFFSET );
295
+
296
+ /* Check status register */
297
+ return readl_poll_timeout (divider -> base + WZRD_DR_STATUS_REG_OFFSET , value ,
298
+ value & WZRD_DR_LOCK_BIT_MASK ,
299
+ WZRD_USEC_POLL , WZRD_TIMEOUT_POLL );
300
+ }
301
+
302
+ static int clk_wzrd_dynamic_all (struct clk_hw * hw , unsigned long rate ,
303
+ unsigned long parent_rate )
304
+ {
305
+ struct clk_wzrd_divider * divider = to_clk_wzrd_divider (hw );
306
+ unsigned long flags = 0 ;
307
+ int ret ;
308
+
309
+ spin_lock_irqsave (divider -> lock , flags );
310
+
311
+ ret = clk_wzrd_dynamic_all_nolock (hw , rate , parent_rate );
312
+
313
+ spin_unlock_irqrestore (divider -> lock , flags );
314
+
315
+ return ret ;
316
+ }
317
+
318
+ static unsigned long clk_wzrd_recalc_rate_all (struct clk_hw * hw ,
319
+ unsigned long parent_rate )
320
+ {
321
+ struct clk_wzrd_divider * divider = to_clk_wzrd_divider (hw );
322
+ u32 m , d , o , div , reg , f ;
323
+
324
+ reg = readl (divider -> base + WZRD_CLK_CFG_REG (0 ));
325
+ d = FIELD_GET (WZRD_DIVCLK_DIVIDE_MASK , reg );
326
+ m = FIELD_GET (WZRD_CLKFBOUT_MULT_MASK , reg );
327
+ reg = readl (divider -> base + WZRD_CLK_CFG_REG (2 ));
328
+ o = FIELD_GET (WZRD_DIVCLK_DIVIDE_MASK , reg );
329
+ f = FIELD_GET (WZRD_CLKOUT0_FRAC_MASK , reg );
330
+
331
+ div = DIV_ROUND_CLOSEST (d * (WZRD_FRAC_POINTS * o + f ), WZRD_FRAC_POINTS );
332
+ return divider_recalc_rate (hw , parent_rate * m , div , divider -> table ,
333
+ divider -> flags , divider -> width );
334
+ }
335
+
336
+ static long clk_wzrd_round_rate_all (struct clk_hw * hw , unsigned long rate ,
337
+ unsigned long * prate )
338
+ {
339
+ struct clk_wzrd_divider * divider = to_clk_wzrd_divider (hw );
340
+ unsigned long int_freq ;
341
+ u32 m , d , o , div , f ;
342
+ int err ;
343
+
344
+ err = clk_wzrd_get_divisors (hw , rate , * prate );
345
+ if (err )
346
+ return err ;
347
+
348
+ m = divider -> m ;
349
+ d = divider -> d ;
350
+ o = divider -> o ;
351
+
352
+ div = d * o ;
353
+ int_freq = divider_recalc_rate (hw , * prate * m , div , divider -> table ,
354
+ divider -> flags , divider -> width );
355
+
356
+ if (rate > int_freq ) {
357
+ f = DIV_ROUND_CLOSEST_ULL (rate * WZRD_FRAC_POINTS , int_freq );
358
+ rate = DIV_ROUND_CLOSEST (int_freq * f , WZRD_FRAC_POINTS );
359
+ }
360
+ return rate ;
361
+ }
362
+
201
363
static const struct clk_ops clk_wzrd_clk_divider_ops = {
202
364
.round_rate = clk_wzrd_round_rate ,
203
365
.set_rate = clk_wzrd_dynamic_reconfig ,
204
366
.recalc_rate = clk_wzrd_recalc_rate ,
205
367
};
206
368
369
+ static const struct clk_ops clk_wzrd_clk_div_all_ops = {
370
+ .round_rate = clk_wzrd_round_rate_all ,
371
+ .set_rate = clk_wzrd_dynamic_all ,
372
+ .recalc_rate = clk_wzrd_recalc_rate_all ,
373
+ };
374
+
207
375
static unsigned long clk_wzrd_recalc_ratef (struct clk_hw * hw ,
208
376
unsigned long parent_rate )
209
377
{
@@ -280,7 +448,7 @@ static struct clk *clk_wzrd_register_divf(struct device *dev,
280
448
void __iomem * base , u16 offset ,
281
449
u8 shift , u8 width ,
282
450
u8 clk_divider_flags ,
283
- const struct clk_div_table * table ,
451
+ u32 div_type ,
284
452
spinlock_t * lock )
285
453
{
286
454
struct clk_wzrd_divider * div ;
@@ -307,7 +475,6 @@ static struct clk *clk_wzrd_register_divf(struct device *dev,
307
475
div -> flags = clk_divider_flags ;
308
476
div -> lock = lock ;
309
477
div -> hw .init = & init ;
310
- div -> table = table ;
311
478
312
479
hw = & div -> hw ;
313
480
ret = devm_clk_hw_register (dev , hw );
@@ -324,7 +491,7 @@ static struct clk *clk_wzrd_register_divider(struct device *dev,
324
491
void __iomem * base , u16 offset ,
325
492
u8 shift , u8 width ,
326
493
u8 clk_divider_flags ,
327
- const struct clk_div_table * table ,
494
+ u32 div_type ,
328
495
spinlock_t * lock )
329
496
{
330
497
struct clk_wzrd_divider * div ;
@@ -337,7 +504,12 @@ static struct clk *clk_wzrd_register_divider(struct device *dev,
337
504
return ERR_PTR (- ENOMEM );
338
505
339
506
init .name = name ;
340
- init .ops = & clk_wzrd_clk_divider_ops ;
507
+ if (clk_divider_flags & CLK_DIVIDER_READ_ONLY )
508
+ init .ops = & clk_divider_ro_ops ;
509
+ else if (div_type == DIV_O )
510
+ init .ops = & clk_wzrd_clk_divider_ops ;
511
+ else
512
+ init .ops = & clk_wzrd_clk_div_all_ops ;
341
513
init .flags = flags ;
342
514
init .parent_names = & parent_name ;
343
515
init .num_parents = 1 ;
@@ -349,7 +521,6 @@ static struct clk *clk_wzrd_register_divider(struct device *dev,
349
521
div -> flags = clk_divider_flags ;
350
522
div -> lock = lock ;
351
523
div -> hw .init = & init ;
352
- div -> table = table ;
353
524
354
525
hw = & div -> hw ;
355
526
ret = devm_clk_hw_register (dev , hw );
@@ -425,6 +596,7 @@ static int clk_wzrd_probe(struct platform_device *pdev)
425
596
const char * clk_name ;
426
597
void __iomem * ctrl_reg ;
427
598
struct clk_wzrd * clk_wzrd ;
599
+ const char * clkout_name ;
428
600
struct device_node * np = pdev -> dev .of_node ;
429
601
int nr_outputs ;
430
602
unsigned long flags = 0 ;
@@ -469,27 +641,38 @@ static int clk_wzrd_probe(struct platform_device *pdev)
469
641
goto err_disable_clk ;
470
642
}
471
643
644
+ ret = of_property_read_u32 (np , "xlnx,nr-outputs" , & nr_outputs );
645
+ if (ret || nr_outputs > WZRD_NUM_OUTPUTS ) {
646
+ ret = - EINVAL ;
647
+ goto err_disable_clk ;
648
+ }
649
+
650
+ clkout_name = devm_kasprintf (& pdev -> dev , GFP_KERNEL , "%s_out0" , dev_name (& pdev -> dev ));
651
+ if (nr_outputs == 1 ) {
652
+ clk_wzrd -> clkout [0 ] = clk_wzrd_register_divider
653
+ (& pdev -> dev , clkout_name ,
654
+ __clk_get_name (clk_wzrd -> clk_in1 ), 0 ,
655
+ clk_wzrd -> base , WZRD_CLK_CFG_REG (3 ),
656
+ WZRD_CLKOUT_DIVIDE_SHIFT ,
657
+ WZRD_CLKOUT_DIVIDE_WIDTH ,
658
+ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO ,
659
+ DIV_ALL , & clkwzrd_lock );
660
+
661
+ goto out ;
662
+ }
663
+
472
664
reg = readl (clk_wzrd -> base + WZRD_CLK_CFG_REG (0 ));
473
665
reg_f = reg & WZRD_CLKFBOUT_FRAC_MASK ;
474
666
reg_f = reg_f >> WZRD_CLKFBOUT_FRAC_SHIFT ;
475
667
476
668
reg = reg & WZRD_CLKFBOUT_MULT_MASK ;
477
669
reg = reg >> WZRD_CLKFBOUT_MULT_SHIFT ;
478
670
mult = (reg * 1000 ) + reg_f ;
479
- clk_name = kasprintf ( GFP_KERNEL , "%s_mul" , dev_name (& pdev -> dev ));
671
+ clk_name = devm_kasprintf ( & pdev -> dev , GFP_KERNEL , "%s_mul" , dev_name (& pdev -> dev ));
480
672
if (!clk_name ) {
481
673
ret = - ENOMEM ;
482
674
goto err_disable_clk ;
483
675
}
484
-
485
- ret = of_property_read_u32 (np , "xlnx,nr-outputs" , & nr_outputs );
486
- if (ret || nr_outputs > WZRD_NUM_OUTPUTS ) {
487
- ret = - EINVAL ;
488
- goto err_disable_clk ;
489
- }
490
- if (nr_outputs == 1 )
491
- flags = CLK_SET_RATE_PARENT ;
492
-
493
676
clk_wzrd -> clks_internal [wzrd_clk_mul ] = clk_register_fixed_factor
494
677
(& pdev -> dev , clk_name ,
495
678
__clk_get_name (clk_wzrd -> clk_in1 ),
@@ -500,7 +683,7 @@ static int clk_wzrd_probe(struct platform_device *pdev)
500
683
goto err_disable_clk ;
501
684
}
502
685
503
- clk_name = kasprintf ( GFP_KERNEL , "%s_mul_div" , dev_name (& pdev -> dev ));
686
+ clk_name = devm_kasprintf ( & pdev -> dev , GFP_KERNEL , "%s_mul_div" , dev_name (& pdev -> dev ));
504
687
if (!clk_name ) {
505
688
ret = - ENOMEM ;
506
689
goto err_rm_int_clk ;
@@ -521,9 +704,8 @@ static int clk_wzrd_probe(struct platform_device *pdev)
521
704
522
705
/* register div per output */
523
706
for (i = nr_outputs - 1 ; i >= 0 ; i -- ) {
524
- const char * clkout_name ;
525
-
526
- clkout_name = kasprintf (GFP_KERNEL , "%s_out%d" , dev_name (& pdev -> dev ), i );
707
+ clkout_name = devm_kasprintf (& pdev -> dev , GFP_KERNEL ,
708
+ "%s_out%d" , dev_name (& pdev -> dev ), i );
527
709
if (!clkout_name ) {
528
710
ret = - ENOMEM ;
529
711
goto err_rm_int_clk ;
@@ -537,7 +719,7 @@ static int clk_wzrd_probe(struct platform_device *pdev)
537
719
WZRD_CLKOUT_DIVIDE_SHIFT ,
538
720
WZRD_CLKOUT_DIVIDE_WIDTH ,
539
721
CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO ,
540
- NULL , & clkwzrd_lock );
722
+ DIV_O , & clkwzrd_lock );
541
723
else
542
724
clk_wzrd -> clkout [i ] = clk_wzrd_register_divider
543
725
(& pdev -> dev , clkout_name ,
@@ -546,7 +728,7 @@ static int clk_wzrd_probe(struct platform_device *pdev)
546
728
WZRD_CLKOUT_DIVIDE_SHIFT ,
547
729
WZRD_CLKOUT_DIVIDE_WIDTH ,
548
730
CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO ,
549
- NULL , & clkwzrd_lock );
731
+ DIV_O , & clkwzrd_lock );
550
732
if (IS_ERR (clk_wzrd -> clkout [i ])) {
551
733
int j ;
552
734
@@ -559,8 +741,7 @@ static int clk_wzrd_probe(struct platform_device *pdev)
559
741
}
560
742
}
561
743
562
- kfree (clk_name );
563
-
744
+ out :
564
745
clk_wzrd -> clk_data .clks = clk_wzrd -> clkout ;
565
746
clk_wzrd -> clk_data .clk_num = ARRAY_SIZE (clk_wzrd -> clkout );
566
747
of_clk_add_provider (np , of_clk_src_onecell_get , & clk_wzrd -> clk_data );
@@ -585,7 +766,6 @@ static int clk_wzrd_probe(struct platform_device *pdev)
585
766
err_rm_int_clks :
586
767
clk_unregister (clk_wzrd -> clks_internal [1 ]);
587
768
err_rm_int_clk :
588
- kfree (clk_name );
589
769
clk_unregister (clk_wzrd -> clks_internal [0 ]);
590
770
err_disable_clk :
591
771
clk_disable_unprepare (clk_wzrd -> axi_clk );
0 commit comments