11
11
#include <dt-bindings/clock/microchip,mpfs-clock.h>
12
12
13
13
/* 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
14
17
#define REG_CLOCK_CONFIG_CR 0x08u
15
18
#define REG_SUBBLK_CLOCK_CR 0x84u
16
19
#define REG_SUBBLK_RESET_CR 0x88u
17
20
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
+
18
29
struct mpfs_clock_data {
19
30
void __iomem * base ;
31
+ void __iomem * msspll_base ;
20
32
struct clk_hw_onecell_data hw_data ;
21
33
};
22
34
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
+
23
48
struct mpfs_cfg_clock {
24
49
const struct clk_div_table * table ;
25
50
unsigned int id ;
51
+ u32 reg_offset ;
26
52
u8 shift ;
27
53
u8 width ;
54
+ u8 flags ;
28
55
};
29
56
30
57
struct mpfs_cfg_hw_clock {
@@ -55,7 +82,7 @@ struct mpfs_periph_hw_clock {
55
82
*/
56
83
static DEFINE_SPINLOCK (mpfs_clk_lock );
57
84
58
- static const struct clk_parent_data mpfs_cfg_parent [] = {
85
+ static const struct clk_parent_data mpfs_ext_ref [] = {
59
86
{ .index = 0 },
60
87
};
61
88
@@ -69,17 +96,86 @@ static const struct clk_div_table mpfs_div_ahb_table[] = {
69
96
{ 0 , 0 }
70
97
};
71
98
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
+
72
168
static unsigned long mpfs_cfg_clk_recalc_rate (struct clk_hw * hw , unsigned long prate )
73
169
{
74
170
struct mpfs_cfg_hw_clock * cfg_hw = to_mpfs_cfg_clk (hw );
75
171
struct mpfs_cfg_clock * cfg = & cfg_hw -> cfg ;
76
172
void __iomem * base_addr = cfg_hw -> sys_base ;
77
173
u32 val ;
78
174
79
- val = readl_relaxed (base_addr + REG_CLOCK_CONFIG_CR ) >> cfg -> shift ;
175
+ val = readl_relaxed (base_addr + cfg -> reg_offset ) >> cfg -> shift ;
80
176
val &= clk_div_mask (cfg -> width );
81
177
82
- return prate / ( 1u << val );
178
+ return divider_recalc_rate ( hw , prate , val , cfg -> table , cfg -> flags , cfg -> width );
83
179
}
84
180
85
181
static 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
105
201
return divider_setting ;
106
202
107
203
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 );
110
205
val &= ~(clk_div_mask (cfg -> width ) << cfg_hw -> cfg .shift );
111
206
val |= divider_setting << cfg -> shift ;
112
- writel_relaxed (val , base_addr + REG_CLOCK_CONFIG_CR );
207
+ writel_relaxed (val , base_addr + cfg -> reg_offset );
113
208
114
209
spin_unlock_irqrestore (& mpfs_clk_lock , flags );
115
210
@@ -122,19 +217,23 @@ static const struct clk_ops mpfs_clk_cfg_ops = {
122
217
.set_rate = mpfs_cfg_clk_set_rate ,
123
218
};
124
219
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), \
132
228
}
133
229
134
230
static 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 ),
138
237
};
139
238
140
239
static 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 *
160
259
return dev_err_probe (dev , ret , "failed to register clock id: %d\n" ,
161
260
cfg_hw -> cfg .id );
162
261
163
- id = cfg_hws [ i ]. cfg .id ;
262
+ id = cfg_hw -> cfg .id ;
164
263
data -> hw_data .hws [id ] = & cfg_hw -> hw ;
165
264
}
166
265
167
266
return 0 ;
168
267
}
169
268
269
+ /*
270
+ * peripheral clocks - devices connected to axi or ahb buses.
271
+ */
272
+
170
273
static int mpfs_periph_clk_enable (struct clk_hw * hw )
171
274
{
172
275
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)
320
423
unsigned int num_clks ;
321
424
int ret ;
322
425
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 ;
325
429
326
430
clk_data = devm_kzalloc (dev , struct_size (clk_data , hw_data .hws , num_clks ), GFP_KERNEL );
327
431
if (!clk_data )
@@ -331,8 +435,17 @@ static int mpfs_clk_probe(struct platform_device *pdev)
331
435
if (IS_ERR (clk_data -> base ))
332
436
return PTR_ERR (clk_data -> base );
333
437
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
+
334
442
clk_data -> hw_data .num = num_clks ;
335
443
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
+
336
449
ret = mpfs_clk_register_cfgs (dev , mpfs_cfg_clks , ARRAY_SIZE (mpfs_cfg_clks ), clk_data );
337
450
if (ret )
338
451
return ret ;
0 commit comments