Commit | Line | Data |
---|---|---|
8f8f484b PG |
1 | /* |
2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms and conditions of the GNU General Public License, | |
6 | * version 2, as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | */ | |
16 | ||
17 | #include <linux/slab.h> | |
18 | #include <linux/io.h> | |
19 | #include <linux/delay.h> | |
20 | #include <linux/err.h> | |
21 | #include <linux/clk-provider.h> | |
22 | #include <linux/clk.h> | |
23 | ||
24 | #include "clk.h" | |
25 | ||
26 | #define PLL_BASE_BYPASS BIT(31) | |
27 | #define PLL_BASE_ENABLE BIT(30) | |
28 | #define PLL_BASE_REF_ENABLE BIT(29) | |
29 | #define PLL_BASE_OVERRIDE BIT(28) | |
30 | ||
31 | #define PLL_BASE_DIVP_SHIFT 20 | |
32 | #define PLL_BASE_DIVP_WIDTH 3 | |
33 | #define PLL_BASE_DIVN_SHIFT 8 | |
34 | #define PLL_BASE_DIVN_WIDTH 10 | |
35 | #define PLL_BASE_DIVM_SHIFT 0 | |
36 | #define PLL_BASE_DIVM_WIDTH 5 | |
37 | #define PLLU_POST_DIVP_MASK 0x1 | |
38 | ||
39 | #define PLL_MISC_DCCON_SHIFT 20 | |
40 | #define PLL_MISC_CPCON_SHIFT 8 | |
41 | #define PLL_MISC_CPCON_WIDTH 4 | |
42 | #define PLL_MISC_CPCON_MASK ((1 << PLL_MISC_CPCON_WIDTH) - 1) | |
43 | #define PLL_MISC_LFCON_SHIFT 4 | |
44 | #define PLL_MISC_LFCON_WIDTH 4 | |
45 | #define PLL_MISC_LFCON_MASK ((1 << PLL_MISC_LFCON_WIDTH) - 1) | |
46 | #define PLL_MISC_VCOCON_SHIFT 0 | |
47 | #define PLL_MISC_VCOCON_WIDTH 4 | |
48 | #define PLL_MISC_VCOCON_MASK ((1 << PLL_MISC_VCOCON_WIDTH) - 1) | |
49 | ||
50 | #define OUT_OF_TABLE_CPCON 8 | |
51 | ||
52 | #define PMC_PLLP_WB0_OVERRIDE 0xf8 | |
53 | #define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE BIT(12) | |
54 | #define PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE BIT(11) | |
55 | ||
56 | #define PLL_POST_LOCK_DELAY 50 | |
57 | ||
58 | #define PLLDU_LFCON_SET_DIVN 600 | |
59 | ||
60 | #define PLLE_BASE_DIVCML_SHIFT 24 | |
61 | #define PLLE_BASE_DIVCML_WIDTH 4 | |
62 | #define PLLE_BASE_DIVP_SHIFT 16 | |
63 | #define PLLE_BASE_DIVP_WIDTH 7 | |
64 | #define PLLE_BASE_DIVN_SHIFT 8 | |
65 | #define PLLE_BASE_DIVN_WIDTH 8 | |
66 | #define PLLE_BASE_DIVM_SHIFT 0 | |
67 | #define PLLE_BASE_DIVM_WIDTH 8 | |
68 | ||
69 | #define PLLE_MISC_SETUP_BASE_SHIFT 16 | |
70 | #define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT) | |
71 | #define PLLE_MISC_LOCK_ENABLE BIT(9) | |
72 | #define PLLE_MISC_READY BIT(15) | |
73 | #define PLLE_MISC_SETUP_EX_SHIFT 2 | |
74 | #define PLLE_MISC_SETUP_EX_MASK (3 << PLLE_MISC_SETUP_EX_SHIFT) | |
75 | #define PLLE_MISC_SETUP_MASK (PLLE_MISC_SETUP_BASE_MASK | \ | |
76 | PLLE_MISC_SETUP_EX_MASK) | |
77 | #define PLLE_MISC_SETUP_VALUE (7 << PLLE_MISC_SETUP_BASE_SHIFT) | |
78 | ||
79 | #define PLLE_SS_CTRL 0x68 | |
80 | #define PLLE_SS_DISABLE (7 << 10) | |
81 | ||
82 | #define PMC_SATA_PWRGT 0x1ac | |
83 | #define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5) | |
84 | #define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4) | |
85 | ||
86 | #define pll_readl(offset, p) readl_relaxed(p->clk_base + offset) | |
87 | #define pll_readl_base(p) pll_readl(p->params->base_reg, p) | |
88 | #define pll_readl_misc(p) pll_readl(p->params->misc_reg, p) | |
89 | ||
90 | #define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset) | |
91 | #define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p) | |
92 | #define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p) | |
93 | ||
94 | #define mask(w) ((1 << (w)) - 1) | |
95 | #define divm_mask(p) mask(p->divm_width) | |
96 | #define divn_mask(p) mask(p->divn_width) | |
97 | #define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \ | |
98 | mask(p->divp_width)) | |
99 | ||
100 | #define divm_max(p) (divm_mask(p)) | |
101 | #define divn_max(p) (divn_mask(p)) | |
102 | #define divp_max(p) (1 << (divp_mask(p))) | |
103 | ||
104 | static void clk_pll_enable_lock(struct tegra_clk_pll *pll) | |
105 | { | |
106 | u32 val; | |
107 | ||
108 | if (!(pll->flags & TEGRA_PLL_USE_LOCK)) | |
109 | return; | |
110 | ||
111 | val = pll_readl_misc(pll); | |
112 | val |= BIT(pll->params->lock_enable_bit_idx); | |
113 | pll_writel_misc(val, pll); | |
114 | } | |
115 | ||
116 | static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll, | |
117 | void __iomem *lock_addr, u32 lock_bit_idx) | |
118 | { | |
119 | int i; | |
120 | u32 val; | |
121 | ||
122 | if (!(pll->flags & TEGRA_PLL_USE_LOCK)) { | |
123 | udelay(pll->params->lock_delay); | |
124 | return 0; | |
125 | } | |
126 | ||
127 | for (i = 0; i < pll->params->lock_delay; i++) { | |
128 | val = readl_relaxed(lock_addr); | |
129 | if (val & BIT(lock_bit_idx)) { | |
130 | udelay(PLL_POST_LOCK_DELAY); | |
131 | return 0; | |
132 | } | |
133 | udelay(2); /* timeout = 2 * lock time */ | |
134 | } | |
135 | ||
136 | pr_err("%s: Timed out waiting for pll %s lock\n", __func__, | |
137 | __clk_get_name(pll->hw.clk)); | |
138 | ||
139 | return -1; | |
140 | } | |
141 | ||
142 | static int clk_pll_is_enabled(struct clk_hw *hw) | |
143 | { | |
144 | struct tegra_clk_pll *pll = to_clk_pll(hw); | |
145 | u32 val; | |
146 | ||
147 | if (pll->flags & TEGRA_PLLM) { | |
148 | val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); | |
149 | if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) | |
150 | return val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE ? 1 : 0; | |
151 | } | |
152 | ||
153 | val = pll_readl_base(pll); | |
154 | ||
155 | return val & PLL_BASE_ENABLE ? 1 : 0; | |
156 | } | |
157 | ||
158 | static int _clk_pll_enable(struct clk_hw *hw) | |
159 | { | |
160 | struct tegra_clk_pll *pll = to_clk_pll(hw); | |
161 | u32 val; | |
162 | ||
163 | clk_pll_enable_lock(pll); | |
164 | ||
165 | val = pll_readl_base(pll); | |
166 | val &= ~PLL_BASE_BYPASS; | |
167 | val |= PLL_BASE_ENABLE; | |
168 | pll_writel_base(val, pll); | |
169 | ||
170 | if (pll->flags & TEGRA_PLLM) { | |
171 | val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); | |
172 | val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; | |
173 | writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE); | |
174 | } | |
175 | ||
176 | clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->base_reg, | |
177 | pll->params->lock_bit_idx); | |
178 | ||
179 | return 0; | |
180 | } | |
181 | ||
182 | static void _clk_pll_disable(struct clk_hw *hw) | |
183 | { | |
184 | struct tegra_clk_pll *pll = to_clk_pll(hw); | |
185 | u32 val; | |
186 | ||
187 | val = pll_readl_base(pll); | |
188 | val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); | |
189 | pll_writel_base(val, pll); | |
190 | ||
191 | if (pll->flags & TEGRA_PLLM) { | |
192 | val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); | |
193 | val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; | |
194 | writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE); | |
195 | } | |
196 | } | |
197 | ||
198 | static int clk_pll_enable(struct clk_hw *hw) | |
199 | { | |
200 | struct tegra_clk_pll *pll = to_clk_pll(hw); | |
201 | unsigned long flags = 0; | |
202 | int ret; | |
203 | ||
204 | if (pll->lock) | |
205 | spin_lock_irqsave(pll->lock, flags); | |
206 | ||
207 | ret = _clk_pll_enable(hw); | |
208 | ||
209 | if (pll->lock) | |
210 | spin_unlock_irqrestore(pll->lock, flags); | |
211 | ||
212 | return ret; | |
213 | } | |
214 | ||
215 | static void clk_pll_disable(struct clk_hw *hw) | |
216 | { | |
217 | struct tegra_clk_pll *pll = to_clk_pll(hw); | |
218 | unsigned long flags = 0; | |
219 | ||
220 | if (pll->lock) | |
221 | spin_lock_irqsave(pll->lock, flags); | |
222 | ||
223 | _clk_pll_disable(hw); | |
224 | ||
225 | if (pll->lock) | |
226 | spin_unlock_irqrestore(pll->lock, flags); | |
227 | } | |
228 | ||
229 | static int _get_table_rate(struct clk_hw *hw, | |
230 | struct tegra_clk_pll_freq_table *cfg, | |
231 | unsigned long rate, unsigned long parent_rate) | |
232 | { | |
233 | struct tegra_clk_pll *pll = to_clk_pll(hw); | |
234 | struct tegra_clk_pll_freq_table *sel; | |
235 | ||
236 | for (sel = pll->freq_table; sel->input_rate != 0; sel++) | |
237 | if (sel->input_rate == parent_rate && | |
238 | sel->output_rate == rate) | |
239 | break; | |
240 | ||
241 | if (sel->input_rate == 0) | |
242 | return -EINVAL; | |
243 | ||
244 | BUG_ON(sel->p < 1); | |
245 | ||
246 | cfg->input_rate = sel->input_rate; | |
247 | cfg->output_rate = sel->output_rate; | |
248 | cfg->m = sel->m; | |
249 | cfg->n = sel->n; | |
250 | cfg->p = sel->p; | |
251 | cfg->cpcon = sel->cpcon; | |
252 | ||
253 | return 0; | |
254 | } | |
255 | ||
256 | static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, | |
257 | unsigned long rate, unsigned long parent_rate) | |
258 | { | |
259 | struct tegra_clk_pll *pll = to_clk_pll(hw); | |
260 | unsigned long cfreq; | |
261 | u32 p_div = 0; | |
262 | ||
263 | switch (parent_rate) { | |
264 | case 12000000: | |
265 | case 26000000: | |
266 | cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000; | |
267 | break; | |
268 | case 13000000: | |
269 | cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000; | |
270 | break; | |
271 | case 16800000: | |
272 | case 19200000: | |
273 | cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000; | |
274 | break; | |
275 | case 9600000: | |
276 | case 28800000: | |
277 | /* | |
278 | * PLL_P_OUT1 rate is not listed in PLLA table | |
279 | */ | |
280 | cfreq = parent_rate/(parent_rate/1000000); | |
281 | break; | |
282 | default: | |
283 | pr_err("%s Unexpected reference rate %lu\n", | |
284 | __func__, parent_rate); | |
285 | BUG(); | |
286 | } | |
287 | ||
288 | /* Raise VCO to guarantee 0.5% accuracy */ | |
289 | for (cfg->output_rate = rate; cfg->output_rate < 200 * cfreq; | |
290 | cfg->output_rate <<= 1) | |
291 | p_div++; | |
292 | ||
293 | cfg->p = 1 << p_div; | |
294 | cfg->m = parent_rate / cfreq; | |
295 | cfg->n = cfg->output_rate / cfreq; | |
296 | cfg->cpcon = OUT_OF_TABLE_CPCON; | |
297 | ||
298 | if (cfg->m > divm_max(pll) || cfg->n > divn_max(pll) || | |
299 | cfg->p > divp_max(pll) || cfg->output_rate > pll->params->vco_max) { | |
300 | pr_err("%s: Failed to set %s rate %lu\n", | |
301 | __func__, __clk_get_name(hw->clk), rate); | |
302 | return -EINVAL; | |
303 | } | |
304 | ||
305 | return 0; | |
306 | } | |
307 | ||
308 | static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, | |
309 | unsigned long rate) | |
310 | { | |
311 | struct tegra_clk_pll *pll = to_clk_pll(hw); | |
312 | unsigned long flags = 0; | |
313 | u32 divp, val, old_base; | |
314 | int state; | |
315 | ||
316 | divp = __ffs(cfg->p); | |
317 | ||
318 | if (pll->flags & TEGRA_PLLU) | |
319 | divp ^= 1; | |
320 | ||
321 | if (pll->lock) | |
322 | spin_lock_irqsave(pll->lock, flags); | |
323 | ||
324 | old_base = val = pll_readl_base(pll); | |
325 | val &= ~((divm_mask(pll) << pll->divm_shift) | | |
326 | (divn_mask(pll) << pll->divn_shift) | | |
327 | (divp_mask(pll) << pll->divp_shift)); | |
328 | val |= ((cfg->m << pll->divm_shift) | | |
329 | (cfg->n << pll->divn_shift) | | |
330 | (divp << pll->divp_shift)); | |
331 | if (val == old_base) { | |
332 | if (pll->lock) | |
333 | spin_unlock_irqrestore(pll->lock, flags); | |
334 | return 0; | |
335 | } | |
336 | ||
337 | state = clk_pll_is_enabled(hw); | |
338 | ||
339 | if (state) { | |
340 | _clk_pll_disable(hw); | |
341 | val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); | |
342 | } | |
343 | pll_writel_base(val, pll); | |
344 | ||
345 | if (pll->flags & TEGRA_PLL_HAS_CPCON) { | |
346 | val = pll_readl_misc(pll); | |
347 | val &= ~(PLL_MISC_CPCON_MASK << PLL_MISC_CPCON_SHIFT); | |
348 | val |= cfg->cpcon << PLL_MISC_CPCON_SHIFT; | |
349 | if (pll->flags & TEGRA_PLL_SET_LFCON) { | |
350 | val &= ~(PLL_MISC_LFCON_MASK << PLL_MISC_LFCON_SHIFT); | |
351 | if (cfg->n >= PLLDU_LFCON_SET_DIVN) | |
352 | val |= 0x1 << PLL_MISC_LFCON_SHIFT; | |
353 | } else if (pll->flags & TEGRA_PLL_SET_DCCON) { | |
354 | val &= ~(0x1 << PLL_MISC_DCCON_SHIFT); | |
355 | if (rate >= (pll->params->vco_max >> 1)) | |
356 | val |= 0x1 << PLL_MISC_DCCON_SHIFT; | |
357 | } | |
358 | pll_writel_misc(val, pll); | |
359 | } | |
360 | ||
361 | if (pll->lock) | |
362 | spin_unlock_irqrestore(pll->lock, flags); | |
363 | ||
364 | if (state) | |
365 | clk_pll_enable(hw); | |
366 | ||
367 | return 0; | |
368 | } | |
369 | ||
370 | static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, | |
371 | unsigned long parent_rate) | |
372 | { | |
373 | struct tegra_clk_pll *pll = to_clk_pll(hw); | |
374 | struct tegra_clk_pll_freq_table cfg; | |
375 | ||
376 | if (pll->flags & TEGRA_PLL_FIXED) { | |
377 | if (rate != pll->fixed_rate) { | |
378 | pr_err("%s: Can not change %s fixed rate %lu to %lu\n", | |
379 | __func__, __clk_get_name(hw->clk), | |
380 | pll->fixed_rate, rate); | |
381 | return -EINVAL; | |
382 | } | |
383 | return 0; | |
384 | } | |
385 | ||
386 | if (_get_table_rate(hw, &cfg, rate, parent_rate) && | |
387 | _calc_rate(hw, &cfg, rate, parent_rate)) | |
388 | return -EINVAL; | |
389 | ||
390 | return _program_pll(hw, &cfg, rate); | |
391 | } | |
392 | ||
393 | static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, | |
394 | unsigned long *prate) | |
395 | { | |
396 | struct tegra_clk_pll *pll = to_clk_pll(hw); | |
397 | struct tegra_clk_pll_freq_table cfg; | |
398 | u64 output_rate = *prate; | |
399 | ||
400 | if (pll->flags & TEGRA_PLL_FIXED) | |
401 | return pll->fixed_rate; | |
402 | ||
403 | /* PLLM is used for memory; we do not change rate */ | |
404 | if (pll->flags & TEGRA_PLLM) | |
405 | return __clk_get_rate(hw->clk); | |
406 | ||
407 | if (_get_table_rate(hw, &cfg, rate, *prate) && | |
408 | _calc_rate(hw, &cfg, rate, *prate)) | |
409 | return -EINVAL; | |
410 | ||
411 | output_rate *= cfg.n; | |
412 | do_div(output_rate, cfg.m * cfg.p); | |
413 | ||
414 | return output_rate; | |
415 | } | |
416 | ||
417 | static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, | |
418 | unsigned long parent_rate) | |
419 | { | |
420 | struct tegra_clk_pll *pll = to_clk_pll(hw); | |
421 | u32 val = pll_readl_base(pll); | |
422 | u32 divn = 0, divm = 0, divp = 0; | |
423 | u64 rate = parent_rate; | |
424 | ||
425 | if (val & PLL_BASE_BYPASS) | |
426 | return parent_rate; | |
427 | ||
428 | if ((pll->flags & TEGRA_PLL_FIXED) && !(val & PLL_BASE_OVERRIDE)) { | |
429 | struct tegra_clk_pll_freq_table sel; | |
430 | if (_get_table_rate(hw, &sel, pll->fixed_rate, parent_rate)) { | |
431 | pr_err("Clock %s has unknown fixed frequency\n", | |
432 | __clk_get_name(hw->clk)); | |
433 | BUG(); | |
434 | } | |
435 | return pll->fixed_rate; | |
436 | } | |
437 | ||
438 | divp = (val >> pll->divp_shift) & (divp_mask(pll)); | |
439 | if (pll->flags & TEGRA_PLLU) | |
440 | divp ^= 1; | |
441 | ||
442 | divn = (val >> pll->divn_shift) & (divn_mask(pll)); | |
443 | divm = (val >> pll->divm_shift) & (divm_mask(pll)); | |
444 | divm *= (1 << divp); | |
445 | ||
446 | rate *= divn; | |
447 | do_div(rate, divm); | |
448 | return rate; | |
449 | } | |
450 | ||
451 | static int clk_plle_training(struct tegra_clk_pll *pll) | |
452 | { | |
453 | u32 val; | |
454 | unsigned long timeout; | |
455 | ||
456 | if (!pll->pmc) | |
457 | return -ENOSYS; | |
458 | ||
459 | /* | |
460 | * PLLE is already disabled, and setup cleared; | |
461 | * create falling edge on PLLE IDDQ input. | |
462 | */ | |
463 | val = readl(pll->pmc + PMC_SATA_PWRGT); | |
464 | val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; | |
465 | writel(val, pll->pmc + PMC_SATA_PWRGT); | |
466 | ||
467 | val = readl(pll->pmc + PMC_SATA_PWRGT); | |
468 | val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL; | |
469 | writel(val, pll->pmc + PMC_SATA_PWRGT); | |
470 | ||
471 | val = readl(pll->pmc + PMC_SATA_PWRGT); | |
472 | val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; | |
473 | writel(val, pll->pmc + PMC_SATA_PWRGT); | |
474 | ||
475 | val = pll_readl_misc(pll); | |
476 | ||
477 | timeout = jiffies + msecs_to_jiffies(100); | |
478 | while (1) { | |
479 | val = pll_readl_misc(pll); | |
480 | if (val & PLLE_MISC_READY) | |
481 | break; | |
482 | if (time_after(jiffies, timeout)) { | |
483 | pr_err("%s: timeout waiting for PLLE\n", __func__); | |
484 | return -EBUSY; | |
485 | } | |
486 | udelay(300); | |
487 | } | |
488 | ||
489 | return 0; | |
490 | } | |
491 | ||
492 | static int clk_plle_enable(struct clk_hw *hw) | |
493 | { | |
494 | struct tegra_clk_pll *pll = to_clk_pll(hw); | |
495 | unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk)); | |
496 | struct tegra_clk_pll_freq_table sel; | |
497 | u32 val; | |
498 | int err; | |
499 | ||
500 | if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate)) | |
501 | return -EINVAL; | |
502 | ||
503 | clk_pll_disable(hw); | |
504 | ||
505 | val = pll_readl_misc(pll); | |
506 | val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK); | |
507 | pll_writel_misc(val, pll); | |
508 | ||
509 | val = pll_readl_misc(pll); | |
510 | if (!(val & PLLE_MISC_READY)) { | |
511 | err = clk_plle_training(pll); | |
512 | if (err) | |
513 | return err; | |
514 | } | |
515 | ||
516 | if (pll->flags & TEGRA_PLLE_CONFIGURE) { | |
517 | /* configure dividers */ | |
518 | val = pll_readl_base(pll); | |
519 | val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll)); | |
520 | val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT); | |
521 | val |= sel.m << pll->divm_shift; | |
522 | val |= sel.n << pll->divn_shift; | |
523 | val |= sel.p << pll->divp_shift; | |
524 | val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; | |
525 | pll_writel_base(val, pll); | |
526 | } | |
527 | ||
528 | val = pll_readl_misc(pll); | |
529 | val |= PLLE_MISC_SETUP_VALUE; | |
530 | val |= PLLE_MISC_LOCK_ENABLE; | |
531 | pll_writel_misc(val, pll); | |
532 | ||
533 | val = readl(pll->clk_base + PLLE_SS_CTRL); | |
534 | val |= PLLE_SS_DISABLE; | |
535 | writel(val, pll->clk_base + PLLE_SS_CTRL); | |
536 | ||
537 | val |= pll_readl_base(pll); | |
538 | val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE); | |
539 | pll_writel_base(val, pll); | |
540 | ||
541 | clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->misc_reg, | |
542 | pll->params->lock_bit_idx); | |
543 | return 0; | |
544 | } | |
545 | ||
546 | static unsigned long clk_plle_recalc_rate(struct clk_hw *hw, | |
547 | unsigned long parent_rate) | |
548 | { | |
549 | struct tegra_clk_pll *pll = to_clk_pll(hw); | |
550 | u32 val = pll_readl_base(pll); | |
551 | u32 divn = 0, divm = 0, divp = 0; | |
552 | u64 rate = parent_rate; | |
553 | ||
554 | divp = (val >> pll->divp_shift) & (divp_mask(pll)); | |
555 | divn = (val >> pll->divn_shift) & (divn_mask(pll)); | |
556 | divm = (val >> pll->divm_shift) & (divm_mask(pll)); | |
557 | divm *= divp; | |
558 | ||
559 | rate *= divn; | |
560 | do_div(rate, divm); | |
561 | return rate; | |
562 | } | |
563 | ||
564 | const struct clk_ops tegra_clk_pll_ops = { | |
565 | .is_enabled = clk_pll_is_enabled, | |
566 | .enable = clk_pll_enable, | |
567 | .disable = clk_pll_disable, | |
568 | .recalc_rate = clk_pll_recalc_rate, | |
569 | .round_rate = clk_pll_round_rate, | |
570 | .set_rate = clk_pll_set_rate, | |
571 | }; | |
572 | ||
573 | const struct clk_ops tegra_clk_plle_ops = { | |
574 | .recalc_rate = clk_plle_recalc_rate, | |
575 | .is_enabled = clk_pll_is_enabled, | |
576 | .disable = clk_pll_disable, | |
577 | .enable = clk_plle_enable, | |
578 | }; | |
579 | ||
580 | static struct clk *_tegra_clk_register_pll(const char *name, | |
581 | const char *parent_name, void __iomem *clk_base, | |
582 | void __iomem *pmc, unsigned long flags, | |
583 | unsigned long fixed_rate, | |
584 | struct tegra_clk_pll_params *pll_params, u8 pll_flags, | |
585 | struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock, | |
586 | const struct clk_ops *ops) | |
587 | { | |
588 | struct tegra_clk_pll *pll; | |
589 | struct clk *clk; | |
590 | struct clk_init_data init; | |
591 | ||
592 | pll = kzalloc(sizeof(*pll), GFP_KERNEL); | |
593 | if (!pll) | |
594 | return ERR_PTR(-ENOMEM); | |
595 | ||
596 | init.name = name; | |
597 | init.ops = ops; | |
598 | init.flags = flags; | |
599 | init.parent_names = (parent_name ? &parent_name : NULL); | |
600 | init.num_parents = (parent_name ? 1 : 0); | |
601 | ||
602 | pll->clk_base = clk_base; | |
603 | pll->pmc = pmc; | |
604 | ||
605 | pll->freq_table = freq_table; | |
606 | pll->params = pll_params; | |
607 | pll->fixed_rate = fixed_rate; | |
608 | pll->flags = pll_flags; | |
609 | pll->lock = lock; | |
610 | ||
611 | pll->divp_shift = PLL_BASE_DIVP_SHIFT; | |
612 | pll->divp_width = PLL_BASE_DIVP_WIDTH; | |
613 | pll->divn_shift = PLL_BASE_DIVN_SHIFT; | |
614 | pll->divn_width = PLL_BASE_DIVN_WIDTH; | |
615 | pll->divm_shift = PLL_BASE_DIVM_SHIFT; | |
616 | pll->divm_width = PLL_BASE_DIVM_WIDTH; | |
617 | ||
618 | /* Data in .init is copied by clk_register(), so stack variable OK */ | |
619 | pll->hw.init = &init; | |
620 | ||
621 | clk = clk_register(NULL, &pll->hw); | |
622 | if (IS_ERR(clk)) | |
623 | kfree(pll); | |
624 | ||
625 | return clk; | |
626 | } | |
627 | ||
628 | struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, | |
629 | void __iomem *clk_base, void __iomem *pmc, | |
630 | unsigned long flags, unsigned long fixed_rate, | |
631 | struct tegra_clk_pll_params *pll_params, u8 pll_flags, | |
632 | struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) | |
633 | { | |
634 | return _tegra_clk_register_pll(name, parent_name, clk_base, pmc, | |
635 | flags, fixed_rate, pll_params, pll_flags, freq_table, | |
636 | lock, &tegra_clk_pll_ops); | |
637 | } | |
638 | ||
639 | struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, | |
640 | void __iomem *clk_base, void __iomem *pmc, | |
641 | unsigned long flags, unsigned long fixed_rate, | |
642 | struct tegra_clk_pll_params *pll_params, u8 pll_flags, | |
643 | struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) | |
644 | { | |
645 | return _tegra_clk_register_pll(name, parent_name, clk_base, pmc, | |
646 | flags, fixed_rate, pll_params, pll_flags, freq_table, | |
647 | lock, &tegra_clk_plle_ops); | |
648 | } |