88 *
99 */
1010
11+ #include <linux/bitfield.h>
1112#include <linux/platform_device.h>
1213#include <linux/clk.h>
1314#include <linux/clk-provider.h>
1415#include <linux/slab.h>
1516#include <linux/io.h>
1617#include <linux/of.h>
18+ #include <linux/math64.h>
1719#include <linux/module.h>
1820#include <linux/err.h>
1921#include <linux/iopoll.h>
3739#define WZRD_CLKOUT_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT)
3840#define WZRD_CLKOUT_FRAC_SHIFT 8
3941#define WZRD_CLKOUT_FRAC_MASK 0x3ff
42+ #define WZRD_CLKOUT0_FRAC_MASK GENMASK(17, 8)
4043
4144#define WZRD_DR_MAX_INT_DIV_VALUE 255
4245#define WZRD_DR_STATUS_REG_OFFSET 0x04
4952
5053#define WZRD_USEC_POLL 10
5154#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+
5271/* Get the mask from width */
5372#define div_mask (width ) ((1 << (width)) - 1)
5473
@@ -97,6 +116,9 @@ struct clk_wzrd {
97116 * @width: width of the divider bit field
98117 * @flags: clk_wzrd divider flags
99118 * @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
100122 * @lock: register lock
101123 */
102124struct clk_wzrd_divider {
@@ -107,6 +129,9 @@ struct clk_wzrd_divider {
107129 u8 width ;
108130 u8 flags ;
109131 const struct clk_div_table * table ;
132+ u32 m ;
133+ u32 d ;
134+ u32 o ;
110135 spinlock_t * lock ; /* divider lock */
111136};
112137
@@ -198,12 +223,155 @@ static long clk_wzrd_round_rate(struct clk_hw *hw, unsigned long rate,
198223 return * prate / div ;
199224}
200225
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+
201363static const struct clk_ops clk_wzrd_clk_divider_ops = {
202364 .round_rate = clk_wzrd_round_rate ,
203365 .set_rate = clk_wzrd_dynamic_reconfig ,
204366 .recalc_rate = clk_wzrd_recalc_rate ,
205367};
206368
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+
207375static unsigned long clk_wzrd_recalc_ratef (struct clk_hw * hw ,
208376 unsigned long parent_rate )
209377{
@@ -280,7 +448,7 @@ static struct clk *clk_wzrd_register_divf(struct device *dev,
280448 void __iomem * base , u16 offset ,
281449 u8 shift , u8 width ,
282450 u8 clk_divider_flags ,
283- const struct clk_div_table * table ,
451+ u32 div_type ,
284452 spinlock_t * lock )
285453{
286454 struct clk_wzrd_divider * div ;
@@ -307,7 +475,6 @@ static struct clk *clk_wzrd_register_divf(struct device *dev,
307475 div -> flags = clk_divider_flags ;
308476 div -> lock = lock ;
309477 div -> hw .init = & init ;
310- div -> table = table ;
311478
312479 hw = & div -> hw ;
313480 ret = devm_clk_hw_register (dev , hw );
@@ -324,7 +491,7 @@ static struct clk *clk_wzrd_register_divider(struct device *dev,
324491 void __iomem * base , u16 offset ,
325492 u8 shift , u8 width ,
326493 u8 clk_divider_flags ,
327- const struct clk_div_table * table ,
494+ u32 div_type ,
328495 spinlock_t * lock )
329496{
330497 struct clk_wzrd_divider * div ;
@@ -337,7 +504,12 @@ static struct clk *clk_wzrd_register_divider(struct device *dev,
337504 return ERR_PTR (- ENOMEM );
338505
339506 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 ;
341513 init .flags = flags ;
342514 init .parent_names = & parent_name ;
343515 init .num_parents = 1 ;
@@ -349,7 +521,6 @@ static struct clk *clk_wzrd_register_divider(struct device *dev,
349521 div -> flags = clk_divider_flags ;
350522 div -> lock = lock ;
351523 div -> hw .init = & init ;
352- div -> table = table ;
353524
354525 hw = & div -> hw ;
355526 ret = devm_clk_hw_register (dev , hw );
@@ -425,6 +596,7 @@ static int clk_wzrd_probe(struct platform_device *pdev)
425596 const char * clk_name ;
426597 void __iomem * ctrl_reg ;
427598 struct clk_wzrd * clk_wzrd ;
599+ const char * clkout_name ;
428600 struct device_node * np = pdev -> dev .of_node ;
429601 int nr_outputs ;
430602 unsigned long flags = 0 ;
@@ -469,27 +641,38 @@ static int clk_wzrd_probe(struct platform_device *pdev)
469641 goto err_disable_clk ;
470642 }
471643
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+
472664 reg = readl (clk_wzrd -> base + WZRD_CLK_CFG_REG (0 ));
473665 reg_f = reg & WZRD_CLKFBOUT_FRAC_MASK ;
474666 reg_f = reg_f >> WZRD_CLKFBOUT_FRAC_SHIFT ;
475667
476668 reg = reg & WZRD_CLKFBOUT_MULT_MASK ;
477669 reg = reg >> WZRD_CLKFBOUT_MULT_SHIFT ;
478670 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 ));
480672 if (!clk_name ) {
481673 ret = - ENOMEM ;
482674 goto err_disable_clk ;
483675 }
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-
493676 clk_wzrd -> clks_internal [wzrd_clk_mul ] = clk_register_fixed_factor
494677 (& pdev -> dev , clk_name ,
495678 __clk_get_name (clk_wzrd -> clk_in1 ),
@@ -500,7 +683,7 @@ static int clk_wzrd_probe(struct platform_device *pdev)
500683 goto err_disable_clk ;
501684 }
502685
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 ));
504687 if (!clk_name ) {
505688 ret = - ENOMEM ;
506689 goto err_rm_int_clk ;
@@ -521,9 +704,8 @@ static int clk_wzrd_probe(struct platform_device *pdev)
521704
522705 /* register div per output */
523706 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 );
527709 if (!clkout_name ) {
528710 ret = - ENOMEM ;
529711 goto err_rm_int_clk ;
@@ -537,7 +719,7 @@ static int clk_wzrd_probe(struct platform_device *pdev)
537719 WZRD_CLKOUT_DIVIDE_SHIFT ,
538720 WZRD_CLKOUT_DIVIDE_WIDTH ,
539721 CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO ,
540- NULL , & clkwzrd_lock );
722+ DIV_O , & clkwzrd_lock );
541723 else
542724 clk_wzrd -> clkout [i ] = clk_wzrd_register_divider
543725 (& pdev -> dev , clkout_name ,
@@ -546,7 +728,7 @@ static int clk_wzrd_probe(struct platform_device *pdev)
546728 WZRD_CLKOUT_DIVIDE_SHIFT ,
547729 WZRD_CLKOUT_DIVIDE_WIDTH ,
548730 CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO ,
549- NULL , & clkwzrd_lock );
731+ DIV_O , & clkwzrd_lock );
550732 if (IS_ERR (clk_wzrd -> clkout [i ])) {
551733 int j ;
552734
@@ -559,8 +741,7 @@ static int clk_wzrd_probe(struct platform_device *pdev)
559741 }
560742 }
561743
562- kfree (clk_name );
563-
744+ out :
564745 clk_wzrd -> clk_data .clks = clk_wzrd -> clkout ;
565746 clk_wzrd -> clk_data .clk_num = ARRAY_SIZE (clk_wzrd -> clkout );
566747 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)
585766err_rm_int_clks :
586767 clk_unregister (clk_wzrd -> clks_internal [1 ]);
587768err_rm_int_clk :
588- kfree (clk_name );
589769 clk_unregister (clk_wzrd -> clks_internal [0 ]);
590770err_disable_clk :
591771 clk_disable_unprepare (clk_wzrd -> axi_clk );
0 commit comments