15
15
16
16
/* address offset of control registers */
17
17
#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
19
20
#define REG_MSSPLL_SSCG_2_CR 0x2Cu
20
21
#define REG_CLOCK_CONFIG_CR 0x08u
21
22
#define REG_RTC_CLOCK_CR 0x0Cu
26
27
#define MSSPLL_FBDIV_WIDTH 0x0Cu
27
28
#define MSSPLL_REFDIV_SHIFT 0x08u
28
29
#define MSSPLL_REFDIV_WIDTH 0x06u
29
- #define MSSPLL_POSTDIV_SHIFT 0x08u
30
+ #define MSSPLL_POSTDIV02_SHIFT 0x08u
31
+ #define MSSPLL_POSTDIV13_SHIFT 0x18u
30
32
#define MSSPLL_POSTDIV_WIDTH 0x07u
31
33
#define MSSPLL_FIXED_DIV 4u
32
34
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
+
33
42
struct mpfs_clock_data {
34
43
struct device * dev ;
35
44
void __iomem * base ;
@@ -39,17 +48,27 @@ struct mpfs_clock_data {
39
48
40
49
struct mpfs_msspll_hw_clock {
41
50
void __iomem * base ;
51
+ struct clk_hw hw ;
52
+ struct clk_init_data init ;
42
53
unsigned int id ;
43
54
u32 reg_offset ;
44
55
u32 shift ;
45
56
u32 width ;
46
57
u32 flags ;
47
- struct clk_hw hw ;
48
- struct clk_init_data init ;
49
58
};
50
59
51
60
#define to_mpfs_msspll_clk (_hw ) container_of(_hw, struct mpfs_msspll_hw_clock, hw)
52
61
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
+
53
72
struct mpfs_cfg_hw_clock {
54
73
struct clk_divider cfg ;
55
74
struct clk_init_data init ;
@@ -93,93 +112,40 @@ static const struct clk_div_table mpfs_div_rtcref_table[] = {
93
112
{ 0 , 0 }
94
113
};
95
114
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
+ */
113
118
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 )
115
120
{
116
121
struct mpfs_msspll_hw_clock * msspll_hw = to_mpfs_msspll_clk (hw );
117
122
void __iomem * mult_addr = msspll_hw -> base + msspll_hw -> reg_offset ;
118
123
void __iomem * ref_div_addr = msspll_hw -> base + REG_MSSPLL_REF_CR ;
119
124
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 ;
142
125
143
126
mult = readl_relaxed (mult_addr ) >> MSSPLL_FBDIV_SHIFT ;
144
127
mult &= clk_div_mask (MSSPLL_FBDIV_WIDTH );
145
128
ref_div = readl_relaxed (ref_div_addr ) >> MSSPLL_REFDIV_SHIFT ;
146
129
ref_div &= clk_div_mask (MSSPLL_REFDIV_WIDTH );
147
130
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 );
164
132
}
165
133
166
134
static const struct clk_ops mpfs_clk_msspll_ops = {
167
135
.recalc_rate = mpfs_clk_msspll_recalc_rate ,
168
- .round_rate = mpfs_clk_msspll_round_rate ,
169
- .set_rate = mpfs_clk_msspll_set_rate ,
170
136
};
171
137
172
138
#define CLK_PLL (_id , _name , _parent , _shift , _width , _flags , _offset ) { \
173
139
.id = _id, \
140
+ .flags = _flags, \
174
141
.shift = _shift, \
175
142
.width = _width, \
176
143
.reg_offset = _offset, \
177
- .flags = _flags, \
178
144
.hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent, &mpfs_clk_msspll_ops, 0), \
179
145
}
180
146
181
147
static 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 ,
183
149
MSSPLL_FBDIV_WIDTH , 0 , REG_MSSPLL_SSCG_2_CR ),
184
150
};
185
151
@@ -196,14 +162,62 @@ static int mpfs_clk_register_mssplls(struct device *dev, struct mpfs_msspll_hw_c
196
162
ret = devm_clk_hw_register (dev , & msspll_hw -> hw );
197
163
if (ret )
198
164
return dev_err_probe (dev , ret , "failed to register msspll id: %d\n" ,
199
- CLK_MSSPLL );
165
+ CLK_MSSPLL_INTERNAL );
200
166
201
167
data -> hw_data .hws [msspll_hw -> id ] = & msspll_hw -> hw ;
202
168
}
203
169
204
170
return 0 ;
205
171
}
206
172
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
+
207
221
/*
208
222
* "CFG" clocks
209
223
*/
@@ -442,8 +456,8 @@ static int mpfs_clk_probe(struct platform_device *pdev)
442
456
int ret ;
443
457
444
458
/* 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 ;
447
461
448
462
clk_data = devm_kzalloc (dev , struct_size (clk_data , hw_data .hws , num_clks ), GFP_KERNEL );
449
463
if (!clk_data )
@@ -466,6 +480,12 @@ static int mpfs_clk_probe(struct platform_device *pdev)
466
480
if (ret )
467
481
return ret ;
468
482
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
+
469
489
ret = mpfs_clk_register_cfgs (dev , mpfs_cfg_clks , ARRAY_SIZE (mpfs_cfg_clks ), clk_data );
470
490
if (ret )
471
491
return ret ;
0 commit comments