Lines Matching +full:pll +full:-
1 // SPDX-License-Identifier: GPL-2.0
11 * In the most basic form, a Meson PLL is composed as follows:
13 * PLL
14 * +--------------------------------+
16 * | +--+ |
17 * in >>-----[ /N ]--->| | +-----+ |
18 * | | |------| DCO |---->> out
19 * | +--------->| | +--v--+ |
20 * | | +--+ | |
22 * | +--[ *(M + (F/Fmax) ]<--+ |
24 * +--------------------------------+
29 #include <linux/clk-provider.h>
36 #include "clk-regmap.h"
37 #include "clk-pll.h"
42 return (struct meson_clk_pll_data *)clk->data;
45 static int __pll_round_closest_mult(struct meson_clk_pll_data *pll)
47 if ((pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) &&
48 !MESON_PARM_APPLICABLE(&pll->frac))
57 struct meson_clk_pll_data *pll)
60 unsigned int frac_max = pll->frac_max ? pll->frac_max :
61 (1 << pll->frac.width);
63 if (frac && MESON_PARM_APPLICABLE(&pll->frac)) {
76 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
79 n = meson_parm_read(clk->map, &pll->n);
89 m = meson_parm_read(clk->map, &pll->m);
91 frac = MESON_PARM_APPLICABLE(&pll->frac) ?
92 meson_parm_read(clk->map, &pll->frac) :
95 return __pll_params_to_rate(parent_rate, m, n, frac, pll);
102 struct meson_clk_pll_data *pll)
104 unsigned int frac_max = pll->frac_max ? pll->frac_max :
105 (1 << pll->frac.width);
112 if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST)
117 val -= m * frac_max;
119 return min((unsigned int)val, (frac_max - 1));
125 struct meson_clk_pll_data *pll)
127 if (__pll_round_closest_mult(pll)) {
129 if (abs(now - rate) < abs(best - rate))
143 struct meson_clk_pll_data *pll)
145 if (!pll->table[index].n)
146 return -EINVAL;
148 *m = pll->table[index].m;
149 *n = pll->table[index].n;
157 struct meson_clk_pll_data *pll)
161 if (__pll_round_closest_mult(pll))
172 struct meson_clk_pll_data *pll)
177 if (*n >= (1 << pll->n.width))
178 return -EINVAL;
182 if (rate <= pll->range->min * parent_rate) {
183 *m = pll->range->min;
184 return -ENODATA;
185 } else if (rate >= pll->range->max * parent_rate) {
186 *m = pll->range->max;
187 return -ENODATA;
191 *m = meson_clk_get_pll_range_m(rate, parent_rate, *n, pll);
193 /* the pre-divider gives a multiplier too big - stop */
194 if (*m >= (1 << pll->m.width))
195 return -EINVAL;
205 struct meson_clk_pll_data *pll)
207 if (pll->range)
209 index, m, n, pll);
210 else if (pll->table)
211 return meson_clk_get_pll_table_index(index, m, n, pll);
213 return -EINVAL;
220 struct meson_clk_pll_data *pll)
228 i, &m, &n, pll);
229 if (ret == -EINVAL)
232 now = __pll_params_to_rate(parent_rate, m, n, 0, pll);
233 if (meson_clk_pll_is_better(rate, best, now, pll)) {
243 return best ? 0 : -EINVAL;
250 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
255 ret = meson_clk_get_pll_settings(req->rate, req->best_parent_rate,
256 &m, &n, pll);
260 round = __pll_params_to_rate(req->best_parent_rate, m, n, 0, pll);
262 if (!MESON_PARM_APPLICABLE(&pll->frac) || req->rate == round) {
263 req->rate = round;
271 frac = __pll_params_with_frac(req->rate, req->best_parent_rate, m, n, pll);
272 req->rate = __pll_params_to_rate(req->best_parent_rate, m, n, frac, pll);
280 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
285 if (meson_parm_read(clk->map, &pll->l))
289 } while (--delay);
291 return -ETIMEDOUT;
297 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
299 if (MESON_PARM_APPLICABLE(&pll->rst) &&
300 meson_parm_read(clk->map, &pll->rst))
303 if (!meson_parm_read(clk->map, &pll->en) ||
304 !meson_parm_read(clk->map, &pll->l))
313 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
324 if ((pll->flags & CLK_MESON_PLL_NOINIT_ENABLED) &&
328 if (pll->init_count) {
329 if (MESON_PARM_APPLICABLE(&pll->rst))
330 meson_parm_write(clk->map, &pll->rst, 1);
332 regmap_multi_reg_write(clk->map, pll->init_regs,
333 pll->init_count);
335 if (MESON_PARM_APPLICABLE(&pll->rst))
336 meson_parm_write(clk->map, &pll->rst, 0);
350 pr_info("Retry enabling PCIe PLL clock\n");
351 } while (--retries);
353 return -EIO;
359 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
361 /* do nothing if the PLL is already enabled */
365 /* Make sure the pll is in reset */
366 if (MESON_PARM_APPLICABLE(&pll->rst))
367 meson_parm_write(clk->map, &pll->rst, 1);
369 /* Enable the pll */
370 meson_parm_write(clk->map, &pll->en, 1);
372 /* Take the pll out reset */
373 if (MESON_PARM_APPLICABLE(&pll->rst))
374 meson_parm_write(clk->map, &pll->rst, 0);
377 * Compared with the previous SoCs, self-adaption current module
378 * is newly added for A1, keep the new power-on sequence to enable the
379 * PLL. The sequence is:
380 * 1. enable the pll, delay for 10us
381 * 2. enable the pll self-adaption current module, delay for 40us
384 if (MESON_PARM_APPLICABLE(&pll->current_en)) {
386 meson_parm_write(clk->map, &pll->current_en, 1);
390 if (MESON_PARM_APPLICABLE(&pll->l_detect)) {
391 meson_parm_write(clk->map, &pll->l_detect, 1);
392 meson_parm_write(clk->map, &pll->l_detect, 0);
396 return -EIO;
404 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
406 /* Put the pll is in reset */
407 if (MESON_PARM_APPLICABLE(&pll->rst))
408 meson_parm_write(clk->map, &pll->rst, 1);
410 /* Disable the pll */
411 meson_parm_write(clk->map, &pll->en, 0);
413 /* Disable PLL internal self-adaption current module */
414 if (MESON_PARM_APPLICABLE(&pll->current_en))
415 meson_parm_write(clk->map, &pll->current_en, 0);
422 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
428 return -EINVAL;
432 ret = meson_clk_get_pll_settings(rate, parent_rate, &m, &n, pll);
436 enabled = meson_parm_read(clk->map, &pll->en);
440 meson_parm_write(clk->map, &pll->n, n);
441 meson_parm_write(clk->map, &pll->m, m);
443 if (MESON_PARM_APPLICABLE(&pll->frac)) {
444 frac = __pll_params_with_frac(rate, parent_rate, m, n, pll);
445 meson_parm_write(clk->map, &pll->frac, frac);
448 /* If the pll is stopped, bail out now */
454 pr_warn("%s: pll %s didn't lock, trying to set old rate %lu\n",
469 * The Meson G12A PCIE PLL is fined tuned to deliver a very precise
471 * a strict register sequence to enable the PLL.
472 * To simplify, re-use the _init() op to enable the PLL and keep
503 MODULE_DESCRIPTION("Amlogic PLL driver");