diff options
Diffstat (limited to 'patches.tizen/0114-clk-samsung-exynos4-Add-support-for-PLL46xx-rate-con.patch')
-rw-r--r-- | patches.tizen/0114-clk-samsung-exynos4-Add-support-for-PLL46xx-rate-con.patch | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/patches.tizen/0114-clk-samsung-exynos4-Add-support-for-PLL46xx-rate-con.patch b/patches.tizen/0114-clk-samsung-exynos4-Add-support-for-PLL46xx-rate-con.patch new file mode 100644 index 00000000000..78c9605fa45 --- /dev/null +++ b/patches.tizen/0114-clk-samsung-exynos4-Add-support-for-PLL46xx-rate-con.patch @@ -0,0 +1,235 @@ +From d87c869d7b002395837ae1ca7e37b67301785a67 Mon Sep 17 00:00:00 2001 +From: Tomasz Figa <t.figa@samsung.com> +Date: Tue, 14 May 2013 19:20:03 +0200 +Subject: [PATCH 0114/1302] clk: samsung: exynos4: Add support for PLL46xx rate + configuration + +This patch adds support for rate configuration of PLL46xx, which is used +for EPLL and VPLL on Exynos4210. + +Signed-off-by: Tomasz Figa <t.figa@samsung.com> +Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> +--- + drivers/clk/samsung/clk-exynos4.c | 6 +- + drivers/clk/samsung/clk-pll.c | 124 ++++++++++++++++++++++++++++++++++---- + drivers/clk/samsung/clk-pll.h | 4 +- + 3 files changed, 117 insertions(+), 17 deletions(-) + +diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c +index 8572652..f2a338f 100644 +--- a/drivers/clk/samsung/clk-exynos4.c ++++ b/drivers/clk/samsung/clk-exynos4.c +@@ -1078,9 +1078,11 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so + reg_base + E4210_MPLL_LOCK, pll_4508, + pll45xx_exynos4210_pll45xx_pms); + epll = samsung_clk_register_pll46xx("fout_epll", "fin_pll", +- reg_base + EPLL_CON0, pll_4600); ++ reg_base + EPLL_LOCK, pll_4600, ++ exynos4_epll_pms); + vpll = samsung_clk_register_pll46xx("fout_vpll", "mout_vpllsrc", +- reg_base + VPLL_CON0, pll_4650c); ++ reg_base + VPLL_LOCK, pll_4650c, ++ exynos4_vpll_pms); + } else { + apll = samsung_clk_register_pll35xx("fout_apll", "fin_pll", + reg_base + APLL_LOCK, pll35xx_exynos4412_pms); +diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c +index 86a6423..6be496a 100644 +--- a/drivers/clk/samsung/clk-pll.c ++++ b/drivers/clk/samsung/clk-pll.c +@@ -554,50 +554,141 @@ struct clk * __init samsung_clk_register_pll45xx(const char *name, + + #define PLL46XX_KDIV_MASK (0xFFFF) + #define PLL4650C_KDIV_MASK (0xFFF) ++#define PLL46XX_MFR_MASK 0x3f ++#define PLL46XX_MRR_MASK 0x1f + #define PLL46XX_KDIV_SHIFT (0) ++#define PLL46XX_MFR_SHIFT 16 ++#define PLL46XX_MRR_SHIFT 24 ++ ++#define PLL46XX_PLL_LOCK 0x0 ++#define PLL46XX_PLL_CON0 0x100 ++#define PLL46XX_PLL_CON1 0x104 ++ ++#define PLL46XX_PLL_LOCK_CONST 3000 ++#define PLL46XX_PLL_CON0_LOCKED (1 << 29) + + struct samsung_clk_pll46xx { + struct clk_hw hw; + enum pll46xx_type type; +- const void __iomem *con_reg; ++ void __iomem *base; ++ struct pll_pms *pms; + }; + + #define to_clk_pll46xx(_hw) container_of(_hw, struct samsung_clk_pll46xx, hw) + ++static inline unsigned long samsung_pll46xx_calc_f_out(u64 f_in, ++ u32 p, u32 m, u32 s, u32 k, enum pll46xx_type type) ++{ ++ u8 shift = (type == pll_4600) ? 16 : 10; ++ ++ f_in *= (m << shift) + k; ++ do_div(f_in, (p << s)); ++ ++ return (unsigned long)(f_in >> shift); ++} ++ + static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + { + struct samsung_clk_pll46xx *pll = to_clk_pll46xx(hw); +- u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift; +- u64 fvco = parent_rate; ++ u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1; + +- pll_con0 = __raw_readl(pll->con_reg); +- pll_con1 = __raw_readl(pll->con_reg + 4); ++ pll_con0 = __raw_readl(pll->base + PLL46XX_PLL_CON0); ++ pll_con1 = __raw_readl(pll->base + PLL46XX_PLL_CON1); + mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK; + pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK; + sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK; + kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK : + pll_con1 & PLL46XX_KDIV_MASK; + +- shift = pll->type == pll_4600 ? 16 : 10; +- fvco *= (mdiv << shift) + kdiv; +- do_div(fvco, (pdiv << sdiv)); +- fvco >>= shift; ++ return samsung_pll46xx_calc_f_out(parent_rate, ++ pdiv, mdiv, sdiv, kdiv, pll->type); ++} + +- return (unsigned long)fvco; ++static long samsung_pll46xx_round_rate(struct clk_hw *hw, ++ unsigned long drate, unsigned long *prate) ++{ ++ struct samsung_clk_pll46xx *pll = to_clk_pll46xx(hw); ++ struct pll_pms *pms = pll->pms; ++ int i; ++ ++ if (!pms) { ++ pr_err("%s: no pms table passed", __func__); ++ return samsung_pll46xx_recalc_rate(hw, *prate); ++ } ++ ++ i = get_index(drate, pms); ++ if (i >= 0) ++ return pms[i].f_out; ++ ++ return samsung_pll46xx_recalc_rate(hw, *prate); ++} ++ ++static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate, ++ unsigned long prate) ++{ ++ struct samsung_clk_pll46xx *pll = to_clk_pll46xx(hw); ++ struct pll_pms *pms = pll->pms; ++ u32 tmp; ++ int index; ++ ++ if (!pms) { ++ pr_err("%s: no pms table passed", __func__); ++ return -ENOTSUPP; ++ } ++ ++ index = get_index(drate, pms); ++ if (index < 0) ++ return index; ++ ++ /* Define PLL lock time */ ++ __raw_writel(pms[index].p * PLL46XX_PLL_LOCK_CONST, ++ pll->base + PLL46XX_PLL_LOCK); ++ ++ /* Change PLL divisors */ ++ tmp = __raw_readl(pll->base + PLL46XX_PLL_CON0); ++ tmp &= ~((PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) | ++ (PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT) | ++ (PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT)); ++ tmp |= (pms[index].p << PLL46XX_PDIV_SHIFT) | ++ (pms[index].m << PLL46XX_MDIV_SHIFT) | ++ (pms[index].s << PLL46XX_SDIV_SHIFT); ++ __raw_writel(tmp, pll->base + PLL46XX_PLL_CON0); ++ ++ tmp = __raw_readl(pll->base + PLL46XX_PLL_CON1); ++ tmp &= ~((PLL46XX_KDIV_MASK << PLL46XX_KDIV_SHIFT) | ++ (PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT) | ++ (PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT)); ++ tmp |= (pms[index].k << PLL46XX_KDIV_SHIFT) | ++ (pms[index].mrr << PLL46XX_MRR_SHIFT) | ++ (pms[index].mfr << PLL46XX_MFR_SHIFT); ++ __raw_writel(tmp, pll->base + PLL46XX_PLL_CON1); ++ ++ /* Wait for locking */ ++ do { ++ cpu_relax(); ++ tmp = __raw_readl(pll->base + PLL46XX_PLL_CON0); ++ } while (!(tmp & PLL46XX_PLL_CON0_LOCKED)); ++ ++ return 0; + } + ++ + static const struct clk_ops samsung_pll46xx_clk_ops = { + .recalc_rate = samsung_pll46xx_recalc_rate, ++ .round_rate = samsung_pll46xx_round_rate, ++ .set_rate = samsung_pll46xx_set_rate, + }; + + struct clk * __init samsung_clk_register_pll46xx(const char *name, +- const char *pname, const void __iomem *con_reg, +- enum pll46xx_type type) ++ const char *pname, void __iomem *base, ++ enum pll46xx_type type, struct pll_pms *pms) + { + struct samsung_clk_pll46xx *pll; + struct clk *clk; + struct clk_init_data init; ++ unsigned long parent_rate; ++ unsigned int i; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) { +@@ -612,8 +703,9 @@ struct clk * __init samsung_clk_register_pll46xx(const char *name, + init.num_parents = 1; + + pll->hw.init = &init; +- pll->con_reg = con_reg; ++ pll->base = base; + pll->type = type; ++ pll->pms = pms; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) { +@@ -625,6 +717,12 @@ struct clk * __init samsung_clk_register_pll46xx(const char *name, + if (clk_register_clkdev(clk, name, NULL)) + pr_err("%s: failed to register lookup for %s", __func__, name); + ++ /* Fill in received frequency table */ ++ parent_rate = clk_get_rate(clk_get_parent(clk)); ++ for (i = 0; pms[i].f_out != F_OUT_INVAL; i++) ++ pms[i].f_out = samsung_pll46xx_calc_f_out(parent_rate, ++ pms[i].p, pms[i].m, pms[i].s, pms[i].k, type); ++ + return clk; + } + +diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h +index 3fae687..c00c2bd 100644 +--- a/drivers/clk/samsung/clk-pll.h ++++ b/drivers/clk/samsung/clk-pll.h +@@ -47,8 +47,8 @@ extern struct clk * __init samsung_clk_register_pll45xx(const char *name, + const char *pname, void __iomem *base_reg, + enum pll45xx_type type, struct pll_pms *pms); + extern struct clk * __init samsung_clk_register_pll46xx(const char *name, +- const char *pname, const void __iomem *con_reg, +- enum pll46xx_type type); ++ const char *pname, void __iomem *base, ++ enum pll46xx_type type, struct pll_pms *pms); + extern struct clk * __init samsung_clk_register_pll2550x(const char *name, + const char *pname, const void __iomem *reg_base, + const unsigned long offset); +-- +1.8.3.2 + |