Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: meson: Add support for parameters for specific PLLs

In recent Amlogic GXBB, GXL and GXM SoCs, the GP0 PLL needs some specific
parameters in order to initialize and lock correctly.

This patch adds an optional PARAM table used to initialize the PLL to a
default value with it's parameters in order to achieve to desired frequency.

The GP0 PLL in GXBB, GXL/GXM also needs some tweaks in the initialization
steps, and these are exposed along the PARAM table.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Michael Turquette <mturquette@baylibre.com>
Link: lkml.kernel.org/r/1490178747-14837-2-git-send-email-narmstrong@baylibre.com

authored by

Neil Armstrong and committed by
Kevin Hilman
45fcbec7 fac9a55b

+74 -2
+51 -2
drivers/clk/meson/clk-pll.c
··· 116 116 return NULL; 117 117 } 118 118 119 + /* Specific wait loop for GXL/GXM GP0 PLL */ 120 + static int meson_clk_pll_wait_lock_reset(struct meson_clk_pll *pll, 121 + struct parm *p_n) 122 + { 123 + int delay = 100; 124 + u32 reg; 125 + 126 + while (delay > 0) { 127 + reg = readl(pll->base + p_n->reg_off); 128 + writel(reg | MESON_PLL_RESET, pll->base + p_n->reg_off); 129 + udelay(10); 130 + writel(reg & ~MESON_PLL_RESET, pll->base + p_n->reg_off); 131 + 132 + /* This delay comes from AMLogic tree clk-gp0-gxl driver */ 133 + mdelay(1); 134 + 135 + reg = readl(pll->base + p_n->reg_off); 136 + if (reg & MESON_PLL_LOCK) 137 + return 0; 138 + delay--; 139 + } 140 + return -ETIMEDOUT; 141 + } 142 + 119 143 static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll, 120 144 struct parm *p_n) 121 145 { ··· 154 130 delay--; 155 131 } 156 132 return -ETIMEDOUT; 133 + } 134 + 135 + static void meson_clk_pll_init_params(struct meson_clk_pll *pll) 136 + { 137 + int i; 138 + 139 + for (i = 0 ; i < pll->params.params_count ; ++i) 140 + writel(pll->params.params_table[i].value, 141 + pll->base + pll->params.params_table[i].reg_off); 157 142 } 158 143 159 144 static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, ··· 184 151 if (!rate_set) 185 152 return -EINVAL; 186 153 154 + /* Initialize the PLL in a clean state if specified */ 155 + if (pll->params.params_count) 156 + meson_clk_pll_init_params(pll); 157 + 187 158 /* PLL reset */ 188 159 p = &pll->n; 189 160 reg = readl(pll->base + p->reg_off); 190 - writel(reg | MESON_PLL_RESET, pll->base + p->reg_off); 161 + /* If no_init_reset is provided, avoid resetting at this point */ 162 + if (!pll->params.no_init_reset) 163 + writel(reg | MESON_PLL_RESET, pll->base + p->reg_off); 191 164 192 165 reg = PARM_SET(p->width, p->shift, reg, rate_set->n); 193 166 writel(reg, pll->base + p->reg_off); ··· 223 184 } 224 185 225 186 p = &pll->n; 226 - ret = meson_clk_pll_wait_lock(pll, p); 187 + /* If clear_reset_for_lock is provided, remove the reset bit here */ 188 + if (pll->params.clear_reset_for_lock) { 189 + reg = readl(pll->base + p->reg_off); 190 + writel(reg & ~MESON_PLL_RESET, pll->base + p->reg_off); 191 + } 192 + 193 + /* If reset_lock_loop, use a special loop including resetting */ 194 + if (pll->params.reset_lock_loop) 195 + ret = meson_clk_pll_wait_lock_reset(pll, p); 196 + else 197 + ret = meson_clk_pll_wait_lock(pll, p); 227 198 if (ret) { 228 199 pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", 229 200 __func__, old_rate);
+23
drivers/clk/meson/clkc.h
··· 62 62 .frac = (_frac), \ 63 63 } \ 64 64 65 + struct pll_params_table { 66 + unsigned int reg_off; 67 + unsigned int value; 68 + }; 69 + 70 + #define PLL_PARAM(_reg, _val) \ 71 + { \ 72 + .reg_off = (_reg), \ 73 + .value = (_val), \ 74 + } 75 + 76 + struct pll_setup_params { 77 + struct pll_params_table *params_table; 78 + unsigned int params_count; 79 + /* Workaround for GP0, do not reset before configuring */ 80 + bool no_init_reset; 81 + /* Workaround for GP0, unreset right before checking for lock */ 82 + bool clear_reset_for_lock; 83 + /* Workaround for GXL GP0, reset in the lock checking loop */ 84 + bool reset_lock_loop; 85 + }; 86 + 65 87 struct meson_clk_pll { 66 88 struct clk_hw hw; 67 89 void __iomem *base; ··· 92 70 struct parm frac; 93 71 struct parm od; 94 72 struct parm od2; 73 + const struct pll_setup_params params; 95 74 const struct pll_rate_table *rate_table; 96 75 unsigned int rate_count; 97 76 spinlock_t *lock;