1515
1616/* address offset of control registers */
1717#define REG_MSSPLL_REF_CR 0x08u
18- #define REG_MSSPLL_POSTDIV_CR 0x10u
18+ #define REG_MSSPLL_POSTDIV01_CR 0x10u
19+ #define REG_MSSPLL_POSTDIV23_CR 0x14u
1920#define REG_MSSPLL_SSCG_2_CR 0x2Cu
2021#define REG_CLOCK_CONFIG_CR 0x08u
2122#define REG_RTC_CLOCK_CR 0x0Cu
2627#define MSSPLL_FBDIV_WIDTH 0x0Cu
2728#define MSSPLL_REFDIV_SHIFT 0x08u
2829#define MSSPLL_REFDIV_WIDTH 0x06u
29- #define MSSPLL_POSTDIV_SHIFT 0x08u
30+ #define MSSPLL_POSTDIV02_SHIFT 0x08u
31+ #define MSSPLL_POSTDIV13_SHIFT 0x18u
3032#define MSSPLL_POSTDIV_WIDTH 0x07u
3133#define MSSPLL_FIXED_DIV 4u
3234
35+ /*
36+ * This clock ID is defined here, rather than the binding headers, as it is an
37+ * internal clock only, and therefore has no consumers in other peripheral
38+ * blocks.
39+ */
40+ #define CLK_MSSPLL_INTERNAL 38u
41+
3342struct mpfs_clock_data {
3443 struct device * dev ;
3544 void __iomem * base ;
@@ -39,17 +48,27 @@ struct mpfs_clock_data {
3948
4049struct mpfs_msspll_hw_clock {
4150 void __iomem * base ;
51+ struct clk_hw hw ;
52+ struct clk_init_data init ;
4253 unsigned int id ;
4354 u32 reg_offset ;
4455 u32 shift ;
4556 u32 width ;
4657 u32 flags ;
47- struct clk_hw hw ;
48- struct clk_init_data init ;
4958};
5059
5160#define to_mpfs_msspll_clk (_hw ) container_of(_hw, struct mpfs_msspll_hw_clock, hw)
5261
62+ struct mpfs_msspll_out_hw_clock {
63+ void __iomem * base ;
64+ struct clk_divider output ;
65+ struct clk_init_data init ;
66+ unsigned int id ;
67+ u32 reg_offset ;
68+ };
69+
70+ #define to_mpfs_msspll_out_clk (_hw ) container_of(_hw, struct mpfs_msspll_out_hw_clock, hw)
71+
5372struct mpfs_cfg_hw_clock {
5473 struct clk_divider cfg ;
5574 struct clk_init_data init ;
@@ -93,93 +112,40 @@ static const struct clk_div_table mpfs_div_rtcref_table[] = {
93112 { 0 , 0 }
94113};
95114
96- static unsigned long mpfs_clk_msspll_recalc_rate (struct clk_hw * hw , unsigned long prate )
97- {
98- struct mpfs_msspll_hw_clock * msspll_hw = to_mpfs_msspll_clk (hw );
99- void __iomem * mult_addr = msspll_hw -> base + msspll_hw -> reg_offset ;
100- void __iomem * ref_div_addr = msspll_hw -> base + REG_MSSPLL_REF_CR ;
101- void __iomem * postdiv_addr = msspll_hw -> base + REG_MSSPLL_POSTDIV_CR ;
102- u32 mult , ref_div , postdiv ;
103-
104- mult = readl_relaxed (mult_addr ) >> MSSPLL_FBDIV_SHIFT ;
105- mult &= clk_div_mask (MSSPLL_FBDIV_WIDTH );
106- ref_div = readl_relaxed (ref_div_addr ) >> MSSPLL_REFDIV_SHIFT ;
107- ref_div &= clk_div_mask (MSSPLL_REFDIV_WIDTH );
108- postdiv = readl_relaxed (postdiv_addr ) >> MSSPLL_POSTDIV_SHIFT ;
109- postdiv &= clk_div_mask (MSSPLL_POSTDIV_WIDTH );
110-
111- return prate * mult / (ref_div * MSSPLL_FIXED_DIV * postdiv );
112- }
115+ /*
116+ * MSS PLL internal clock
117+ */
113118
114- static long mpfs_clk_msspll_round_rate (struct clk_hw * hw , unsigned long rate , unsigned long * prate )
119+ static unsigned long mpfs_clk_msspll_recalc_rate (struct clk_hw * hw , unsigned long prate )
115120{
116121 struct mpfs_msspll_hw_clock * msspll_hw = to_mpfs_msspll_clk (hw );
117122 void __iomem * mult_addr = msspll_hw -> base + msspll_hw -> reg_offset ;
118123 void __iomem * ref_div_addr = msspll_hw -> base + REG_MSSPLL_REF_CR ;
119124 u32 mult , ref_div ;
120- unsigned long rate_before_ctrl ;
121-
122- mult = readl_relaxed (mult_addr ) >> MSSPLL_FBDIV_SHIFT ;
123- mult &= clk_div_mask (MSSPLL_FBDIV_WIDTH );
124- ref_div = readl_relaxed (ref_div_addr ) >> MSSPLL_REFDIV_SHIFT ;
125- ref_div &= clk_div_mask (MSSPLL_REFDIV_WIDTH );
126-
127- rate_before_ctrl = rate * (ref_div * MSSPLL_FIXED_DIV ) / mult ;
128-
129- return divider_round_rate (hw , rate_before_ctrl , prate , NULL , MSSPLL_POSTDIV_WIDTH ,
130- msspll_hw -> flags );
131- }
132-
133- static int mpfs_clk_msspll_set_rate (struct clk_hw * hw , unsigned long rate , unsigned long prate )
134- {
135- struct mpfs_msspll_hw_clock * msspll_hw = to_mpfs_msspll_clk (hw );
136- void __iomem * mult_addr = msspll_hw -> base + msspll_hw -> reg_offset ;
137- void __iomem * ref_div_addr = msspll_hw -> base + REG_MSSPLL_REF_CR ;
138- void __iomem * postdiv_addr = msspll_hw -> base + REG_MSSPLL_POSTDIV_CR ;
139- u32 mult , ref_div , postdiv ;
140- int divider_setting ;
141- unsigned long rate_before_ctrl , flags ;
142125
143126 mult = readl_relaxed (mult_addr ) >> MSSPLL_FBDIV_SHIFT ;
144127 mult &= clk_div_mask (MSSPLL_FBDIV_WIDTH );
145128 ref_div = readl_relaxed (ref_div_addr ) >> MSSPLL_REFDIV_SHIFT ;
146129 ref_div &= clk_div_mask (MSSPLL_REFDIV_WIDTH );
147130
148- rate_before_ctrl = rate * (ref_div * MSSPLL_FIXED_DIV ) / mult ;
149- divider_setting = divider_get_val (rate_before_ctrl , prate , NULL , MSSPLL_POSTDIV_WIDTH ,
150- msspll_hw -> flags );
151-
152- if (divider_setting < 0 )
153- return divider_setting ;
154-
155- spin_lock_irqsave (& mpfs_clk_lock , flags );
156-
157- postdiv = readl_relaxed (postdiv_addr );
158- postdiv &= ~(clk_div_mask (MSSPLL_POSTDIV_WIDTH ) << MSSPLL_POSTDIV_SHIFT );
159- writel_relaxed (postdiv , postdiv_addr );
160-
161- spin_unlock_irqrestore (& mpfs_clk_lock , flags );
162-
163- return 0 ;
131+ return prate * mult / (ref_div * MSSPLL_FIXED_DIV );
164132}
165133
166134static const struct clk_ops mpfs_clk_msspll_ops = {
167135 .recalc_rate = mpfs_clk_msspll_recalc_rate ,
168- .round_rate = mpfs_clk_msspll_round_rate ,
169- .set_rate = mpfs_clk_msspll_set_rate ,
170136};
171137
172138#define CLK_PLL (_id , _name , _parent , _shift , _width , _flags , _offset ) { \
173139 .id = _id, \
140+ .flags = _flags, \
174141 .shift = _shift, \
175142 .width = _width, \
176143 .reg_offset = _offset, \
177- .flags = _flags, \
178144 .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent, &mpfs_clk_msspll_ops, 0), \
179145}
180146
181147static struct mpfs_msspll_hw_clock mpfs_msspll_clks [] = {
182- CLK_PLL (CLK_MSSPLL , "clk_msspll " , mpfs_ext_ref , MSSPLL_FBDIV_SHIFT ,
148+ CLK_PLL (CLK_MSSPLL_INTERNAL , "clk_msspll_internal " , mpfs_ext_ref , MSSPLL_FBDIV_SHIFT ,
183149 MSSPLL_FBDIV_WIDTH , 0 , REG_MSSPLL_SSCG_2_CR ),
184150};
185151
@@ -196,14 +162,62 @@ static int mpfs_clk_register_mssplls(struct device *dev, struct mpfs_msspll_hw_c
196162 ret = devm_clk_hw_register (dev , & msspll_hw -> hw );
197163 if (ret )
198164 return dev_err_probe (dev , ret , "failed to register msspll id: %d\n" ,
199- CLK_MSSPLL );
165+ CLK_MSSPLL_INTERNAL );
200166
201167 data -> hw_data .hws [msspll_hw -> id ] = & msspll_hw -> hw ;
202168 }
203169
204170 return 0 ;
205171}
206172
173+ /*
174+ * MSS PLL output clocks
175+ */
176+
177+ #define CLK_PLL_OUT (_id , _name , _parent , _flags , _shift , _width , _offset ) { \
178+ .id = _id, \
179+ .output.shift = _shift, \
180+ .output.width = _width, \
181+ .output.table = NULL, \
182+ .reg_offset = _offset, \
183+ .output.flags = _flags, \
184+ .output.hw.init = CLK_HW_INIT(_name, _parent, &clk_divider_ops, 0), \
185+ .output.lock = &mpfs_clk_lock, \
186+ }
187+
188+ static struct mpfs_msspll_out_hw_clock mpfs_msspll_out_clks [] = {
189+ CLK_PLL_OUT (CLK_MSSPLL0 , "clk_msspll" , "clk_msspll_internal" , CLK_DIVIDER_ONE_BASED ,
190+ MSSPLL_POSTDIV02_SHIFT , MSSPLL_POSTDIV_WIDTH , REG_MSSPLL_POSTDIV01_CR ),
191+ CLK_PLL_OUT (CLK_MSSPLL1 , "clk_msspll1" , "clk_msspll_internal" , CLK_DIVIDER_ONE_BASED ,
192+ MSSPLL_POSTDIV13_SHIFT , MSSPLL_POSTDIV_WIDTH , REG_MSSPLL_POSTDIV01_CR ),
193+ CLK_PLL_OUT (CLK_MSSPLL2 , "clk_msspll2" , "clk_msspll_internal" , CLK_DIVIDER_ONE_BASED ,
194+ MSSPLL_POSTDIV02_SHIFT , MSSPLL_POSTDIV_WIDTH , REG_MSSPLL_POSTDIV23_CR ),
195+ CLK_PLL_OUT (CLK_MSSPLL3 , "clk_msspll3" , "clk_msspll_internal" , CLK_DIVIDER_ONE_BASED ,
196+ MSSPLL_POSTDIV13_SHIFT , MSSPLL_POSTDIV_WIDTH , REG_MSSPLL_POSTDIV23_CR ),
197+ };
198+
199+ static int mpfs_clk_register_msspll_outs (struct device * dev ,
200+ struct mpfs_msspll_out_hw_clock * msspll_out_hws ,
201+ unsigned int num_clks , struct mpfs_clock_data * data )
202+ {
203+ unsigned int i ;
204+ int ret ;
205+
206+ for (i = 0 ; i < num_clks ; i ++ ) {
207+ struct mpfs_msspll_out_hw_clock * msspll_out_hw = & msspll_out_hws [i ];
208+
209+ msspll_out_hw -> output .reg = data -> msspll_base + msspll_out_hw -> reg_offset ;
210+ ret = devm_clk_hw_register (dev , & msspll_out_hw -> output .hw );
211+ if (ret )
212+ return dev_err_probe (dev , ret , "failed to register msspll out id: %d\n" ,
213+ msspll_out_hw -> id );
214+
215+ data -> hw_data .hws [msspll_out_hw -> id ] = & msspll_out_hw -> output .hw ;
216+ }
217+
218+ return 0 ;
219+ }
220+
207221/*
208222 * "CFG" clocks
209223 */
@@ -442,8 +456,8 @@ static int mpfs_clk_probe(struct platform_device *pdev)
442456 int ret ;
443457
444458 /* CLK_RESERVED is not part of clock arrays, so add 1 */
445- num_clks = ARRAY_SIZE (mpfs_msspll_clks ) + ARRAY_SIZE (mpfs_cfg_clks )
446- + ARRAY_SIZE (mpfs_periph_clks ) + 1 ;
459+ num_clks = ARRAY_SIZE (mpfs_msspll_clks ) + ARRAY_SIZE (mpfs_msspll_out_clks )
460+ + ARRAY_SIZE (mpfs_cfg_clks ) + ARRAY_SIZE ( mpfs_periph_clks ) + 1 ;
447461
448462 clk_data = devm_kzalloc (dev , struct_size (clk_data , hw_data .hws , num_clks ), GFP_KERNEL );
449463 if (!clk_data )
@@ -466,6 +480,12 @@ static int mpfs_clk_probe(struct platform_device *pdev)
466480 if (ret )
467481 return ret ;
468482
483+ ret = mpfs_clk_register_msspll_outs (dev , mpfs_msspll_out_clks ,
484+ ARRAY_SIZE (mpfs_msspll_out_clks ),
485+ clk_data );
486+ if (ret )
487+ return ret ;
488+
469489 ret = mpfs_clk_register_cfgs (dev , mpfs_cfg_clks , ARRAY_SIZE (mpfs_cfg_clks ), clk_data );
470490 if (ret )
471491 return ret ;
0 commit comments