| /* |
| * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> |
| * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org> |
| * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> |
| * Copyright (C) 2013-2014 Imagination Technologies Ltd. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * True Circuits PLL in TZ1090 SoC. |
| */ |
| |
| #include <linux/clk-provider.h> |
| #include <linux/delay.h> |
| #include <linux/err.h> |
| #include <linux/io.h> |
| #include <linux/slab.h> |
| |
| #include "clk.h" |
| |
| /* Register definitions */ |
| |
| #define PLL_CTL0 0 |
| #define PLL_CTL0_BWADJ_M 0xfff |
| #define PLL_CTL0_BWADJ_S 20 |
| #define PLL_CTL0_CLKF_M 0x1fff |
| #define PLL_CTL0_CLKF_S 4 |
| #define PLL_CTL0_CLKOD_M 0x7 |
| #define PLL_CTL0_CLKOD_S 0 |
| #define PLL_CTL1 4 |
| #define PLL_CTL1_RESET_B BIT(28) |
| #define PLL_CTL1_FASTEN_B BIT(27) |
| #define PLL_CTL1_ENSAT_B BIT(26) |
| #define PLL_CTL1_BYPASS_B BIT(25) |
| #define PLL_CTL1_PWRDN_B BIT(24) |
| #define PLL_CTL1_CLKR_M 0x3f |
| #define PLL_CTL1_CLKR_S 0 |
| |
| /** |
| * struct tz1090_clk_pll_priv - PLL in TZ1090 |
| * |
| * @hw: handle between common and hardware-specific interfaces |
| * @reg: first of two registers |
| * |
| * PLL in TZ1090. |
| */ |
| struct tz1090_clk_pll_priv { |
| struct clk_hw hw; |
| void __iomem *reg; |
| }; |
| |
| #define to_tz1090_clk_pll(_hw) container_of(_hw, struct tz1090_clk_pll_priv, hw) |
| |
| static unsigned long tz1090_clk_pll_recalc_rate(struct clk_hw *hw, |
| unsigned long f_in) |
| { |
| struct tz1090_clk_pll_priv *pll = to_tz1090_clk_pll(hw); |
| u32 ctl0, ctl1; |
| unsigned int clk_f; /* feedback divide */ |
| unsigned int clk_od; /* output divide */ |
| unsigned int clk_r; /* reference divide */ |
| unsigned long f_out; |
| |
| ctl0 = readl(pll->reg + PLL_CTL0); |
| ctl1 = readl(pll->reg + PLL_CTL1); |
| |
| /* Bypass? */ |
| if (ctl1 & PLL_CTL1_BYPASS_B) |
| return f_in; |
| |
| /* Get divider values */ |
| clk_f = 1 + ((ctl0 >> PLL_CTL0_CLKF_S) & PLL_CTL0_CLKF_M); |
| clk_od = 1 + ((ctl0 >> PLL_CTL0_CLKOD_S) & PLL_CTL0_CLKOD_M); |
| clk_r = 1 + ((ctl1 >> PLL_CTL1_CLKR_S) & PLL_CTL1_CLKR_M); |
| |
| /* |
| * formula: |
| * f_out = (f_in / clk_r) * (clk_f / 2) / clk_od |
| * = (f_in * clk_f) / (2 * clk_r * clk_od) |
| */ |
| f_out = div_u64((u64)f_in * clk_f, |
| 2 * clk_r * clk_od); |
| return f_out; |
| } |
| |
| /* finds best pll parameters and returns rate on success (or 0) */ |
| static int tz1090_clk_pll_bestvals(struct clk_hw *hw, unsigned long parent_rate, |
| unsigned long rate, unsigned long *clkf, |
| unsigned long *clkr, unsigned long *clkod) |
| { |
| unsigned long odmin, odmax; |
| unsigned long bestf = 1, bestr = 1, bestod = 1; |
| unsigned long rod2, cur, best = 0; |
| unsigned long f, r, od; |
| |
| /* 120MHz/freq < od < 600MHz/freq */ |
| odmin = 120000000/rate + 1; |
| odmax = 600000000/rate; |
| |
| if (odmin < 1) |
| odmin = 1; |
| if (odmax > PLL_CTL0_CLKOD_M + 1) |
| odmax = PLL_CTL0_CLKOD_M + 1; |
| |
| /* |
| * Search through valid combinations of od and r, starting with lower |
| * output divider values to get a lower intermediate frequency. |
| */ |
| for (od = odmin; od <= odmax; ++od) { |
| for (r = 1; r <= PLL_CTL1_CLKR_M + 1; ++r) { |
| /* |
| * Calculate best f for given r and od, rounding down |
| * So for f, freq <= rate |
| * And for f+1, freq > rate |
| * We have to do rate+1 because rate may have itself |
| * been rounded down. |
| */ |
| rod2 = 2 * r * od; |
| f = div_u64((u64)(rate + 1) * rod2, parent_rate); |
| if (f < 1) |
| continue; |
| if (f > PLL_CTL0_CLKF_M + 1) |
| f = PLL_CTL0_CLKF_M + 1; |
| |
| /* Calculate final rate and see if it's the best */ |
| cur = div_u64((u64)parent_rate * f, rod2); |
| if (cur > best) { |
| bestf = f; |
| bestr = r; |
| bestod = od; |
| best = cur; |
| /* Can't improve on a perfect match */ |
| if (cur == rate) |
| goto done; |
| } |
| } |
| } |
| if (!best) |
| return 0; |
| done: |
| pr_debug("tz1090_clk_pll: final %lu/%lu * %lu/2/%lu=%lu (req=%lu, err=%ld)\n", |
| parent_rate, bestr, bestf, bestod, best, rate, best - rate); |
| |
| *clkf = bestf; |
| *clkr = bestr; |
| *clkod = bestod; |
| return best; |
| } |
| |
| static long tz1090_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, |
| unsigned long *prate) |
| { |
| unsigned long clkf, clkr, clkod; |
| unsigned long parent_rate = *prate; |
| |
| return tz1090_clk_pll_bestvals(hw, parent_rate, rate, &clkf, &clkr, |
| &clkod); |
| } |
| |
| static int tz1090_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, |
| unsigned long parent_rate) |
| { |
| struct tz1090_clk_pll_priv *pll = to_tz1090_clk_pll(hw); |
| unsigned long clkf, clkr, clkod, bwadj; |
| u32 ctl0, ctl1; |
| |
| if (!tz1090_clk_pll_bestvals(hw, parent_rate, rate, |
| &clkf, &clkr, &clkod)) |
| return -EINVAL; |
| |
| /* offset the values ready to go in the PLL registers */ |
| --clkr; |
| --clkf; |
| --clkod; |
| bwadj = clkf / 2; |
| |
| /* bypass, reset and configure PLL */ |
| ctl0 = (bwadj << PLL_CTL0_BWADJ_S) | |
| (clkf << PLL_CTL0_CLKF_S) | |
| (clkod << PLL_CTL0_CLKOD_S); |
| ctl1 = PLL_CTL1_RESET_B | |
| PLL_CTL1_ENSAT_B | |
| PLL_CTL1_BYPASS_B | |
| (clkr << PLL_CTL1_CLKR_S); |
| writel(ctl1, pll->reg + PLL_CTL1); |
| writel(ctl0, pll->reg + PLL_CTL0); |
| |
| /* allow 5us after clkf before deasserting reset */ |
| udelay(5); |
| |
| /* take PLL out of reset and enable fasten */ |
| ctl1 &= ~PLL_CTL1_RESET_B; |
| ctl1 |= PLL_CTL1_FASTEN_B; |
| writel(ctl1, pll->reg + PLL_CTL1); |
| |
| /* count at least 500 divided ref clks to allow time to lock */ |
| msleep(1 + 500*1000*(clkr+1)/parent_rate); |
| |
| /* take PLL out of fasten / bypass */ |
| ctl1 &= ~PLL_CTL1_FASTEN_B; |
| ctl1 &= ~PLL_CTL1_BYPASS_B; |
| writel(ctl1, pll->reg + PLL_CTL1); |
| |
| return 0; |
| } |
| |
| static const struct clk_ops tz1090_clk_pll_ops = { |
| .recalc_rate = tz1090_clk_pll_recalc_rate, |
| .round_rate = tz1090_clk_pll_round_rate, |
| .set_rate = tz1090_clk_pll_set_rate, |
| }; |
| |
| /** |
| * __register_pll() - register a PLL with the clock framework |
| * @name: name of this clock |
| * @parent_name: name of clock's parent |
| * @flags: framework-specific flags |
| * @reg: register address to adjust PLL |
| * |
| * Register a TZ1090 PLL clock to the clock framework. |
| */ |
| static struct clk *__init __register_pll(const char *name, |
| const char *parent_name, |
| unsigned long flags, |
| void __iomem *reg) |
| { |
| struct tz1090_clk_pll_priv *pll; |
| struct clk *clk; |
| struct clk_init_data init; |
| |
| /* allocate the pll */ |
| pll = kzalloc(sizeof(struct tz1090_clk_pll_priv), GFP_KERNEL); |
| if (!pll) |
| return ERR_PTR(-ENOMEM); |
| |
| init.name = name; |
| init.ops = &tz1090_clk_pll_ops; |
| init.flags = flags | CLK_IS_BASIC; |
| init.parent_names = (parent_name ? &parent_name : NULL); |
| init.num_parents = (parent_name ? 1 : 0); |
| |
| /* struct tz1090_clk_pll_priv assignments */ |
| pll->reg = reg; |
| pll->hw.init = &init; |
| |
| /* register the clock */ |
| clk = clk_register(NULL, &pll->hw); |
| |
| if (IS_ERR(clk)) |
| kfree(pll); |
| |
| return clk; |
| } |
| |
| /** |
| * tz1090_clk_register_plls() - Register set of PLLs with a provider. |
| * @p: TZ1090 clock provider. |
| * @plls: Array of PLL descriptions. |
| * @count Number of PLLs described in the array. |
| */ |
| void __init tz1090_clk_register_plls(struct tz1090_clk_provider *p, |
| const struct tz1090_clk_pll *plls, |
| unsigned int count) |
| { |
| const struct tz1090_clk_pll *pll; |
| struct clk *clk; |
| unsigned int i; |
| |
| for (pll = plls, i = 0; i < count; ++pll, ++i) { |
| clk = __register_pll(tz1090_clk_xlate(p, pll->name), |
| tz1090_clk_xlate(p, pll->parent), 0, |
| p->base + pll->reg_base); |
| p->clk_data.clks[pll->id] = clk; |
| } |
| } |