1111#include <dt-bindings/clock/microchip,mpfs-clock.h>
1212
1313/* address offset of control registers */
14+ #define REG_MSSPLL_REF_CR 0x08u
15+ #define REG_MSSPLL_POSTDIV_CR 0x10u
16+ #define REG_MSSPLL_SSCG_2_CR 0x2Cu
1417#define REG_CLOCK_CONFIG_CR 0x08u
1518#define REG_SUBBLK_CLOCK_CR 0x84u
1619#define REG_SUBBLK_RESET_CR 0x88u
1720
21+ #define MSSPLL_FBDIV_SHIFT 0x00u
22+ #define MSSPLL_FBDIV_WIDTH 0x0Cu
23+ #define MSSPLL_REFDIV_SHIFT 0x08u
24+ #define MSSPLL_REFDIV_WIDTH 0x06u
25+ #define MSSPLL_POSTDIV_SHIFT 0x08u
26+ #define MSSPLL_POSTDIV_WIDTH 0x07u
27+ #define MSSPLL_FIXED_DIV 4u
28+
1829struct mpfs_clock_data {
1930 void __iomem * base ;
31+ void __iomem * msspll_base ;
2032 struct clk_hw_onecell_data hw_data ;
2133};
2234
35+ struct mpfs_msspll_hw_clock {
36+ void __iomem * base ;
37+ unsigned int id ;
38+ u32 reg_offset ;
39+ u32 shift ;
40+ u32 width ;
41+ u32 flags ;
42+ struct clk_hw hw ;
43+ struct clk_init_data init ;
44+ };
45+
46+ #define to_mpfs_msspll_clk (_hw ) container_of(_hw, struct mpfs_msspll_hw_clock, hw)
47+
2348struct mpfs_cfg_clock {
2449 const struct clk_div_table * table ;
2550 unsigned int id ;
51+ u32 reg_offset ;
2652 u8 shift ;
2753 u8 width ;
54+ u8 flags ;
2855};
2956
3057struct mpfs_cfg_hw_clock {
@@ -55,7 +82,7 @@ struct mpfs_periph_hw_clock {
5582 */
5683static DEFINE_SPINLOCK (mpfs_clk_lock );
5784
58- static const struct clk_parent_data mpfs_cfg_parent [] = {
85+ static const struct clk_parent_data mpfs_ext_ref [] = {
5986 { .index = 0 },
6087};
6188
@@ -69,17 +96,86 @@ static const struct clk_div_table mpfs_div_ahb_table[] = {
6996 { 0 , 0 }
7097};
7198
99+ static unsigned long mpfs_clk_msspll_recalc_rate (struct clk_hw * hw , unsigned long prate )
100+ {
101+ struct mpfs_msspll_hw_clock * msspll_hw = to_mpfs_msspll_clk (hw );
102+ void __iomem * mult_addr = msspll_hw -> base + msspll_hw -> reg_offset ;
103+ void __iomem * ref_div_addr = msspll_hw -> base + REG_MSSPLL_REF_CR ;
104+ void __iomem * postdiv_addr = msspll_hw -> base + REG_MSSPLL_POSTDIV_CR ;
105+ u32 mult , ref_div , postdiv ;
106+
107+ mult = readl_relaxed (mult_addr ) >> MSSPLL_FBDIV_SHIFT ;
108+ mult &= clk_div_mask (MSSPLL_FBDIV_WIDTH );
109+ ref_div = readl_relaxed (ref_div_addr ) >> MSSPLL_REFDIV_SHIFT ;
110+ ref_div &= clk_div_mask (MSSPLL_REFDIV_WIDTH );
111+ postdiv = readl_relaxed (postdiv_addr ) >> MSSPLL_POSTDIV_SHIFT ;
112+ postdiv &= clk_div_mask (MSSPLL_POSTDIV_WIDTH );
113+
114+ return prate * mult / (ref_div * MSSPLL_FIXED_DIV * postdiv );
115+ }
116+
117+ static const struct clk_ops mpfs_clk_msspll_ops = {
118+ .recalc_rate = mpfs_clk_msspll_recalc_rate ,
119+ };
120+
121+ #define CLK_PLL (_id , _name , _parent , _shift , _width , _flags , _offset ) { \
122+ .id = _id, \
123+ .shift = _shift, \
124+ .width = _width, \
125+ .reg_offset = _offset, \
126+ .flags = _flags, \
127+ .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent, &mpfs_clk_msspll_ops, 0), \
128+ }
129+
130+ static struct mpfs_msspll_hw_clock mpfs_msspll_clks [] = {
131+ CLK_PLL (CLK_MSSPLL , "clk_msspll" , mpfs_ext_ref , MSSPLL_FBDIV_SHIFT ,
132+ MSSPLL_FBDIV_WIDTH , 0 , REG_MSSPLL_SSCG_2_CR ),
133+ };
134+
135+ static int mpfs_clk_register_msspll (struct device * dev , struct mpfs_msspll_hw_clock * msspll_hw ,
136+ void __iomem * base )
137+ {
138+ msspll_hw -> base = base ;
139+
140+ return devm_clk_hw_register (dev , & msspll_hw -> hw );
141+ }
142+
143+ static int mpfs_clk_register_mssplls (struct device * dev , struct mpfs_msspll_hw_clock * msspll_hws ,
144+ unsigned int num_clks , struct mpfs_clock_data * data )
145+ {
146+ void __iomem * base = data -> msspll_base ;
147+ unsigned int i ;
148+ int ret ;
149+
150+ for (i = 0 ; i < num_clks ; i ++ ) {
151+ struct mpfs_msspll_hw_clock * msspll_hw = & msspll_hws [i ];
152+
153+ ret = mpfs_clk_register_msspll (dev , msspll_hw , base );
154+ if (ret )
155+ return dev_err_probe (dev , ret , "failed to register msspll id: %d\n" ,
156+ CLK_MSSPLL );
157+
158+ data -> hw_data .hws [msspll_hw -> id ] = & msspll_hw -> hw ;
159+ }
160+
161+ return 0 ;
162+ }
163+
164+ /*
165+ * "CFG" clocks
166+ */
167+
72168static unsigned long mpfs_cfg_clk_recalc_rate (struct clk_hw * hw , unsigned long prate )
73169{
74170 struct mpfs_cfg_hw_clock * cfg_hw = to_mpfs_cfg_clk (hw );
75171 struct mpfs_cfg_clock * cfg = & cfg_hw -> cfg ;
76172 void __iomem * base_addr = cfg_hw -> sys_base ;
77173 u32 val ;
78174
79- val = readl_relaxed (base_addr + REG_CLOCK_CONFIG_CR ) >> cfg -> shift ;
175+ val = readl_relaxed (base_addr + cfg -> reg_offset ) >> cfg -> shift ;
80176 val &= clk_div_mask (cfg -> width );
81177
82- return prate / ( 1u << val );
178+ return divider_recalc_rate ( hw , prate , val , cfg -> table , cfg -> flags , cfg -> width );
83179}
84180
85181static long mpfs_cfg_clk_round_rate (struct clk_hw * hw , unsigned long rate , unsigned long * prate )
@@ -105,11 +201,10 @@ static int mpfs_cfg_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned
105201 return divider_setting ;
106202
107203 spin_lock_irqsave (& mpfs_clk_lock , flags );
108-
109- val = readl_relaxed (base_addr + REG_CLOCK_CONFIG_CR );
204+ val = readl_relaxed (base_addr + cfg -> reg_offset );
110205 val &= ~(clk_div_mask (cfg -> width ) << cfg_hw -> cfg .shift );
111206 val |= divider_setting << cfg -> shift ;
112- writel_relaxed (val , base_addr + REG_CLOCK_CONFIG_CR );
207+ writel_relaxed (val , base_addr + cfg -> reg_offset );
113208
114209 spin_unlock_irqrestore (& mpfs_clk_lock , flags );
115210
@@ -122,19 +217,23 @@ static const struct clk_ops mpfs_clk_cfg_ops = {
122217 .set_rate = mpfs_cfg_clk_set_rate ,
123218};
124219
125- #define CLK_CFG (_id , _name , _parent , _shift , _width , _table , _flags ) { \
126- .cfg.id = _id, \
127- .cfg.shift = _shift, \
128- .cfg.width = _width, \
129- .cfg.table = _table, \
130- .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent, &mpfs_clk_cfg_ops, \
131- _flags), \
220+ #define CLK_CFG (_id , _name , _parent , _shift , _width , _table , _flags , _offset ) { \
221+ .cfg.id = _id, \
222+ .cfg.shift = _shift, \
223+ .cfg.width = _width, \
224+ .cfg.table = _table, \
225+ .cfg.reg_offset = _offset, \
226+ .cfg.flags = _flags, \
227+ .hw.init = CLK_HW_INIT(_name, _parent, &mpfs_clk_cfg_ops, 0), \
132228}
133229
134230static struct mpfs_cfg_hw_clock mpfs_cfg_clks [] = {
135- CLK_CFG (CLK_CPU , "clk_cpu" , mpfs_cfg_parent , 0 , 2 , mpfs_div_cpu_axi_table , 0 ),
136- CLK_CFG (CLK_AXI , "clk_axi" , mpfs_cfg_parent , 2 , 2 , mpfs_div_cpu_axi_table , 0 ),
137- CLK_CFG (CLK_AHB , "clk_ahb" , mpfs_cfg_parent , 4 , 2 , mpfs_div_ahb_table , 0 ),
231+ CLK_CFG (CLK_CPU , "clk_cpu" , "clk_msspll" , 0 , 2 , mpfs_div_cpu_axi_table , 0 ,
232+ REG_CLOCK_CONFIG_CR ),
233+ CLK_CFG (CLK_AXI , "clk_axi" , "clk_msspll" , 2 , 2 , mpfs_div_cpu_axi_table , 0 ,
234+ REG_CLOCK_CONFIG_CR ),
235+ CLK_CFG (CLK_AHB , "clk_ahb" , "clk_msspll" , 4 , 2 , mpfs_div_ahb_table , 0 ,
236+ REG_CLOCK_CONFIG_CR ),
138237};
139238
140239static int mpfs_clk_register_cfg (struct device * dev , struct mpfs_cfg_hw_clock * cfg_hw ,
@@ -160,13 +259,17 @@ static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *
160259 return dev_err_probe (dev , ret , "failed to register clock id: %d\n" ,
161260 cfg_hw -> cfg .id );
162261
163- id = cfg_hws [ i ]. cfg .id ;
262+ id = cfg_hw -> cfg .id ;
164263 data -> hw_data .hws [id ] = & cfg_hw -> hw ;
165264 }
166265
167266 return 0 ;
168267}
169268
269+ /*
270+ * peripheral clocks - devices connected to axi or ahb buses.
271+ */
272+
170273static int mpfs_periph_clk_enable (struct clk_hw * hw )
171274{
172275 struct mpfs_periph_hw_clock * periph_hw = to_mpfs_periph_clk (hw );
@@ -320,8 +423,9 @@ static int mpfs_clk_probe(struct platform_device *pdev)
320423 unsigned int num_clks ;
321424 int ret ;
322425
323- /* CLK_RESERVED is not part of cfg_clks nor periph_clks, so add 1 */
324- num_clks = ARRAY_SIZE (mpfs_cfg_clks ) + ARRAY_SIZE (mpfs_periph_clks ) + 1 ;
426+ /* CLK_RESERVED is not part of clock arrays, so add 1 */
427+ num_clks = ARRAY_SIZE (mpfs_msspll_clks ) + ARRAY_SIZE (mpfs_cfg_clks )
428+ + ARRAY_SIZE (mpfs_periph_clks ) + 1 ;
325429
326430 clk_data = devm_kzalloc (dev , struct_size (clk_data , hw_data .hws , num_clks ), GFP_KERNEL );
327431 if (!clk_data )
@@ -331,8 +435,17 @@ static int mpfs_clk_probe(struct platform_device *pdev)
331435 if (IS_ERR (clk_data -> base ))
332436 return PTR_ERR (clk_data -> base );
333437
438+ clk_data -> msspll_base = devm_platform_ioremap_resource (pdev , 1 );
439+ if (IS_ERR (clk_data -> msspll_base ))
440+ return PTR_ERR (clk_data -> msspll_base );
441+
334442 clk_data -> hw_data .num = num_clks ;
335443
444+ ret = mpfs_clk_register_mssplls (dev , mpfs_msspll_clks , ARRAY_SIZE (mpfs_msspll_clks ),
445+ clk_data );
446+ if (ret )
447+ return ret ;
448+
336449 ret = mpfs_clk_register_cfgs (dev , mpfs_cfg_clks , ARRAY_SIZE (mpfs_cfg_clks ), clk_data );
337450 if (ret )
338451 return ret ;
0 commit comments