Commit | Line | Data |
---|---|---|
8ff1f4c4 SB |
1 | /* |
2 | * Copyright (c) 2015, The Linux Foundation. All rights reserved. | |
3 | * | |
4 | * This software is licensed under the terms of the GNU General Public | |
5 | * License version 2, as published by the Free Software Foundation, and | |
6 | * may be copied, distributed, and modified under those terms. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | */ | |
13 | ||
14 | #include <linux/kernel.h> | |
15 | #include <linux/export.h> | |
16 | #include <linux/clk-provider.h> | |
17 | #include <linux/regmap.h> | |
18 | #include <linux/delay.h> | |
19 | ||
20 | #include "clk-alpha-pll.h" | |
21 | ||
22 | #define PLL_MODE 0x00 | |
23 | # define PLL_OUTCTRL BIT(0) | |
24 | # define PLL_BYPASSNL BIT(1) | |
25 | # define PLL_RESET_N BIT(2) | |
26 | # define PLL_LOCK_COUNT_SHIFT 8 | |
27 | # define PLL_LOCK_COUNT_MASK 0x3f | |
28 | # define PLL_BIAS_COUNT_SHIFT 14 | |
29 | # define PLL_BIAS_COUNT_MASK 0x3f | |
30 | # define PLL_VOTE_FSM_ENA BIT(20) | |
31 | # define PLL_VOTE_FSM_RESET BIT(21) | |
32 | # define PLL_ACTIVE_FLAG BIT(30) | |
33 | # define PLL_LOCK_DET BIT(31) | |
34 | ||
35 | #define PLL_L_VAL 0x04 | |
36 | #define PLL_ALPHA_VAL 0x08 | |
37 | #define PLL_ALPHA_VAL_U 0x0c | |
38 | ||
39 | #define PLL_USER_CTL 0x10 | |
40 | # define PLL_POST_DIV_SHIFT 8 | |
41 | # define PLL_POST_DIV_MASK 0xf | |
42 | # define PLL_ALPHA_EN BIT(24) | |
43 | # define PLL_VCO_SHIFT 20 | |
44 | # define PLL_VCO_MASK 0x3 | |
45 | ||
46 | #define PLL_USER_CTL_U 0x14 | |
47 | ||
48 | #define PLL_CONFIG_CTL 0x18 | |
49 | #define PLL_TEST_CTL 0x1c | |
50 | #define PLL_TEST_CTL_U 0x20 | |
51 | #define PLL_STATUS 0x24 | |
52 | ||
53 | /* | |
54 | * Even though 40 bits are present, use only 32 for ease of calculation. | |
55 | */ | |
56 | #define ALPHA_REG_BITWIDTH 40 | |
57 | #define ALPHA_BITWIDTH 32 | |
58 | ||
59 | #define to_clk_alpha_pll(_hw) container_of(to_clk_regmap(_hw), \ | |
60 | struct clk_alpha_pll, clkr) | |
61 | ||
62 | #define to_clk_alpha_pll_postdiv(_hw) container_of(to_clk_regmap(_hw), \ | |
63 | struct clk_alpha_pll_postdiv, clkr) | |
64 | ||
65 | static int wait_for_pll(struct clk_alpha_pll *pll) | |
66 | { | |
67 | u32 val, mask, off; | |
68 | int count; | |
69 | int ret; | |
70 | const char *name = clk_hw_get_name(&pll->clkr.hw); | |
71 | ||
72 | off = pll->offset; | |
73 | ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); | |
74 | if (ret) | |
75 | return ret; | |
76 | ||
77 | if (val & PLL_VOTE_FSM_ENA) | |
78 | mask = PLL_ACTIVE_FLAG; | |
79 | else | |
80 | mask = PLL_LOCK_DET; | |
81 | ||
82 | /* Wait for pll to enable. */ | |
83 | for (count = 100; count > 0; count--) { | |
84 | ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); | |
85 | if (ret) | |
86 | return ret; | |
87 | if ((val & mask) == mask) | |
88 | return 0; | |
89 | ||
90 | udelay(1); | |
91 | } | |
92 | ||
93 | WARN(1, "%s didn't enable after voting for it!\n", name); | |
94 | return -ETIMEDOUT; | |
95 | } | |
96 | ||
97 | static int clk_alpha_pll_enable(struct clk_hw *hw) | |
98 | { | |
99 | int ret; | |
100 | struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); | |
101 | u32 val, mask, off; | |
102 | ||
103 | off = pll->offset; | |
104 | ||
105 | mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL; | |
106 | ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); | |
107 | if (ret) | |
108 | return ret; | |
109 | ||
110 | /* If in FSM mode, just vote for it */ | |
111 | if (val & PLL_VOTE_FSM_ENA) { | |
112 | ret = clk_enable_regmap(hw); | |
113 | if (ret) | |
114 | return ret; | |
115 | return wait_for_pll(pll); | |
116 | } | |
117 | ||
118 | /* Skip if already enabled */ | |
119 | if ((val & mask) == mask) | |
120 | return 0; | |
121 | ||
122 | ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, | |
123 | PLL_BYPASSNL, PLL_BYPASSNL); | |
124 | if (ret) | |
125 | return ret; | |
126 | ||
127 | /* | |
128 | * H/W requires a 5us delay between disabling the bypass and | |
129 | * de-asserting the reset. | |
130 | */ | |
131 | mb(); | |
132 | udelay(5); | |
133 | ||
134 | ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, | |
135 | PLL_RESET_N, PLL_RESET_N); | |
136 | if (ret) | |
137 | return ret; | |
138 | ||
139 | ret = wait_for_pll(pll); | |
140 | if (ret) | |
141 | return ret; | |
142 | ||
143 | ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, | |
144 | PLL_OUTCTRL, PLL_OUTCTRL); | |
145 | ||
146 | /* Ensure that the write above goes through before returning. */ | |
147 | mb(); | |
148 | return ret; | |
149 | } | |
150 | ||
151 | static void clk_alpha_pll_disable(struct clk_hw *hw) | |
152 | { | |
153 | int ret; | |
154 | struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); | |
155 | u32 val, mask, off; | |
156 | ||
157 | off = pll->offset; | |
158 | ||
159 | ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); | |
160 | if (ret) | |
161 | return; | |
162 | ||
163 | /* If in FSM mode, just unvote it */ | |
164 | if (val & PLL_VOTE_FSM_ENA) { | |
165 | clk_disable_regmap(hw); | |
166 | return; | |
167 | } | |
168 | ||
169 | mask = PLL_OUTCTRL; | |
170 | regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, mask, 0); | |
171 | ||
172 | /* Delay of 2 output clock ticks required until output is disabled */ | |
173 | mb(); | |
174 | udelay(1); | |
175 | ||
176 | mask = PLL_RESET_N | PLL_BYPASSNL; | |
177 | regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, mask, 0); | |
178 | } | |
179 | ||
180 | static unsigned long alpha_pll_calc_rate(u64 prate, u32 l, u32 a) | |
181 | { | |
182 | return (prate * l) + ((prate * a) >> ALPHA_BITWIDTH); | |
183 | } | |
184 | ||
185 | static unsigned long | |
186 | alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a) | |
187 | { | |
188 | u64 remainder; | |
189 | u64 quotient; | |
190 | ||
191 | quotient = rate; | |
192 | remainder = do_div(quotient, prate); | |
193 | *l = quotient; | |
194 | ||
195 | if (!remainder) { | |
196 | *a = 0; | |
197 | return rate; | |
198 | } | |
199 | ||
200 | /* Upper ALPHA_BITWIDTH bits of Alpha */ | |
201 | quotient = remainder << ALPHA_BITWIDTH; | |
202 | remainder = do_div(quotient, prate); | |
203 | ||
204 | if (remainder) | |
205 | quotient++; | |
206 | ||
207 | *a = quotient; | |
208 | return alpha_pll_calc_rate(prate, *l, *a); | |
209 | } | |
210 | ||
211 | static const struct pll_vco * | |
212 | alpha_pll_find_vco(const struct clk_alpha_pll *pll, unsigned long rate) | |
213 | { | |
214 | const struct pll_vco *v = pll->vco_table; | |
215 | const struct pll_vco *end = v + pll->num_vco; | |
216 | ||
217 | for (; v < end; v++) | |
218 | if (rate >= v->min_freq && rate <= v->max_freq) | |
219 | return v; | |
220 | ||
221 | return NULL; | |
222 | } | |
223 | ||
224 | static unsigned long | |
225 | clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | |
226 | { | |
227 | u32 l, low, high, ctl; | |
228 | u64 a = 0, prate = parent_rate; | |
229 | struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); | |
230 | u32 off = pll->offset; | |
231 | ||
232 | regmap_read(pll->clkr.regmap, off + PLL_L_VAL, &l); | |
233 | ||
234 | regmap_read(pll->clkr.regmap, off + PLL_USER_CTL, &ctl); | |
235 | if (ctl & PLL_ALPHA_EN) { | |
236 | regmap_read(pll->clkr.regmap, off + PLL_ALPHA_VAL, &low); | |
237 | regmap_read(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, &high); | |
238 | a = (u64)high << 32 | low; | |
239 | a >>= ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH; | |
240 | } | |
241 | ||
242 | return alpha_pll_calc_rate(prate, l, a); | |
243 | } | |
244 | ||
245 | static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate, | |
246 | unsigned long prate) | |
247 | { | |
248 | struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); | |
249 | const struct pll_vco *vco; | |
250 | u32 l, off = pll->offset; | |
251 | u64 a; | |
252 | ||
253 | rate = alpha_pll_round_rate(rate, prate, &l, &a); | |
254 | vco = alpha_pll_find_vco(pll, rate); | |
255 | if (!vco) { | |
256 | pr_err("alpha pll not in a valid vco range\n"); | |
257 | return -EINVAL; | |
258 | } | |
259 | ||
260 | a <<= (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH); | |
261 | ||
262 | regmap_write(pll->clkr.regmap, off + PLL_L_VAL, l); | |
263 | regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL, a); | |
264 | regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, a >> 32); | |
265 | ||
266 | regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL, | |
267 | PLL_VCO_MASK << PLL_VCO_SHIFT, | |
268 | vco->val << PLL_VCO_SHIFT); | |
269 | ||
270 | regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL, PLL_ALPHA_EN, | |
271 | PLL_ALPHA_EN); | |
272 | ||
273 | return 0; | |
274 | } | |
275 | ||
276 | static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate, | |
277 | unsigned long *prate) | |
278 | { | |
279 | struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); | |
280 | u32 l; | |
281 | u64 a; | |
282 | unsigned long min_freq, max_freq; | |
283 | ||
284 | rate = alpha_pll_round_rate(rate, *prate, &l, &a); | |
285 | if (alpha_pll_find_vco(pll, rate)) | |
286 | return rate; | |
287 | ||
288 | min_freq = pll->vco_table[0].min_freq; | |
289 | max_freq = pll->vco_table[pll->num_vco - 1].max_freq; | |
290 | ||
291 | return clamp(rate, min_freq, max_freq); | |
292 | } | |
293 | ||
294 | const struct clk_ops clk_alpha_pll_ops = { | |
295 | .enable = clk_alpha_pll_enable, | |
296 | .disable = clk_alpha_pll_disable, | |
297 | .recalc_rate = clk_alpha_pll_recalc_rate, | |
298 | .round_rate = clk_alpha_pll_round_rate, | |
299 | .set_rate = clk_alpha_pll_set_rate, | |
300 | }; | |
301 | EXPORT_SYMBOL_GPL(clk_alpha_pll_ops); | |
302 | ||
303 | static unsigned long | |
304 | clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | |
305 | { | |
306 | struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); | |
307 | u32 ctl; | |
308 | ||
309 | regmap_read(pll->clkr.regmap, pll->offset + PLL_USER_CTL, &ctl); | |
310 | ||
311 | ctl >>= PLL_POST_DIV_SHIFT; | |
312 | ctl &= PLL_POST_DIV_MASK; | |
313 | ||
314 | return parent_rate >> fls(ctl); | |
315 | } | |
316 | ||
317 | static const struct clk_div_table clk_alpha_div_table[] = { | |
318 | { 0x0, 1 }, | |
319 | { 0x1, 2 }, | |
320 | { 0x3, 4 }, | |
321 | { 0x7, 8 }, | |
322 | { 0xf, 16 }, | |
323 | { } | |
324 | }; | |
325 | ||
326 | static long | |
327 | clk_alpha_pll_postdiv_round_rate(struct clk_hw *hw, unsigned long rate, | |
328 | unsigned long *prate) | |
329 | { | |
330 | struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); | |
331 | ||
332 | return divider_round_rate(hw, rate, prate, clk_alpha_div_table, | |
333 | pll->width, CLK_DIVIDER_POWER_OF_TWO); | |
334 | } | |
335 | ||
336 | static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, | |
337 | unsigned long parent_rate) | |
338 | { | |
339 | struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); | |
340 | int div; | |
341 | ||
342 | /* 16 -> 0xf, 8 -> 0x7, 4 -> 0x3, 2 -> 0x1, 1 -> 0x0 */ | |
343 | div = DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1; | |
344 | ||
345 | return regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_USER_CTL, | |
346 | PLL_POST_DIV_MASK << PLL_POST_DIV_SHIFT, | |
347 | div << PLL_POST_DIV_SHIFT); | |
348 | } | |
349 | ||
350 | const struct clk_ops clk_alpha_pll_postdiv_ops = { | |
351 | .recalc_rate = clk_alpha_pll_postdiv_recalc_rate, | |
352 | .round_rate = clk_alpha_pll_postdiv_round_rate, | |
353 | .set_rate = clk_alpha_pll_postdiv_set_rate, | |
354 | }; | |
355 | EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_ops); |