diff options
Diffstat (limited to 'drivers/clk/meson/clk-pll.c')
-rw-r--r-- | drivers/clk/meson/clk-pll.c | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 4adc1e89212c..01341553f50b 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -116,6 +116,30 @@ static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_ return NULL; } +/* Specific wait loop for GXL/GXM GP0 PLL */ +static int meson_clk_pll_wait_lock_reset(struct meson_clk_pll *pll, + struct parm *p_n) +{ + int delay = 100; + u32 reg; + + while (delay > 0) { + reg = readl(pll->base + p_n->reg_off); + writel(reg | MESON_PLL_RESET, pll->base + p_n->reg_off); + udelay(10); + writel(reg & ~MESON_PLL_RESET, pll->base + p_n->reg_off); + + /* This delay comes from AMLogic tree clk-gp0-gxl driver */ + mdelay(1); + + reg = readl(pll->base + p_n->reg_off); + if (reg & MESON_PLL_LOCK) + return 0; + delay--; + } + return -ETIMEDOUT; +} + static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll, struct parm *p_n) { @@ -132,6 +156,15 @@ static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll, return -ETIMEDOUT; } +static void meson_clk_pll_init_params(struct meson_clk_pll *pll) +{ + int i; + + for (i = 0 ; i < pll->params.params_count ; ++i) + writel(pll->params.params_table[i].value, + pll->base + pll->params.params_table[i].reg_off); +} + static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { @@ -151,10 +184,16 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, if (!rate_set) return -EINVAL; + /* Initialize the PLL in a clean state if specified */ + if (pll->params.params_count) + meson_clk_pll_init_params(pll); + /* PLL reset */ p = &pll->n; reg = readl(pll->base + p->reg_off); - writel(reg | MESON_PLL_RESET, pll->base + p->reg_off); + /* If no_init_reset is provided, avoid resetting at this point */ + if (!pll->params.no_init_reset) + writel(reg | MESON_PLL_RESET, pll->base + p->reg_off); reg = PARM_SET(p->width, p->shift, reg, rate_set->n); writel(reg, pll->base + p->reg_off); @@ -184,7 +223,17 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, } p = &pll->n; - ret = meson_clk_pll_wait_lock(pll, p); + /* If clear_reset_for_lock is provided, remove the reset bit here */ + if (pll->params.clear_reset_for_lock) { + reg = readl(pll->base + p->reg_off); + writel(reg & ~MESON_PLL_RESET, pll->base + p->reg_off); + } + + /* If reset_lock_loop, use a special loop including resetting */ + if (pll->params.reset_lock_loop) + ret = meson_clk_pll_wait_lock_reset(pll, p); + else + ret = meson_clk_pll_wait_lock(pll, p); if (ret) { pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", __func__, old_rate); |