diff options
Diffstat (limited to 'drivers/clk/samsung/clk-pll.c')
| -rw-r--r-- | drivers/clk/samsung/clk-pll.c | 487 |
1 files changed, 248 insertions, 239 deletions
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 0ff28938943f..0a8fc9649ae2 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -11,14 +11,12 @@ #include <linux/iopoll.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/timekeeping.h> #include <linux/clk-provider.h> #include <linux/io.h> #include "clk.h" #include "clk-pll.h" -#define PLL_TIMEOUT_US 20000U -#define PLL_TIMEOUT_LOOPS 1000000U +#define PLL_TIMEOUT_LOOPS 20000U struct samsung_clk_pll { struct clk_hw hw; @@ -49,37 +47,33 @@ static const struct samsung_pll_rate_table *samsung_get_pll_settings( return NULL; } -static long samsung_pll_round_rate(struct clk_hw *hw, - unsigned long drate, unsigned long *prate) +static int samsung_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct samsung_clk_pll *pll = to_clk_pll(hw); const struct samsung_pll_rate_table *rate_table = pll->rate_table; int i; - /* Assumming rate_table is in descending order */ + /* Assuming rate_table is in descending order */ for (i = 0; i < pll->rate_count; i++) { - if (drate >= rate_table[i].rate) - return rate_table[i].rate; + if (req->rate >= rate_table[i].rate) { + req->rate = rate_table[i].rate; + + return 0; + } } /* return minimum supported value */ - return rate_table[i - 1].rate; -} - -static bool pll_early_timeout = true; + req->rate = rate_table[i - 1].rate; -static int __init samsung_pll_disable_early_timeout(void) -{ - pll_early_timeout = false; return 0; } -arch_initcall(samsung_pll_disable_early_timeout); /* Wait until the PLL is locked */ static int samsung_pll_lock_wait(struct samsung_clk_pll *pll, unsigned int reg_mask) { - int i, ret; + int ret; u32 val; /* @@ -88,25 +82,15 @@ static int samsung_pll_lock_wait(struct samsung_clk_pll *pll, * initialized, another when the timekeeping is suspended. udelay() also * cannot be used when the clocksource is not running on arm64, since * the current timer is used as cycle counter. So a simple busy loop - * is used here in that special cases. The limit of iterations has been - * derived from experimental measurements of various PLLs on multiple - * Exynos SoC variants. Single register read time was usually in range - * 0.4...1.5 us, never less than 0.4 us. + * is used here. + * The limit of iterations has been derived from experimental + * measurements of various PLLs on multiple Exynos SoC variants. Single + * register read time was usually in range 0.4...1.5 us, never less than + * 0.4 us. */ - if (pll_early_timeout || timekeeping_suspended) { - i = PLL_TIMEOUT_LOOPS; - while (i-- > 0) { - if (readl_relaxed(pll->con_reg) & reg_mask) - return 0; - - cpu_relax(); - } - ret = -ETIMEDOUT; - } else { - ret = readl_relaxed_poll_timeout_atomic(pll->con_reg, val, - val & reg_mask, 0, PLL_TIMEOUT_US); - } - + ret = readl_relaxed_poll_timeout_atomic(pll->con_reg, val, + val & reg_mask, 0, + PLL_TIMEOUT_LOOPS); if (ret < 0) pr_err("Could not lock PLL %s\n", clk_hw_get_name(&pll->hw)); @@ -206,6 +190,7 @@ static const struct clk_ops samsung_pll3000_clk_ops = { */ /* Maximum lock time can be 270 * PDIV cycles */ #define PLL35XX_LOCK_FACTOR (270) +#define PLL142XX_LOCK_FACTOR (150) #define PLL35XX_MDIV_MASK (0x3FF) #define PLL35XX_PDIV_MASK (0x3F) @@ -272,7 +257,11 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, } /* Set PLL lock time. */ - writel_relaxed(rate->pdiv * PLL35XX_LOCK_FACTOR, + if (pll->type == pll_142xx || pll->type == pll_1017x) + writel_relaxed(rate->pdiv * PLL142XX_LOCK_FACTOR, + pll->lock_reg); + else + writel_relaxed(rate->pdiv * PLL35XX_LOCK_FACTOR, pll->lock_reg); /* Change PLL PMS values */ @@ -293,7 +282,7 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll35xx_clk_ops = { .recalc_rate = samsung_pll35xx_recalc_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .set_rate = samsung_pll35xx_set_rate, .enable = samsung_pll3xxx_enable, .disable = samsung_pll3xxx_disable, @@ -406,7 +395,7 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll36xx_clk_ops = { .recalc_rate = samsung_pll36xx_recalc_rate, .set_rate = samsung_pll36xx_set_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .enable = samsung_pll3xxx_enable, .disable = samsung_pll3xxx_disable, }; @@ -430,6 +419,12 @@ static const struct clk_ops samsung_pll36xx_clk_min_ops = { #define PLL0822X_LOCK_STAT_SHIFT (29) #define PLL0822X_ENABLE_SHIFT (31) +/* + * PLL1418x, PLL0717x and PLL0718x are similar + * to PLL0822x, except that MDIV is one bit smaller + */ +#define PLL1418X_MDIV_MASK (0x1FF) + static unsigned long samsung_pll0822x_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -438,11 +433,21 @@ static unsigned long samsung_pll0822x_recalc_rate(struct clk_hw *hw, u64 fvco = parent_rate; pll_con3 = readl_relaxed(pll->con_reg); - mdiv = (pll_con3 >> PLL0822X_MDIV_SHIFT) & PLL0822X_MDIV_MASK; + + if (pll->type != pll_1418x && + pll->type != pll_0717x && + pll->type != pll_0718x) + mdiv = (pll_con3 >> PLL0822X_MDIV_SHIFT) & PLL0822X_MDIV_MASK; + else + mdiv = (pll_con3 >> PLL0822X_MDIV_SHIFT) & PLL1418X_MDIV_MASK; + pdiv = (pll_con3 >> PLL0822X_PDIV_SHIFT) & PLL0822X_PDIV_MASK; sdiv = (pll_con3 >> PLL0822X_SDIV_SHIFT) & PLL0822X_SDIV_MASK; fvco *= mdiv; + if (pll->type == pll_0516x) + fvco *= 2; + do_div(fvco, (pdiv << sdiv)); return (unsigned long)fvco; @@ -453,7 +458,12 @@ static int samsung_pll0822x_set_rate(struct clk_hw *hw, unsigned long drate, { const struct samsung_pll_rate_table *rate; struct samsung_clk_pll *pll = to_clk_pll(hw); - u32 pll_con3; + u32 mdiv_mask, pll_con3; + + if (pll->type != pll_1418x) + mdiv_mask = PLL0822X_MDIV_MASK; + else + mdiv_mask = PLL1418X_MDIV_MASK; /* Get required rate settings from table */ rate = samsung_get_pll_settings(pll, drate); @@ -465,7 +475,7 @@ static int samsung_pll0822x_set_rate(struct clk_hw *hw, unsigned long drate, /* Change PLL PMS values */ pll_con3 = readl_relaxed(pll->con_reg); - pll_con3 &= ~((PLL0822X_MDIV_MASK << PLL0822X_MDIV_SHIFT) | + pll_con3 &= ~((mdiv_mask << PLL0822X_MDIV_SHIFT) | (PLL0822X_PDIV_MASK << PLL0822X_PDIV_SHIFT) | (PLL0822X_SDIV_MASK << PLL0822X_SDIV_SHIFT)); pll_con3 |= (rate->mdiv << PLL0822X_MDIV_SHIFT) | @@ -488,7 +498,7 @@ static int samsung_pll0822x_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll0822x_clk_ops = { .recalc_rate = samsung_pll0822x_recalc_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .set_rate = samsung_pll0822x_set_rate, .enable = samsung_pll3xxx_enable, .disable = samsung_pll3xxx_disable, @@ -586,7 +596,7 @@ static int samsung_pll0831x_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll0831x_clk_ops = { .recalc_rate = samsung_pll0831x_recalc_rate, .set_rate = samsung_pll0831x_set_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .enable = samsung_pll3xxx_enable, .disable = samsung_pll3xxx_disable, }; @@ -709,7 +719,7 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll45xx_clk_ops = { .recalc_rate = samsung_pll45xx_recalc_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .set_rate = samsung_pll45xx_set_rate, }; @@ -854,7 +864,7 @@ static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll46xx_clk_ops = { .recalc_rate = samsung_pll46xx_recalc_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .set_rate = samsung_pll46xx_set_rate, }; @@ -941,169 +951,6 @@ static const struct clk_ops samsung_pll6553_clk_ops = { }; /* - * PLL Clock Type of S3C24XX before S3C2443 - */ - -#define PLLS3C2410_MDIV_MASK (0xff) -#define PLLS3C2410_PDIV_MASK (0x1f) -#define PLLS3C2410_SDIV_MASK (0x3) -#define PLLS3C2410_MDIV_SHIFT (12) -#define PLLS3C2410_PDIV_SHIFT (4) -#define PLLS3C2410_SDIV_SHIFT (0) - -#define PLLS3C2410_ENABLE_REG_OFFSET 0x10 - -static unsigned long samsung_s3c2410_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct samsung_clk_pll *pll = to_clk_pll(hw); - u32 pll_con, mdiv, pdiv, sdiv; - u64 fvco = parent_rate; - - pll_con = readl_relaxed(pll->con_reg); - mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK; - pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK; - sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK; - - fvco *= (mdiv + 8); - do_div(fvco, (pdiv + 2) << sdiv); - - return (unsigned int)fvco; -} - -static unsigned long samsung_s3c2440_mpll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct samsung_clk_pll *pll = to_clk_pll(hw); - u32 pll_con, mdiv, pdiv, sdiv; - u64 fvco = parent_rate; - - pll_con = readl_relaxed(pll->con_reg); - mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK; - pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK; - sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK; - - fvco *= (2 * (mdiv + 8)); - do_div(fvco, (pdiv + 2) << sdiv); - - return (unsigned int)fvco; -} - -static int samsung_s3c2410_pll_set_rate(struct clk_hw *hw, unsigned long drate, - unsigned long prate) -{ - struct samsung_clk_pll *pll = to_clk_pll(hw); - const struct samsung_pll_rate_table *rate; - u32 tmp; - - /* Get required rate settings from table */ - rate = samsung_get_pll_settings(pll, drate); - if (!rate) { - pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, - drate, clk_hw_get_name(hw)); - return -EINVAL; - } - - tmp = readl_relaxed(pll->con_reg); - - /* Change PLL PMS values */ - tmp &= ~((PLLS3C2410_MDIV_MASK << PLLS3C2410_MDIV_SHIFT) | - (PLLS3C2410_PDIV_MASK << PLLS3C2410_PDIV_SHIFT) | - (PLLS3C2410_SDIV_MASK << PLLS3C2410_SDIV_SHIFT)); - tmp |= (rate->mdiv << PLLS3C2410_MDIV_SHIFT) | - (rate->pdiv << PLLS3C2410_PDIV_SHIFT) | - (rate->sdiv << PLLS3C2410_SDIV_SHIFT); - writel_relaxed(tmp, pll->con_reg); - - /* Time to settle according to the manual */ - udelay(300); - - return 0; -} - -static int samsung_s3c2410_pll_enable(struct clk_hw *hw, int bit, bool enable) -{ - struct samsung_clk_pll *pll = to_clk_pll(hw); - u32 pll_en = readl_relaxed(pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET); - u32 pll_en_orig = pll_en; - - if (enable) - pll_en &= ~BIT(bit); - else - pll_en |= BIT(bit); - - writel_relaxed(pll_en, pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET); - - /* if we started the UPLL, then allow to settle */ - if (enable && (pll_en_orig & BIT(bit))) - udelay(300); - - return 0; -} - -static int samsung_s3c2410_mpll_enable(struct clk_hw *hw) -{ - return samsung_s3c2410_pll_enable(hw, 5, true); -} - -static void samsung_s3c2410_mpll_disable(struct clk_hw *hw) -{ - samsung_s3c2410_pll_enable(hw, 5, false); -} - -static int samsung_s3c2410_upll_enable(struct clk_hw *hw) -{ - return samsung_s3c2410_pll_enable(hw, 7, true); -} - -static void samsung_s3c2410_upll_disable(struct clk_hw *hw) -{ - samsung_s3c2410_pll_enable(hw, 7, false); -} - -static const struct clk_ops samsung_s3c2410_mpll_clk_min_ops = { - .recalc_rate = samsung_s3c2410_pll_recalc_rate, - .enable = samsung_s3c2410_mpll_enable, - .disable = samsung_s3c2410_mpll_disable, -}; - -static const struct clk_ops samsung_s3c2410_upll_clk_min_ops = { - .recalc_rate = samsung_s3c2410_pll_recalc_rate, - .enable = samsung_s3c2410_upll_enable, - .disable = samsung_s3c2410_upll_disable, -}; - -static const struct clk_ops samsung_s3c2440_mpll_clk_min_ops = { - .recalc_rate = samsung_s3c2440_mpll_recalc_rate, - .enable = samsung_s3c2410_mpll_enable, - .disable = samsung_s3c2410_mpll_disable, -}; - -static const struct clk_ops samsung_s3c2410_mpll_clk_ops = { - .recalc_rate = samsung_s3c2410_pll_recalc_rate, - .enable = samsung_s3c2410_mpll_enable, - .disable = samsung_s3c2410_mpll_disable, - .round_rate = samsung_pll_round_rate, - .set_rate = samsung_s3c2410_pll_set_rate, -}; - -static const struct clk_ops samsung_s3c2410_upll_clk_ops = { - .recalc_rate = samsung_s3c2410_pll_recalc_rate, - .enable = samsung_s3c2410_upll_enable, - .disable = samsung_s3c2410_upll_disable, - .round_rate = samsung_pll_round_rate, - .set_rate = samsung_s3c2410_pll_set_rate, -}; - -static const struct clk_ops samsung_s3c2440_mpll_clk_ops = { - .recalc_rate = samsung_s3c2440_mpll_recalc_rate, - .enable = samsung_s3c2410_mpll_enable, - .disable = samsung_s3c2410_mpll_disable, - .round_rate = samsung_pll_round_rate, - .set_rate = samsung_s3c2410_pll_set_rate, -}; - -/* * PLL2550x Clock Type */ @@ -1230,7 +1077,7 @@ static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll2550xx_clk_ops = { .recalc_rate = samsung_pll2550xx_recalc_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .set_rate = samsung_pll2550xx_set_rate, }; @@ -1322,7 +1169,7 @@ static int samsung_pll2650x_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll2650x_clk_ops = { .recalc_rate = samsung_pll2650x_recalc_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .set_rate = samsung_pll2650x_set_rate, }; @@ -1414,16 +1261,175 @@ static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll2650xx_clk_ops = { .recalc_rate = samsung_pll2650xx_recalc_rate, .set_rate = samsung_pll2650xx_set_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, }; static const struct clk_ops samsung_pll2650xx_clk_min_ops = { .recalc_rate = samsung_pll2650xx_recalc_rate, }; +/* + * PLL531X Clock Type + */ +/* Maximum lock time can be 500 * PDIV cycles */ +#define PLL531X_LOCK_FACTOR (500) +#define PLL531X_MDIV_MASK (0x3FF) +#define PLL531X_PDIV_MASK (0x3F) +#define PLL531X_SDIV_MASK (0x7) +#define PLL531X_FDIV_MASK (0xFFFFFFFF) +#define PLL531X_MDIV_SHIFT (16) +#define PLL531X_PDIV_SHIFT (8) +#define PLL531X_SDIV_SHIFT (0) + +static unsigned long samsung_pll531x_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 pdiv, sdiv, fdiv, pll_con0, pll_con8; + u64 mdiv, fout = parent_rate; + + pll_con0 = readl_relaxed(pll->con_reg); + pll_con8 = readl_relaxed(pll->con_reg + 20); + mdiv = (pll_con0 >> PLL531X_MDIV_SHIFT) & PLL531X_MDIV_MASK; + pdiv = (pll_con0 >> PLL531X_PDIV_SHIFT) & PLL531X_PDIV_MASK; + sdiv = (pll_con0 >> PLL531X_SDIV_SHIFT) & PLL531X_SDIV_MASK; + fdiv = (pll_con8 & PLL531X_FDIV_MASK); + + if (fdiv >> 31) + mdiv--; + + fout *= (mdiv << 24) + (fdiv >> 8); + do_div(fout, (pdiv << sdiv)); + fout >>= 24; + + return (unsigned long)fout; +} + +static const struct clk_ops samsung_pll531x_clk_ops = { + .recalc_rate = samsung_pll531x_recalc_rate, +}; + +/* + * PLL1031x Clock Type + */ +#define PLL1031X_LOCK_FACTOR (500) + +#define PLL1031X_MDIV_MASK (0x3ff) +#define PLL1031X_PDIV_MASK (0x3f) +#define PLL1031X_SDIV_MASK (0x7) +#define PLL1031X_MDIV_SHIFT (16) +#define PLL1031X_PDIV_SHIFT (8) +#define PLL1031X_SDIV_SHIFT (0) + +#define PLL1031X_KDIV_MASK (0xffff) +#define PLL1031X_KDIV_SHIFT (0) +#define PLL1031X_MFR_MASK (0x3f) +#define PLL1031X_MRR_MASK (0x1f) +#define PLL1031X_MFR_SHIFT (16) +#define PLL1031X_MRR_SHIFT (24) + +static unsigned long samsung_pll1031x_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con3; + u64 fvco = parent_rate; + + pll_con0 = readl_relaxed(pll->con_reg); + pll_con3 = readl_relaxed(pll->con_reg + 0xc); + mdiv = (pll_con0 >> PLL1031X_MDIV_SHIFT) & PLL1031X_MDIV_MASK; + pdiv = (pll_con0 >> PLL1031X_PDIV_SHIFT) & PLL1031X_PDIV_MASK; + sdiv = (pll_con0 >> PLL1031X_SDIV_SHIFT) & PLL1031X_SDIV_MASK; + kdiv = (pll_con3 & PLL1031X_KDIV_MASK); + + fvco *= (mdiv << PLL1031X_MDIV_SHIFT) + kdiv; + do_div(fvco, (pdiv << sdiv)); + fvco >>= PLL1031X_MDIV_SHIFT; + + return (unsigned long)fvco; +} + +static bool samsung_pll1031x_mpk_change(u32 pll_con0, u32 pll_con3, + const struct samsung_pll_rate_table *rate) +{ + u32 old_mdiv, old_pdiv, old_kdiv; + + old_mdiv = (pll_con0 >> PLL1031X_MDIV_SHIFT) & PLL1031X_MDIV_MASK; + old_pdiv = (pll_con0 >> PLL1031X_PDIV_SHIFT) & PLL1031X_PDIV_MASK; + old_kdiv = (pll_con3 >> PLL1031X_KDIV_SHIFT) & PLL1031X_KDIV_MASK; + + return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv || + old_kdiv != rate->kdiv); +} + +static int samsung_pll1031x_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate; + u32 con0, con3; + + /* Get required rate settings from table */ + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, clk_hw_get_name(hw)); + return -EINVAL; + } + + con0 = readl_relaxed(pll->con_reg); + con3 = readl_relaxed(pll->con_reg + 0xc); + + if (!(samsung_pll1031x_mpk_change(con0, con3, rate))) { + /* If only s change, change just s value only */ + con0 &= ~(PLL1031X_SDIV_MASK << PLL1031X_SDIV_SHIFT); + con0 |= rate->sdiv << PLL1031X_SDIV_SHIFT; + writel_relaxed(con0, pll->con_reg); + + return 0; + } + + /* Set PLL lock time. */ + writel_relaxed(rate->pdiv * PLL1031X_LOCK_FACTOR, pll->lock_reg); + + /* Set PLL M, P, and S values. */ + con0 &= ~((PLL1031X_MDIV_MASK << PLL1031X_MDIV_SHIFT) | + (PLL1031X_PDIV_MASK << PLL1031X_PDIV_SHIFT) | + (PLL1031X_SDIV_MASK << PLL1031X_SDIV_SHIFT)); + + con0 |= (rate->mdiv << PLL1031X_MDIV_SHIFT) | + (rate->pdiv << PLL1031X_PDIV_SHIFT) | + (rate->sdiv << PLL1031X_SDIV_SHIFT); + + /* Set PLL K, MFR and MRR values. */ + con3 = readl_relaxed(pll->con_reg + 0xc); + con3 &= ~((PLL1031X_KDIV_MASK << PLL1031X_KDIV_SHIFT) | + (PLL1031X_MFR_MASK << PLL1031X_MFR_SHIFT) | + (PLL1031X_MRR_MASK << PLL1031X_MRR_SHIFT)); + con3 |= (rate->kdiv << PLL1031X_KDIV_SHIFT) | + (rate->mfr << PLL1031X_MFR_SHIFT) | + (rate->mrr << PLL1031X_MRR_SHIFT); + + /* Write configuration to PLL */ + writel_relaxed(con0, pll->con_reg); + writel_relaxed(con3, pll->con_reg + 0xc); + + /* Wait for PLL lock if the PLL is enabled */ + return samsung_pll_lock_wait(pll, BIT(pll->lock_offs)); +} + +static const struct clk_ops samsung_pll1031x_clk_ops = { + .recalc_rate = samsung_pll1031x_recalc_rate, + .determine_rate = samsung_pll_determine_rate, + .set_rate = samsung_pll1031x_set_rate, +}; + +static const struct clk_ops samsung_pll1031x_clk_min_ops = { + .recalc_rate = samsung_pll1031x_recalc_rate, +}; + static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, - const struct samsung_pll_clock *pll_clk, - void __iomem *base) + const struct samsung_pll_clock *pll_clk) { struct samsung_clk_pll *pll; struct clk_init_data init; @@ -1447,10 +1453,10 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, len++; pll->rate_count = len; - pll->rate_table = kmemdup(pll_clk->rate_table, - pll->rate_count * - sizeof(struct samsung_pll_rate_table), - GFP_KERNEL); + pll->rate_table = kmemdup_array(pll_clk->rate_table, + pll->rate_count, + sizeof(*pll->rate_table), + GFP_KERNEL); WARN(!pll->rate_table, "%s: could not allocate rate table for %s\n", __func__, pll_clk->name); @@ -1470,6 +1476,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, case pll_1451x: case pll_1452x: case pll_142xx: + case pll_1017x: pll->enable_offs = PLL35XX_ENABLE_SHIFT; pll->lock_offs = PLL35XX_LOCK_STAT_SHIFT; if (!pll->rate_table) @@ -1478,7 +1485,17 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, init.ops = &samsung_pll35xx_clk_ops; break; case pll_1417x: + case pll_1418x: + case pll_1051x: + case pll_1052x: + case pll_0818x: case pll_0822x: + case pll_0516x: + case pll_0517x: + case pll_0518x: + case pll_0717x: + case pll_0718x: + case pll_0732x: pll->enable_offs = PLL0822X_ENABLE_SHIFT; pll->lock_offs = PLL0822X_LOCK_STAT_SHIFT; if (!pll->rate_table) @@ -1530,24 +1547,6 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, else init.ops = &samsung_pll46xx_clk_ops; break; - case pll_s3c2410_mpll: - if (!pll->rate_table) - init.ops = &samsung_s3c2410_mpll_clk_min_ops; - else - init.ops = &samsung_s3c2410_mpll_clk_ops; - break; - case pll_s3c2410_upll: - if (!pll->rate_table) - init.ops = &samsung_s3c2410_upll_clk_min_ops; - else - init.ops = &samsung_s3c2410_upll_clk_ops; - break; - case pll_s3c2440_mpll: - if (!pll->rate_table) - init.ops = &samsung_s3c2440_mpll_clk_min_ops; - else - init.ops = &samsung_s3c2440_mpll_clk_ops; - break; case pll_2550x: init.ops = &samsung_pll2550x_clk_ops; break; @@ -1569,6 +1568,16 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, else init.ops = &samsung_pll2650xx_clk_ops; break; + case pll_531x: + case pll_4311: + init.ops = &samsung_pll531x_clk_ops; + break; + case pll_1031x: + if (!pll->rate_table) + init.ops = &samsung_pll1031x_clk_min_ops; + else + init.ops = &samsung_pll1031x_clk_ops; + break; default: pr_warn("%s: Unknown pll type for pll clk %s\n", __func__, pll_clk->name); @@ -1576,8 +1585,8 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, pll->hw.init = &init; pll->type = pll_clk->type; - pll->lock_reg = base + pll_clk->lock_offset; - pll->con_reg = base + pll_clk->con_offset; + pll->lock_reg = ctx->reg_base + pll_clk->lock_offset; + pll->con_reg = ctx->reg_base + pll_clk->con_offset; ret = clk_hw_register(ctx->dev, &pll->hw); if (ret) { @@ -1593,10 +1602,10 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx, const struct samsung_pll_clock *pll_list, - unsigned int nr_pll, void __iomem *base) + unsigned int nr_pll) { int cnt; for (cnt = 0; cnt < nr_pll; cnt++) - _samsung_clk_register_pll(ctx, &pll_list[cnt], base); + _samsung_clk_register_pll(ctx, &pll_list[cnt]); } |
