diff options
Diffstat (limited to 'drivers/clk/pistachio')
-rw-r--r-- | drivers/clk/pistachio/clk-pistachio.c | 19 | ||||
-rw-r--r-- | drivers/clk/pistachio/clk-pll.c | 77 | ||||
-rw-r--r-- | drivers/clk/pistachio/clk.h | 14 |
3 files changed, 80 insertions, 30 deletions
diff --git a/drivers/clk/pistachio/clk-pistachio.c b/drivers/clk/pistachio/clk-pistachio.c index 8c0fe8828..c4ceb5eaf 100644 --- a/drivers/clk/pistachio/clk-pistachio.c +++ b/drivers/clk/pistachio/clk-pistachio.c @@ -159,9 +159,15 @@ PNAME(mux_debug) = { "mips_pll_mux", "rpu_v_pll_mux", "wifi_pll_mux", "bt_pll_mux" }; static u32 mux_debug_idx[] = { 0x0, 0x1, 0x2, 0x4, 0x8, 0x10 }; -static unsigned int pistachio_critical_clks[] __initdata = { - CLK_MIPS, - CLK_PERIPH_SYS, +static unsigned int pistachio_critical_clks_core[] __initdata = { + CLK_MIPS +}; + +static unsigned int pistachio_critical_clks_sys[] __initdata = { + PERIPH_CLK_SYS, + PERIPH_CLK_SYS_BUS, + PERIPH_CLK_DDR, + PERIPH_CLK_ROM, }; static void __init pistachio_clk_init(struct device_node *np) @@ -193,8 +199,8 @@ static void __init pistachio_clk_init(struct device_node *np) pistachio_clk_register_provider(p); - pistachio_clk_force_enable(p, pistachio_critical_clks, - ARRAY_SIZE(pistachio_critical_clks)); + pistachio_clk_force_enable(p, pistachio_critical_clks_core, + ARRAY_SIZE(pistachio_critical_clks_core)); } CLK_OF_DECLARE(pistachio_clk, "img,pistachio-clk", pistachio_clk_init); @@ -261,6 +267,9 @@ static void __init pistachio_clk_periph_init(struct device_node *np) ARRAY_SIZE(pistachio_periph_gates)); pistachio_clk_register_provider(p); + + pistachio_clk_force_enable(p, pistachio_critical_clks_sys, + ARRAY_SIZE(pistachio_critical_clks_sys)); } CLK_OF_DECLARE(pistachio_clk_periph, "img,pistachio-clk-periph", pistachio_clk_periph_init); diff --git a/drivers/clk/pistachio/clk-pll.c b/drivers/clk/pistachio/clk-pll.c index e17dada0d..c9b459821 100644 --- a/drivers/clk/pistachio/clk-pll.c +++ b/drivers/clk/pistachio/clk-pll.c @@ -65,6 +65,12 @@ #define MIN_OUTPUT_FRAC 12000000UL #define MAX_OUTPUT_FRAC 1600000000UL +/* Fractional PLL operating modes */ +enum pll_mode { + PLL_MODE_FRAC, + PLL_MODE_INT, +}; + struct pistachio_clk_pll { struct clk_hw hw; void __iomem *base; @@ -88,12 +94,10 @@ static inline void pll_lock(struct pistachio_clk_pll *pll) cpu_relax(); } -static inline u32 do_div_round_closest(u64 dividend, u32 divisor) +static inline u64 do_div_round_closest(u64 dividend, u64 divisor) { dividend += divisor / 2; - do_div(dividend, divisor); - - return dividend; + return div64_u64(dividend, divisor); } static inline struct pistachio_clk_pll *to_pistachio_pll(struct clk_hw *hw) @@ -101,6 +105,29 @@ static inline struct pistachio_clk_pll *to_pistachio_pll(struct clk_hw *hw) return container_of(hw, struct pistachio_clk_pll, hw); } +static inline enum pll_mode pll_frac_get_mode(struct clk_hw *hw) +{ + struct pistachio_clk_pll *pll = to_pistachio_pll(hw); + u32 val; + + val = pll_readl(pll, PLL_CTRL3) & PLL_FRAC_CTRL3_DSMPD; + return val ? PLL_MODE_INT : PLL_MODE_FRAC; +} + +static inline void pll_frac_set_mode(struct clk_hw *hw, enum pll_mode mode) +{ + struct pistachio_clk_pll *pll = to_pistachio_pll(hw); + u32 val; + + val = pll_readl(pll, PLL_CTRL3); + if (mode == PLL_MODE_INT) + val |= PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_DACPD; + else + val &= ~(PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_DACPD); + + pll_writel(pll, val, PLL_CTRL3); +} + static struct pistachio_pll_rate_table * pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref, unsigned long fout) @@ -136,8 +163,7 @@ static int pll_gf40lp_frac_enable(struct clk_hw *hw) u32 val; val = pll_readl(pll, PLL_CTRL3); - val &= ~(PLL_FRAC_CTRL3_PD | PLL_FRAC_CTRL3_DACPD | - PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_FOUTPOSTDIVPD | + val &= ~(PLL_FRAC_CTRL3_PD | PLL_FRAC_CTRL3_FOUTPOSTDIVPD | PLL_FRAC_CTRL3_FOUT4PHASEPD | PLL_FRAC_CTRL3_FOUTVCOPD); pll_writel(pll, val, PLL_CTRL3); @@ -173,7 +199,7 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate, struct pistachio_clk_pll *pll = to_pistachio_pll(hw); struct pistachio_pll_rate_table *params; int enabled = pll_gf40lp_frac_is_enabled(hw); - u32 val, vco, old_postdiv1, old_postdiv2; + u64 val, vco, old_postdiv1, old_postdiv2; const char *name = __clk_get_name(hw->clk); if (rate < MIN_OUTPUT_FRAC || rate > MAX_OUTPUT_FRAC) @@ -183,17 +209,21 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate, if (!params || !params->refdiv) return -EINVAL; - vco = params->fref * params->fbdiv / params->refdiv; + /* calculate vco */ + vco = params->fref; + vco *= (params->fbdiv << 24) + params->frac; + vco = div64_u64(vco, params->refdiv << 24); + if (vco < MIN_VCO_FRAC_FRAC || vco > MAX_VCO_FRAC_FRAC) - pr_warn("%s: VCO %u is out of range %lu..%lu\n", name, vco, + pr_warn("%s: VCO %llu is out of range %lu..%lu\n", name, vco, MIN_VCO_FRAC_FRAC, MAX_VCO_FRAC_FRAC); - val = params->fref / params->refdiv; + val = div64_u64(params->fref, params->refdiv); if (val < MIN_PFD) - pr_warn("%s: PFD %u is too low (min %lu)\n", + pr_warn("%s: PFD %llu is too low (min %lu)\n", name, val, MIN_PFD); if (val > vco / 16) - pr_warn("%s: PFD %u is too high (max %u)\n", + pr_warn("%s: PFD %llu is too high (max %llu)\n", name, val, vco / 16); val = pll_readl(pll, PLL_CTRL1); @@ -227,6 +257,12 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate, (params->postdiv2 << PLL_FRAC_CTRL2_POSTDIV2_SHIFT); pll_writel(pll, val, PLL_CTRL2); + /* set operating mode */ + if (params->frac) + pll_frac_set_mode(hw, PLL_MODE_FRAC); + else + pll_frac_set_mode(hw, PLL_MODE_INT); + if (enabled) pll_lock(pll); @@ -237,8 +273,7 @@ static unsigned long pll_gf40lp_frac_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct pistachio_clk_pll *pll = to_pistachio_pll(hw); - u32 val, prediv, fbdiv, frac, postdiv1, postdiv2; - u64 rate = parent_rate; + u64 val, prediv, fbdiv, frac, postdiv1, postdiv2, rate; val = pll_readl(pll, PLL_CTRL1); prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK; @@ -251,7 +286,13 @@ static unsigned long pll_gf40lp_frac_recalc_rate(struct clk_hw *hw, PLL_FRAC_CTRL2_POSTDIV2_MASK; frac = (val >> PLL_FRAC_CTRL2_FRAC_SHIFT) & PLL_FRAC_CTRL2_FRAC_MASK; - rate *= (fbdiv << 24) + frac; + /* get operating mode (int/frac) and calculate rate accordingly */ + rate = parent_rate; + if (pll_frac_get_mode(hw) == PLL_MODE_FRAC) + rate *= (fbdiv << 24) + frac; + else + rate *= (fbdiv << 24); + rate = do_div_round_closest(rate, (prediv * postdiv1 * postdiv2) << 24); return rate; @@ -279,7 +320,7 @@ static int pll_gf40lp_laint_enable(struct clk_hw *hw) u32 val; val = pll_readl(pll, PLL_CTRL1); - val &= ~(PLL_INT_CTRL1_PD | PLL_INT_CTRL1_DSMPD | + val &= ~(PLL_INT_CTRL1_PD | PLL_INT_CTRL1_FOUTPOSTDIVPD | PLL_INT_CTRL1_FOUTVCOPD); pll_writel(pll, val, PLL_CTRL1); @@ -325,12 +366,12 @@ static int pll_gf40lp_laint_set_rate(struct clk_hw *hw, unsigned long rate, if (!params || !params->refdiv) return -EINVAL; - vco = params->fref * params->fbdiv / params->refdiv; + vco = div_u64(params->fref * params->fbdiv, params->refdiv); if (vco < MIN_VCO_LA || vco > MAX_VCO_LA) pr_warn("%s: VCO %u is out of range %lu..%lu\n", name, vco, MIN_VCO_LA, MAX_VCO_LA); - val = params->fref / params->refdiv; + val = div_u64(params->fref, params->refdiv); if (val < MIN_PFD) pr_warn("%s: PFD %u is too low (min %lu)\n", name, val, MIN_PFD); diff --git a/drivers/clk/pistachio/clk.h b/drivers/clk/pistachio/clk.h index 52fabbc24..8d45178db 100644 --- a/drivers/clk/pistachio/clk.h +++ b/drivers/clk/pistachio/clk.h @@ -95,13 +95,13 @@ struct pistachio_fixed_factor { } struct pistachio_pll_rate_table { - unsigned long fref; - unsigned long fout; - unsigned int refdiv; - unsigned int fbdiv; - unsigned int postdiv1; - unsigned int postdiv2; - unsigned int frac; + unsigned long long fref; + unsigned long long fout; + unsigned long long refdiv; + unsigned long long fbdiv; + unsigned long long postdiv1; + unsigned long long postdiv2; + unsigned long long frac; }; enum pistachio_pll_type { |